Tener un repositorio privado en AWS ECR resulta muy útil para mantener las versiones de nuestra aplicación dentro de la nube y ejecutar tareas con ellas. Pero todavía es más interesante gestionar estas versiones a través de un motor de CI/CD, además de etiquetarlas automáticamente para disponer de un registro de los cambios realizados en cada versión y poder promocionarlas entre nuestros distintos entornos.
En este breve artículo voy a mostrar cómo integrar una acción de push dentro de un flujo de trabajo de Github Actions. El momento en el que debemos subir nuestras imágenes depende del flujo de publicación que hayamos diseñado para la aplicación. En mi caso, suelo configurar dos entornos en mis proyectos (dev / pro), y publico automáticamente en el entorno de desarrollo cuando hago merge de un pull request con la rama develop.
Es en ese momento cuando genero una nueva imagen que, una vez probada en el entorno de desarrollo mediante tests automáticos y manuales, promociono al entorno de producción. Para desplegar nuestras imágenes, normalmente configuro un flujo de trabajo con los siguientes pasos:

Con el diagrama anterior en mente, podemos empezar a configurar nuestro archivo de Github Actions dentro del proyecto. Veamos el siguiente fragmento de código:
# ./.github/workflows/develop_push.yml
# -----------------------------------------------
name: "On merge inside develop"
on:
push:
branches:
- develop
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
jobs:
applytf:
runs-on: ubuntu-latest
name: "Apply TF"
permissions:
pull-requests: write
contents: read
defaults:
run:
working-directory: ./iac
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
- name: Terraform Init
id: init
run: terraform init
- name: Terraform apply
run: terraform apply -auto-approve -input=false
publishdocker:
name: "Build docker and publish to ECR"
needs: [ applytf ]
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./src
steps:
- name: Check out code
uses: actions/checkout@v3
- name: Bump version and push tag
id: tag_version
uses: mathieudutour/github-tag-action@v6.1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
release_branches: "main,develop"
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build, tag, and push image to Amazon ECR
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: example
IMAGE_TAG: ${{ steps.tag_version.outputs.new_version }}
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -t $ECR_REGISTRY/$ECR_REPOSITORY:latest .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest
El primer job aplica la infraestructura de Terraform dentro de nuestra cuenta de AWS. No es el objetivo principal de este artículo, pero podemos repasar lo que hace:
./iac. Esta carpeta contiene todo nuestro código de Terraform que creará, junto con otros recursos, nuestro repositorio privado de ECR.El segundo job depende de la ejecución del job de Terraform. Paso a paso, esto es lo que hace:
./src. Suponemos que ahí tenemos todo el código junto con el archivo Dockerfile para construir nuestra imagen.release_branches con los nombres de las ramas develop y main. Esto es porque, como expliqué al inicio del artículo, suelo promocionar la misma versión desde develop al entorno de producción (sin reconstruirla). Así me aseguro de liberar en producción exactamente la misma versión que ha sido probada en develop. 👉 Código de la acción en Github: github-tag-action./src, etiquetándola con dos tags distintos:
Como vemos, la acción para subir nuestras imágenes a un repositorio privado de ECR es bastante directa. Lo más importante es definir correctamente nuestros flujos de publicación, decidir exactamente cuándo queremos hacer el push y cuál será el ciclo de vida de las imágenes que subimos al servidor.