文档首页/ 云容器引擎 CCE/ 最佳实践/ 弹性伸缩/ 通过Nginx Ingress对多个应用进行弹性伸缩
更新时间:2024-10-10 GMT+08:00
分享

通过Nginx Ingress对多个应用进行弹性伸缩

在实际的生产环境中,应用多实例部署可以提高应用的稳定性和可靠性,但也会增加资源的浪费和成本。因此,在进行多实例部署时,需要权衡资源利用率和应用性能之间的平衡,但手动调节实例数量存在伸缩不及时的问题,难以达到最佳的效果。

如果该应用使用Nginx Ingress实现对外的流量路由转发,您可以使用nginx_ingress_controller_requests的指标为应用配置HPA策略,可以实现随着流量的变化动态调整Pod实例数的功能,优化资源利用率。

前提条件

  • 集群中已安装NGINX Ingress控制器插件。
  • 集群中已安装云原生监控插件(server模式)。
  • 已使用kubectl命令行工具或CloudShell连接集群。
  • 已安装压力测试工具Apache Benchmark。

创建业务负载和对应的Service

本文以两个服务通过Nginx Ingress实现对外的流量路由为例进行演示。

  1. 创建应用test-app和对应Service。

    1. 创建test-app.yaml文件。
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: test-app
        labels:
          app: test-app
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: test-app
        template:
          metadata:
            labels:
              app: test-app
          spec:
            containers:
            - image: skto/sample-app:v2
              name: metrics-provider
              ports:
              - name: http
                containerPort: 8080
      --- 
      apiVersion: v1
      kind: Service
      metadata:
        name: test-app
        namespace: default
        labels:
          app: test-app
      spec:
        ports:
          - port: 8080
            name: http
            protocol: TCP
            targetPort: 8080
        selector: 
          app: test-app 
        type: ClusterIP
    2. 部署test-app和对应Service。
      kubectl apply -f test-app.yaml

  2. 创建应用sample-app和对应Service。

    1. 创建sample-app.yaml文件。
      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: skto/sample-app:v2
              name: metrics-provider
              ports:
              - name: http
                containerPort: 8080
      --- 
      apiVersion: v1
      kind: Service
      metadata:
        name: sample-app
        namespace: default
        labels:
          app: sample-app
      spec:
        ports:
          - port: 80
            name: http
            protocol: TCP
            targetPort: 8080
        selector:
          app: sample-app
        type: ClusterIP
    2. 部署sample-app和对应Service。
      kubectl apply -f sample-app.yaml

  3. 部署Ingress资源。

    1. 创建ingress.yaml文件。
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: test-ingress
        namespace: default
      spec:
        ingressClassName: nginx
        rules:
          - host: test.example.com
            http:
              paths:
                - backend:
                    service:
                      name: sample-app
                      port:
                        number: 80
                  path: /
                  pathType: ImplementationSpecific
                - backend:
                    service:
                      name: test-app
                      port:
                        number: 8080
                  path: /home
                  pathType: ImplementationSpecific
      • host:指定服务访问域名。本示例使用test.example.com。
      • path:指定访问的URL路径。请求到来之后会根据路由规则匹配相应的Service,然后通过Service访问相应的Pod。
      • backend:由Service名称和Service端口组成,指定当前path转发的Service。
    2. 部署Ingress资源。
      kubectl apply -f ingress.yaml
    3. 获取Ingress资源。
      kubectl get ingress -o wide

    4. 部署成功后,登录集群节点,将服务域名和nginx-ingress的ELB服务地址添加到节点本地hosts文件。nginx-ingress的ELB服务地址即为3.c查询的ADDRESS IP地址。
      export NGINXELB=xx.xx.xx.xx 
      echo -n "${NGINXELB}  test.example.com" >> /etc/hosts
    5. 登录集群节点通过/和/home两个路径分别访问Host地址。Nginx Ingress Controller会根据上方配置分别访问sample-app和test-app。
      # curl test.example.com/
      Hello from '/' path!
      
      # curl test.example.com/home
      Hello from '/home' path!

修改普罗配置项user-adapter-config

  1. 执行以下命令编辑user-adapter-config配置项。

    kubectl -n monitoring edit configmap user-adapter-config

  2. 添加以下规则到adapter的configmap。

    apiVersion: v1
    data:
      config.yaml: |
        rules:
        - metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)
          name:
            as: ${1}_per_second
            matches: ^(.*)_requests
          resources:
            namespaced: false
            overrides:
              exported_namespace:
                resource: namespace
              service:
                resource: service
          seriesQuery: nginx_ingress_controller_requests
        resourceRules:
          cpu:
            containerQuery: sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>,container!="",pod!=""}[1m])) by (<<.GroupBy>>)
            nodeQuery: sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>, id='/'}[1m])) by (<<.GroupBy>>)
            resources:
              overrides:
                instance:
                  resource: node
                namespace:
                  resource: namespace
                pod:
                  resource: pod
            containerLabel: container
          memory:
            containerQuery: sum(container_memory_working_set_bytes{<<.LabelMatchers>>,container!="",pod!=""}) by (<<.GroupBy>>)
            nodeQuery: sum(container_memory_working_set_bytes{<<.LabelMatchers>>,id='/'}) by (<<.GroupBy>>)
            resources:
              overrides:
                instance:
                  resource: node
                namespace:
                  resource: namespace
                pod:
                  resource: pod
            containerLabel: container

  3. 重启custom-metrics-apiserver服务。

    kubectl -n monitoring delete pod -l app=custom-metrics-apiserver

  4. 登录集群节点通过/和/home两个路径持续访问Host地址。

    # curl test.example.com/
    Hello from '/' path!
    
    # curl test.example.com/home
    Hello from '/home' path!

  5. 执行命令查看指标是否添加成功。

    kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/namespaces/default/services/*/nginx_ingress_controller_per_second | python -m json.tool

创建HPA规则

  1. 创建hpa.yaml文件,配置test-app和sample-app工作负载通过普罗指标进行弹性伸缩。

    apiVersion: autoscaling/v2 
    kind: HorizontalPodAutoscaler 
    metadata: 
      name: sample-hpa  # HPA名称
    spec: 
      scaleTargetRef: 
        apiVersion: apps/v1 
        kind: Deployment 
        name: sample-app  # 无状态工作负载名称
      minReplicas: 1      # 最小实例数
      maxReplicas: 10     # 最大实例数
      metrics: 
        - type: Object 
          object: 
            metric: 
              name: nginx_ingress_controller_per_second  # 指标
            describedObject: 
              apiVersion: v1 
              kind: service 
              name: sample-app  # 无状态工作负载的service
            target: 
              type: Value 
              value: 30   # 指标满足(实际值/30)±0.1范围就会触发扩缩容
    --- 
    apiVersion: autoscaling/v2 
    kind: HorizontalPodAutoscaler 
    metadata: 
      name: test-hpa 
    spec: 
      scaleTargetRef: 
        apiVersion: apps/v1 
        kind: Deployment 
        name: test-app 
      minReplicas: 1 
      maxReplicas: 10 
      metrics: 
        - type: Object 
          object: 
            metric: 
              name: nginx_ingress_controller_per_second 
            describedObject: 
              apiVersion: v1 
              kind: service 
              name: test-app 
            target: 
              type: Value 
              value: 30

  2. 部署HPA策略。

    kubectl apply -f hpa.yaml

  3. 查看HPA部署情况。

    kubectl get hpa

压力测试验证

  1. 登录集群节点,对/home路径进行压力测试。

    ab -c 50 -n 5000 test.example.com/home

  2. 查看HPA情况

    kubectl get hpa

  3. 登录集群节点,对根路径进行压力测试。

    ab -c 50 -n 5000 test.example.com/

  4. 查看HPA情况。

    kubectl get hpa

    和压力测试前查询的HPA指标对比,业务应用在请求量增大超过阈值的情况下成功扩容。

相关文档