Todos los productos
Search
Centro de documentos

Container Service for Kubernetes:Use ASM metrics to automatically scale workloads

Última actualización: Sep 21, 2026

Service Mesh (ASM) recopila datos de telemetría de los clústeres ACK y ACS de forma no intrusiva. A partir de estos datos genera métricas de servicio basadas en las cuatro señales doradas: latencia, tráfico, errores y saturación. Este tema explica cómo configurar un Horizontal Pod Autoscaler (HPA) que escala las cargas de trabajo según estas métricas de ASM. De este modo, el escalado responde a patrones de tráfico reales y no solo al uso de CPU o memoria.

Funcionamiento

ASM expone las métricas de servicio (como las solicitudes por segundo) a Prometheus. Un adaptador de métricas personalizadas, kube-metrics-adapter, registra estas métricas de Prometheus en la capa de agregación de Kubernetes. Gracias a esto, los HPA pueden consultarlas mediante la API de métricas personalizadas.

image

El flujo completo es el siguiente:

  1. ASM recopila las métricas de solicitud y las escribe en Prometheus.

  2. kube-metrics-adapter consulta Prometheus y registra las métricas como métricas externas en Kubernetes.

  3. El HPA sondea la API de métricas externas cada 30 segundos y ajusta la cantidad de réplicas cuando el valor de la métrica cruza el umbral.

Para consultar la lista completa de métricas que genera ASM, consulte Istio Standard Metrics.

Requisitos previos

Antes de empezar, asegúrese de contar con lo siguiente:

Paso 1: Habilitar el monitoreo de Prometheus para la instancia de ASM

Siga las instrucciones de Collect metrics to Managed Service for Prometheus para habilitar la recolección de métricas de Prometheus en su instancia de ASM.

Paso 2: Desplegar el adaptador de métricas personalizadas

El adaptador de métricas personalizadas (kube-metrics-adapter) conecta las métricas de Prometheus con la API de métricas externas de Kubernetes. Así, los HPA consultan las métricas de ASM directamente.

  1. Instale kube-metrics-adapter en el namespace kube-system mediante Helm 3. Establezca prometheus.url con la dirección interna del clúster de su instancia de Prometheus. Para obtener el origen del chart, consulte kube-metrics-adapter.

    Parámetro

    Descripción

    asm-custom-metrics

    Nombre de la versión de Helm

    prometheus.url

    Dirección interna del clúster de la instancia de Prometheus que recopila las métricas de ASM

    helm -n kube-system install asm-custom-metrics ./kube-metrics-adapter \
      --set prometheus.url=http://prometheus.istio-system.svc:9090
  2. Compruebe que el adaptador se está ejecutando:

    1. Verifique que el grupo de API autoscaling/v2beta esté registrado:

      kubectl api-versions | grep "autoscaling/v2beta"

      Resultado esperado:

      autoscaling/v2beta
    2. Compruebe que el pod del adaptador se está ejecutando:

      kubectl get po -n kube-system | grep metrics-adapter

      Resultado esperado:

      asm-custom-metrics-kube-metrics-adapter-85c6d5d865-2****   1/1   Running   0   19s
    3. Verifique que la API de métricas externas esté disponible (aún no hay métricas registradas):

      kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1" | jq .

      Resultado esperado:

      {
        "kind": "APIResourceList",
        "apiVersion": "v1",
        "groupVersion": "external.metrics.k8s.io/v1beta1",
        "resources": []
      }

Paso 3: Desplegar una aplicación de ejemplo

En este paso se despliega una aplicación podinfo y un servicio de pruebas de carga en el namespace test. Esto le permitirá activar y observar el escalado automático más adelante.

  1. Cree el namespace test. Consulte Manage namespaces and resource quotas.

  2. Habilite la inyección automática del proxy sidecar en el namespace test. Consulte Enable automatic sidecar proxy injection.

  3. Despliegue la aplicación podinfo. Cree un archivo llamado podinfo.yaml con el contenido a continuación y aplíquelo.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: podinfo
      namespace: test
      labels:
        app: podinfo
    spec:
      minReadySeconds: 5
      strategy:
        rollingUpdate:
          maxUnavailable: 0
        type: RollingUpdate
      selector:
        matchLabels:
          app: podinfo
      template:
        metadata:
          annotations:
            prometheus.io/scrape: "true"
          labels:
            app: podinfo
        spec:
          containers:
          - name: podinfod
            image: stefanprodan/podinfo:latest
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 9898
              name: http
              protocol: TCP
            command:
            - ./podinfo
            - --port=9898
            - --level=info
            livenessProbe:
              exec:
                command:
                - podcli
                - check
                - http
                - localhost:9898/healthz
              initialDelaySeconds: 5
              timeoutSeconds: 5
            readinessProbe:
              exec:
                command:
                - podcli
                - check
                - http
                - localhost:9898/readyz
              initialDelaySeconds: 5
              timeoutSeconds: 5
            resources:
              limits:
                cpu: 2000m
                memory: 512Mi
              requests:
                cpu: 100m
                memory: 64Mi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: podinfo
      namespace: test
      labels:
        app: podinfo
    spec:
      type: ClusterIP
      ports:
        - name: http
          port: 9898
          targetPort: 9898
          protocol: TCP
      selector:
        app: podinfo
    kubectl apply -n test -f podinfo.yaml
  4. Despliegue el servicio de pruebas de carga. Cree un archivo llamado loadtester.yaml con el contenido a continuación y aplíquelo.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: loadtester
      namespace: test
      labels:
        app: loadtester
    spec:
      selector:
        matchLabels:
          app: loadtester
      template:
        metadata:
          labels:
            app: loadtester
          annotations:
            prometheus.io/scrape: "true"
        spec:
          containers:
            - name: loadtester
              image: weaveworks/flagger-loadtester:0.18.0
              imagePullPolicy: IfNotPresent
              ports:
                - name: http
                  containerPort: 8080
              command:
                - ./loadtester
                - -port=8080
                - -log-level=info
                - -timeout=1h
              livenessProbe:
                exec:
                  command:
                    - wget
                    - --quiet
                    - --tries=1
                    - --timeout=4
                    - --spider
                    - http://localhost:8080/healthz
                timeoutSeconds: 5
              readinessProbe:
                exec:
                  command:
                    - wget
                    - --quiet
                    - --tries=1
                    - --timeout=4
                    - --spider
                    - http://localhost:8080/healthz
                timeoutSeconds: 5
              resources:
                limits:
                  memory: "512Mi"
                  cpu: "1000m"
                requests:
                  memory: "32Mi"
                  cpu: "10m"
              securityContext:
                readOnlyRootFilesystem: true
                runAsUser: 10001
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: loadtester
      namespace: test
      labels:
        app: loadtester
    spec:
      type: ClusterIP
      selector:
        app: loadtester
      ports:
        - name: http
          port: 80
          protocol: TCP
          targetPort: http
    kubectl apply -n test -f loadtester.yaml
  5. Compruebe que ambas cargas de trabajo se estén ejecutando:

    kubectl get pod -n test

    Resultado esperado (ambos pods muestran 2/2 Running, lo cual indica que el contenedor de la aplicación y el sidecar de Istio están listos):

    NAME                          READY   STATUS    RESTARTS   AGE
    loadtester-64df4846b9-nxhvv   2/2     Running   0          2m8s
    podinfo-6d845cc8fc-26xbq      2/2     Running   0          11m
  6. Envíe una ráfaga breve de tráfico para confirmar que la configuración funciona de extremo a extremo:

    export loadtester=$(kubectl -n test get pod -l "app=loadtester" -o jsonpath='{.items[0].metadata.name}')
    kubectl -n test exec -it ${loadtester} -c loadtester -- hey -z 5s -c 10 -q 2 http://podinfo.test:9898

    Si hey devuelve una respuesta exitosa, significa que el servicio podinfo es accesible a través de la malla.

Paso 4: Configurar un HPA con las métricas de ASM

Defina un HPA que escale el despliegue de podinfo según la cantidad de solicitudes entrantes por segundo. Esta medición se obtiene de la métrica istio_requests_total en Prometheus.

El HPA utiliza dos elementos de Kubernetes de manera conjunta:

  • Una anotación que integra la consulta PromQL y le asigna un nombre (processed-requests-per-second).

  • Una referencia de métrica en spec.metrics que apunta a la consulta nombrada y establece el umbral de escalado.

Cree un archivo llamado hpa.yaml con el contenido a continuación y aplíquelo:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: podinfo
  namespace: test
  annotations:
    # The annotation key format is:
    # metric-config.external.prometheus-query.prometheus/<query-name>
    # The query-name must match the value of the matchLabels selector below.
    metric-config.external.prometheus-query.prometheus/processed-requests-per-second: |
      sum(
          rate(
              istio_requests_total{
                destination_workload="podinfo",
                destination_workload_namespace="test",
                reporter="destination"
              }[1m]
          )
      )
spec:
  maxReplicas: 10
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  metrics:
    - type: External
      external:
        metric:
          name: prometheus-query
          selector:
            matchLabels:
              query-name: processed-requests-per-second  # matches the annotation key suffix above
        target:
          type: AverageValue
          averageValue: "10"  # scale out when average RPS per replica exceeds 10
kubectl apply -f hpa.yaml

Explicación de los campos principales:

Campo

Valor

Descripción

Anotación metric-config.external.prometheus-query.prometheus/<query-name>

Expresión PromQL

Define la consulta que kube-metrics-adapter ejecuta contra Prometheus. El sufijo <query-name> debe coincidir con la etiqueta query-name en spec.metrics.

Etiqueta query-name

processed-requests-per-second

Vincula la anotación (la consulta PromQL) con la referencia de métrica en spec.metrics.

averageValue

"10"

El HPA escala horizontalmente cuando el promedio de solicitudes por segundo por réplica supera 10.

minReplicas / maxReplicas

1 / 10

Límites de la cantidad de réplicas.

Después de aplicar el HPA, compruebe que la métrica externa ya esté registrada:

kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1" | jq .

Resultado esperado:

{
  "kind": "APIResourceList",
  "apiVersion": "v1",
  "groupVersion": "external.metrics.k8s.io/v1beta1",
  "resources": [
    {
      "name": "prometheus-query",
      "singularName": "",
      "namespaced": true,
      "kind": "ExternalMetricValueList",
      "verbs": [
        "get"
      ]
    }
  ]
}

La entrada prometheus-query en resources confirma que kube-metrics-adapter registró la métrica y que el HPA está activo.

Comprobación del escalado automático

  1. Abra una terminal e inicie una carga sostenida contra podinfo (5 minutos, 10 usuarios simultáneos y 5 solicitudes por segundo cada uno):

    kubectl -n test exec -it ${loadtester} -c loadtester -- sh
    ~ $ hey -z 5m -c 10 -q 5 http://podinfo.test:9898
  2. En otra terminal, observe cómo el HPA escala verticalmente:

    De forma predeterminada, las métricas se sincronizan cada 30 segundos. Además, el HPA aplica un periodo de enfriamiento de 3 a 5 minutos entre eventos de escalado para evitar oscilaciones.
    watch kubectl -n test get hpa/podinfo

    Cuando la carga supera el umbral, el HPA escala horizontalmente:

    NAME      REFERENCE            TARGETS          MINPODS   MAXPODS   REPLICAS   AGE
    podinfo   Deployment/podinfo   8308m/10 (avg)   1         10        6          124m

    El valor 8308m corresponde a la notación de milésimas de Kubernetes y equivale a 8.308 solicitudes por segundo. Como el promedio de solicitudes por segundo por réplica (8.3) está por debajo del umbral de 10, el HPA se estabilizó en 6 réplicas. Si la carga fuera mayor, el HPA seguiría escalando hasta alcanzar el máximo de 10 réplicas.

  3. Al terminar la prueba de carga, la tasa de solicitudes cae a cero. El HPA comienza a reducir la escala y, en unos minutos, la cantidad de réplicas vuelve a 1.