Logo GCP con Eduardo

GCP con Eduardo

Descarga el código de la lección

Cómo conectar GitHub con Cloud Build (Gen 2) y subir imágenes a Artifact Registry
✦ Guía Técnica & Arquitectura

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

Crear una conexión de GitHub de 2ª generación en Cloud Build.
Diseñar un trigger basado en rama y conectado a un repositorio concreto.
Construir y publicar imágenes Docker directamente en Artifact Registry.
Evitar errores de IAM, regiones, tags mutables y autenticación innecesaria.
GitHub Cloud Build Gen 2 Artifact Registry Docker gcloud CLI IAM YAML

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.

01 / SOURCE

GitHub

Contiene el Dockerfile, el código de aplicación y el archivo cloudbuild.yaml.

02 / CONNECTION

Cloud Build Gen 2

La conexión regional integra GitHub mediante la Cloud Build GitHub App.

03 / BUILD

Trigger

Un evento como un push sobre main inicia el pipeline.

04 / ARTIFACT

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
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:

IDENTITY

Cuenta de servicio

Identidad explícita para ejecutar el pipeline.

SCOPE

Repositorio

Permisos limitados al Artifact Registry necesario.

ROLE

Writer

Permiso de escritura únicamente donde sea necesario.

SECRET

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.

CI

Build determinista

Build reproducible y asociado a un commit concreto.

SECURITY

Supply Chain

Escaneo, SBOM, provenance y políticas antes de promoción.

CD

Promoción

Promover el mismo digest entre staging y producción.

GOVERNANCE

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

1

Definir la topología

Selecciona proyecto, región, repositorio Artifact Registry y estrategia de ambientes.

2

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.

3

Crear Artifact Registry

Utiliza un repositorio Docker dedicado y aplica IAM a nivel de repositorio cuando sea posible.

4

Construir el cloudbuild.yaml

Separa build y push, utiliza tags derivados del commit y evita secretos estáticos.

5

Crear el trigger

Vincula el repositorio Gen 2, configura rama o tags y selecciona la configuración del build.

6

Validar IAM

Comprueba que la identidad efectiva del build pueda escribir en Artifact Registry sin privilegios excesivos.

7

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.

Sobre el Autor: Eduardo Martínez Agrelo

AI & Data Architect

Eduardo Martínez Agrelo es AI & Data Architect, especializado en arquitectura de datos, inteligencia artificial, plataformas cloud y diseño de sistemas tecnológicos orientados a producción.

Su enfoque combina profundidad técnica, arquitectura empresarial y toma de decisiones basada en trade-offs reales de escalabilidad, seguridad, rendimiento, gobernanza y coste.

© 2026 Eduardo Martínez Agrelo · AI & Data Architect