Actualiza un clúster de GKE que ejecuta una carga de trabajo con estado

En este instructivo, se proporcionan 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 instructivo, se proporcionan ejemplos para implementar una aplicación de Redis, pero los mismos conceptos se aplican a otros tipos de aplicaciones con estado implementadas en GKE.

Glosario

Los términos que se usan en este instructivo son los siguientes:

  • Redis es un almacén de estructura de datos en la memoria de código abierto (con licencia BSD), que se usa como base de datos, caché y agente de mensajes.
  • Un clúster de Redis es una implementación distribuida de Redis que proporciona alta disponibilidad. Los clústeres de Redis consisten en nodos líderes y nodos seguidores.
  • Una aplicación con estado puede recordar información sobre su estado cada vez que se ejecuta. Redis es una popular base de datos en la memoria para aplicaciones con estado.

Objetivos

En este instructivo, se analizan los siguientes pasos:

  • Crear un clúster de Redis en GKE con tres líderes y tres seguidores sobre tres nodos de GKE
  • Implementar una aplicación cliente de Redis. La aplicación cuenta la cantidad de solicitudes que se envían a un sitio web
  • Actualizar el clúster con la actualización de aumento
  • Probar la interrupción de la carga de trabajo y la interrupción del estado de la aplicación

En el siguiente diagrama, se muestra una descripción general de la arquitectura de clúster que crearás cuando completes estos objetivos:

Diagrama de arquitectura

Costos

En este instructivo, se usan los siguientes componentes facturables de Google Cloud:

  • GKE

Usa la calculadora de precios para generar una estimación de los costos según el uso previsto. Los usuarios nuevos de Google Cloud pueden ser elegibles para obtener una prueba gratuita.

Antes de comenzar

Sigue los pasos que se indican a continuación para habilitar la API de Kubernetes Engine:
  1. Consulta la página de Kubernetes Engine en Google Cloud Console.
  2. Crea o selecciona un proyecto.
  3. Espera a que la API y los servicios relacionados se habiliten. Esto puede tardar varios minutos.
  4. Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Descubre cómo confirmar que tienes habilitada la facturación en un proyecto.

Instala las siguientes herramientas de línea de comandos de este instructivo:

  • gcloud se usa para crear y borrar clústeres de Kubernetes Engine. gcloud se incluye en el SDK de Google Cloud.
  • kubectl se usa para administrar Kubernetes, el sistema de organización de clústeres que emplea Kubernetes Engine. Puedes instalar kubectl mediante gcloud:
    gcloud components install kubectl

Crea un clúster de GKE

En esta sección, crearás un clúster en GKE con tres nodos y verificarás que el clúster esté en funcionamiento.

Establece valores predeterminados para la herramienta de línea de comandos de gcloud

Para ahorrar tiempo cuando escribes las opciones del ID del proyecto y la zona de Compute Engine en la herramienta de línea de comandos de gcloud, configura los siguientes valores predeterminados:

gcloud config set project PROJECT-ID
gcloud config set compute/zone COMPUTE-ZONE

Crea un clúster de GKE

Para crear un clúster de GKE, completa los siguientes pasos:

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

    gcloud container clusters create redis-test \
        --num-nodes=3
    

    Una vez que se cree el clúster, deberías ver un resultado similar al siguiente:

    NAME        LOCATION      MASTER_VERSION  MASTER_IP     MACHINE_TYPE   NODE_VERSION    NUM_NODES  STATUS
    redis-test  COMPUTE-ZONE  1.15.12-gke.20  35.232.77.38  n1-standard-1  1.15.12-gke.20  3          RUNNING
    
  2. Configura kubectl para comunicarse con el clúster:

    gcloud container clusters get-credentials redis-test
    
  3. Verifica que el clúster esté en ejecución:

    kubectl get nodes
    

    Deberías ver un resultado similar al siguiente:

    NAME                                        STATUS   ROLES    AGE     VERSION
    gke-redis-test-default-pool-c4e4225c-mw3w   Ready    <none>   2m1s    v1.15.12-gke.20
    gke-redis-test-default-pool-c4e4225c-pv51   Ready    <none>   2m1s    v1.15.12-gke.20
    gke-redis-test-default-pool-c4e4225c-whl5   Ready    <none>   2m1s    v1.15.12-gke.20
    

Crea un clúster de Redis en GKE

En esta sección, crearás un clúster de Redis sobre el clúster de GKE que creaste en la sección anterior mediante la creación de un ConfigMap, un StatefulSet, y un Service sin interfaz gráfica.

  1. Clona los manifiestos de muestra:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    cd kubernetes-engine-samples/hello-app-redis/manifests
    
  2. Un ConfigMap llamado redis-configmap.yaml almacena la configuración de Redis.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: redis-cluster
    data:
      redis.conf:  |+
        cluster-enabled yes
        cluster-node-timeout 15000
        cluster-config-file /data/nodes.conf
        appendonly yes
        protected-mode no
        dir /data
        port 6379
    
    

    Para obtener más información sobre los parámetros de Redis en este ConfigMap, consulta la sección de parámetros de configuración del clúster de Redis en el Instructivo del clúster de Redis.

  3. Implementa el ConfigMap mediante la ejecución del siguiente comando:

    kubectl apply -f redis-configmap.yaml
    
  4. El Statefulset llamado redis-cluster.yaml tiene los siguientes campos clave:

    • El campo replicas está configurado como 6. Esto significa que cada nodo de GKE tiene dos Pods para los 3 líderes de Redis y los 3 seguidores de Redis.
    • El campo volumeClaimTemplates proporciona almacenamiento estable mediante PersistentVolumes.
    • El campo affinity crea una regla de antiafinidad de Pods a fin de distribuir Pods en los nodos de Kubernetes.
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: redis
    spec:
      serviceName: "redis-service"
      replicas: 6
      selector:
        matchLabels:
          app: redis
      template:
        metadata:
          labels:
            app: redis
            appCluster: redis-cluster
        spec:
          terminationGracePeriodSeconds: 20
          affinity:
            podAntiAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
              - weight: 100
                podAffinityTerm:
                  labelSelector:
                    matchExpressions:
                    - key: app
                      operator: In
                      values:
                      - redis
                  topologyKey: kubernetes.io/hostname
          containers:
          - name: redis
            image: "redis"
            command:
              - "redis-server"
            args:
              - "/conf/redis.conf"
              - "--protected-mode"
              - "no"
            resources:
              requests:
                cpu: "100m"
                memory: "100Mi"
            ports:
                - name: redis
                  containerPort: 6379
                  protocol: "TCP"
                - name: cluster
                  containerPort: 16379
                  protocol: "TCP"
            volumeMounts:
            - name: conf
              mountPath: /conf
              readOnly: false
            - name: data
              mountPath: /data
              readOnly: false
          volumes:
          - name: conf
            configMap:
              name: redis-cluster
              defaultMode: 0755
      volumeClaimTemplates:
      - metadata:
          name: data
        spec:
          accessModes: [ "ReadWriteOnce" ]
          resources:
            requests:
              storage: 1Gi
    
    
  5. Para implementar StatefulSet, ejecuta el siguiente comando:

    kubectl apply -f redis-cluster.yaml
    
  6. El Service sin interfaz gráfica llamado redis-service.yaml es para la conexión de nodos de Redis. Para crear un Service sin interfaz gráfica, establece el campo clusterIP en None.

    apiVersion: v1
    kind: Service
    metadata:
      name: redis-cluster
    spec:
      clusterIP: None
      ports:
      - name: redis-port
        port: 6379
        protocol: TCP
        targetPort: 6379
      selector:
        app: redis
        appCluster: redis-cluster
      sessionAffinity: None
      type: ClusterIP
    
    
  7. Para implementar el Service, ejecuta el siguiente comando:

    kubectl apply -f redis-service.yaml
    
  8. Espera aproximadamente dos minutos y verifica que todos los Pods estén en ejecución mediante el siguiente comando:

    kubectl get pods
    

    Deberías ver un resultado similar al siguiente:

    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
    
  9. Ejecuta el siguiente comando para verificar que se crearon los volúmenes persistentes:

    kubectl get pv
    

    Deberías ver un resultado similar al siguiente:

    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 adjunto a cada nombre de volumen persistente.

Asigna funciones al clúster de Redis

Una vez que completes la configuración, asignarás funciones al clúster de Redis.

Para asignar las funciones, completa los siguientes pasos:

  1. Establece los tres primeros nodos de Redis como líderes y los tres últimos nodos de Redis como seguidores:

    1. Recupera y haz una copia de las direcciones IP del Pod:

      kubectl get pods -l app=redis -o jsonpath='{range.items[*]}{.status.podIP} '
      
    2. Asigna las funciones de líder y de seguidor. Para ello, pega cada una de las direcciones IP del Pod en el siguiente comando y escribe yes cuando se te solicite:

      kubectl exec -it redis-0 -- redis-cli --cluster create --cluster-replicas 1 \
      POD-IP-1:6379 POD-IP-2:6379 POD-IP-3:6379 \
      POD-IP-4:6379 POD-IP-5:6379 POD-IP-6:6379
      
  2. Verifica que el clúster de Redis esté en ejecución:

    kubectl exec -it redis-0 -- redis-cli cluster info
    

    Deberías ver un resultado similar al siguiente:

    cluster_state:ok
    # ...other output...
    
  3. Accede a un nodo de Redis para verificar su función. Por ejemplo, para verificar que redis-0 tenga una función líder, ejecuta el siguiente comando:

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

    Deberías ver un resultado similar al siguiente:

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

Crea una aplicación cliente de Redis

En esta sección, crearás una aplicación llamada hello-app-redis que use Redis como base de datos de caché, cuente la cantidad de solicitudes que recibe y copie esta cantidad en un sitio web. Si el Service de Redis funciona, la cantidad seguirá aumentando.

Puedes descargar la imagen directamente desde gcr.io/google-samples/hello-app-redis:1.0 en Google Cloud Console.

Para extraer la imagen, ejecuta el siguiente comando:

docker pull gcr.io/google-samples/hello-app-redis:1.0

Para obtener más información sobre cómo compilar imágenes, consulta Compila la imagen de contenedor.

Implementa la aplicación cliente de Redis en GKE

A fin de implementar la aplicación en el clúster de GKE que creaste, necesitas un Deployment para definir la aplicación.

Para crear el Deployment, sigue estos pasos:

  1. El archivo llamado app-deployment.yaml contiene los detalles de la aplicación.

    # Copyright 2020 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: hello-web
      name: hello-web
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: hello-web
      template:
        metadata:
          labels:
            app: hello-web
        spec:
          # Pod anti affinity config START
          affinity:
            podAntiAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
              - labelSelector:
                  matchExpressions:
                  - key: app
                    operator: In
                    values:
                    - hello-web
                topologyKey: kubernetes.io/hostname
          # Pod anti affinity config END
          containers:
          - image: gcr.io/google-samples/hello-app-redis:1.0  # change to the image name you built
            name: hello-app
            # Readiness probe config START
            readinessProbe:
              failureThreshold: 1
              httpGet:
                path: /healthz
                port: 8080
                scheme: HTTP
              initialDelaySeconds: 1
              periodSeconds: 1
              successThreshold: 1
              timeoutSeconds: 1
    

    Para obtener más información sobre los sondeos y las reglas de afinidad de Pods que se usan en esta implementación, consulta Prácticas recomendadas de GKE: Diseña y compila clústeres con alta disponibilidad.

  2. Ejecuta el siguiente comando para aplicar el Deployment:

    kubectl apply -f app-deployment.yaml
    

    Asegúrate de ejecutar este comando en el mismo directorio en el que se encuentra app-deployment.yaml.

  3. Expón la aplicación a través de un balanceador de cargas:

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

    kubectl get service
    

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

    NAME             TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)              AGE
    hello-web        LoadBalancer   10.13.10.55   EXTERNAL_IP   80:30703/TCP         166m
    
  5. Verifica que la aplicación funcione. Para ello, pega EXTERNAL_IP en el navegador web. Deberías ver un resultado similar al siguiente:

    I have been hit [1] times since deployment!
    

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

  6. Establece una variable para la EXTERNAL_IP que acabas de copiar. Este valor se usa cuando creas secuencias de comandos para probar la aplicación en la siguiente sección:

    export IP=EXTERNAL_IP
    

Actualiza el clúster de GKE y prueba la interrupción de la carga de trabajo

En las siguientes secciones, actualizarás el clúster de GKE y notarás lo que sucede mediante el uso de las secuencias de comandos que creas.

Prueba la aplicación

En esta sección, usarás dos secuencias de comandos, una que envía solicitudes a la aplicación y otra que mide la tasa de éxito de las solicitudes. Usarás estas secuencias de comandos para medir lo que sucede cuando actualizas el clúster.

Para crear las secuencias de comandos, sigue estos pasos:

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

    cd
    cd kubernetes-engine-samples/hello-app-redis/scripts
    
  2. La secuencia de comandos llamada generate_load.sh envía una solicitud de consultas por segundo (QPS) a la aplicación. Esta 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 paso siguiente.

    # Copyright 2020 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    #!/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. Una segunda secuencia de comandos llamada print_error_rate.sh calcula la tasa de éxito en función del resultado que generó generate_load.sh.

    # Copyright 2020 Google LLC
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    #!/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. Otórgate permiso para ejecutar las secuencias de comandos:

    chmod u+x generate_load.sh print_error_rate.sh
    
  5. Establece una variable para la cantidad de QPS. Este valor se usa en la secuencia de comandos generate_load.sh como la variable que configuraste para la EXTERNAL_IP. Te recomendamos establecer un valor de 40.

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

    ./generate_load.sh $IP $QPS 2>&1
    
  7. Deja la secuencia de comandos generate_load.sh en ejecución y abre una terminal nueva. En la terminal nueva, ejecuta la secuencia de comandos print_error_rate.sh para verificar la tasa de error:

    watch ./print_error_rate.sh
    

    Deberías ver una tasa de éxito del 100% y una tasa de error del 0% a medida que se realizan las QPS.

  8. Deja las secuencias de comandos en ejecución y abre una tercera terminal en preparación para la siguiente sección.

Actualiza el clúster

En esta sección, actualizarás las cargas de trabajo:

  1. En la terminal que acabas de abrir, define la configuración de la actualización mediante la actualización de aumento:

    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 agregar un nodo de aumento al grupo de nodos durante una actualización, de modo que solo se puede actualizar un nodo a la vez. Esta configuración acelera el reinicio de los Pods durante las actualizaciones mientras se procesa de forma conservadora.

  2. 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ías ver un resultado similar al siguiente ejemplo: 1.15.12-gke.20.

  3. Recupera una lista de las versiones de Kubernetes disponibles:

    gcloud container get-server-config
    
  4. En la lista de versiones, ubica la sección validMasterVersions: y busca la versión de redis-cluster que recuperaste en el paso anterior. Para evitar el sesgo de versión, copia la versión de la lista que aparece justo sobre la versión de redis-cluster.

  5. Actualiza el plano de control del clúster a la versión que seleccionaste y escribe y cuando se te solicite:

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

    Reemplaza VERSION por la versión que seleccionaste de la lista en el paso anterior.

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

  6. Actualiza los nodos del clúster a la versión que seleccionaste y escribe y cuando se te solicite:

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

    Reemplaza VERSION por la versión que seleccionaste de la lista.

Prueba la interrupción de la carga de trabajo

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

  1. Regresa a la ventana de la terminal que ejecuta ./print_error_rate.sh y observa cómo cambió la tasa de éxito durante la actualización. Deberías notar una leve disminución en la tasa de éxito y un ligero aumento en la tasa de error de red de la app, ya que se quitaron los nodos para actualizarlos.

    En el campo Success rate, verás cuántas visitas al sitio web se realizaron de manera correcta. Toma nota de este valor.

  2. Ingresa CTRL+C en las terminales relevantes para evitar que se ejecuten ambas secuencias de comandos.

  3. Para volver al sitio web de la aplicación, ingresa la dirección IP (es la EXTERNAL_IP que copiaste durante la sección Implementa en GKE) en el navegador.

  4. Observa el número de visita de la aplicación. El número que ves debe ser igual a lo siguiente:

    ORIGINAL_VISIT_NUMBER + SUCCESSFUL_VISIT_NUMBER

    En el ejemplo anterior, ORIGINAL_VISIT_NUMBER es el número que registraste en el paso final de Implementa en GKE, y SUCCESSFUL_VISIT_NUMBER es el valor que registraste en el primer paso de esta sección.

Realiza una limpieza

Luego de finalizar el instructivo de actualización de una carga de trabajo con estado, puedes limpiar los recursos que creaste en Google Cloud para que no consuman tu cuota y no se te cobre por ellos en el futuro. En las siguientes secciones, se describe cómo borrar o desactivar estos recursos.

Borra el proyecto

La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.

Para borrar el proyecto, haz lo siguiente:

  1. En Cloud Console, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

Borra clústeres

Para borrar el clúster que creaste en este instructivo, ejecuta el siguiente comando:

gcloud container clusters delete redis-test

¿Qué sigue?

  • Explora arquitecturas de referencia, diagramas, instructivos y prácticas recomendadas sobre Google Cloud. Consulta nuestro Cloud Architecture Center.