Desplegar un clúster de Redis en GKE

En este tutorial se ofrecen prácticas recomendadas para crear una aplicación con estado y actualizar el clúster de Google Kubernetes Engine (GKE) que ejecuta la aplicación. En este tutorial se usa Redis como ejemplo para desplegar una aplicación con reconocimiento del estado, pero los mismos conceptos se pueden aplicar a otros tipos de aplicaciones con reconocimiento del estado desplegadas en GKE.

Crear un clúster de GKE registrado en un canal de lanzamiento

Para crear tu clúster de GKE, sigue estos pasos:

  1. Crea un clúster llamado redis-test con tres nodos:

    gcloud container clusters create redis-test \
        --location CONTROL_PLANE_LOCATION \
        --num-nodes=3 \
        --release-channel regular
    

    Sustituye CONTROL_PLANE_LOCATION por la ubicación de Compute Engine del plano de control de tu clúster. Proporciona una región para los clústeres regionales o una zona para los clústeres zonales.

    Una vez creado el clúster, debería ver un resultado similar al siguiente ejemplo:

      NAME: redis-test
      LOCATION: us-central1-c
      MASTER_VERSION: 1.22.10-gke.600
      MASTER_IP: 34.69.67.7
      MACHINE_TYPE: e2-medium
      NODE_VERSION: 1.22.10-gke.600
      NUM_NODES: 3
      STATUS: RUNNING
    
  2. Configura kubectl para que se comunique con el clúster:

    gcloud container clusters get-credentials redis-test
    

Crear un clúster de Redis en GKE

En esta sección, añadirás un clúster de Redis al clúster de GKE que has creado anteriormente implementando un ConfigMap, un StatefulSet y un servicio sin encabezado.

Para crear un clúster de Redis, sigue estos pasos:

  1. Consulta el archivo ConfigMap (redis-configmap.yaml), que almacena la configuración de Redis. En el siguiente fragmento se muestran las secuencias de comandos de las comprobaciones de preparación y de vivacidad.

    readiness.sh: |-
      #!/bin/sh
    
      pingResponse="$(redis-cli -h localhost ping)"
      if [ "$?" -eq "124" ]; then
        echo "PING timed out"
        exit 1
      fi
    
      if [ "$pingResponse" != "PONG"]; then
        echo "$pingResponse"
        exit 1
      fi
    liveness.sh: |-
      #!/bin/sh
    
      pingResponse="$(redis-cli -h localhost ping | head -n1 | awk '{print $1;}')"
      if [ "$?" -eq "124" ]; then
        echo "PING timed out"
        exit 1
      fi
    
      if [ "$pingResponse" != "PONG"] && [ "$pingResponse" != "LOADING" ] && [ "$pingResponse" != "MASTERDOWN" ]; then
        echo "$pingResponse"
        exit 1
      fi

    Las secuencias de comandos readiness.sh y liveness.sh usan redis-cli ping para comprobar si el servidor de Redis está en funcionamiento o no. Si devuelve PONG, el servidor Redis está en funcionamiento. Estas secuencias de comandos se usarán en el redis-cluster.yaml.

    Para obtener más información sobre los parámetros de Redis de este ConfigMap, consulta la sección de parámetros de configuración de Redis Cluster en el tutorial de Redis Cluster.

  2. Despliega el ConfigMap:

    kubectl apply -f redis-configmap.yaml
    
  3. Consulta el fragmento de StatefulSet (redis-cluster.yaml) que se muestra a continuación, donde se indica cómo usar la comprobación de disponibilidad y la comprobación de actividad.

    Para saber cómo configurar comprobaciones en Kubernetes, consulta Configurar comprobaciones.

    startupProbe:
      periodSeconds: 5
      timeoutSeconds: 5
      successThreshold: 1
      failureThreshold: 20
      tcpSocket:
        port: redis
    livenessProbe:
      periodSeconds: 5
      timeoutSeconds: 5
      successThreshold: 1
      failureThreshold: 5
      exec:
        command: ["sh", "-c", "/probes/liveness.sh"]
    readinessProbe:
      periodSeconds: 5
      timeoutSeconds: 1
      successThreshold: 1
      failureThreshold: 5
      exec:
        command: ["sh", "-c", "/probes/readiness.sh"]

    Te recomendamos que uses sondas de disponibilidad y de actividad al actualizar grupos de nodos. De esta forma, te aseguras de que tus pods estén listos durante la actualización.

  4. Implementa el StatefulSet:

    kubectl apply -f redis-cluster.yaml
    
  5. El servicio sin encabezado llamado redis-service.yaml es para la conexión de los nodos de Redis. El campo clusterIP se define como None para crear un servicio sin interfaz gráfica.

    Despliega el servicio:

    kubectl apply -f redis-service.yaml
    
  6. Espera unos dos minutos y comprueba que todos los pods se estén ejecutando con el siguiente comando:

    kubectl get pods
    

    Debería ver un resultado similar al siguiente ejemplo:

    NAME      READY   STATUS              RESTARTS   AGE
    redis-0   1/1     Running             0          2m29s
    redis-1   1/1     Running             0          2m8s
    redis-2   1/1     Running             0          107s
    redis-3   1/1     Running             0          85s
    redis-4   1/1     Running             0          54s
    redis-5   1/1     Running             0          23s
    
  7. Para verificar que se han creado los volúmenes persistentes, ejecuta el siguiente comando:

    kubectl get pv
    

    Debería ver un resultado similar al siguiente ejemplo:

    NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS   REASON   AGE
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-5   standard                75s
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-1   standard                2m59s
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-3   standard                2m16s
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-2   standard                2m38s
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-0   standard                3m20s
    pvc-HASH   1Gi        RWO            Delete           Bound    default/data-redis-4   standard                104s
    

    En este resultado, HASH representa un hash que se adjunta a cada nombre de volumen persistente.

Asignar roles a tu clúster de Redis

Una vez completada la configuración, asigna roles al clúster de Redis.

La siguiente secuencia de comandos obtiene las direcciones IP de los pods y, a continuación, asigna los roles de líder y seguidor pasando cada una de las direcciones IP de los pods al comando:

#!/bin/bash
# Usage: ./roles.sh

urls=$(kubectl get pods -l app=redis -o jsonpath='{range.items[*]}{.status.podIP} ')
command="kubectl exec -it redis-0 -- redis-cli --cluster create --cluster-replicas 1 "

for url in $urls
do
    command+=$url":6379 "
done

echo "Executing command: " $command
$command

Para asignar roles a tu clúster de Redis, sigue estos pasos:

  1. Ejecuta la secuencia de comandos:

    chmod +x ./roles.sh
    ./roles.sh
    
  2. Escribe yes cuando se te pida.

  3. Inicia sesión en un nodo de Redis para comprobar su rol. Por ejemplo, para verificar que redis-0 tiene el rol de líder, ejecuta el siguiente comando:

    kubectl exec -it redis-0 -- redis-cli role
    

    Debería ver un resultado similar al siguiente ejemplo:

    1) "master"
    2) (integer) 574
    3) 1) 1) "10.28.2.3"
           2) "6379"
           3) "574"
    

Desplegar la aplicación cliente de Redis

Para desplegar tu aplicación en el clúster de GKE que has creado, define un Deployment para tu aplicación. El archivo llamado app-deployment.yaml contiene la definición de implementación de la aplicación.

Para obtener más información sobre las sondas y las reglas de afinidad de pods que se usan en esta implementación, consulta Prácticas recomendadas de GKE: diseñar y crear clústeres de alta disponibilidad.

Para crear la implementación, sigue estos pasos:

  1. Aplica el despliegue:

    kubectl apply -f app-deployment.yaml
    
  2. Exponga la aplicación a través de un balanceador de carga:

    kubectl expose deployment hello-web \
        --type=LoadBalancer \
        --port 80 \
        --target-port 8080
    
  3. Espera aproximadamente un minuto y recupera la dirección IP externa de la aplicación ejecutando el siguiente comando:

    kubectl get service
    

    En el resultado, copie el valor que aparece en la columna hello-web's EXTERNAL-IP:

    NAME             TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)              AGE
    hello-web        LoadBalancer   10.13.10.55   EXTERNAL_IP   80:30703/TCP         166m
    
  4. Verifica que la aplicación funciona pegando el EXTERNAL_IP en tu navegador web. Debería ver un resultado similar al siguiente ejemplo:

    I have been hit [1] times since deployment!
    

    Anota el número de visita. Debes usarlo en la sección Probar la interrupción de la aplicación.

  5. Define una variable para el EXTERNAL_IP que acabas de copiar. Usará este valor cuando cree secuencias de comandos para probar su aplicación en la siguiente sección:

    export IP=EXTERNAL_IP
    

Configurar las prácticas recomendadas para las actualizaciones de grupos de nodos

Sigue estas prácticas recomendadas para aplicaciones con estado y optimiza la disponibilidad durante las actualizaciones de grupos de nodos.

Configurar el presupuesto de interrupción de pods (PDB)

Crea un presupuesto de interrupción de pods para limitar el número de pods replicados que no funcionan simultáneamente durante una interrupción voluntaria. Esto es útil para las aplicaciones con estado en las que debe haber un quórum para que el número de réplicas esté disponible durante una actualización.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: redis-pdb
spec:
  minAvailable: 3
  selector:
    matchLabels:
      app: redis

En una definición de PDB:

  • app especifica a qué aplicación se aplica este PDB.
  • minAvailable define el número mínimo de pods que deben estar disponibles durante una interrupción. Puede ser un valor o un porcentaje (por ejemplo, 30%).
  • maxUnavailable define el número máximo de pods que pueden no estar disponibles durante una interrupción. También puede ser un valor o un porcentaje.

Para configurar la PDB, sigue estos pasos:

  1. Implementa el PDB:

    kubectl apply -f pdb-minavailable.yaml
    
  2. Comprueba que se haya creado el PDB:

    kubectl get pdb
    

Configurar las ventanas de mantenimiento y las exclusiones

Las actualizaciones automáticas de nodos simplifican el proceso de actualización y mantienen los nodos del clúster actualizados cuando se actualiza el plano de control en tu nombre. Esta opción está habilitada de forma predeterminada. Para obtener más información, consulta Actualizar la versión de los nodos automáticamente.

Usa las ventanas de mantenimiento y las exclusiones de mantenimiento para configurar periodos y controlar cuándo se puede y cuándo no se puede llevar a cabo el mantenimiento en los clústeres de GKE:

  1. Configura una ventana de mantenimiento que empiece el 19 de agosto del 2022 a las 2:00 (UTC) y termine cuatro horas después. Esta ventana de mantenimiento se ejecuta a diario. Durante este periodo, se permite el mantenimiento automático.

    gcloud container clusters update redis-test \
       --maintenance-window-start 2022-08-19T02:00:00Z \
       --maintenance-window-end 2022-08-19T06:00:00Z \
       --maintenance-window-recurrence FREQ=DAILY
    
  2. Configura una ventana de exclusión que impida que se realicen tareas de mantenimiento durante las vacaciones de Año Nuevo. Esta exclusión de mantenimiento usa el ámbito no_upgrades. Durante este periodo, no se permite ningún tipo de mantenimiento automático. Para obtener más información, consulta Ámbito del mantenimiento que se va a excluir.

    gcloud container clusters update redis-test \
       --add-maintenance-exclusion-name new-year \
       --add-maintenance-exclusion-start 2022-12-26T00:00:00Z \
       --add-maintenance-exclusion-end 2023-01-02T02:00:00Z \
       --add-maintenance-exclusion-scope no_upgrades
    
  3. Verifica que se hayan aplicado la ventana de mantenimiento y las exclusiones. Busca en maintenancePolicy:.

    gcloud container clusters describe redis-test
    

Para obtener más información, consulta el artículo Configurar ventanas de mantenimiento y exclusiones.

Configurar una estrategia de actualización de nodos

Puedes usar dos estrategias de actualización de nodos para los grupos de nodos de tu clúster de GKE: actualizaciones azul-verde y actualizaciones de aumento. Para obtener más información, consulta Estrategias de actualización de nodos.

Actualizaciones azul-verde

Elige las actualizaciones azul-verde si las cargas de trabajo toleran menos las interrupciones y se puede aceptar un aumento temporal de los costes debido a un mayor uso de los recursos.

Ejecuta el siguiente comando para cambiar los grupos de nodos actuales a la estrategia actualización azul-verde.

gcloud container node-pools update default-pool \
--cluster=redis-test \
--enable-blue-green-upgrade \
--location CONTROL_PLANE_LOCATION \
--node-pool-soak-duration=120s

La duración de la prueba de resistencia del grupo de nodos se ha establecido en dos minutos para ahorrar tiempo durante la fase de prueba de resistencia del grupo de nodos en este tutorial. Esta fase se usa para verificar el estado de la carga de trabajo después de que se hayan vaciado los nodos del grupo azul. Recomendamos definir la duración de la prueba de resistencia del grupo de nodos en una hora (3600 segundos) o en la duración que mejor se adapte a la aplicación.

Para obtener más información sobre cómo gestionar la asignación de pods, consulta los artículos Desplegar un pod en un grupo de nodos específico y Desplegar servicios en grupos de nodos específicos.

Para obtener más información sobre cómo configurar las actualizaciones azul-verde, consulta Configurar actualizaciones azul-verde.

Sobreaprovisionamiento para actualizaciones

Elige actualizaciones de picos si la optimización de costes es importante y si las cargas de trabajo pueden tolerar un cierre ordenado en menos de 60 minutos (GKE respeta los PDBs hasta 60 minutos).

Ejecuta el siguiente comando para cambiar los grupos de nodos actuales a la estrategia actualización de picos.

gcloud container node-pools update default-pool \
--max-surge-upgrade=1 \
--max-unavailable-upgrade=0 \
--cluster=redis-test

Con esta configuración (maxSurge=1 y maxUnavailable=0), solo se puede añadir un nodo de aumento al grupo de nodos durante una actualización, por lo que solo se puede actualizar un nodo a la vez. Este ajuste acelera los reinicios de los pods durante las actualizaciones mientras se avanza de forma conservadora.

Para obtener más información sobre cómo configurar las actualizaciones de subida de tensión, consulta Configurar actualizaciones de subida de tensión.

Comprueba la configuración del grupo de nodos actual:

   gcloud container node-pools describe default-pool \
   --cluster redis-test \
   --location CONTROL_PLANE_LOCATION

Para obtener más información sobre cómo ver los grupos de nodos, consulta Ver grupos de nodos en un clúster.

Probar la aplicación

En esta sección, usará dos secuencias de comandos: una que envía solicitudes a su aplicación y otra que mide la tasa de éxito de las solicitudes. Estos scripts se usan para medir lo que ocurre cuando actualizas el clúster.

Para crear las secuencias de comandos, sigue estos pasos:

  1. Ve al directorio que contiene las secuencias de comandos:

    cd
    cd kubernetes-engine-samples/quickstarts/hello-app-redis/scripts
    
  2. Consulta la secuencia de comandos llamada generate_load.sh, que envía una solicitud de consultas por segundo (CPS) a tu aplicación. La secuencia de comandos guarda el código de respuesta HTTP en el directorio actual en un archivo llamado output. El valor de output se usa en la secuencia de comandos que creas en el siguiente paso.

    #!/bin/bash
    # Usage: ./generate_load.sh <IP> <QPS>
    
    IP=$1
    QPS=$2
    
    while true
      do for N in $(seq 1 $QPS)
        do curl -I -m 5 -s -w "%{http_code}\n" -o /dev/null http://${IP}/ >> output &
        done
      sleep 1
    done
  3. Consulta la secuencia de comandos llamada print_error_rate.sh, que calcula la tasa de éxito en función del resultado generado por generate_load.sh.

    #!/bin/bash
    # Usage: watch ./print_error_rate.sh
    
    TOTAL=$(cat output | wc -l);
    SUCCESS=$(grep "200" output |  wc -l);
    ERROR1=$(grep "000" output |  wc -l)
    ERROR2=$(grep "503" output |  wc -l)
    ERROR3=$(grep "500" output |  wc -l)
    SUCCESS_RATE=$(($SUCCESS * 100 / TOTAL))
    ERROR_RATE=$(($ERROR1 * 100 / TOTAL))
    ERROR_RATE_2=$(($ERROR2 * 100 / TOTAL))
    ERROR_RATE_3=$(($ERROR3 * 100 / TOTAL))
    echo "Success rate: $SUCCESS/$TOTAL (${SUCCESS_RATE}%)"
    echo "App network Error rate: $ERROR1/$TOTAL (${ERROR_RATE}%)"
    echo "Resource Error rate: $ERROR2/$TOTAL (${ERROR_RATE_2}%)"
    echo "Redis Error rate: $ERROR3/$TOTAL (${ERROR_RATE_3}%)"
  4. Concédele permiso para ejecutar las secuencias de comandos:

    chmod u+x generate_load.sh print_error_rate.sh
    
  5. Define una variable para el número de consultas por segundo. Este valor se usa en la secuencia de comandos generate_load.sh, al igual que la variable que hayas definido para EXTERNAL_IP. Te recomendamos que definas un valor de 40.

    export QPS=40
    
  6. Ejecuta la secuencia de comandos generate_load.sh para empezar a enviar QPS:

    ./generate_load.sh $IP $QPS 2>&1
    
  7. Deja que se ejecute la secuencia de comandos generate_load.sh y abre una nueva terminal. En la nueva terminal, ejecuta la secuencia de comandos print_error_rate.sh para comprobar la tasa de errores:

    cd
    cd kubernetes-engine-samples/quickstarts/hello-app-redis/scripts
    watch ./print_error_rate.sh
    

    Deberías ver un porcentaje de éxito del 100% y un porcentaje de errores del 0% a medida que se realicen las QPS.

  8. Deja ambos scripts en ejecución y abre una tercera terminal para prepararte para la siguiente sección.

Actualizar el clúster

Para actualizar el clúster, sigue estos pasos:

  1. Determina qué versión de GKE usa el clúster redis-test:

    V=$(gcloud container clusters describe redis-test | grep "version:" | sed "s/version: //")
    echo $V
    

    Debería ver un resultado similar al siguiente ejemplo: 1.22.9-gke.2000.

  2. Obtén una lista de las versiones de Kubernetes disponibles:

    gcloud container get-server-config
    
  3. En la lista de versiones, busca la sección validMasterVersions: y la versión redis-test que has recuperado en el paso anterior. Para evitar infringir la política de diferencia de versiones de GKE al elegir una versión incompatible con los nodos, copia la versión de la lista que aparece inmediatamente antes de la versión redis-test.

  4. Actualiza el plano de control del clúster a la versión que has seleccionado y escribe y cuando se te pida:

    gcloud container clusters upgrade redis-test \
        --master \
        --cluster-version VERSION
    

    Sustituye VERSION por la versión que has seleccionado en la lista del paso anterior.

    La actualización del plano de control tarda varios minutos.

  5. Actualiza los nodos del clúster a la versión que has seleccionado y escribe y cuando se te pida:

    gcloud container clusters upgrade redis-test \
        --cluster-version=VERSION \
        --node-pool=default-pool
    

    Sustituye VERSION por la versión que has seleccionado de la lista.

Prueba de interrupción de la carga de trabajo

En esta sección, probarás el estado de tu aplicación y observarás la interrupción de la carga de trabajo.

  1. Vuelve a la ventana del terminal en la que se ejecuta ./print_error_rate.sh y observa cómo ha cambiado la tasa de éxito durante la actualización. Deberías notar una ligera disminución en la tasa de éxito y un ligero aumento en la tasa de error de la red de la aplicación a medida que se retiran los nodos para actualizarlos.

    En el campo Success rate, verás cuántas visitas se han realizado correctamente al sitio web. Anota este valor.

  2. Detén la ejecución de ambos scripts introduciendo CTRL+C en las terminales correspondientes.

  3. Vuelve al sitio web de tu aplicación introduciendo su dirección IP (el EXTERNAL_IP que has copiado en la sección Implementar la aplicación cliente de Redis) en tu navegador.

  4. Observa el número de visitas de tu aplicación. El número que veas debería ser igual a lo siguiente:

    ORIGINAL_VISIT_NUMBER + SUCCESSFUL_VISIT_NUMBER

    donde ORIGINAL_VISIT_NUMBER es el número que has registrado en el último paso de Implementar la aplicación cliente de Redis y SUCCESSFUL_VISIT_NUMBER es el valor que has registrado en el primer paso de esta sección.