GitHub Actions: Construir y Desplegar Imagenes Docker Automaticamente
Construir imagenes Docker manualmente y subirlas a un registro cada vez que cambias el codigo es un proceso repetitivo y propenso a errores. GitHub Actions permite automatizar completamente este flujo — desde el build de la imagen hasta su publicacion en GHCR o Docker Hub — cada vez que haces push a una rama o creas un tag de release. Esta guia cubre la creacion de workflows de CI/CD robustos para proyectos basados en Docker.
Workflow Basico de Build y Push
Un workflow minimo necesita autenticarse con el registro de contenedores, construir la imagen y publicarla. GitHub Container Registry (GHCR) es la opcion mas sencilla ya que utiliza el GITHUB_TOKEN automatico sin necesidad de configurar secretos adicionales.
# .github/workflows/docker-build.yml
name: Build and Push Docker Image
on:
push:
branches: [main]
tags: ['v*']
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha,prefix=
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Este workflow se activa en pushes a la rama main y en tags que comienzan con v. Para pull requests, construye la imagen sin publicarla (push: false), lo que permite validar que el Dockerfile compila correctamente antes de fusionar los cambios.
La accion docker/metadata-action genera automaticamente las etiquetas de la imagen basandose en el contexto de Git. Para un tag v1.2.3, genera la etiqueta 1.2.3. Para la rama main, genera la etiqueta main. Esto elimina la gestion manual de versiones de imagenes.
Builds Multi-Arquitectura
Las aplicaciones modernas necesitan ejecutarse en diferentes arquitecturas, especialmente con la adopcion creciente de procesadores ARM como los chips Apple Silicon y AWS Graviton. Docker Buildx permite construir imagenes para multiples plataformas en un solo workflow.
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push multi-platform image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/${{ github.repository }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
QEMU proporciona la emulacion necesaria para compilar en arquitecturas diferentes a la del runner. La opcion cache-from y cache-to con type=gha usa el cache de GitHub Actions para acelerar builds posteriores, reduciendo significativamente los tiempos de construccion.
Escaneo de Vulnerabilidades
Integrar un escaneo de seguridad en el pipeline garantiza que las imagenes publicadas no contengan vulnerabilidades conocidas. Trivy es una herramienta popular de codigo abierto que escanea imagenes Docker, sistemas de archivos y configuraciones de IaC.
- name: Build image for scanning
uses: docker/build-push-action@v5
with:
context: .
load: true
tags: ${{ env.IMAGE_NAME }}:scan
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.IMAGE_NAME }}:scan
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
El paso load: true carga la imagen en el daemon Docker local en lugar de publicarla, permitiendo que Trivy la escanee antes del push. Los resultados en formato SARIF se cargan a la pestana Security de GitHub, proporcionando visibilidad sobre vulnerabilidades directamente en la interfaz del repositorio.
Estrategias de Despliegue
Una vez que la imagen esta publicada en el registro, el paso final es desplegarla en el entorno de destino. Las estrategias varian segun la infraestructura: actualizacion directa via SSH para servidores simples, actualizacion del manifiesto de Kubernetes para clusters orquestados, o trigger de un pipeline de despliegue separado.
Para servidores que ejecutan Docker Compose, puedes agregar un step que se conecte por SSH y actualice los contenedores:
- name: Deploy to production
if: github.ref == 'refs/heads/main'
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
cd /opt/app
docker compose pull
docker compose up -d --remove-orphans
Para entornos de Kubernetes, considera usar herramientas como ArgoCD o Flux que detectan automaticamente nuevas imagenes en el registro y aplican la actualizacion siguiendo una estrategia de rolling update. Esta aproximacion GitOps desacopla el build del despliegue y proporciona un historial completo de cambios en el cluster.