Ejecuta cargas de trabajo tolerantes a errores a costos más bajos en Spot Pods

En esta página, se muestra cómo ejecutar cargas de trabajo tolerantes a errores a costos más bajos mediante Spot Pods en los clústeres de Autopilot de Google Kubernetes Engine (GKE).

Descripción general

En los clústeres de Autopilot para GKE, Spot Pods son Pods que se ejecutan en nodos respaldados por VM Spot de Compute Engine. Los Spot Pods tienen un precio menor que los de Autopilot estándar, pero GKE los puede expulsar siempre que se necesiten recursos de procesamiento para ejecutar Pods estándar.

Los Spot Pods son ideales para ejecutar cargas de trabajo sin estado, por lotes o tolerantes a errores a costos más bajos en comparación con la ejecución de esas cargas de trabajo como Pods estándar. Para usar Spot Pods en clústeres de Autopilot, modifica el manifiesto con tu especificación de Pod a fin de solicitar Spot Pods.

Puedes ejecutar Pods Spot en la clase de procesamiento de Autopilot de uso general predeterminada, así como en clases de procesamiento especializadas que cumplan con requisitos de hardware específicos. Para obtener información sobre estas clases de procesamiento, consulta Clases de procesamiento en Autopilot.

Para obtener más información sobre los precios de los Spot Pods en los clústeres de Autopilot, consulta los precios de Google Kubernetes Engine.

Los Spot Pods se excluyen del Acuerdo de Nivel de Servicio de Autopilot.

Beneficios

El uso de Spot Pods en tus clústeres de Autopilot te proporciona los siguientes beneficios:

  • Precios más bajos que ejecutar las mismas cargas de trabajo en los Pods de Autopilot estándar.
  • GKE administra automáticamente el ajuste de escala automático y la programación.
  • GKE realiza taints de automáticamente en los nodos que ejecutan Spot Pods para garantizar que los Pods estándar, como tus cargas de trabajo críticas, no estén programados en esos nodos. Las implementaciones que usan Spot Pods se actualizan de forma automática con una tolerancia correspondiente.

Antes de comenzar

Antes de comenzar, asegúrate de haber realizado las siguientes tareas:

  • Habilita la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Si deseas usar Google Cloud CLI para esta tarea, instala y, luego, inicializa gcloud CLI. Si ya instalaste gcloud CLI, ejecuta el comando gcloud components update para obtener la versión más reciente. Es posible que las versiones anteriores de gcloud CLI no admitan la ejecución de los comandos que se describen en este documento.

Solicita Spot Pods en tus cargas de trabajo de Autopilot

Para solicitar que tus Pods se ejecuten como Spot Pods, usa la etiqueta cloud.google.com/gke-spot=true en un nodeSelector o afinidad de nodos en tu especificación de Pods. GKE aprovisiona nodos de forma automática que pueden ejecutar Spot Pods.

Los Spot Pods pueden expulsarse y finalizarse en cualquier momento, por ejemplo, si los recursos de procesamiento se necesitan en otra parte de Google Cloud. Cuando ocurre una finalización, los Spot Pods en el nodo de finalización pueden solicitar hasta un período de gracia de 15 segundos antes de la finalización, que se otorga según el mejor esfuerzo mediante la especificación del campo terminationGracePeriodSeconds.

El período de gracia máximo que se le otorga a los Spot Pods durante la interrupción es de 15 segundos. Solicitar más de 15 segundos en terminationGracePeriodSeconds no otorga más de 15 segundos durante la interrupción. Cuando se produce la expulsión, el Pod recibe la señal SIGTERM y debe tomar las medidas necesarias para cerrar el servicio durante el período de gracia.

En Autopilot, GKE también habilita taints de forma automática en los nodos creados para ejecutar Spot Pods y modifica esas cargas de trabajo con la tolerancia correspondiente. El taint evita que los Pods estándar se programen en nodos que ejecutan Spot Pods.

Usa un nodeSelector para requerir Spot Pods

Puedes usar un nodeSelector para requerir Spot Pods en una implementación. Agrega la etiqueta cloud.google.com/gke-spot=true a tu Deployment, como en el siguiente ejemplo:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    metadata:
      labels:
        app: pi
    spec:
      nodeSelector:
        cloud.google.com/gke-spot: "true"
      terminationGracePeriodSeconds: 15
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

Usa la afinidad de nodos para solicitar Spot Pods

Como alternativa, puedes usar la afinidad de nodos para solicitar Spot Pods. La afinidad de nodos te brinda una forma más extensible para seleccionar nodos a fin de ejecutar tus cargas de trabajo. Por ejemplo, puedes combinar varios criterios de selección para obtener un control más preciso sobre dónde se ejecutan tus Pods. Cuando usas la afinidad de nodos para solicitar Spot Pods, puedes especificar el tipo de afinidad de nodo que se usará, de la siguiente manera:

  • requiredDuringSchedulingIgnoredDuringExecution: Debes usar Spot Pods.
  • preferredDuringSchedulingIgnoredDuringExecution: Usa Spot Pods en función del mejor esfuerzo.

Si deseas usar la afinidad de nodos para requerir Spot Pods en una implementación, agrega la siguiente regla nodeAffinity a tu manifiesto de implementación:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    metadata:
      labels:
        app: pi
    spec:
      terminationGracePeriodSeconds: 15
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: cloud.google.com/gke-spot
                operator: In
                values:
                - "true"
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

Solicita Spot Pods según el mejor esfuerzo

Si deseas usar la afinidad de nodos para solicitar Spot Pods según el criterio del mejor esfuerzo, usa preferredDuringSchedulingIgnoredDuringExecution. Cuando solicitas Spot Pods de forma preferida, GKE programa tus Pods en el siguiente orden:

  1. Nodos existentes que pueden ejecutar Spot Pods que tienen capacidad asignable disponible
  2. Nodos estándar existentes que tienen capacidad asignable disponible
  3. Nodos nuevos que pueden ejecutar Spot Pods, si los recursos de procesamiento están disponibles
  4. Nuevos nodos estándar

Debido a que GKE prefiere nodos estándar existentes que tienen capacidad asignable en lugar de crear nodos nuevos para Spot Pods, es posible que notes más Pods que se ejecutan como Pods estándar que como Spot Pods, lo que evita que aproveches al máximo el reducir los precios de los Spot Pods.

Solicitudes de Pods interrumpibles

Los clústeres de Autopilot admiten solicitudes de Pods interrumpibles mediante el selector cloud.google.com/gke-preemptible. Los Pods que usan este selector se migran de forma automática a Spot Pods y el selector se cambia a cloud.google.com/gke-spot.

Busca y borra los Pods terminados

Durante la finalización ordenada del Pod, el kubelet asigna un estado Failed y un motivo Shutdown a los Pods finalizados. Cuando la cantidad de Pods finalizados alcanza un umbral de 1,000, la recolección de elementos no usados limpia los Pods. También puedes borrar los Pods de cierre de forma manual con el siguiente comando:

kubectl get pods --all-namespaces | grep -i shutdown | awk '{print $1, $2}' | xargs -n2 kubectl delete pod -n

Cómo evitar que las cargas de trabajo usen Pods Spot

Si tienes Spot Pods existentes que deseas actualizar para que se ejecuten como Pods estándar, puedes usar uno de los siguientes métodos:

  • Vuelve a crear la carga de trabajo: Borra la Deployment, quita las líneas del manifiesto que seleccionan Pods interrumpibles y, luego, aplica el manifiesto de Deployment actualizado al clúster.
  • Edita la carga de trabajo: Edita la especificación de Deployment mientras los Pods se ejecutan en el clúster.

Con ambos métodos, es posible que experimentes interrupciones menores en la carga de trabajo.

Cómo volver a crear la carga de trabajo

En los siguientes pasos, se muestra cómo borrar el Deployment existente y aplicar un manifiesto actualizado al clúster. También puedes usar estos pasos para otros tipos de cargas de trabajo de Kubernetes, como los trabajos.

Para asegurarte de que GKE coloque los Pods actualizados en el tipo correcto de nodo, debes exportar el estado existente de la carga de trabajo desde el servidor de la API de Kubernetes a un archivo y editar ese archivo.

  1. Escribe la especificación de la carga de trabajo en un archivo YAML:

    kubectl get deployment DEPLOYMENT_NAME -o yaml > DEPLOYMENT_NAME-on-demand.yaml
    

    Reemplaza DEPLOYMENT_NAME por el nombre de tu implementación. Para otros tipos de cargas de trabajo, como Jobs o Pods, usa el nombre de recurso correspondiente en tu comando kubectl get, como kubectl get pod.

  2. Abre el archivo YAML en un editor de texto:

    vi DEPLOYMENT_NAME-on-demand.yaml
    
  3. Quita el selector de nodos para los Pods Spot y la tolerancia que GKE agregó para los Pods Spot del archivo:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
      # lines omitted for clarity
    spec:
      progressDeadlineSeconds: 600
      replicas: 6
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          pod: nginx-pod
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
        # lines omitted for clarity
        spec:
          containers:
          - image: nginx
            imagePullPolicy: Always
            name: web-server
            resources:
              limits:
                ephemeral-storage: 1Gi
              requests:
                cpu: 500m
                ephemeral-storage: 1Gi
                memory: 2Gi
            securityContext:
              capabilities:
                drop:
                - NET_RAW
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          nodeSelector:
            cloud.google.com/gke-spot: "true"
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext:
            seccompProfile:
              type: RuntimeDefault
          terminationGracePeriodSeconds: 15
          tolerations:
          - effect: NoSchedule
            key: kubernetes.io/arch
            operator: Equal
            value: amd64
          - effect: NoSchedule
            key: cloud.google.com/gke-spot
            operator: Equal
            value: "true"
    status:
      #lines omitted for clarity
    

    Debes quitar la tolerancia y el nodeSelector para indicarle a GKE que los Pods deben ejecutarse en nodos bajo demanda en lugar de en nodos Spot.

  4. Guarda el manifiesto actualizado.

  5. Borra y vuelve a aplicar el manifiesto de Deployment al clúster:

    kubectl replace -f DEPLOYMENT_NAME-on-demand.yaml
    

    La duración de esta operación depende de la cantidad de Pods que GKE necesita finalizar y limpiar.

Edita la carga de trabajo en el lugar

En los siguientes pasos, se muestra cómo editar una Deployment en ejecución de forma local para indicarle a GKE que los Pods deben ejecutarse en nodos a pedido. También puedes usar estos pasos para otros tipos de cargas de trabajo de Kubernetes, como Jobs.

Debes editar el objeto de carga de trabajo en la API de Kubernetes, ya que GKE agrega automáticamente una tolerancia para los Spot Pods a la especificación de la carga de trabajo durante la admisión de la carga de trabajo.

  1. Abre el manifiesto de la carga de trabajo para editarlo en un editor de texto:

    kubectl edit deployment/DEPLOYMENT_NAME
    

    Reemplaza DEPLOYMENT_NAME por el nombre de la Deployment. Para otros tipos de cargas de trabajo, como Jobs o Pods, usa el nombre de recurso correspondiente en tu comando kubectl edit, como kubectl edit pod/POD_NAME.

  2. En tu editor de texto, borra el selector de nodos o la regla de afinidad de nodos para los Pods Spot y la tolerancia que GKE agregó al manifiesto, como en el siguiente ejemplo:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-deployment
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          type: dev
      template:
        metadata:
          labels:
            type: dev
        spec:
          nodeSelector:
            cloud.google.com/gke-spot: "true"
          tolerations:
          - effect: NoSchedule
            key: cloud.google.com/gke-spot
            operator: Equal
            value: "true"
          containers:
          - name: nginx
            image: nginx
            ports:
            - containerPort: 80
    
  3. Guarda el manifiesto actualizado y cierra el editor de texto. La configuración del objeto actualizado le indica a GKE que los Pods deben ejecutarse en nodos bajo demanda. GKE vuelve a crear los Pods para colocarlos en nodos nuevos a pedido.

Verifica que las cargas de trabajo se ejecuten en nodos a pedido

Para verificar que tus cargas de trabajo actualizadas ya no se ejecuten en Pods de Spot, inspecciona la carga de trabajo y busca la tolerancia para los Pods de Spot:

  • Inspecciona la carga de trabajo:

    kubectl describe deployment DEPLOYMENT_NAME
    

El resultado no muestra una entrada para cloud.google.com/gke-spot en el campo spec.tolerations.

¿Qué sigue?