Cómo conectar GitHub con Cloud Build (Gen 2) y subir imágenes a Artifact Registry
Automatizar el camino desde un push en GitHub hasta una imagen Docker versionada en Artifact Registry parece sencillo, pero en entornos empresariales la arquitectura correcta depende de cómo se gestionan las conexiones de GitHub, los triggers de Cloud Build, las identidades de ejecución, las regiones y los permisos IAM.
En esta guía construimos una arquitectura CI/CD reproducible con Cloud Build Gen 2, GitHub y Artifact Registry, evitando credenciales Docker innecesarias y separando claramente source integration, build execution y artifact storage.
Lo que aprenderás
La arquitectura correcta: separar Source, Build y Registry
La arquitectura recomendada no consiste en "conectar GitHub a Docker", sino en construir una cadena de responsabilidades explícita. GitHub actúa como sistema de control de código, Cloud Build como motor de ejecución y Artifact Registry como almacén de imágenes OCI.
GitHub
Contiene el Dockerfile, el código de aplicación y el archivo cloudbuild.yaml.
Cloud Build Gen 2
La conexión regional integra GitHub mediante la Cloud Build GitHub App.
Trigger
Un evento como un push sobre main inicia el pipeline.
Artifact Registry
Almacena la imagen Docker con una dirección regional del tipo *.pkg.dev.
Flujo de CI/CD de extremo a extremo
El flujo conceptual es:
GitHub
│
│ push / tag
▼
Cloud Build Gen 2
│
│ Trigger
▼
cloudbuild.yaml
│
├── docker build
│
└── docker push
│
▼
Artifact Registry
│
▼
imagen OCI versionada
La clave arquitectónica es que el trigger no "contiene" las credenciales de Docker: delega la ejecución al servicio de build y utiliza la identidad configurada para acceder a los recursos de Google Cloud.
Matriz de decisión: ¿qué patrón utilizar?
Para un pipeline empresarial, no todos los mecanismos de integración tienen el mismo comportamiento operativo. La elección debe considerar control de identidad, mantenibilidad, aislamiento regional y capacidad de evolución.
| Patrón | Latencia operativa | Consistencia | Coste / complejidad | Uso recomendado |
|---|---|---|---|---|
| Cloud Build Gen 2 + GitHub App | Baja | Alta | Baja-media | CI/CD estándar empresarial |
| Pipeline externo + gcloud | Variable | Depende del sistema externo | Media-alta | Organizaciones con CI centralizado fuera de GCP |
| GitHub Actions + push a Artifact Registry | Baja | Alta | Media | Cuando GitHub Actions es el estándar corporativo |
| Build manual desde local | Alta | Baja | Baja inicialmente | Desarrollo y debugging, no producción |
Para este caso, Cloud Build Gen 2 ofrece una integración nativa especialmente adecuada cuando Google Cloud debe controlar la ejecución y el almacenamiento del artefacto.
Prerrequisitos reales
- Un proyecto de Google Cloud con Cloud Build habilitado.
- Un repositorio GitHub accesible mediante la integración de Cloud Build.
- Un Dockerfile válido.
- Un repositorio Docker creado en Artifact Registry.
- Una región coherente entre conexión, trigger y recursos cuando corresponda.
- Permisos IAM adecuados para la identidad que ejecutará el build.
En Gen 2, la conexión con GitHub es regional: la documentación actual de Google Cloud indica que una conexión no puede existir globalmente. La GitHub App autoriza el acceso y Cloud Build almacena el token de autenticación como secreto gestionado por Google Cloud.
Paso 1: conectar GitHub con Cloud Build Gen 2
Una conexión de 2ª generación se crea con gcloud builds connections. El comando inicia el flujo de autorización de la Cloud Build GitHub App.
gcloud builds connections create github github-prod \
--region=europe-west1
Después de ejecutar el comando, Google Cloud proporciona el flujo necesario para autorizar la aplicación en GitHub. Una vez instalada la GitHub App sobre la cuenta u organización correspondiente, conviene verificar explícitamente el estado de la conexión.
gcloud builds connections describe github-prod \
--region=europe-west1
El estado esperado es COMPLETE. Si la conexión no está completa, el propio recurso proporciona información para continuar con la instalación.
En organizaciones grandes, es preferible utilizar una cuenta técnica o una cuenta robot para evitar que una conexión crítica de CI/CD dependa de la cuenta personal de un ingeniero.
Paso 2: crear Artifact Registry
Artifact Registry es el destino recomendado para almacenar imágenes de contenedores en Google Cloud. Una referencia Docker típica tiene esta estructura:
REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:TAG
Por ejemplo, para un proyecto denominado platform-prod, un repositorio containers en europe-west1 podría producir una referencia como:
europe-west1-docker.pkg.dev/platform-prod/containers/my-api:1.0.0
El repositorio debe existir antes de que el pipeline intente publicar la imagen. Además, la identidad utilizada por Cloud Build necesita permiso de escritura sobre el repositorio cuando ese acceso no esté cubierto por los permisos predeterminados.
gcloud artifacts repositories create containers \
--repository-format=docker \
--location=europe-west1 \
--description="Production container images"
Paso 3: preparar un Dockerfile reproducible
El pipeline no debería ocultar malas prácticas de construcción. Una imagen reproducible debe minimizar capas innecesarias, fijar versiones cuando el riesgo operativo lo justifique y evitar introducir secretos en el contexto de Docker.
# syntax=docker/dockerfile:1
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ ./src/
EXPOSE 8080
CMD ["python", "-m", "src.main"]
En producción, la mejora natural es añadir controles de seguridad de imágenes, escaneo de vulnerabilidades, SBOM, políticas de promoción y despliegue mediante digest en lugar de confiar únicamente en tags mutables.
Paso 4: crear un cloudbuild.yaml de producción
Una configuración sencilla y explícita puede separar la construcción del push. La variable _IMAGE evita duplicar la referencia completa de Artifact Registry en varios pasos.
steps:
- name: 'gcr.io/cloud-builders/docker'
id: 'build-image'
args:
- 'build'
- '-t'
- '${_IMAGE}:${SHORT_SHA}'
- '.'
- name: 'gcr.io/cloud-builders/docker'
id: 'push-image'
args:
- 'push'
- '${_IMAGE}:${SHORT_SHA}'
images:
- '${_IMAGE}:${SHORT_SHA}'
substitutions:
_IMAGE: 'europe-west1-docker.pkg.dev/PROJECT_ID/containers/my-api'
options:
logging: CLOUD_LOGGING_ONLY
El uso de ${SHORT_SHA} es preferible a construir exclusivamente con latest: proporciona una asociación directa entre el artefacto y el commit que originó la build.
Sustituye PROJECT_ID por el ID real de tu proyecto. En una plataforma reutilizable, la referencia de imagen suele parametrizarse a nivel de trigger o configuración del pipeline.
Antipatrón crítico: usar latest como mecanismo de versionado
Uno de los errores más costosos en CI/CD es publicar siempre:
europe-west1-docker.pkg.dev/PROJECT_ID/containers/my-api:latest
El problema no es que latest sea técnicamente inválido. El problema es que elimina información esencial de trazabilidad: dos builds diferentes pueden apuntar al mismo tag y resulta más difícil determinar qué commit produjo el artefacto actualmente desplegado.
Patrón recomendado: utilizar un tag inmutable derivado del commit, por ejemplo SHORT_SHA, y promover la misma imagen mediante su digest entre ambientes.
El objetivo arquitectónico es que el camino sea:
Git commit
↓
Build
↓
Image:abc1234
↓
Digest:sha256:...
↓
Staging
↓
Production
Así, producción no necesita reconstruir la imagen. Promueve exactamente el artefacto que fue validado anteriormente.
IAM: el punto donde más pipelines aparentemente correctos fallan
Un build puede compilar correctamente y aun así fallar en el último paso con un PERMISSION_DENIED. La razón habitual es que la identidad que ejecuta el build no tiene permisos de escritura sobre el repositorio de Artifact Registry.
La solución no es almacenar una clave JSON de una cuenta de servicio dentro de GitHub. Ese patrón aumenta innecesariamente el riesgo de filtración de credenciales.
El patrón recomendado es:
Cuenta de servicio
Identidad explícita para ejecutar el pipeline.
Repositorio
Permisos limitados al Artifact Registry necesario.
Writer
Permiso de escritura únicamente donde sea necesario.
Sin claves estáticas
Evitar service-account keys como mecanismo de autenticación del pipeline.
Si el repositorio está en un proyecto distinto al proyecto de Cloud Build o se utiliza una cuenta de servicio especificada por el usuario, deben concederse los permisos apropiados en el proyecto donde reside Artifact Registry.
Paso 5: crear el trigger de GitHub Gen 2
Una vez creada la conexión y disponible el repositorio, el trigger asocia el evento de GitHub con el archivo de configuración del build.
gcloud builds triggers create github \
--name=github-main-build \
--repository=projects/PROJECT_ID/locations/europe-west1/connections/github-prod/repositories/my-api \
--branch-pattern='^main$' \
--build-config=cloudbuild.yaml \
--region=europe-west1
El campo repository utiliza la referencia completa del repositorio conectado a la conexión de 2ª generación. Esto es importante: no debe confundirse con una URL GitHub arbitraria.
Para una estrategia basada en tags, puede sustituirse el filtro de rama por un patrón de tags. Para pull requests, el diseño del trigger debe considerar si se desea ejecutar validaciones sin publicar artefactos de producción.
Patrones de diseño recomendados
1. Separar validación y publicación
Un pipeline maduro no debería interpretar "el código compila" como equivalente a "la imagen está lista para producción". Conviene separar lint, unit tests, build, security scanning y publicación.
2. Publicar por commit, promover por digest
El commit proporciona trazabilidad humana; el digest proporciona identidad criptográfica del artefacto. La combinación es mucho más robusta que latest.
3. Mantener regiones coherentes
Las conexiones Gen 2 son regionales y Artifact Registry también utiliza ubicaciones concretas. Diseñar deliberadamente la topología regional reduce latencia y evita configuraciones accidentales difíciles de operar.
4. Principio de mínimo privilegio
El pipeline debe tener permisos suficientes para construir y publicar, pero no una identidad con privilegios administrativos globales. El repositorio de imágenes es un excelente límite natural para aplicar permisos.
5. No introducir autenticación Docker innecesaria
Cloud Build ya dispone de integración con los servicios de Google Cloud. En un pipeline ejecutado por Cloud Build no tiene sentido copiar al repositorio comandos como docker login con credenciales estáticas si el acceso puede resolverse mediante IAM.
Evolucionar de CI básico a una plataforma de producción
El ejemplo anterior resuelve el problema inicial, pero una arquitectura Staff o Architect debe contemplar qué ocurre cuando aparecen decenas de repositorios, múltiples ambientes y requisitos de compliance.
Build determinista
Build reproducible y asociado a un commit concreto.
Supply Chain
Escaneo, SBOM, provenance y políticas antes de promoción.
Promoción
Promover el mismo digest entre staging y producción.
IAM
Identidades dedicadas y permisos mínimos por recurso.
El verdadero salto arquitectónico consiste en pasar de "un trigger que hace docker build" a una software supply chain controlada. Artifact Registry deja de ser simplemente un almacén de imágenes y pasa a formar parte del sistema de confianza de la plataforma.
FinOps: optimizar el coste sin degradar la trazabilidad
En pipelines de alto volumen, el coste no suele venir únicamente del almacenamiento de imágenes. También importan el tiempo de ejecución, builds duplicadas, tamaño de contextos Docker y acumulación de artefactos no utilizados.
- Usa un .dockerignore para reducir el contexto de build.
- Evita ejecutar builds de producción para cambios que solo afectan documentación.
- Separa validaciones rápidas de builds completos.
- Define políticas de retención para imágenes antiguas.
- No reconstruyas una imagen durante cada promoción de ambiente.
- Utiliza caching cuando el patrón de build y el nivel de reproducibilidad lo permitan.
El objetivo no es minimizar cada segundo de build a cualquier precio. El objetivo es optimizar el coste total de la cadena sin sacrificar reproducibilidad, seguridad y capacidad de auditoría.
Checklist de implementación empresarial
Definir la topología
Selecciona proyecto, región, repositorio Artifact Registry y estrategia de ambientes.
Crear la conexión GitHub Gen 2
Instala y autoriza la Cloud Build GitHub App y verifica que la conexión quede en estado COMPLETE.
Crear Artifact Registry
Utiliza un repositorio Docker dedicado y aplica IAM a nivel de repositorio cuando sea posible.
Construir el cloudbuild.yaml
Separa build y push, utiliza tags derivados del commit y evita secretos estáticos.
Crear el trigger
Vincula el repositorio Gen 2, configura rama o tags y selecciona la configuración del build.
Validar IAM
Comprueba que la identidad efectiva del build pueda escribir en Artifact Registry sin privilegios excesivos.
Promover por digest
Después de validar la imagen, promueve el mismo artefacto entre ambientes en lugar de reconstruirlo.
Errores frecuentes y diagnóstico
| Síntoma | Causa probable | Corrección |
|---|---|---|
| La conexión GitHub no termina | GitHub App no instalada o permisos insuficientes. | Completar autorización e instalación de la App. |
| Repository not found | Referencia Gen 2 incorrecta o repositorio no vinculado. | Verificar conexión, región y nombre del repositorio. |
| PERMISSION_DENIED al hacer push | La identidad de build no tiene permisos sobre Artifact Registry. | Conceder el rol mínimo necesario a la cuenta de servicio efectiva. |
| La imagen siempre aparece como latest | Tag mutable utilizado como única versión. | Etiquetar con commit SHA y promover por digest. |
| Build demasiado lenta | Contexto Docker excesivo o ausencia de caching. | Optimizar Dockerfile, .dockerignore y estrategia de cache. |
| Se intenta hacer docker login manual | Se trasladó un patrón local a Cloud Build. | Usar IAM y la integración nativa con Artifact Registry. |
Preguntas frecuentes
¿Cómo conecto un repositorio de GitHub con Cloud Build Gen 2?
Debes crear una conexión regional de GitHub mediante la Cloud Build GitHub App. Una vez autorizada e instalada en GitHub, la conexión permite vincular repositorios y crear triggers Gen 2. La conexión puede verificarse con gcloud builds connections describe.
¿Cómo sube Cloud Build una imagen Docker a Artifact Registry?
El archivo cloudbuild.yaml puede utilizar el builder Docker para ejecutar docker build y posteriormente docker push contra una ruta REGION-docker.pkg.dev/PROJECT/REPOSITORY/IMAGE. La identidad de ejecución debe tener los permisos necesarios sobre el repositorio.
¿Necesito ejecutar docker login dentro de Cloud Build?
Normalmente no. Google Cloud documenta que Cloud Build no requiere una configuración manual de autenticación Docker para interactuar con Artifact Registry; lo fundamental es que la identidad utilizada por el build tenga los permisos adecuados. Para flujos externos, sí existen mecanismos de autenticación específicos, pero no es recomendable introducir claves de cuentas de servicio en el repositorio.
Conclusión: el trigger es solo el principio
Conectar GitHub con Cloud Build Gen 2 y publicar una imagen Docker en Artifact Registry puede resolverse con unas pocas líneas de configuración. El verdadero trabajo de arquitectura aparece cuando el pipeline tiene que ser seguro, reproducible, auditable, escalable y económicamente sostenible.
La arquitectura base recomendada es clara: GitHub → Cloud Build Gen 2 → Docker build → Artifact Registry → promoción por digest.
A partir de ahí, los siguientes niveles de madurez son supply-chain security, SBOM, provenance, políticas de promoción, observabilidad de builds, gestión de identidades y automatización de la gobernanza.
Si estás diseñando una plataforma GCP para múltiples equipos, no pienses en este flujo como un simple "trigger de Docker". Piensa en él como una pieza de la cadena de suministro de software.
