【Karmada使用教程】FederatedHPA 基于自定义指标扩缩容

举报
云容器大未来 发表于 2025/12/18 10:45:33 2025/12/18
【摘要】 Karmada 是开放的多云多集群容器编排引擎,旨在帮助用户在多云环境下部署和运维业务应用。凭借兼容 Kubernetes 原生 API 的能力,Karmada 可以平滑迁移单集群工作负载,并且仍可保持与 Kubernetes 周边生态工具链协同。本系列文章将介绍Karmada的使用教程,本文介绍如何通过FederatedHPA 基于自定义指标扩缩容。

Karmada 是开放的多云多集群容器编排引擎,旨在帮助用户在多云环境下部署和运维业务应用。凭借兼容 Kubernetes 原生 API 的能力,Karmada 可以平滑迁移单集群工作负载,并且仍可保持与 Kubernetes 周边生态工具链协同。本系列文章将介绍Karmada的使用教程,本文介绍如何通过FederatedHPA 基于自定义指标扩缩容

KARMADA.png

在 Karmada 中,为了自动扩展工作负载以满足需求,FederatedHPA 会跨多个集群扩/缩容工作负载。

FederatedHPA 不仅支持 CPU 和内存等资源指标,还支持自定义指标,这有助于扩展 FederatedHPA 的使用场景。

本文档将引导您完成这样一个案例:启用 FederatedHPA 利用自定义指标来自动扩缩容跨集群应用。

演示案例将执行以下操作:

  • 指标扩缩容.pngmember1 集群中存在一个示例 Deployment 的 Pod。
  • Service 部署在 member1 和 member2 集群。

  • 请求多集群 Service 并触发 Pod 的自定义指标(http_requests_total)增长。

  • Pod 副本将在 member1 和 member2 集群中扩容。


前提条件

▍Karmada 已安装

您可以参考快速入门安装 Karmada,或直接运行 hack/local-up-karmada.sh 脚本,该脚本也用于运行 E2E 测试。

成员集群网络

确保至少已有两个集群加入 Karmada,并且成员集群之间的容器网络已连通。

  • 如果您使用 hack/local-up-karmada.sh 脚本部署 Karmada,Karmada 中会有 3 个成员集群,并且集群 member1 和 member2 间的容器网络已连通。

  • 您可以使用 Submariner 或其他相关开源项目来连接成员集群之间的网络。

📌 注意:为了防止路由冲突,集群中 Pod 和 Service 的 CIDR 必须互不重叠。

ServiceExport 和 ServiceImport 自定义资源已安装

我们需要在成员集群中安装 ServiceExport 和 ServiceImport 以启用多集群 Service。

在 Karmada 控制平面 上安装了 ServiceExport 和 ServiceImport 后,我们就可以创建 ClusterPropagationPolicy,将以下两个 CRD 分发到成员集群。

# propagate ServiceExport CRD
apiVersion: policy.karmada.io/v1alpha1
kind: ClusterPropagationPolicy
metadata:
  name: serviceexport-policy
spec:
  resourceSelectors:
    - apiVersion: apiextensions.k8s.io/v1
      kind: CustomResourceDefinition
      name: serviceexports.multicluster.x-k8s.io
  placement:
    clusterAffinity:
      clusterNames:
        - member1
        - member2
---        
# propagate ServiceImport CRD
apiVersion: policy.karmada.io/v1alpha1
kind: ClusterPropagationPolicy
metadata:
  name: serviceimport-policy
spec:
  resourceSelectors:
    - apiVersion: apiextensions.k8s.io/v1
      kind: CustomResourceDefinition
      name: serviceimports.multicluster.x-k8s.io
  placement:
    clusterAffinity:
      clusterNames:
        - member1
        - member2

成员集群中已安装 prometheus 和 prometheus-adapter

我们需要为成员集群安装 prometheus 和 prometheus-adapter 以提供自定义 metrics API。 可以通过在成员集群中运行以下命令来安装:

git clone https://github.com/prometheus-operator/kube-prometheus.git
cd kube-prometheus
kubectl apply --server-side -f manifests/setup
kubectl wait \
	--for condition=Established \
	--all CustomResourceDefinition \
	--namespace=monitoring
kubectl apply -f manifests/

我们可以通过下面的命令验证安装:

$ kubectl --kubeconfig=/root/.kube/members.config --context=member1 get po -nmonitoring
NAME                                   READY   STATUS    RESTARTS   AGE
alertmanager-main-0                    2/2     Running   0          30h
alertmanager-main-1                    2/2     Running   0          30h
alertmanager-main-2                    2/2     Running   0          30h
blackbox-exporter-6bc47b9578-zcbb7     3/3     Running   0          30h
grafana-6b68cd6b-vmw74                 1/1     Running   0          30h
kube-state-metrics-597db7f85d-2hpfs    3/3     Running   0          30h
node-exporter-q8hdx                    2/2     Running   0          30h
prometheus-adapter-57d9587488-86ckj    1/1     Running   0          29h
prometheus-adapter-57d9587488-zrt29    1/1     Running   0          29h
prometheus-k8s-0                       2/2     Running   0          30h
prometheus-k8s-1                       2/2     Running   0          30h
prometheus-operator-7d4b94944f-kkwkk   2/2     Running   0          30h

Karmada 控制平面已安装 karmada-metrics-adapter

我们需要在 Karmada 控制平面中安装 karmada-metrics-adapter 以提供 metrics API,通过运行以下命令来安装:

hack/deploy-metrics-adapter.sh ${host_cluster_kubeconfig} ${host_cluster_context} ${karmada_apiserver_kubeconfig} ${karmada_apiserver_context_name}

如果您使用 hack/local-up-karmada.sh 脚本部署 Karmada,将默认安装 karmada-metrics-adapter


 member1 和 member2 集群中部署 Deployment

我们需要在 member1 和 member2 集群中部署示例 Deployment(1 个副本)和 Service。 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-app
  labels:
    app: sample-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
      - image: luxas/autoscale-demo:v0.1.2
        name: metrics-provider
        ports:
        - name: http
          containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: sample-app
  name: sample-app
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: sample-app
  type: ClusterIP
---
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
  name: app-propagation
spec:
  resourceSelectors:
    - apiVersion: apps/v1
      kind: Deployment
      name: sample-app
    - apiVersion: v1
      kind: Service
      name: sample-app
  placement:
    clusterAffinity:
      clusterNames:
        - member1
        - member2
    replicaScheduling:
      replicaDivisionPreference: Weighted
      replicaSchedulingType: Divided
      weightPreference:
        staticWeightList:
          - targetCluster:
              clusterNames:
                - member1
            weight: 1
          - targetCluster:
              clusterNames:
                - member2
            weight: 1

部署完成后,您可以检查 Pod 和 Service 的分发情况:

$ karmadactl get pods --operation-scope members
NAME                                  CLUSTER   READY   STATUS    RESTARTS   AGE
sample-app-9b7d8c9f5-xrnfx            member1   1/1     Running   0          111s
$ karmadactl get svc --operation-scope members
NAME                 CLUSTER   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE     ADOPTION
sample-app           member1   ClusterIP   10.11.29.250    <none>        80/TCP    3m53s   Y


在 member1 和 member2 集群中监控您的应用

为了监控您的应用,您需要配置一个指向该应用的 ServiceMonitor。假设您已配置 Prometheus 实例来使用带有 app:sample-app 标签的 ServiceMonitor,那么请创建一个 ServiceMonitor 以通过 Service 监控应用的指标:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: sample-app
  labels:
    app: sample-app
spec:
  selector:
    matchLabels:
      app: sample-app
  endpoints:
  - port: http
kubectl create -f sample-app.monitor.yaml

现在,您应该可以看到自定义指标 (http_requests_total) 出现在 Prometheus 实例中。通过仪表盘找到指标,并确保其含有 Namespace 和 Pod 标签。如果没有,请检查 ServiceMonitor 中的标签与 Prometheus CRD 中的标签是否匹配。


在 member1 和 member2 集群中启动您的适配器

部署了 prometheus-adapter 之后,为了暴露自定义指标,您需要更新适配器配置。

apiVersion: v1
kind: ConfigMap
metadata:
  name: adapter-config
  namespace: monitoring
data:
  config.yaml: |-
    "rules":
    - "seriesQuery": |
         {namespace!="",__name__!~"^container_.*"}
      "resources":
        "template": "<<.Resource>>"
      "name":
        "matches": "^(.*)_total"
        "as": ""
      "metricsQuery": |
        sum by (<<.GroupBy>>) (
          irate (
            <<.Series>>{<<.LabelMatchers>>}[1m]
          )
        )
kubectl apply -f prom-adapter.config.yaml
# Restart prom-adapter pods
kubectl rollout restart deployment prometheus-adapter -n monitoring


在 member1 和 member2 集群中注册 metrics API

您还需要向 API 聚合器(主 Kubernetes API 服务器的一部分)注册自定义指标 API。为此,您需要创建一个 APIService 资源。

apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  name: v1beta2.custom.metrics.k8s.io
spec:
  group: custom.metrics.k8s.io
  groupPriorityMinimum: 100
  insecureSkipTLSVerify: true
  service:
    name: prometheus-adapter
    namespace: monitoring
  version: v1beta2
  versionPriority: 100
kubectl create -f api-service.yaml

该 API 已注册为 custom.metrics.k8s.io/v1beta2,您可以使用以下命令进行验证:

kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta2/namespaces/default/pods/*/http_requests?selector=app%3Dsample-app"

输出结果类似于:

{
  "kind": "MetricValueList", 
  "apiVersion": "custom.metrics.k8s.io/v1beta2", 
  "metadata": {}, 
  "items": [
    {
      "describedObject": {
        "kind": "Pod", 
        "namespace": "default", 
        "name": "sample-app-9b7d8c9f5-9lw6b", 
        "apiVersion": "/v1"
      }, 
      "metric": {
        "name": "http_requests", 
        "selector": null
      }, 
      "timestamp": "2023-06-14T09:09:54Z", 
      "value": "66m"
    }
  ]
}

如果 karmada-metrics-adapter 安装成功,您也可以在 Karmada 控制平面中使用上述命令进行验证。


在 Karmada 控制平面部署 FederatedHPA

接下来让我们在 Karmada 控制平面中部署 FederatedHPA。

apiVersion: autoscaling.karmada.io/v1alpha1
kind: FederatedHPA
metadata:
  name: sample-app
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: sample-app
  minReplicas: 1
  maxReplicas: 10
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 10
    scaleUp:
      stabilizationWindowSeconds: 10
  metrics:
    - type: Pods
      pods:
        metric:
          name: http_requests
        target:
          averageValue: 700m
          type: Value

部署完成后,您可以检查 FederatedHPA:

NAME          REFERENCE-KIND   REFERENCE-NAME   MINPODS   MAXPODS   REPLICAS   AGE
sample-app    Deployment       sample-app       1         10        1          15d


将 Service 导出到 member1 集群

正如前文所提到的,我们需要一个多集群 Service 来将请求转发到 member1 和 member2 集群中的 Pod,因此让我们创建这个多集群 Service。

  • 在 Karmada 控制平面创建一个 ServiceExport 对象,然后创建一个 PropagationPolicy 将 ServiceExport 对象分发到 member1 和 member2 集群。
apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceExport
metadata:
  name: sample-app
---
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
  name: serve-export-policy
spec:
  resourceSelectors:
    - apiVersion: multicluster.x-k8s.io/v1alpha1
      kind: ServiceExport
      name: sample-app
  placement:
    clusterAffinity:
      clusterNames:
        - member1
        - member2
  • 在 Karmada 控制平面创建一个 ServiceImport 对象,然后创建一个 PropagationPolicy 将 ServiceImport 对象分发到 member1 集群。
apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceImport
metadata:
  name: sample-app
spec:
  type: ClusterSetIP
  ports:
  - port: 80
    protocol: TCP
---
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
  name: serve-import-policy
spec:
  resourceSelectors:
    - apiVersion: multicluster.x-k8s.io/v1alpha1
      kind: ServiceImport
      name: sample-app
  placement:
    clusterAffinity:
      clusterNames:
        - member1

部署完成后,您可以检查多集群 Service:

$ karmadactl get svc --operation-scope members
NAME                    CLUSTER   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   ADOPTION
derived-sample-app      member1   ClusterIP   10.11.59.213    <none>        80/TCP    9h    Y


在 member1 集群中安装 hey http 负载测试工具

为了发送 http 请求,这里我们使用 hey

  • 下载 hey 并复制到 kind 集群容器中。

wget https://hey-release.s3.us-east-2.amazonaws.com/hey_linux_amd64
chmod +x hey_linux_amd64
docker cp hey_linux_amd64 member1-control-plane:/usr/local/bin/hey


测试扩容

  • 首先检查 Pod 的分发情况。
$ karmadactl get pods --operation-scope members
NAME                                  CLUSTER   READY   STATUS    RESTARTS   AGE
sample-app-9b7d8c9f5-xrnfx            member1   1/1     Running   0          111s
  • 检查多集群 Service ip。
$ karmadactl get svc --operation-scope members
NAME                    CLUSTER   TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)   AGE   ADOPTION
derived-sample-app      member1   ClusterIP   10.11.59.213      <none>        80/TCP    20m   Y
  • 使用 hey 请求多集群 Service,以提高 nginx Pod 的自定义指标(http_requests_total)。
docker exec member1-control-plane hey -c 1000 -z 1m http://10.11.59.213/metrics
  • 等待 15 秒,副本将扩容,然后您可以再次检查 Pod 分发状态。
$ karmadactl get po --operation-scope members -l app=sample-app
NAME                         CLUSTER   READY   STATUS    RESTARTS   AGE
sample-app-9b7d8c9f5-454vz   member2   1/1     Running   0          84s
sample-app-9b7d8c9f5-7fjhn   member2   1/1     Running   0          69s
sample-app-9b7d8c9f5-ddf4s   member2   1/1     Running   0          69s
sample-app-9b7d8c9f5-mxqmh   member2   1/1     Running   0          84s
sample-app-9b7d8c9f5-qbc2j   member2   1/1     Running   0          69s
sample-app-9b7d8c9f5-2tgxt   member1   1/1     Running   0          69s
sample-app-9b7d8c9f5-66n9s   member1   1/1     Running   0          69s
sample-app-9b7d8c9f5-fbzps   member1   1/1     Running   0          84s
sample-app-9b7d8c9f5-ldmhz   member1   1/1     Running   0          84s
sample-app-9b7d8c9f5-xrnfx   member1   1/1     Running   0          87m


测试缩容

1 分钟后,负载测试工具将停止运行,然后您可以看到工作负载在多个集群中缩容

$ karmadactl get pods --operation-scope members -l app=sample-app
NAME                         CLUSTER   READY   STATUS    RESTARTS   AGE
sample-app-9b7d8c9f5-xrnfx   member1   1/1     Running   0          91m

更多Karmada云原生多云容器引擎使用教程与技术交流,欢迎关注Karmada社区公众号或添加社区小助手k8s2222,回复Karmada进群。


karmada公众号.jpg

Karmada 公众号

 


Karmada 是CNCF 首个多云多集群容器编排项目(孵化级),旨在帮助用户像使用单个集群一样轻松管理跨云多集群,让基于 Karmada 的多云方案无缝融入云原生技术生态。社区吸引了来自华为、道客、浙江大学、滴滴、腾讯、中国电子云等60多家公司的全球贡献者,广泛分布于22个国家和地区。Karmada 现已在华为云、道客、兴业数金、中国移动、中国联通、携程、360集团、新浪、中通快递等众多企业单位生产应用,为企业提供从单集群到多云架构的平滑演进方案。

Karmada官网:https://karmada.io/

项目地址:https://github.com/karmada-io/karmada

Slack地址:https://slack.cncf.io/(#karmada)

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。