Entrega continua tipo GitOps con Cloud Build

En esta página se explica cómo crear una canalización de integración y entrega continuas (IC/EC) en Google Cloud Platform usando solo productos alojados y la metodología popular de GitOps.

GitOps es un enfoque de entrega continua que Weaveworks describió por primera vez. Una parte clave de GitOps es la idea de “entornos como código”, que describen tus implementaciones de forma declarativa con archivos (por ejemplo, los manifiestos de Kubernetes) almacenados en un repositorio de Git.

En este instructivo, crearás una canalización de IC/EC que compila de forma automática una imagen de contenedor desde el código confirmado, almacena la imagen en Container Registry, actualiza un manifiesto de Kubernetes en un repositorio de Git y, luego, implementa la aplicación en Google Kubernetes Engine con ese manifiesto.

Arquitectura de la canalización de IC/EC

En este instructivo se utilizan dos repositorios de Git:

  • Repositorio app: contiene el código fuente de la aplicación.
  • Repositorio env: contiene los manifiestos para la implementación de Kubernetes.

Cuando envías un cambio al repositorio app, la canalización de Cloud Build ejecuta las pruebas, compila una imagen de contenedor y la envía a Container Registry. Después de enviar la imagen, Cloud Build actualiza el manifiesto de implementación y lo envía al repositorio env. Esto activa otra canalización de Cloud Build que aplica el manifiesto al clúster de GKE y, si se aplica correctamente, lo almacena en otra rama del repositorio env.

Los repositorios app y env deben estar separados porque tienen diferentes ciclos de vida y usos. Los usuarios principales del repositorio app son personas reales, y este repositorio está destinado para una aplicación específica. Los usuarios principales del repositorio env son sistemas automáticos (como Cloud Build), y varias aplicaciones pueden compartir este repositorio. El repositorio de env puede tener varias ramas que se asignan a un entorno específico (solo utilizas la rama de producción en este instructivo), y hace referencia a una imagen de contenedor específica, mientras que el repositorio app no.

Cuando termines este instructivo, obtendrás un sistema en el que fácilmente podrás realizar las siguientes acciones:

  • Diferenciar las implementaciones fallidas y correctas mediante una observación del historial de Cloud Build.
  • Acceder al manifiesto utilizado en este momento mediante la observación de la rama production del repositorio env.
  • Revertir cualquier versión anterior mediante una nueva ejecución de la compilación correspondiente de Cloud Build.

Flujo de la canalización de IC/EC

Acerca de este instructivo

En este instructivo se utiliza Cloud Source Repositories para alojar los repositorios de Git, pero puedes obtener los mismos resultados con otros productos de terceros como GitHub, Bitbucket o GitLab.

Esta canalización no implementa un mecanismo de validación antes de la implementación. Si usas GitHub, Bitbucket o GitLab, puedes modificarla a fin de usar una solicitud de extracción para este fin.

Si bien recomendamos Spinnaker a los equipos que quieren implementar patrones de implementación avanzada (azul/verde, análisis de detección de fallos, múltiples nubes, etc.), es posible que su conjunto de atributos no sea necesario para una estrategia de IC/EC exitosa en organizaciones o proyectos más pequeños. En este instructivo, obtendrás información sobre cómo crear una canalización de IC/EC para aplicaciones alojadas en GKE con herramientas simples.

Para que este instructivo sea más simple, se utiliza solo el entorno de producción en el repositorio env, pero puedes ampliarlo para implementar varios entornos, en caso necesario.

Costos

Antes de comenzar

  1. Selecciona o crea un proyecto de GCP.

    IR A LA PÁGINA ADMINISTRAR RECURSOS

  2. Habilita la facturación para tu proyecto.

    HABILITAR FACTURACIÓN

  3. Abre Cloud Shell para ejecutar los comandos detallados en este instructivo.

    IR A CLOUD SHELL

  4. Si el comando gcloud config get-value project no muestra el ID del proyecto que seleccionaste, configura Cloud Shell para usar tu proyecto.

    gcloud config set project [PROJECT_ID]
    
  5. En Cloud Shell, habilita las API requeridas.

    gcloud services enable container.googleapis.com \
        cloudbuild.googleapis.com \
        sourcerepo.googleapis.com \
        containeranalysis.googleapis.com
    
  6. En Cloud Shell, crea un clúster de GKE que usarás para implementar la aplicación de ejemplo de este instructivo.

    gcloud container clusters create hello-cloudbuild \
        --num-nodes 1 --zone us-central1-b
    
  7. Si nunca usaste Git en Cloud Shell, configúralo con tu nombre y dirección de correo electrónico. Git usará esos datos para identificarte como el autor de las confirmaciones que crearás en Cloud Shell.

    git config --global user.email "[YOUR_EMAIL_ADDRESS]"
    git config --global user.name "[YOUR_NAME]"
    

Cuando finalices este instructivo, puedes borrar los recursos que creaste para evitar que se te sigan facturando. Consulta Limpieza para obtener más información.

Crear repositorios de Git en Cloud Source Repositories

En esta sección, crearás dos repositorios de Git (app y env) utilizados en este instructivo, y, luego, inicializarás app con algún código de ejemplo.

  1. En Cloud Shell, crea los dos repositorios de Git.

    gcloud source repos create hello-cloudbuild-app
    gcloud source repos create hello-cloudbuild-env
    
  2. Clona el código de ejemplo desde GitHub.

    cd ~
    git clone https://github.com/GoogleCloudPlatform/gke-gitops-tutorial-cloudbuild \
        hello-cloudbuild-app
    
  3. Configura Cloud Source Repositories como remoto.

    cd ~/hello-cloudbuild-app
    PROJECT_ID=$(gcloud config get-value project)
    git remote add google \
        "https://source.developers.google.com/p/${PROJECT_ID}/r/hello-cloudbuild-app"
    

El código que clonaste contiene una aplicación simple llamada "Hello World".

from flask import Flask
app = Flask('hello-cloudbuild')

@app.route('/')
def hello():
  return "Hello World!\n"

if __name__ == '__main__':
  app.run(host = '0.0.0.0', port = 8080)

Crear una imagen de contenedor con Cloud Build

El código que clonaste ya contiene el siguiente Dockerfile.

FROM python:3.7-slim
RUN pip install flask
WORKDIR /app
COPY app.py /app/app.py
ENTRYPOINT ["python"]
CMD ["/app/app.py"]

Con este Dockerfile, crea una imagen de contenedor con Cloud Build y guárdala en Container Registry.

  1. En Cloud Shell, crea una compilación de Cloud Build basada en la última confirmación con el siguiente comando:

    cd ~/hello-cloudbuild-app
    COMMIT_ID="$(git rev-parse --short=7 HEAD)"
    gcloud builds submit --tag="gcr.io/${PROJECT_ID}/hello-cloudbuild:${COMMIT_ID}" .
    

    Cloud Build transmite los registros que generó la creación de la imagen de contenedor a tu terminal cuando ejecutas este comando.

  2. Cuando se complete la compilación, verifica que la imagen de contenedor nueva esté disponible en Container Registry.

    IR A CONTAINER REGISTRY

    Imagen hello-cloudbuild en Container Registry

Crear una canalización de integración continua

En esta sección, configurarás Cloud Build para ejecutar automáticamente una prueba de unidades pequeñas, compilar la imagen de contenedor y enviarla a Container Registry. Enviar una confirmación nueva a Cloud Source Repositories activa automáticamente esta canalización. El archivo cloudbuild.yaml ya incluido en el código es la configuración de la canalización.

steps:
# This step runs the unit tests on the app
- name: 'python:3.7-slim'
  id: Test
  entrypoint: /bin/sh
  args:
  - -c
  - 'pip install flask && python test_app.py -v'

# This step builds the container image.
- name: 'gcr.io/cloud-builders/docker'
  id: Build
  args:
  - 'build'
  - '-t'
  - 'gcr.io/$PROJECT_ID/hello-cloudbuild:$SHORT_SHA'
  - '.'

# This step pushes the image to Container Registry
# The PROJECT_ID and SHORT_SHA variables are automatically
# replaced by Cloud Build.
- name: 'gcr.io/cloud-builders/docker'
  id: Push
  args:
  - 'push'
  - 'gcr.io/$PROJECT_ID/hello-cloudbuild:$SHORT_SHA'
  1. Abre la página de Activadores de Cloud Build.

    IR A ACTIVADORES

  2. Haz clic en Crear activador.

  3. Selecciona “Cloud Source Repositories” como fuente y haz clic en Continuar.

  4. Selecciona el repositorio hello-cloudbuild-app y haz clic en Continuar.

  5. En la pantalla “Configuración de activadores”, ingresa los siguientes parámetros:

    • Nombre: hello-cloudbuild
    • Rama (expresión regular): master
    • Configuración de compilación: cloudbuild.yaml
  6. Haz clic en Crear activador.

  7. En Cloud Shell, envía el código de la aplicación a Cloud Source Repositories para activar la canalización de IC en Cloud Build.

    cd ~/hello-cloudbuild-app
    git push google master
    
  8. Abre la consola de Cloud Build.

    IR A CLOUD BUILD

    Deberías ver una compilación en ejecución o finalizada recientemente. Puedes hacer clic en la compilación para seguir la ejecución y examinar sus registros.

Crear una canalización de entrega continua

Cloud Build también se usa para la canalización de entrega continua. La canalización se ejecuta cada vez que se envía una confirmación a la rama candidate del repositorio hello-cloudbuild-env. La canalización aplica la versión nueva del manifiesto al clúster de Kubernetes, y si se realiza correctamente, lo copia en la rama production. Este proceso tiene las siguientes propiedades:

  • La rama candidate es un historial de los intentos de implementación.
  • La rama production es un historial de las implementaciones correctas.
  • En Cloud Build, tienes una vista de las implementaciones fallidas y correctas.
  • Puedes revertir cualquier implementación anterior si vuelves a ejecutar la compilación correspondiente en Cloud Build. Una reversión también actualiza la rama production para reflejar verdaderamente el historial de implementaciones.

Modificarás la canalización de integración continua para actualizar la rama candidate del repositorio hello-cloudbuild-env, lo que activa la canalización de entrega continua.

Otorgar a Cloud Build acceso a GKE

Para implementar la aplicación en tu clúster de Kubernetes, Cloud Build necesita una función de IAM de desarrollador de contenedor. En Cloud Shell, ejecuta el siguiente comando:

PROJECT_NUMBER="$(gcloud projects describe ${PROJECT_ID} --format='get(projectNumber)')"
gcloud projects add-iam-policy-binding ${PROJECT_NUMBER} \
    --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
    --role=roles/container.developer

Inicializar el repositorio hello-cloudbuild-env

Debes inicializar el repositorio hello-cloudbuild-env con dos ramas (production y candidate) y un archivo de configuración de Cloud Build que describa el proceso de implementación.

  1. En Cloud Shell, clona el repositorio hello-cloudbuild-env y crea la rama production. Todavía estará vacía.

    cd ~
    gcloud source repos clone hello-cloudbuild-env
    cd ~/hello-cloudbuild-env
    git checkout -b production
    
  2. Copia el archivo cloudbuild-delivery.yaml disponible en el repositorio hello-cloudbuild-app y confirma el cambio.

    cd ~/hello-cloudbuild-env
    cp ~/hello-cloudbuild-app/cloudbuild-delivery.yaml ~/hello-cloudbuild-env/cloudbuild.yaml
    git add .
    git commit -m "Create cloudbuild.yaml for deployment"
    

    El archivo cloudbuild-delivery.yaml describe el proceso de implementación para ejecutar en Cloud Build. Este tiene dos pasos:

    1. Cloud Build aplica el manifiesto en el clúster de GKE.

    2. Si lo hace correctamente, Cloud Build lo copia en la rama production.

    steps:
    # This step deploys the new version of our container image
    # in the hello-cloudbuild Kubernetes Engine cluster.
    - name: 'gcr.io/cloud-builders/kubectl'
      id: Deploy
      args:
      - 'apply'
      - '-f'
      - 'kubernetes.yaml'
      env:
      - 'CLOUDSDK_COMPUTE_ZONE=us-central1-b'
      - 'CLOUDSDK_CONTAINER_CLUSTER=hello-cloudbuild'
    
    # This step copies the applied manifest to the production branch
    # The COMMIT_SHA variable is automatically
    # replaced by Cloud Build.
    - name: 'gcr.io/cloud-builders/git'
      id: Copy to production branch
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
        set -x && \
        # Configure Git to create commits with Cloud Build's service account
        git config user.email $(gcloud auth list --filter=status:ACTIVE --format='value(account)') && \
        # Switch to the production branch and copy the kubernetes.yaml file from the candidate branch
        git fetch origin production && git checkout production && \
        git checkout $COMMIT_SHA kubernetes.yaml && \
        # Commit the kubernetes.yaml file with a descriptive commit message
        git commit -m "Manifest from commit $COMMIT_SHA
        $(git log --format=%B -n 1 $COMMIT_SHA)" && \
        # Push the changes back to Cloud Source Repository
        git push origin production

  3. Crea la rama candidate y envía ambas ramas para que estén disponibles en Cloud Source Repositories.

    git checkout -b candidate
    git push origin production
    git push origin candidate
    
  4. Otorga la función de IAM del escritor del repositorio de código fuente a la cuenta de servicio de Cloud Build para el repositorio hello-cloudbuild-env.

    PROJECT_NUMBER="$(gcloud projects describe ${PROJECT_ID} \
        --format='get(projectNumber)')"
    cat >/tmp/hello-cloudbuild-env-policy.yaml <<EOF
    bindings:
    - members:
      - serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com
      role: roles/source.writer
    EOF
    gcloud source repos set-iam-policy \
        hello-cloudbuild-env /tmp/hello-cloudbuild-env-policy.yaml
    

Cómo crear un activador para la canalización de entrega continua

En esta sección, configurarás Cloud Build para que se active con un envío a la rama candidate del repositorio hello-cloudbuild-env.

  1. Abre la página de Activadores de Cloud Build.

    IR A ACTIVADORES

  2. Haz clic en Agregar activador.

  3. Selecciona “Cloud Source Repositories” como fuente y haz clic en Continuar.

  4. Selecciona el repositorio hello-cloudbuild-env y haz clic en Continuar.

  5. En la pantalla “Configuración de activadores”, ingresa los siguientes parámetros:

    • Nombre: hello-cloudbuild-deploy
    • Rama (expresión regular): candidate
    • Configuración de compilación: cloudbuild.yaml
  6. Haz clic en Crear activador.

Modificar la canalización de integración continua para activar la canalización de entrega continua

En esta sección, agregarás algunos pasos a la canalización de integración continua que generará una versión nueva del manifiesto de Kubernetes y lo enviará al repositorio hello-cloudbuild-env para activar la canalización de entrega continua.

  1. Copia la versión extendida del archivo cloudbuild.yaml para el repositorio app.

    cd ~/hello-cloudbuild-app
    cp cloudbuild-trigger-cd.yaml cloudbuild.yaml
    

    El archivo cloudbuild-trigger-cd.yaml es una versión extendida del archivo cloudbuild.yaml. Este agrega los pasos que se detallan a continuación, que generan el manifiesto nuevo de Kubernetes y activan la canalización de entrega continua.

    # This step clones the hello-cloudbuild-env repository
    - name: 'gcr.io/cloud-builders/gcloud'
      id: Clone env repository
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
        gcloud source repos clone hello-cloudbuild-env && \
        cd hello-cloudbuild-env && \
        git checkout candidate && \
        git config user.email $(gcloud auth list --filter=status:ACTIVE --format='value(account)')
    
    # This step generates the new manifest
    - name: 'gcr.io/cloud-builders/gcloud'
      id: Generate manifest
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
         sed "s/GOOGLE_CLOUD_PROJECT/${PROJECT_ID}/g" kubernetes.yaml.tpl | \
         sed "s/COMMIT_SHA/${SHORT_SHA}/g" > hello-cloudbuild-env/kubernetes.yaml
    
    # This step pushes the manifest back to hello-cloudbuild-env
    - name: 'gcr.io/cloud-builders/gcloud'
      id: Push manifest
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
        set -x && \
        cd hello-cloudbuild-env && \
        git add kubernetes.yaml && \
        git commit -m "Deploying image gcr.io/${PROJECT_ID}/hello-cloudbuild:${SHORT_SHA}
        Built from commit ${COMMIT_SHA} of repository hello-cloudbuild-app
        Author: $(git log --format='%an <%ae>' -n 1 HEAD)" && \
        git push origin candidate
    

  2. Confirma las modificaciones y envíalas a Cloud Source Repositories.

    cd ~/hello-cloudbuild-app
    git add cloudbuild.yaml
    git commit -m "Trigger CD pipeline"
    git push google master
    

    Esto activa la canalización de integración continua en Cloud Build.

  3. Examina la compilación de integración continua.

    IR A CLOUD BUILD

    Deberías ver una compilación en ejecución o finalizada recientemente para el repositorio hello-cloudbuild-app. Puedes hacer clic en la compilación para seguir la ejecución y examinar sus registros. El último paso de esta canalización envía el manifiesto nuevo al repositorio hello-cloudbuild-env, que activa la canalización de entrega continua.

  4. Examina la compilación de entrega continua.

    IR A CLOUD BUILD

    Deberías ver una compilación en ejecución o finalizada recientemente para el repositorio hello-cloudbuild-env. Puedes hacer clic en la compilación para seguir la ejecución y examinar sus registros.

Probar la canalización completa

La canalización de IC/EC ahora está configurada. En esta sección, la probarás de extremo a extremo.

  1. Ve a la página Servicio de GKE.

    IR A SERVICIOS DE GOOGLE KUBERNETES ENGINE

    Debes tener un solo servicio llamado hello-cloudbuild en la lista. Se creó con la implementación de entrega continua que se acaba de ejecutar.

  2. Haz clic en el extremo del servicio hello-cloudbuild. Deberías ver “Hello World!”. Si no existe el extremo, o si ves un error del balanceador de cargas, es posible que debas esperar algunos minutos para que el balanceador de cargas se inicialice por completo. Haz clic en Actualizar para actualizar la página si es necesario.

  3. En Cloud Shell, reemplaza “Hello World” por “Hello Cloud Build” en la aplicación y en la prueba de unidades.

    cd ~/hello-cloudbuild-app
    sed -i 's/Hello World/Hello Cloud Build/g' app.py
    sed -i 's/Hello World/Hello Cloud Build/g' test_app.py
    
  4. Confirma y envía el cambio a Cloud Source Repositories.

    git add app.py test_app.py
    git commit -m "Hello Cloud Build"
    git push google master
    

    Esto activa la canalización de IC/EC completa.

  5. Después de unos minutos, vuelve a cargar la aplicación en tu navegador. Ahora deberías ver “Hello Cloud Build!”.

Cómo probar la reversión

En esta sección, revertirás la versión de la aplicación que dice “Hello World!”.

  1. Abre la consola Cloud Build para el repositorio hello-cloudbuild-env.

    IR A CLOUD BUILD

  2. Haz clic en la segunda compilación más reciente disponible.

  3. Haz clic en Volver a compilar.

  4. Cuando se termine la compilación, vuelve a cargar la aplicación en tu navegador. Ahora deberías ver “Hello World!” nuevamente.

Limpieza

Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud Platform por los recursos que usaste en este instructivo:

  1. En la GCP Console, dirígete a la página Proyectos.

    Ir a la página Proyectos

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

Borrar recursos

Si deseas conservar el proyecto de GCP que utilizaste para este instructivo, borra los recursos individuales:

  1. Borra los repositorios de Git locales.

    cd ~
    rm -rf ~/hello-cloudbuild-app
    rm -rf ~/hello-cloudbuild-env
    
  2. Borra los repositorios de Git en Cloud Source Repositories.

    gcloud source repos delete hello-cloudbuild-app --quiet
    gcloud source repos delete hello-cloudbuild-env --quiet
    
  3. Borra los activadores de Cloud Build.

    1. Abre la página de Activadores de Cloud Build.

      IR A ACTIVADORES

    2. Para cada activador, haz clic en los tres puntos verticales a la derecha del activador y luego haz clic en Borrar.

  4. Borra las imágenes en Container Registry.

    gcloud beta container images list-tags \
        gcr.io/${PROJECT_ID}/hello-cloudbuild \
        --format="value(tags)" | \
        xargs -I {} gcloud beta container images delete \
        --force-delete-tags --quiet \
        gcr.io/${PROJECT_ID}/hello-cloudbuild:{}
    
  5. Quita el permiso otorgado a Cloud Build para conectarte a GKE.

    PROJECT_NUMBER="$(gcloud projects describe ${PROJECT_ID} \
        --format='get(projectNumber)')"
    gcloud projects remove-iam-policy-binding ${PROJECT_NUMBER} \
        --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
        --role=roles/container.developer
    
  6. Borra el clúster de GKE.

    gcloud container clusters delete hello-cloudbuild \
        --zone us-central1-b
    

Qué sigue

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Instructivos de Kubernetes Engine