Implementación continua en Google Kubernetes Engine (GKE) con Cloud Build

1. Descripción general

En este lab, aprenderás a configurar una canalización de entrega continua para GKE con Cloud Build. En este lab, se destaca cómo activar trabajos de Cloud Build para diferentes eventos de Git, así como un patrón simple para las versiones canary automatizadas en GKE.

Completarás los siguientes pasos:

  • Crea la aplicación de GKE
  • Automatiza las implementaciones para las ramas de Git
  • Automatiza las implementaciones para la rama principal de Git
  • Automatiza las implementaciones para las etiquetas de Git

2. Antes de comenzar

Para esta guía de referencia, necesitas un proyecto de Google Cloud. Puedes crear uno nuevo o seleccionar un proyecto que ya hayas creado:

  1. Selecciona o crea un proyecto de Google Cloud.

IR A LA PÁGINA DEL SELECTOR DE PROYECTOS

  1. Habilita la facturación para tu proyecto.

HABILITAR FACTURACIÓN

3. Prepara tu entorno

  1. Crea variables de entorno para usar en este instructivo:
    export PROJECT_ID=$(gcloud config get-value project)
    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
    
    export ZONE=us-central1-b
    export CLUSTER=gke-progression-cluster
    export APP_NAME=myapp
    
  2. Habilita las siguientes APIs:
    • Resource Manager
    • GKE
    • Cloud Source Repositories
    • Cloud Build
    • Container Registry
    gcloud services enable \
        cloudresourcemanager.googleapis.com \
        container.googleapis.com \
        sourcerepo.googleapis.com \
        cloudbuild.googleapis.com \
        containerregistry.googleapis.com \
        --async
    
  3. Clona el código fuente de muestra y cambia al directorio del lab:
    git clone https://github.com/GoogleCloudPlatform/software-delivery-workshop.git gke-progression
    
    cd gke-progression/labs/gke-progression
    rm -rf ../../.git
    
  4. Reemplaza los valores de marcador de posición en el repositorio de muestra por tu PROJECT_ID:En este paso, crearás instancias de los distintos archivos de configuración exclusivos de tu entorno actual.Para revisar un ejemplo de las plantillas que se actualizan, ejecuta el siguiente comando.
    cat k8s/deployments/dev/frontend-dev.yaml.tmpl
    
    Ejecuta el siguiente comando para realizar la sustitución de variables.
    for template in $(find . -name '*.tmpl'); do envsubst '${PROJECT_ID} ${ZONE} ${CLUSTER} ${APP_NAME}' < ${template} > ${template%.*}; done
    
    Para revisar un ejemplo del archivo después de la sustitución, ejecuta el siguiente comando.
    cat k8s/deployments/dev/frontend-dev.yaml
    
  5. Si nunca usaste Git en Cloud Shell, configura los valores user.name y user.email que deseas usar:
    git config --global user.email "YOUR_EMAIL_ADDRESS"
    git config --global user.name "YOUR_USERNAME"
    
  6. Almacena el código del repositorio de muestra en Cloud Source Repositories:
    gcloud source repos create gke-progression
    git init
    git config credential.helper gcloud.sh
    git remote add gcp https://source.developers.google.com/p/$PROJECT_ID/r/gke-progression
    git branch -m main
    git add . && git commit -m "initial commit"
    git push gcp main
    
  7. Crea tu clúster de GKE.
    gcloud container clusters create ${CLUSTER} \
        --project=${PROJECT_ID} \
        --zone=${ZONE}
    
  8. Otorga derechos de Cloud Build a tu clúster.Cloud Build implementará la aplicación en tu clúster de GKE y necesitará derechos para hacerlo.
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
        --role=roles/container.developer
    

Tu entorno está listo.

4. Crea tu aplicación de GKE

En esta sección, compilarás y también implementarás la aplicación de producción inicial que usarás en este instructivo.

  1. Compila la aplicación con Cloud Build:
    gcloud builds submit --tag gcr.io/$PROJECT_ID/$APP_NAME:1.0.0 src/
    
  2. Realiza la implementación manual en los entornos de producción y Canary:Crea los servicios y las implementaciones de producción y Canary con los comandos kubectl apply.
    kubectl create ns production
    kubectl apply -f k8s/deployments/prod -n production
    kubectl apply -f k8s/deployments/canary -n production
    kubectl apply -f k8s/services -n production
    
    El servicio implementado aquí enrutará el tráfico a las implementaciones de versiones canary y de producción.
  3. Revisa la cantidad de Pods en ejecución. Confirma que tienes cuatro Pods en ejecución para el frontend, incluidos tres para el tráfico de producción y uno para los lanzamientos Canary. Esto significa que los cambios en el lanzamiento Canary solo afectarán a 1 de cada 4 usuarios (el 25%).
    kubectl get pods -n production -l app=$APP_NAME -l role=frontend
    
  4. Recupera la dirección IP externa para los servicios de producción.
    kubectl get service $APP_NAME -n production
    
    Una vez que el balanceador de cargas devuelva la dirección IP, continúa con el siguiente paso.
  5. Almacena la IP externa para usarla más adelante.
    export PRODUCTION_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}"  --namespace=production services $APP_NAME)
    
  6. Revisa la aplicación. Verifica el resultado de la versión del servicio. Debería decir Hello World v1.0
    curl http://$PRODUCTION_IP
    

¡Felicitaciones! Implementaste la app de ejemplo. A continuación, configurarás activadores para implementar tus cambios de forma continua.

5. Automatiza las implementaciones para las ramas de Git

En esta sección, configurarás un activador que ejecutará un trabajo de Cloud Build cuando se confirme cualquier rama que no sea main. El archivo de Cloud Build que se usa aquí creará automáticamente un espacio de nombres y una implementación para cualquier rama existente o nueva, lo que permitirá que los desarrolladores obtengan una vista previa de su código antes de la integración con la rama principal.

  1. Configura el activador:El componente clave de este activador es el uso del parámetro branchName para que coincida con main y el parámetro invertRegex, que se establece en verdadero y altera el patrón branchName para que coincida con cualquier elemento que no sea main. Para tu referencia, puedes encontrar las siguientes líneas en build/branch-trigger.json.
      "branchName": "main",
      "invertRegex": true
    
    Además, las últimas líneas del archivo de Cloud Build que se usa con este activador crean un espacio de nombres con el nombre de la rama que activó el trabajo y, luego, implementan la aplicación y el servicio dentro del nuevo espacio de nombres. Como referencia, puedes encontrar las siguientes líneas en build/branch-cloudbuild.yaml
      kubectl get ns ${BRANCH_NAME} || kubectl create ns ${BRANCH_NAME}
      kubectl apply --namespace ${BRANCH_NAME} --recursive -f k8s/deployments/dev
      kubectl apply --namespace ${BRANCH_NAME} --recursive -f k8s/services
    
    Ahora que comprendes los mecanismos en uso, crea el activador con el siguiente comando de gcloud.
    gcloud beta builds triggers create cloud-source-repositories \
      --trigger-config build/branch-trigger.json
    
  2. Para revisar el activador, ve a la página Activadores de Cloud Build en la consola.Ir a Activadores
  3. Crea una rama nueva:
    git checkout -b new-feature-1
    
  4. Modifica el código para indicar v1.1Edita src/app.py y cambia la respuesta de 1.0 a 1.1
    @app.route('/')
    def hello_world():
        return 'Hello World v1.1'
    
  5. Confirma el cambio y envíalo al repositorio remoto:
    git add . && git commit -m "updated" && git push gcp new-feature-1
    
  6. Para revisar la compilación en curso, ve a la página Historial de Cloud Build en la consola.Ir a CompilacionesUna vez que se complete la compilación, continúa con el siguiente paso.
  7. Recupera la dirección IP externa del servicio de la rama recién implementada.
    kubectl get service $APP_NAME -n new-feature-1
    
    Una vez que el balanceador de cargas devuelva la dirección IP, continúa con el siguiente paso.
  8. Almacena la IP externa para usarla más adelante.
    export BRANCH_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}"  --namespace=new-feature-1 services $APP_NAME)
    
  9. Revisa la aplicación. Verifica el resultado de la versión del servicio. Debería decir Hello World v1.0
    curl http://$BRANCH_IP
    

6. Automatiza las implementaciones para la rama principal de Git

Antes de que el código se lance a producción, es común lanzarlo a un subconjunto pequeño de tráfico en vivo antes de migrar todo el tráfico a la base de código nueva.

En esta sección, implementarás un activador que se activa cuando se confirma el código en la rama principal. El activador implementa la implementación canary, que recibe el 25% de todo el tráfico en vivo a la revisión nueva.

  1. Configura el activador para la rama principal:
    gcloud beta builds triggers create cloud-source-repositories \
      --trigger-config build/main-trigger.json
    
  2. Para revisar el activador nuevo, ve a la página Activadores de Cloud Build en la consola.Ir a Activadores
  3. Combina la rama con la línea principal y envíala al repositorio remoto:
    git checkout main
    git merge new-feature-1
    git push gcp main
    
  4. Para revisar la compilación en curso, ve a la página Historial de Cloud Build en la consola.Ir a CompilacionesUna vez que se complete la compilación, continúa con el siguiente paso.
  5. Revisa varias respuestas del servidor. Ejecuta el siguiente comando y observa que, aproximadamente, el 25% de las respuestas muestran la nueva respuesta de Hello World v1.1.
    while true; do curl -w "\n" http://$PRODUCTION_IP; sleep 1;  done
    
    Cuando esté todo listo para continuar, presiona Ctrl+c para salir del bucle.

7. Automatiza implementaciones para etiquetas de Git

Una vez que la implementación de versiones canary se valida con un pequeño subconjunto de tráfico, libera la implementación en el resto del tráfico en vivo.

En esta sección, configurarás un activador que se activa cuando creas una etiqueta en el repositorio. El activador etiqueta la imagen con la etiqueta adecuada y, luego, implementa las actualizaciones en producción, lo que garantiza que el 100% del tráfico acceda a la imagen etiquetada.

  1. Configura el activador de etiquetas:
    gcloud beta builds triggers create cloud-source-repositories \
      --trigger-config build/tag-trigger.json
    
  2. Para revisar el activador nuevo, ve a la página Activadores de Cloud Build en la consola.Ir a Activadores
  3. Crea una etiqueta nueva y envíala al repositorio remoto:
    git tag 1.1
    git push gcp 1.1
    
  4. Para revisar la compilación en curso, ve a la página Historial de Cloud Build en la consola.Ir a Compilaciones
  5. Revisa varias respuestas del servidor. Ejecuta el siguiente comando y observa que el 100% de las respuestas muestran la nueva respuesta de Hello World v1.1. Esto puede tardar un momento, ya que los Pods nuevos se implementan y se verifica su estado en GKE.
    while true; do curl -w "\n" http://$PRODUCTION_IP; sleep 1;  done
    
    Cuando esté todo listo para continuar, presiona Ctrl+c para salir del bucle. ¡Felicitaciones! Creaste activadores de CI/CD en Cloud Build para ramas y etiquetas para implementar tus apps en GKE.

8. Limpieza

Borra el proyecto

  1. En la consola de Cloud, ve a la página Administrar recursos.
  2. En la lista de proyectos, elige el proyecto que deseas borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrarlo.