CD ? Github Actions ??

CD ? Github Actions ??

¿Qué es un pipeline? ¿Continuous deployment (CD) Podríamos decir que basicamente es el flujo de procesos o acciones que se gatillan desde el teclado del programador hasta el ambiente de producción.

Aquí brevemente veremos un pipeline realizado utilizando los Github Actions. Basicamente se debe agregar un archivo en la carpeta `.github/workflows/` el cual contiene todos los pasos. Veamos un ejemplo, y luego podrás ver el funcionamiento completo en un video (al final) del post.

Condiciones, acciones

Se utiliza un archivo YAML para declarar el flujo. En el ejemplo se definió que se gatillará el flujo para las ramas de staging y master cuando el mensaje del commit tenga al inicio el texto "[Deploy]":

name: ci

on:
  push:
    branches:
      - 'master'
      - 'staging'
jobs:
  ci-build-job:
    runs-on: ubuntu-latest
    if: contains(github.event.head_commit.message, '[Deploy]')

Construcción

  1. En el primer paso (Checkout) utiliza la módulo de acciones "actions/checkout@v2" (¿Ya mencioné que existe un sin fin de acciones que puedes utilizar? Mirá el Marketplace de acciones.). El "Checkout" básicamente hace un "git checkout" del último commit.
steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Set outputs
        id: vars
        run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
      - name: Extract branch name
        shell: bash
        run: echo "::set-output name=branch::$(echo ${GITHUB_REF#refs/heads/})"
        id: extract_branch
      - name: Extract namespace name
        run: echo "::set-output name=namespace::$([ ${GITHUB_REF#refs/heads/} = "master" ] && echo level1)"
        id: extract_namespace
      - name: Extract helm values file
        run: echo "::set-output name=helm_values_file::$([ ${GITHUB_REF#refs/heads/} = "master" ] && echo values-prod || echo values-staging)"
        id: extract_helm_values_file

Build and Push to DockerHub

Luego se gatilla un "docker build" al repositorio y se sube el contenedor a DockerHub:

- name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      - name: Login to DockerHub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          push: true
          build-args: |
            GITHUB_USER=${{ secrets.DEPLOY_GITHUB_USER }}
            GITHUB_TOKEN=${{ secrets.DEPLOY_GITHUB_TOKEN }}
          tags: marketshop/sharetribe_level1:${{ steps.extract_branch.outputs.branch }}-latest

Helm upgrade

Finalmente, se instala el commando Helm, se copia el token del Kubeconfig, y luego se hace el "helm upgrade" para gatillar la actualización de la aplicación con la nueva versión del navegador.

- uses: azure/setup-helm@v1
        with:
          version: 'v3.2.4'
        name: install helm
      - name: configure Kubernetes
        run: echo "${{ secrets.KUBECONFIG_CONTENT }}" > /tmp/kubeconfig
      - name: upgrade helm release
        working-directory: .helm
        run: helm upgrade $HELM_RELEASE_NAME . -f values.yaml -f $VALUES_FILE.yaml -n $NAMESPACE
        env:
          HELM_RELEASE_NAME: sharetribe-level1
          NAMESPACE: ${{ steps.extract_namespace.outputs.namespace }}
          KUBECONFIG: /tmp/kubeconfig
          VALUES_FILE: ${{ steps.extract_helm_values_file.outputs.helm_values_file }}
?
La "gracia" de Helm, es que no hay interrupción del servicio. Es decir, la aplicación está 100% operativa durante todo el proceso del despliegue. Esto permite hacer "pasos a producción" a cualquier hora del día, y lo mejor aún, con mayor frecuencia.

En la imange de abajo vemos como hay 2 contenedores. Uno está "Running" o activo has más de 44 minutos, y el nuevo contendor está "Pending" pero tiene recién 15 segundos de existencia:

Cuando el nuevo contenedor esté listo (en estado "Running"), Kubernetes automáticamente dará de baja el contenidor antiguo ("Terminating") así:

Así, Kubernetes mantiene el servicio 100% operativo.

Flujo completo

Veamos como funciona en la "realidad". Aquí les mostramos el flujo completo: