Otimizar o escalonamento automático de pod com base em métricas


Neste tutorial, demonstramos como escalonar automaticamente as cargas de trabalho do Google Kubernetes Engine (GKE) com base nas métricas disponíveis no Cloud Monitoring.

Neste tutorial, é possível configurar o escalonamento automático com base em uma das seguintes métricas:

CPU

Uso da CPU

Escalone com base na porcentagem de utilização de CPUs em nós. Isso pode ser econômico, permitindo maximizar a utilização de recursos da CPU. No entanto, como o uso de CPU é uma métrica posterior, seus usuários podem ter latência enquanto um escalonamento vertical está em andamento.

Pub/Sub

Backlog do Pub/Sub

Escalonar com base em uma métrica externa que informa o número de mensagens não reconhecidas restantes em uma Assinatura do Pub/Sub. Essa prática pode reduzir a latência de maneira eficiente antes de se tornar um problema, mas talvez utilize relativamente mais recursos do que o escalonamento automático com base na utilização de CPU.

Métrica personalizada

Métrica personalizada do Prometheus

Escalone com base em uma métrica personalizada definida pelo usuário e exportada no Prometheus por meio do Google Managed Prometheus. Sua métrica do Prometheus precisa ser do tipo Gauge.

O escalonamento automático é basicamente sobre encontrar um equilíbrio aceitável entre custo e latência. Recomendamos fazer testes com uma combinação dessas e outras métricas para encontrar uma política que funcione para você.

Objetivos

Este tutorial abrange as seguintes tarefas:

  1. Como implantar o adaptador de métricas personalizadas.
  2. Como exportar métricas a partir do código do aplicativo.
  3. Como visualizar as métricas na interface do Cloud Monitoring.
  4. Como implantar um recurso HorizontalPodAutoscaler (HPA) para escalonar o aplicativo com base nas métricas do Cloud Monitoring.

Custos

Neste documento, você usará os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem estar qualificados para uma avaliação gratuita.

Ao concluir as tarefas descritas neste documento, é possível evitar o faturamento contínuo excluindo os recursos criados. Saiba mais em Limpeza.

Antes de começar

Siga estas etapas para ativar a API do Kubernetes Engine:
  1. Acesse a página do Kubernetes Engine no Console do Google Cloud.
  2. Crie ou selecione um projeto.
  3. Aguarde a ativação da API e dos serviços relacionados. Isso pode levar alguns minutos.
  4. Make sure that billing is enabled for your Google Cloud project.

Siga este tutorial usando o Cloud Shell, que vem pré-instalado com as ferramentas de linha de comando gcloud e kubectl usadas neste tutorial. Se você usa o Cloud Shell, não precisa instalar essas ferramentas de linha de comando na sua estação de trabalho.

Para usar o Cloud Shell:

  1. Acesse o console do Google Cloud.
  2. Clique no botão Ativar Cloud Shell na parte superior da janela do Console do Google Cloud. Botão "Ativar shell"

    Uma sessão do Cloud Shell é aberta dentro de um novo frame na parte inferior do Console do Google Cloud, e exibe um prompt de linha de comando.

    Sessão do Cloud Shell

Como configurar o ambiente

  1. Defina a zona padrão da Google Cloud CLI:

    gcloud config set compute/zone zone
    

    Substitua:

    • zone: escolha uma zona mais próxima de você. Para mais informações, consulte Regiões e zonas.
  2. Defina as variáveis de ambiente PROJECT_ID e PROJECT_NUMBER como o ID e o número do projeto do Google Cloud:

    export PROJECT_ID=project-id
    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format 'get(projectNumber)')
    
  3. Defina a zona padrão da Google Cloud CLI:

    gcloud config set project $PROJECT_ID
    
  4. Crie um cluster do GKE:

    Para ter mais segurança ao acessar os serviços do Google Cloud, recomendamos ativar a federação de identidade da carga de trabalho para o GKE no seu cluster. Esta página inclui exemplos que usam o método legado com a federação de identidade da carga de trabalho para o GKE desativada, mas ativá-la aumenta a proteção.

    Identidade da carga de trabalho

    Para criar um cluster com a federação de identidade da carga de trabalho para GKE ativada, execute o seguinte comando:

    gcloud container clusters create metrics-autoscaling --workload-pool=$PROJECT_ID.svc.id.goog
    

    Autenticação legada

    Para criar um cluster com a federação de identidade da carga de trabalho para GKE desativada, execute o seguinte comando:

    gcloud container clusters create metrics-autoscaling
    

Como implantar o adaptador de métricas personalizadas

O adaptador de métricas personalizadas permite que o cluster envie e receba métricas com o Cloud Monitoring.

CPU

Não aplicável: os escalonadores automáticos de pods horizontais podem escalonar nativamente com base na utilização de CPU. Portanto, o adaptador de métricas personalizadas não é necessário.

Pub/Sub

O procedimento para instalar o adaptador de métricas personalizadas é diferente para clusters com ou sem a federação de identidade da carga de trabalho para GKE ativada. Selecione a opção que corresponde à configuração que você escolheu quando criou o cluster.

Identidade da carga de trabalho

Permita que o usuário crie os papéis de autorização necessários:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

Implante o adaptador de métricas personalizadas no cluster:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml

O adaptador usa a conta de serviço custom-metrics-stackdriver-adapter do Kubernetes no namespace custom-metrics. Permita que esta conta de serviço leia as métricas do Cloud Monitoring atribuindo o papel de Leitor do Monitoring:

gcloud projects add-iam-policy-binding projects/$PROJECT_ID \
  --role roles/monitoring.viewer \
  --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID.svc.id.goog/subject/ns/custom-metrics/sa/custom-metrics-stackdriver-adapter

Autenticação legada

Permita que o usuário crie os papéis de autorização necessários:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

Implante o adaptador de métricas personalizadas no cluster:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml

Métrica personalizada

O procedimento para instalar o adaptador de métricas personalizadas é diferente para clusters com ou sem a federação de identidade da carga de trabalho para GKE ativada. Selecione a opção que corresponde à configuração que você escolheu quando criou o cluster.

Identidade da carga de trabalho

Permita que o usuário crie os papéis de autorização necessários:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

Implante o adaptador de métricas personalizadas no cluster:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml

O adaptador usa a conta de serviço custom-metrics-stackdriver-adapter do Kubernetes no namespace custom-metrics. Permita que esta conta de serviço leia as métricas do Cloud Monitoring atribuindo o papel de Leitor do Monitoring:

gcloud projects add-iam-policy-binding projects/$PROJECT_ID \
  --role roles/monitoring.viewer \
  --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID.svc.id.goog/subject/ns/custom-metrics/sa/custom-metrics-stackdriver-adapter

Autenticação legada

Permita que o usuário crie os papéis de autorização necessários:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

Implante o adaptador de métricas personalizadas no cluster:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml

Como implantar um aplicativo com métricas

Faça o download do repositório que contém o código do aplicativo para este tutorial:

CPU

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/quickstarts/hello-app

Pub/Sub

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/databases/cloud-pubsub

Métrica personalizada

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/observability/custom-metrics-autoscaling/google-managed-prometheus

O repositório contém um código que exporta métricas para o Cloud Monitoring:

CPU

Este aplicativo responde "Hello, world!" para qualquer solicitação da Web na porta 8080. As métricas de CPU do Compute Engine são coletadas automaticamente pelo Cloud Monitoring.

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

func main() {
	// register hello function to handle all requests
	mux := http.NewServeMux()
	mux.HandleFunc("/", hello)

	// use PORT environment variable, or default to 8080
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	// start the web server on port and accept requests
	log.Printf("Server listening on port %s", port)
	log.Fatal(http.ListenAndServe(":"+port, mux))
}

// hello responds to the request with a plain-text "Hello, world" message.
func hello(w http.ResponseWriter, r *http.Request) {
	log.Printf("Serving request: %s", r.URL.Path)
	host, _ := os.Hostname()
	fmt.Fprintf(w, "Hello, world!\n")
	fmt.Fprintf(w, "Version: 1.0.0\n")
	fmt.Fprintf(w, "Hostname: %s\n", host)
}

Pub/Sub

Este aplicativo pesquisa uma inscrição do Pub/Sub para novas mensagens, reconhecendo-as assim que chegam. As métricas de inscrição do Pub/Sub são coletadas automaticamente pelo Cloud Monitoring.

from google import auth
from google.cloud import pubsub_v1


def main():
    """Continuously pull messages from subsciption"""

    # read default project ID
    _, project_id = auth.default()
    subscription_id = 'echo-read'

    subscriber = pubsub_v1.SubscriberClient()
    subscription_path = subscriber.subscription_path(
        project_id, subscription_id)

    def callback(message: pubsub_v1.subscriber.message.Message) -> None:
        """Process received message"""
        print(f"Received message: ID={message.message_id} Data={message.data}")
        print(f"[{datetime.datetime.now()}] Processing: {message.message_id}")
        time.sleep(3)
        print(f"[{datetime.datetime.now()}] Processed: {message.message_id}")
        message.ack()

    streaming_pull_future = subscriber.subscribe(
        subscription_path, callback=callback)
    print(f"Pulling messages from {subscription_path}...")

    with subscriber:
        try:
            streaming_pull_future.result()
        except Exception as e:
            print(e)

Métrica personalizada

O aplicativo responde a qualquer solicitação da Web para o caminho /metrics com uma métrica de valor constante usando o formato do Prometheus.

metric := prometheus.NewGauge(
	prometheus.GaugeOpts{
		Name: *metricName,
		Help: "Custom metric",
	},
)
prometheus.MustRegister(metric)
metric.Set(float64(*metricValue))

http.Handle("/metrics", promhttp.Handler())
log.Printf("Starting to listen on :%d", *port)
err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)

O repositório também contém um manifesto do Kubernetes para implantar o aplicativo no cluster:

CPU

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloweb
  labels:
    app: hello
spec:
  selector:
    matchLabels:
      app: hello
      tier: web
  template:
    metadata:
      labels:
        app: hello
        tier: web
    spec:
      containers:
      - name: hello-app
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 200m

Pub/Sub

O manifesto é diferente para clusters com ou sem a federação de identidade da carga de trabalho para o GKE ativada. Selecione a opção que corresponde à configuração escolhida quando você criou o cluster.

Identidade da carga de trabalho

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      serviceAccountName: pubsub-sa
      containers:
      - name: subscriber
        image: us-docker.pkg.dev/google-samples/containers/gke/pubsub-sample:v2

Autenticação legada

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      volumes:
      - name: google-cloud-key
        secret:
          secretName: pubsub-key
      containers:
      - name: subscriber
        image: us-docker.pkg.dev/google-samples/containers/gke/pubsub-sample:v2
        volumeMounts:
        - name: google-cloud-key
          mountPath: /var/secrets/google
        env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: /var/secrets/google/key.json

Métrica personalizada

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: custom-metrics-gmp
  name: custom-metrics-gmp
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: custom-metrics-gmp
  template:
    metadata:
      labels:
        run: custom-metrics-gmp
    spec:
      containers:
      # sample container generating custom metrics
      - name: prometheus-dummy-exporter
        image: us-docker.pkg.dev/google-samples/containers/gke/prometheus-dummy-exporter:v0.2.0
        command: ["./prometheus-dummy-exporter"]
        args:
        - --metric-name=custom_prometheus
        - --metric-value=40
        - --port=8080

Com o recurso PodMonitoring, o Google Cloud Managed Service para Prometheus exporta métricas do Prometheus para o Cloud Monitoring:

apiVersion: monitoring.googleapis.com/v1
kind: PodMonitoring
metadata:
  name: "custom-metrics-exporter"
spec:
  selector:
    matchLabels:
      run: custom-metrics-gmp
  endpoints:
  - port: 8080
    path: /metrics
    interval: 15s

Implante o aplicativo no cluster:

CPU

kubectl apply -f manifests/helloweb-deployment.yaml

Pub/Sub

O procedimento para implantar o aplicativo é diferente para clusters com ou sem a federação de identidade da carga de trabalho para GKE ativada. Selecione a opção que corresponde à configuração que você escolheu quando criou o cluster.

Identidade da carga de trabalho

  1. Ative a API Pub/Sub no seu projeto:

    gcloud services enable cloudresourcemanager.googleapis.com pubsub.googleapis.com
    
  2. Crie um tópico e uma inscrição do Pub/Sub:

    gcloud pubsub topics create echo
    gcloud pubsub subscriptions create echo-read --topic=echo
    
  3. Implante o aplicativo no cluster:

    kubectl apply -f deployment/pubsub-with-workload-identity.yaml
    
  4. Este aplicativo define uma conta de serviço pubsub-sa do Kubernetes. Atribua à conta o papel de assinante do Pub/Sub para que o aplicativo possa publicar mensagens no tópico do Pub/Sub.

    gcloud projects add-iam-policy-binding projects/$PROJECT_ID \
      --role=roles/pubsub.subscriber \
      --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID.svc.id.goog/subject/ns/default/sa/pubsub-sa
    

Autenticação legada

  1. Ative a API Pub/Sub no seu projeto:

    gcloud services enable cloudresourcemanager.googleapis.com pubsub.googleapis.com
    
  2. Crie um tópico e uma inscrição do Pub/Sub:

    gcloud pubsub topics create echo
    gcloud pubsub subscriptions create echo-read --topic=echo
    
  3. Crie uma conta de serviço com acesso ao Pub/Sub:

    gcloud iam service-accounts create autoscaling-pubsub-sa
    gcloud projects add-iam-policy-binding $PROJECT_ID \
      --member "serviceAccount:autoscaling-pubsub-sa@$PROJECT_ID.iam.gserviceaccount.com" \
      --role "roles/pubsub.subscriber"
    
  4. Faça o download do arquivo de chave da conta de serviço:

    gcloud iam service-accounts keys create key.json \
      --iam-account autoscaling-pubsub-sa@$PROJECT_ID.iam.gserviceaccount.com
    
  5. Importe a chave da conta de serviço para o cluster como um Secret:

    kubectl create secret generic pubsub-key --from-file=key.json=./key.json
    
  6. Implante o aplicativo no cluster:

    kubectl apply -f deployment/pubsub-with-secret.yaml
    

Métrica personalizada

kubectl apply -f custom-metrics-gmp.yaml

Depois de aguardar um momento pela implantação do aplicativo, todos os pods alcançam o estado Ready:

CPU

kubectl get pods

Saída:

NAME                        READY   STATUS    RESTARTS   AGE
helloweb-7f7f7474fc-hzcdq   1/1     Running   0          10s

Pub/Sub

kubectl get pods

Saída:

NAME                     READY   STATUS    RESTARTS   AGE
pubsub-8cd995d7c-bdhqz   1/1     Running   0          58s

Métrica personalizada

kubectl get pods

Saída:

NAME                                  READY   STATUS    RESTARTS   AGE
custom-metrics-gmp-865dffdff9-x2cg9   1/1     Running   0          49s

Como ver métricas no Cloud Monitoring

Durante a execução do aplicativo, ele grava as métricas no Cloud Monitoring.

Para visualizar as métricas de um recurso monitorado usando o Metrics Explorer, faça o seguinte:

  1. No console do Google Cloud, acesse a página do  Metrics Explorer:

    Acesse o Metrics explorer

    Se você usar a barra de pesquisa para encontrar essa página, selecione o resultado com o subtítulo Monitoramento.

  2. No elemento Métrica, expanda o menu Selecionar uma métrica e escolha um tipo de recurso e de métrica. Por exemplo, para gerar um gráfico do uso da CPU de uma máquina virtual, faça o seguinte:
    1. Opcional: para reduzir as opções do menu, insira parte do nome da métrica na Barra de filtros. Neste exemplo, digite utilization.
    2. No menu Recursos ativos, selecione Instância de VM.
    3. No menu Categorias de métrica ativas, selecione Instância.
    4. No menu Métricas ativas, selecione Utilização de CPU e clique em Aplicar.
  3. Para filtrar as séries temporais de texto, use o elemento Filtro.

  4. Para combinar séries temporais, use os menus no elemento Agregação. Por exemplo, para exibir a utilização da CPU para suas VMs, com base na zona, defina o primeiro menu como Média e o segundo como zona.

    Todas as séries temporais são exibidas quando o primeiro menu do elemento Agregação está definido como Não agregado. As configurações padrão do elemento Agregação são determinadas pelo tipo de métrica selecionada.

O tipo de recurso e as métricas são os seguintes:

CPU

Metrics Explorer

Tipo de recurso: gce_instance

Métrica: compute.googleapis.com/instance/cpu/utilization

Pub/Sub

Metrics Explorer

Tipo de recurso: pubsub_subscription

Métrica: pubsub.googleapis.com/subscription/num_undelivered_messages

Métrica personalizada

Metrics Explorer

Tipo de recurso: prometheus_target

Métrica: prometheus.googleapis.com/custom_prometheus/gauge

Como criar um objeto HorizontalPodAutoscaler

Depois de ver a métrica no Cloud Monitoring, será possível implantar um HorizontalPodAutoscaler para redimensionar a implantação com base na métrica.

CPU

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: cpu
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: helloweb
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 30

Pub/Sub

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: pubsub
spec:
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - external:
      metric:
       name: pubsub.googleapis.com|subscription|num_undelivered_messages
       selector:
         matchLabels:
           resource.labels.subscription_id: echo-read
      target:
        type: AverageValue
        averageValue: 2
    type: External
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: pubsub

Métrica personalizada

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: custom-metrics-gmp-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: custom-metrics-gmp
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - type: Pods
    pods:
      metric:
        name: prometheus.googleapis.com|custom_prometheus|gauge
      target:
        type: AverageValue
        averageValue: 20

Implante o HorizontalPodAutoscaler no cluster:

CPU

kubectl apply -f manifests/helloweb-hpa.yaml

Pub/Sub

kubectl apply -f deployment/pubsub-hpa.yaml

Métrica personalizada

kubectl apply -f custom-metrics-gmp-hpa.yaml

Como gerar carga

Para algumas métricas, pode ser necessário gerar carga para monitorar o escalonamento automático:

CPU

Simule 10.000 solicitações para o servidor helloweb:

 kubectl exec -it deployments/helloweb -- /bin/sh -c \
     "for i in $(seq -s' ' 1 10000); do wget -q -O- localhost:8080; done"

Pub/Sub

Publique 200 mensagens no tópico do Pub/Sub:

for i in {1..200}; do gcloud pubsub topics publish echo --message="Autoscaling #${i}"; done

Métrica personalizada

Não aplicável: o código usado na amostra exporta um valor constante de 40 para a métrica personalizada. O HorizontalPodAutoscaler é definido com um valor de destino de 20. Portanto, ele tenta escalonar a implantação automaticamente e de forma vertical.

Como observar o escalonamento vertical do HorizontalPodAutoscaler

É possível verificar o número atual de réplicas da sua implantação, basta executar:

kubectl get deployments

Após algum tempo para a métrica se propagar, a implantação cria cinco pods para lidar com o backlog.

Também é possível inspecionar o estado e a atividade recente do HorizontalPodAutoscaler, basta executar:

kubectl describe hpa

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados neste tutorial, exclua o projeto que os contém ou mantenha o projeto e exclua os recursos individuais.

CPU

Exclua seu Cluster do GKE:

 gcloud container clusters delete metrics-autoscaling

Pub/Sub

  1. Remova a inscrição e o tópico do Pub/Sub:

    gcloud pubsub subscriptions delete echo-read
    gcloud pubsub topics delete echo
    
  2. Exclua seu Cluster do GKE:

    gcloud container clusters delete metrics-autoscaling
    

Métrica personalizada

Exclua seu Cluster do GKE:

 gcloud container clusters delete metrics-autoscaling

A seguir