Desplegar contenedores en AKS usando GitHub Actions

Otro de los flujos que está muy de moda a día de hoy es la generación de imágenes y el despliegue de estas en Kubernetes. Hoy quiero compartir contigo un workflow para GitHub Actions usando Azure Kubernetes Service:

name: Deploy web app on AKS

on:
  push:
    branches:
      - master
    paths:
      - .github/workflows/k8s-webapp.yml
      - "BethanysPieShopHRM.server/**"

env:
  CLUSTER_NAME: gisaks
  CLUSTER_RESOURCE_GROUP: AKS-Refresh
  NAMESPACE: bethanyshop
  IMAGE_NAME: bethanys-webapp

jobs:
  build-and-push-docker-image:
    runs-on: ubuntu-latest
    steps:
      - name: "Get code from the repo"
        uses: actions/[email protected] 
      - uses: azure/[email protected]
        with:
          login-server: ${{ secrets.REGISTRY_LOGIN_SERVER }}
          username: ${{ secrets.REGISTRY_USERNAME }}
          password: ${{ secrets.REGISTRY_PASSWORD }}
      - name: Build and push
        run: |          
          docker build . --file ./BethanysPieShopHRM.server/Dockerfile -t ${{ secrets.REGISTRY_LOGIN_SERVER }}/${{env.IMAGE_NAME}}:${{ github.sha }}
          docker push ${{ secrets.REGISTRY_LOGIN_SERVER }}/${{env.IMAGE_NAME}}:${{ github.sha }}

  deploy-to-aks:
    needs: [build-and-push-docker-image]
    runs-on: ubuntu-latest
    steps:
      - name: "Get code from the repo"
        uses: actions/[email protected]
      - name: "Set the context"
        uses: azure/[email protected]
        with:
          creds: "${{secrets.AZURE_CREDS_AKS_SCOPE}}"
          cluster-name: ${{env.CLUSTER_NAME}}
          resource-group: ${{env.CLUSTER_RESOURCE_GROUP}}
      - name: "Create the namespace if it does not exist"
        run: |
          kubectl create ns ${{env.NAMESPACE}} --dry-run -o json | kubectl apply -f -
      - name: "Create imagePullSecret for Azure Container Registry"
        uses: azure/[email protected]
        with:
          container-registry-url: ${{ secrets.REGISTRY_LOGIN_SERVER}}
          container-registry-username: ${{secrets.REGISTRY_USERNAME}}
          container-registry-password: ${{secrets.REGISTRY_PASSWORD}}
          secret-name: acr-connection
          namespace: ${{env.NAMESPACE}}
      - name: "Deploy app"
        id: deployment
        uses: azure/[email protected]
        timeout-minutes: 5
        with:
          manifests: k8s/webapp-manifest.yaml
          images: ${{secrets.REGISTRY_LOGIN_SERVER}}/${{env.IMAGE_NAME}}:${{github.sha}}
          imagepullsecrets: acr-connection
          namespace: ${{env.NAMESPACE}}
      - name: "If the deployment was not succeeded"
        if: failure()
        run: kubectl rollout undo deployment/bethanyspieshopweb --namespace ${{env.NAMESPACE}}

Muchas de las cosas que aparecen en este YAML las expliqué en el primer artículo sobre GitHub Actions. Este flujo tiene dos jobs:

build-and-push-docker-image

El primero se centra en la creación y publicación de la imagen, a partir del código que se encuentra en el repositorio de GitHub. Para ello, utilizo la acción azure/[email protected] para poder hacer el push en el repositorio privado y, a través del shell, ejecuto docker build y push de la imagen.

deploy-to-aks

Como segundo paso llevo a cabo el despliegue, el cual debe esperar a que finalice el job anterior a través de la propiedad needs (porque sino no tenemos imagen que desplegar). Como son dos jobs diferentes, necesitas volver a hacer el checkout del código, establezco el contexto para kubectl, creo el namespace en el clúster si no existe, añado en el mismo un secreto del tipo imagePullSecret, para poder recuperar la imagen del repositorio privado, y despliego a través de la acción azure/[email protected], la cual entenderás mejor con este artículo sobre el objeto Deployment 🙂
Como novedad a lo explicado hasta ahora, a este paso le he establecido un timeout de 5 minutos por si el despliegue se ha quedado atascado. De ser así, se ejecutaría la última acción donde se comprueba, a través de un condicionante con if: failure(), si el último paso ejecutado ha fallado (en este ejemplo, el despliegue) y de ser así se lanzará un rollout undo sobre el la actualización que estabas intentando.

¡Saludos!