Este documento ha sido traducido utilizando tecnología de traducción automática. Si bien nos esforzamos por proporcionar traducciones precisas, no ofrecemos garantías sobre la integridad, precisión o confiabilidad del contenido traducido. En caso de discrepancia, la versión original en inglés prevalecerá y constituirá el texto autorizado.

Cluster Autoscaler con Grupos de Autoescalado de AWS EC2

Esta guía te mostrará cómo instalar y usar Kubernetes cluster-autoscaler en clusters personalizados de Rancher utilizando Grupos de Autoescalado de AWS EC2.

Vamos a instalar un cluster personalizado RKE2 de Rancher con un número fijo de nodos con los roles de etcd y controlplane, y un número variable de nodos con el rol de trabajador, gestionado por cluster-autoscaler.

Requisitos previos

Estos elementos son necesarios para seguir esta guía:

  • El servidor de Rancher está en funcionamiento

  • Tienes un usuario de AWS EC2 con los permisos adecuados para crear máquinas virtuales, grupos de autoescalado y perfiles y roles de IAM

1. Crear un Cluster Personalizado

En el servidor de Rancher, deberíamos crear un cluster k8s personalizado. Consulta aquí para comprobar la compatibilidad de versiones.

Asegúrate de que el nombre del proveedor de nube esté configurado como amazonec2. Una vez creado el cluster, necesitamos obtener:

  • clusterID: c-xxxxx se utilizará en la etiqueta de instancia EC2 kubernetes.io/cluster/<clusterID>

  • clusterName: se utilizará en la etiqueta de instancia EC2 k8s.io/cluster-autoscaler/<clusterName>

  • nodeCommand: se añadirá en user_data de la instancia EC2 para incluir nuevos nodos en el cluster

      sudo docker run -d --privileged --restart=unless-stopped --net=host -v /etc/kubernetes:/etc/kubernetes -v /var/run:/var/run rancher/rancher-agent:<RANCHER_VERSION> --server https://<RANCHER_URL> --token <RANCHER_TOKEN> --ca-checksum <RANCHER_CHECKSUM> <roles>

2. Configurar el Proveedor de Nube

En AWS EC2, deberíamos crear algunos objetos para configurar nuestro sistema. Hemos definido tres grupos distintos y perfiles de IAM para configurar en AWS.

  1. Grupo de escalado automático: Nodos que formarán parte del Grupo de Escalado Automático de EC2 (ASG). El ASG será utilizado por cluster-autoscaler para escalar hacia arriba y hacia abajo.

    • Perfil de IAM: Requerido por los nodos de k8s donde se ejecutará el escalador automático del clúster. Se recomienda para los nodos maestros de Kubernetes. Este perfil se llama K8sAutoscalerProfile.

       {
           "Version": "2012-10-17",
           "Statement": [
               {
                   "Effect": "Allow",
                   "Action": [
                       "autoscaling:DescribeAutoScalingGroups",
                       "autoscaling:DescribeAutoScalingInstances",
                       "autoscaling:DescribeLaunchConfigurations",
                       "autoscaling:SetDesiredCapacity",
                       "autoscaling:TerminateInstanceInAutoScalingGroup",
                       "autoscaling:DescribeTags",
                       "autoscaling:DescribeLaunchConfigurations",
                       "ec2:DescribeLaunchTemplateVersions"
                   ],
                   "Resource": [
                       "*"
                   ]
               }
           ]
       }
  2. Grupo maestro: Nodos que formarán parte de etcd de Kubernetes y/o de los planos de control. Esto estará fuera del ASG.

    • Perfil de IAM: Requerido por la integración del proveedor de nube de Kubernetes. Opcionalmente, AWS_ACCESS_KEY y AWS_SECRET_KEY pueden ser utilizados en lugar de using-aws-credentials. Este perfil se llama K8sMasterProfile.

       {
           "Version": "2012-10-17",
           "Statement": [
               {
                   "Effect": "Allow",
                   "Action": [
                       "autoscaling:DescribeAutoScalingGroups",
                       "autoscaling:DescribeLaunchConfigurations",
                       "autoscaling:DescribeTags",
                       "ec2:DescribeInstances",
                       "ec2:DescribeRegions",
                       "ec2:DescribeRouteTables",
                       "ec2:DescribeSecurityGroups",
                       "ec2:DescribeSubnets",
                       "ec2:DescribeVolumes",
                       "ec2:CreateSecurityGroup",
                       "ec2:CreateTags",
                       "ec2:CreateVolume",
                       "ec2:ModifyInstanceAttribute",
                       "ec2:ModifyVolume",
                       "ec2:AttachVolume",
                       "ec2:AuthorizeSecurityGroupIngress",
                       "ec2:CreateRoute",
                       "ec2:DeleteRoute",
                       "ec2:DeleteSecurityGroup",
                       "ec2:DeleteVolume",
                       "ec2:DetachVolume",
                       "ec2:RevokeSecurityGroupIngress",
                       "ec2:DescribeVpcs",
                       "elasticloadbalancing:AddTags",
                       "elasticloadbalancing:AttachLoadBalancerToSubnets",
                       "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer",
                       "elasticloadbalancing:CreateLoadBalancer",
                       "elasticloadbalancing:CreateLoadBalancerPolicy",
                       "elasticloadbalancing:CreateLoadBalancerListeners",
                       "elasticloadbalancing:ConfigureHealthCheck",
                       "elasticloadbalancing:DeleteLoadBalancer",
                       "elasticloadbalancing:DeleteLoadBalancerListeners",
                       "elasticloadbalancing:DescribeLoadBalancers",
                       "elasticloadbalancing:DescribeLoadBalancerAttributes",
                       "elasticloadbalancing:DetachLoadBalancerFromSubnets",
                       "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
                       "elasticloadbalancing:ModifyLoadBalancerAttributes",
                       "elasticloadbalancing:RegisterInstancesWithLoadBalancer",
                       "elasticloadbalancing:SetLoadBalancerPoliciesForBackendServer",
                       "elasticloadbalancing:AddTags",
                       "elasticloadbalancing:CreateListener",
                       "elasticloadbalancing:CreateTargetGroup",
                       "elasticloadbalancing:DeleteListener",
                       "elasticloadbalancing:DeleteTargetGroup",
                       "elasticloadbalancing:DescribeListeners",
                       "elasticloadbalancing:DescribeLoadBalancerPolicies",
                       "elasticloadbalancing:DescribeTargetGroups",
                       "elasticloadbalancing:DescribeTargetHealth",
                       "elasticloadbalancing:ModifyListener",
                       "elasticloadbalancing:ModifyTargetGroup",
                       "elasticloadbalancing:RegisterTargets",
                       "elasticloadbalancing:SetLoadBalancerPoliciesOfListener",
                       "iam:CreateServiceLinkedRole",
                       "ecr:GetAuthorizationToken",
                       "ecr:BatchCheckLayerAvailability",
                       "ecr:GetDownloadUrlForLayer",
                       "ecr:GetRepositoryPolicy",
                       "ecr:DescribeRepositories",
                       "ecr:ListImages",
                       "ecr:BatchGetImage",
                       "kms:DescribeKey"
                   ],
                   "Resource": [
                       "*"
                   ]
               }
           ]
       }
    • Rol de IAM: K8sMasterRole: [K8sMasterProfile,K8sAutoscalerProfile].

    • Grupo de seguridad: K8sMasterSg. Más información en Puertos de RKE2 (pestaña de nodos personalizados)

    • Etiquetas: kubernetes.io/cluster/<clusterID>: owned

    • Datos del usuario: K8sMasterUserData Ubuntu 18.04(ami-0e11cbb34015ff725), instala Docker y añade un nodo etcd+controlplane al clúster de K8s.

      #!/bin/bash -x
      
      cat <<EOF > /etc/sysctl.d/90-kubelet.conf
      vm.overcommit_memory = 1
      vm.panic_on_oom = 0
      kernel.panic = 10
      kernel.panic_on_oops = 1
      kernel.keys.root_maxkeys = 1000000
      kernel.keys.root_maxbytes = 25000000
      EOF
      sysctl -p /etc/sysctl.d/90-kubelet.conf
      
      curl -sL https://releases.rancher.com/install-docker/19.03.sh | sh
      sudo usermod -aG docker ubuntu
      
      TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
      PRIVATE_IP=$(curl -H "X-aws-ec2-metadata-token: ${TOKEN}" -s http://169.254.169.254/latest/meta-data/local-ipv4)
      PUBLIC_IP=$(curl -H "X-aws-ec2-metadata-token: ${TOKEN}" -s http://169.254.169.254/latest/meta-data/public-ipv4)
      K8S_ROLES="--etcd --controlplane"
      
      sudo docker run -d --privileged --restart=unless-stopped --net=host -v /etc/kubernetes:/etc/kubernetes -v /var/run:/var/run rancher/rancher-agent:<RANCHER_VERSION> --server https://<RANCHER_URL> --token <RANCHER_TOKEN> --ca-checksum <RANCHER_CA_CHECKSUM> --address ${PUBLIC_IP} --internal-address ${PRIVATE_IP} ${K8S_ROLES}
  3. Grupo de trabajadores: Nodos que formarán parte del plano de trabajadores de k8s. Los nodos trabajadores se escalarán mediante el cluster-autoscaler utilizando el ASG.

    • Perfil de IAM: Proporciona integración de trabajadores del proveedor de la nube. Este perfil se llama K8sWorkerProfile.

       {
           "Version": "2012-10-17",
           "Statement": [
               {
                   "Effect": "Allow",
                   "Action": [
                       "ec2:DescribeInstances",
                       "ec2:DescribeRegions",
                       "ecr:GetAuthorizationToken",
                       "ecr:BatchCheckLayerAvailability",
                       "ecr:GetDownloadUrlForLayer",
                       "ecr:GetRepositoryPolicy",
                       "ecr:DescribeRepositories",
                       "ecr:ListImages",
                       "ecr:BatchGetImage"
                   ],
                   "Resource": "*"
               }
           ]
       }
    • Rol de IAM: K8sWorkerRole: [K8sWorkerProfile].

    • Grupo de seguridad: K8sWorkerSg Más información en Puertos de RKE2 (pestaña de nodos personalizados).

    • Tags (Etiquetas de carga de trabajo):

      • kubernetes.io/cluster/<clusterID>: owned

      • k8s.io/cluster-autoscaler/<clusterName>: true

      • k8s.io/cluster-autoscaler/enabled: true

    • Datos del usuario: K8sWorkerUserData Ubuntu 18.04(ami-0e11cbb34015ff725), instala Docker y añade el nodo trabajador al clúster K8s.

        #!/bin/bash -x
      
        cat <<EOF > /etc/sysctl.d/90-kubelet.conf
        vm.overcommit_memory = 1
        vm.panic_on_oom = 0
        kernel.panic = 10
        kernel.panic_on_oops = 1
        kernel.keys.root_maxkeys = 1000000
        kernel.keys.root_maxbytes = 25000000
        EOF
        sysctl -p /etc/sysctl.d/90-kubelet.conf
      
        curl -sL https://releases.rancher.com/install-docker/19.03.sh | sh
        sudo usermod -aG docker ubuntu
      
        TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
        PRIVATE_IP=$(curl -H "X-aws-ec2-metadata-token: ${TOKEN}" -s http://169.254.169.254/latest/meta-data/local-ipv4)
        PUBLIC_IP=$(curl -H "X-aws-ec2-metadata-token: ${TOKEN}" -s http://169.254.169.254/latest/meta-data/public-ipv4)
        K8S_ROLES="--worker"
      
        sudo docker run -d --privileged --restart=unless-stopped --net=host -v /etc/kubernetes:/etc/kubernetes -v /var/run:/var/run rancher/rancher-agent:<RANCHER_VERSION> --server https://<RANCHER_URL> --token <RANCHER_TOKEN> --ca-checksum <RANCHER_CA_CHECKCSUM> --address ${PUBLIC_IP} --internal-address ${PRIVATE_IP} ${K8S_ROLES}

Más información está en clústeres RKE2 en AWS y Cluster Autoscaler en AWS.

3. Desplegar nodos

Una vez que hayamos configurado AWS, vamos a crear VMs para iniciar nuestro clúster:

  • maestro (etcd+controlplane): Dependiendo de tus necesidades, despliega tres instancias maestras con el tamaño adecuado. Más información está en las recomendaciones para clústeres listos para producción.

    • Rol de IAM: K8sMasterRole

    • Grupo de seguridad: K8sMasterSg

    • Tags (Etiquetas de carga de trabajo):

      • kubernetes.io/cluster/<clusterID>: owned

    • Datos del usuario: K8sMasterUserData

  • trabajador: Define un ASG en EC2 con la siguiente configuración:

    • Nombre: K8sWorkerAsg

    • Rol IAM: K8sWorkerRole

    • Grupo de seguridad: K8sWorkerSg

    • Tags (Etiquetas de carga de trabajo):

      • kubernetes.io/cluster/<clusterID>: owned

      • k8s.io/cluster-autoscaler/<clusterName>: true

      • k8s.io/cluster-autoscaler/enabled: true

    • Datos del usuario: K8sWorkerUserData

    • Instancias:

      • mínimo: 2

      • deseado: 2

      • máximo: 10

Una vez que las VMs estén desplegadas, deberías tener un clúster personalizado de Rancher en funcionamiento con tres nodos maestros y dos nodos trabajadores.

4. Install Cluster-autoscaler

En este punto, deberíamos tener el clúster de Rancher en funcionamiento. Vamos a instalar cluster-autoscaler en los nodos maestros y en el espacio de nombres kube-system, siguiendo la recomendación de cluster-autoscaler.

Parámetros

Esta tabla muestra los parámetros de cluster-autoscaler para un ajuste fino:

Parámetro Default Descripción

cluster-name

-

Nombre del clúster autoescalado, si está disponible

dirección

:8085

La dirección para exponer métricas de Prometheus

kubernetes

-

Ubicación del maestro de Kubernetes. Dejar en blanco para el valor predeterminado

kubeconfig

-

Ruta al archivo kubeconfig con información de autorización y ubicación del maestro

cloud-config

-

La ruta al archivo de configuración del proveedor de la nube. Cadena vacía para no tener archivo de configuración

espacio de nombres

"kube-system"

Espacio de nombres en el que se ejecuta cluster-autoscaler

escalado-hacia-abajo-habilitado

true

¿Debería CA reducir el tamaño del clúster?

scale-down-delay-after-add

"10m"

Cuánto tiempo después de aumentar el tamaño se reanuda la evaluación de reducción de tamaño

scale-down-delay-after-delete

0

Cuánto tiempo después de la eliminación de un nodo se reanuda la evaluación de reducción de tamaño, por defecto es scanInterval

scale-down-delay-after-failure

"3m"

¿Cuánto tiempo después de un fallo en la reducción de escala se reanuda la evaluación de la reducción de escala?

scale-down-unneeded-time

"10m"

¿Cuánto tiempo debe estar un nodo sin necesidad antes de ser elegible para la reducción de escala?

scale-down-unready-time

"20m"

¿Cuánto tiempo debe estar un nodo no listo sin necesidad antes de ser elegible para la reducción de escala?

umbral-utilización-reducción-de-escala

50%

Suma de la CPU o memoria de todos los pods que se ejecutan en el nodo dividida por el recurso asignable correspondiente del nodo, por debajo del cual un nodo puede ser considerado para la reducción de escala.

umbral-utilización-gpu-reducción-de-escala

50%

Suma de las solicitudes de GPU de todos los pods que se ejecutan en el nodo dividida por el recurso asignable del nodo, por debajo del cual un nodo puede ser considerado para la reducción de escala.

scale-down-non-empty-candidates-count

30

Número máximo de nodos no vacíos considerados en una iteración como candidatos para la reducción de escala con drenaje.

scale-down-candidates-pool-ratio

10%

Una proporción de nodos que se consideran como candidatos adicionales no vacíos para la reducción de escala cuando algunos candidatos de la iteración anterior ya no son válidos.

scale-down-candidates-pool-min-count

50

Número mínimo de nodos que se consideran como candidatos adicionales no vacíos para la reducción de escala cuando algunos candidatos de la iteración anterior ya no son válidos.

tiempo-espera-borrado-nodo

"2m"

Tiempo máximo que CA espera para eliminar las anotaciones delay-deletion.cluster-autoscaler.kubernetes.io/ antes de borrar el nodo.

scan-interval

"10s"

Con qué frecuencia se reevaluará el clúster para escalar hacia arriba o hacia abajo

max-nodes-total

0

Número máximo de nodos en todos los grupos de nodos. El escalador automático de clúster no hará crecer el clúster más allá de este número

cores-total

"0:320000"

Número mínimo y máximo de núcleos en el clúster, en el formato <min>:<max>. El escalador automático de clúster no escalará el clúster más allá de estos números

memory-total

"0:6400000"

Número mínimo y máximo de gigabytes de memoria en el clúster, en el formato <min>:<max>. El escalador automático de clúster no escalará el clúster más allá de estos números

proveedor-de-nube

-

Tipo de proveedor de nube

max-bulk-soft-taint-count

10

Número máximo de nodos que pueden estar tainted/untainted con PreferNoSchedule al mismo tiempo. Establecer en 0 para desactivar dicho tainting

max-bulk-soft-taint-time

"3s"

Duración máxima del tainting/untainting de nodos con PreferNoSchedule al mismo tiempo

max-empty-bulk-delete

10

Número máximo de nodos vacíos que pueden ser eliminados al mismo tiempo

max-graceful-termination-sec

600

Número máximo de segundos que CA espera para la terminación del pod al intentar reducir un nodo

max-total-unready-percentage

45

Porcentaje máximo de nodos no listos en el clúster. Una vez superado, CA detiene las operaciones

ok-total-unready-count

3

Número de nodos no listos permitidos, independientemente del porcentaje máximo de nodos no listos

scale-up-from-zero

true

¿Debería CA escalar cuando hay 0 nodos listos?

max-node-provision-time

"15m"

Tiempo máximo que CA espera para que un nodo sea provisionado

nodos

-

establece el tamaño mínimo, máximo y otros datos de configuración para un grupo de nodos en un formato aceptado por el proveedor de la nube. Se puede utilizar múltiples veces. Formato: <min>:<max>:<other…​>

node-group-auto-discovery

-

Una o más definición(es) de descubrimiento automático del grupo de nodos. Una definición se expresa <name of discoverer>:[<key>[=<value>]]

estimator

"binpacking"

Tipo de estimador de recursos que se utilizará en el escalado. Valores disponibles: ["binpacking"]

expansor

"random"

Tipo de grupo de nodos expansor que se utilizará al escalar hacia arriba. Valores disponibles: ["random","most-pods","least-waste","price","priority"]

ignore-daemonsets-utilization

false

¿Debería CA ignorar los pods de DaemonSet al calcular la utilización de recursos para escalar hacia abajo?

ignore-mirror-pods-utilization

false

¿Debería CA ignorar los pods Espejo al calcular la utilización de recursos para escalar hacia abajo?

write-status-configmap

true

¿Debería CA escribir información de estado en un configmap?

máxima-inactividad

"10m"

Tiempo máximo desde la última actividad registrada del escalador automático antes del reinicio automático

máximo-tiempo-fallido

"15m"

Tiempo máximo desde la última ejecución exitosa del escalador automático antes del reinicio automático

balance-similar-node-groups

false

Detectar grupos de nodos similares y equilibrar el número de nodos entre ellos

autoprovisionamiento-de-nodos-habilitado

false

¿Debería CA autoprovisionar grupos de nodos cuando sea necesario?

max-autoprovisioned-node-group-count

15

El número máximo de grupos autoprovisionados en el clúster

unremovable-node-recheck-timeout

"5m"

El tiempo de espera antes de volver a comprobar un nodo que no pudo ser eliminado antes

expendable-pods-priority-cutoff

-10

Los pods con prioridad por debajo del corte serán prescindibles. Pueden ser eliminados sin ninguna consideración durante el escalado hacia abajo y no provocan escalado hacia arriba. Los pods con prioridad nula (prioridad de pod desactivada) no son prescindibles.

regional

false

El clúster es regional

new-pod-scale-up-delay

"0s"

Los pods con menos antigüedad que esto no serán considerados para escalar hacia arriba.

ignore-taint

-

Especifica un taint a ignorar en las plantillas de nodo al considerar escalar un grupo de nodos

balancing-ignore-label

-

Especifica una etiqueta a ignorar además del conjunto básico y de etiquetas del proveedor de la nube al comparar si dos grupos de nodos son similares

aws-usar-lista-estática-de-instancias

false

¿Debería CA obtener tipos de instancia en tiempo de ejecución o usar una lista estática? Solo AWS

perfilado

false

¿Está habilitado el punto final de depuración/pprof?

Distribución

Basado en el ejemplo cluster-autoscaler-run-on-control-plane.yaml, hemos creado nuestro propio cluster-autoscaler-deployment.yaml para usar la configuración preferida de auto-discovery setup, actualizando las tolerancias, el nodeSelector, la versión de la imagen y la configuración de comando:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
  name: cluster-autoscaler
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-autoscaler
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
rules:
  - apiGroups: [""]
    resources: ["events", "endpoints"]
    verbs: ["create", "patch"]
  - apiGroups: [""]
    resources: ["pods/eviction"]
    verbs: ["create"]
  - apiGroups: [""]
    resources: ["pods/status"]
    verbs: ["update"]
  - apiGroups: [""]
    resources: ["endpoints"]
    resourceNames: ["cluster-autoscaler"]
    verbs: ["get", "update"]
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["watch", "list", "get", "update"]
  - apiGroups: [""]
    resources:
      - "pods"
      - "services"
      - "replicationcontrollers"
      - "persistentvolumeclaims"
      - "persistentvolumes"
    verbs: ["watch", "list", "get"]
  - apiGroups: ["extensions"]
    resources: ["replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["policy"]
    resources: ["poddisruptionbudgets"]
    verbs: ["watch", "list"]
  - apiGroups: ["apps"]
    resources: ["statefulsets", "replicasets", "daemonsets"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses", "csinodes"]
    verbs: ["watch", "list", "get"]
  - apiGroups: ["batch", "extensions"]
    resources: ["jobs"]
    verbs: ["get", "list", "watch", "patch"]
  - apiGroups: ["coordination.k8s.io"]
    resources: ["leases"]
    verbs: ["create"]
  - apiGroups: ["coordination.k8s.io"]
    resourceNames: ["cluster-autoscaler"]
    resources: ["leases"]
    verbs: ["get", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["create","list","watch"]
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["cluster-autoscaler-status", "cluster-autoscaler-priority-expander"]
    verbs: ["delete", "get", "update", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-autoscaler
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler
    namespace: kube-system

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    k8s-addon: cluster-autoscaler.addons.k8s.io
    k8s-app: cluster-autoscaler
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: cluster-autoscaler
subjects:
  - kind: ServiceAccount
    name: cluster-autoscaler
    namespace: kube-system

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cluster-autoscaler
  namespace: kube-system
  labels:
    app: cluster-autoscaler
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cluster-autoscaler
  template:
    metadata:
      labels:
        app: cluster-autoscaler
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/port: '8085'
    spec:
      serviceAccountName: cluster-autoscaler
      tolerations:
        - effect: NoSchedule
          operator: "Equal"
          value: "true"
          key: node-role.kubernetes.io/controlplane
      nodeSelector:
        node-role.kubernetes.io/controlplane: "true"
      containers:
        - image: eu.gcr.io/k8s-artifacts-prod/autoscaling/cluster-autoscaler:<VERSION>
          name: cluster-autoscaler
          resources:
            limits:
              cpu: 100m
              memory: 300Mi
            requests:
              cpu: 100m
              memory: 300Mi
          command:
            - ./cluster-autoscaler
            - --v=4
            - --stderrthreshold=info
            - --cloud-provider=aws
            - --skip-nodes-with-local-storage=false
            - --expander=least-waste
            - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/<clusterName>
          volumeMounts:
            - name: ssl-certs
              mountPath: /etc/ssl/certs/ca-certificates.crt
              readOnly: true
          imagePullPolicy: "Always"
      volumes:
        - name: ssl-certs
          hostPath:
            path: "/etc/ssl/certs/ca-certificates.crt"

Una vez que el archivo de manifiesto esté preparado, desplégalo en el clúster de Kubernetes (se puede utilizar la interfaz de usuario de Rancher en su lugar):

kubectl -n kube-system apply -f cluster-autoscaler-deployment.yaml

El despliegue del escalador de clúster también se puede configurar utilizando configuración manual

Evaluación

En este punto, deberíamos tener un escalador de clúster en funcionamiento en nuestro clúster personalizado de Rancher. El escalado del clúster debería gestionar K8sWorkerAsg ASG para escalar hacia arriba y hacia abajo entre 2 y 10 nodos, cuando se cumpla una de las siguientes condiciones:

  • Hay pods que no pudieron ejecutarse en el clúster debido a recursos insuficientes. En este caso, el clúster se escala hacia arriba.

  • Hay nodos en el clúster que han estado infrautilizados durante un período prolongado y sus pods pueden ser colocados en otros nodos existentes. En este caso, el clúster se escala hacia abajo.

Generando carga

Hemos preparado un test-deployment.yaml solo para generar carga en el clúster de Kubernetes y ver si el escalador de clúster está funcionando correctamente. La ampliación de prueba está solicitando 1000m de CPU y 1024Mi de memoria por tres réplicas. Ajusta los recursos solicitados y/o la réplica para asegurarte de agotar los recursos del clúster de Kubernetes:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: hello-world
  name: hello-world
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-world
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
      - image: rancher/hello-world
        imagePullPolicy: Always
        name: hello-world
        ports:
        - containerPort: 80
          protocol: TCP
        resources:
          limits:
            cpu: 1000m
            memory: 1024Mi
          requests:
            cpu: 1000m
            memory: 1024Mi

Una vez que la ampliación de prueba esté preparada, desplégala en el espacio de nombres predeterminado del clúster de Kubernetes (se puede utilizar la interfaz de usuario de Rancher en su lugar):

kubectl -n default apply -f test-deployment.yaml

Comprobando el escalado

Una vez que los recursos de Kubernetes se hayan agotado, el escalador de clúster debería escalar hacia arriba los nodos de trabajo donde los pods no pudieron ser programados. Debería escalar hacia arriba hasta que todos los pods sean programados. Deberías ver los nuevos nodos en el ASG y en el clúster de Kubernetes. Revisa los registros en el pod del escalador de clúster kube-system.

Una vez que se haya comprobado el escalado hacia arriba, verifiquemos el escalado hacia abajo. Para hacerlo, reduce el número de réplicas en la ampliación de prueba hasta que liberes suficientes recursos del clúster de Kubernetes para escalar hacia abajo. Deberíais ver cómo desaparecen los nodos en el ASG y en el clúster de Kubernetes. Revisa los registros en el pod del escalador de clúster kube-system.