# Arquitectura de Docker GitHub Builder


Docker GitHub Builder separa la orquestación del repositorio de la implementación de la compilación.
Un repositorio de consumo decide cuándo se ejecuta una compilación, qué permisos y secretos se conceden,
y qué entradas se pasan. El flujo de trabajo reutilizable en el [repositorio `docker/github-builder`](https://github.com/docker/github-builder)
es el propietario de la implementación de la compilación en sí. Esa división mantiene los flujos de trabajo
de los repositorios cortos a la vez que centraliza BuildKit, el almacenamiento en caché, la procedencia,
la generación de SBOM, la firma y el ensamblaje multiplataforma en una única ruta mantenida por Docker.

![Vista general de GitHub Builder](/build/ci/github-actions/github-builder/images/architecture-overview.png)

## Arquitectura principal

Un flujo de trabajo emisor invoca [`build.yml`](/build/ci/github-actions/github-builder/architecture/build/) o [`bake.yml`](/build/ci/github-actions/github-builder/architecture/bake/).
[`build.yml`](/build/ci/github-actions/github-builder/architecture/build/) es el punto de entrada para compilaciones orientadas a Dockerfile.
[`bake.yml`](/build/ci/github-actions/github-builder/architecture/bake/) es el punto de entrada para compilaciones orientadas a Bake, donde la definición de Bake
sigue siendo la fuente de verdad para los targets y las anulaciones. En ambos casos, el emisor sigue siendo
el propietario de las políticas del repositorio, incluidos los desencadenadores, las condiciones de las ramas,
los permisos, los secretos, la selección de targets, las entradas de metadatos y la elección entre la salida
de imagen y la salida local.

Dentro del flujo de trabajo reutilizable, la primera fase prepara la compilación. Valida las entradas
entrantes, resuelve la configuración del runner y expande una solicitud multiplataforma en un trabajo
por plataforma. El modelo de ejecución se puede visualizar como una matriz donde `linux/amd64` se ejecuta
en `ubuntu-24.04` y `linux/arm64` se ejecuta en `ubuntu-24.04-arm`. Cada trabajo de plataforma se compila
de forma independiente, y luego el flujo de trabajo finaliza el resultado en un único contrato de salida
de cara al emisor.

```yaml
plataformas solicitadas: linux/amd64,linux/arm64

trabajos de plataforma conceptuales: linux/amd64 -> ubuntu-24.04
  linux/arm64 -> ubuntu-24.04-arm
```

### Selección de runners

La entrada `runner` acepta una única etiqueta de runner de Linux alojado en GitHub o una asignación
de plataformas delimitada por saltos de línea.

El valor predeterminado es una asignación de plataformas que utiliza runners de Ubuntu alojados en GitHub:

```yaml
runner: |
  default=ubuntu-24.04
  linux/arm=ubuntu-24.04-arm
  linux/arm64=ubuntu-24.04-arm
```

En el trabajo de plataforma, la etiqueta del runner se resuelve en un único valor:

```yaml
runner: ubuntu-24.04
```

Una asignación debe definir un runner `default`. Las otras claves son prefijos de plataforma, y el
prefijo coincidente más específico tiene prioridad. Por ejemplo, `linux/arm` coincide con variantes
como `linux/arm/v7`, mientras que `linux/arm64` es un prefijo independiente.

En el siguiente ejemplo, `linux` coincide con plataformas Linux que no coinciden con un prefijo
más largo. La clave `default` sigue siendo requerida porque es la opción de respaldo cuando ningún
prefijo de plataforma coincide.

```yaml
runner: |
  default=ubuntu-24.04
  linux=ubuntu-24.04
  linux/arm=ubuntu-24.04-arm
  linux/arm64=ubuntu-24.04-arm
```

Los flujos de trabajo reutilizables requieren runners de Linux alojados en GitHub. Los valores
heredados `auto`, `amd64` y `arm64` se siguen aceptando por compatibilidad, pero emiten advertencias
de obsolescencia. Utiliza en su lugar una etiqueta de runner explícita o una asignación de plataformas.

## Ruta de ejecución

![Flujo de ejecución de GitHub Builder](/build/ci/github-actions/github-builder/images/execution-flow.png)

La ruta de ejecución se mantiene corta a propósito. El repositorio de consumo llama al flujo de
trabajo reutilizable. El flujo de trabajo reutilizable prepara la compilación, ejecuta los trabajos
por plataforma y finaliza el resultado. Para la salida de imágenes, la finalización produce una
imagen de registro y un manifiesto multiplataforma. Para la salida local, la finalización fusiona los
archivos de cada plataforma y puede subir el resultado fusionado como un artefacto de GitHub. El emisor
no necesita reconstruir cómo se conectaron Buildx, BuildKit, el almacenamiento en caché o el ensamblaje
del manifiesto.

## Los dos puntos de entrada reutilizables

[`build.yml`](/build/ci/github-actions/github-builder/architecture/build/) se adapta mejor cuando la compilación ya está expresada como un flujo de
trabajo orientado a Dockerfile. Se alinea de forma natural con conceptos como `context`, `file`, `target`,
`build-args`, `labels`, `annotations` y `platforms`. Este es el punto de entrada que se siente más
cercano a `docker/build-push-action`, excepto que la implementación del flujo de trabajo está centralizada.

[`bake.yml`](/build/ci/github-actions/github-builder/architecture/bake/) se adapta mejor cuando el repositorio ya utiliza Bake como definición de compilación.
Preserva el modelo de Bake, incluida la resolución de targets, `files`, `set` y `vars`, al tiempo que
enruta la ejecución a través de la misma ruta de compilación mantenida por Docker. Un detalle arquitectónico
importante es que el flujo de trabajo de Bake se centra en un target por llamada de flujo de trabajo, lo que
mantiene la procedencia, el manejo de resúmenes (digests) y el ensamblaje final del manifiesto limitados a
una unidad de compilación a la vez.

## Modelo de salida

Los flujos de trabajo reutilizables exponen un conjunto estable de salidas de cara al emisor para que
los trabajos posteriores puedan consumir los resultados sin comprender el gráfico de trabajos internos.
En la práctica, los valores principales son `digest`, `meta-json`, `artifact-name`, `output-type` y
`signed`. Ese contrato es importante porque mantiene la promoción, publicación o automatización
posterior desacoplada de la mecánica de selección de runners y el ensamblaje por plataforma.

## Ejemplos

### Compilación de imagen orientada a Dockerfile

El siguiente ejemplo muestra la forma de una compilación de imagen multiplataforma impulsada
por [`build.yml`](/build/ci/github-actions/github-builder/architecture/build/).

```yaml
name: ci

on:
  push:
    branches:
      - "main"
    tags:
      - "v*"
  pull_request:

permissions:
  contents: read

jobs:
  build:
    uses: docker/github-builder/.github/workflows/build.yml@v1
    permissions:
      contents: read
      id-token: write
    with:
      output: image
      push: ${{ github.event_name != 'pull_request' }}
      platforms: linux/amd64,linux/arm64
      meta-images: name/app
      meta-tags: |
        type=ref,event=branch
        type=ref,event=pr
        type=semver,pattern={{version}}
    secrets:
      registry-auths: |
        - registry: docker.io
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
```

Esta llamada es pequeña porque el flujo de trabajo reutilizable se encarga del trabajo pesado. El
repositorio decide cuándo debe ejecutarse la compilación y qué entradas desea, mientras que la
implementación compartida maneja la configuración de Buildx, la configuración de BuildKit, la distribución
por plataformas (platform fan-out), la generación de metadatos, la procedencia, la generación de SBOM,
la firma y la creación del manifiesto final.

### Salida local orientada a Bake

El siguiente ejemplo muestra la forma de una llamada de Bake que exporta salida local y sube
el artefacto fusionado.

```yaml
name: ci

on:
  pull_request:

permissions:
  contents: read

jobs:
  bake:
    uses: docker/github-builder/.github/workflows/bake.yml@v1
    permissions:
      contents: read
      id-token: write
    with:
      output: local
      target: binaries
      artifact-upload: true
      artifact-name: bake-output
```

Esta forma es útil cuando el repositorio ya mantiene su definición de compilación en Bake y desea
preservar esa fuente de verdad. El flujo de trabajo inyecta el comportamiento de salida local en la
ejecución de Bake, ejecuta el target por plataforma cuando es necesario y fusiona el resultado en un
único artefacto de cara al emisor.

## Por qué funciona esta arquitectura

### Rendimiento

La mejora de rendimiento proviene de la distribución nativa por plataformas (platform fan-out),
la configuración compartida de BuildKit y el manejo centralizado de la caché. El trabajo multiplataforma
se puede distribuir en runners compatibles alojados en GitHub en lugar de forzar a cada arquitectura a
ejecutarse en una sola máquina de compilación. Esto reduce la presión de emulación, acorta la ruta crítica
para compilaciones multiplataforma y proporciona a cada repositorio de consumo la misma línea base de
compilación optimizada.

### Seguridad

El modelo de seguridad proviene de colocar la implementación de la compilación en flujos de trabajo
reutilizables mantenidos por Docker en lugar de pasos de trabajo ad hoc en cada repositorio de consumo.
El emisor sigue controlando los permisos y los secretos, pero la lógica de compilación en sí misma se
revisa y versiona de forma centralizada. El proyecto también trata la procedencia, la generación de SBOM
y la firma como aspectos de primer nivel, lo que fortalece el límite de confianza entre la orquestación
del repositorio y la producción de artefactos.

### Aislamiento y confiabilidad

La confiabilidad proviene de la separación de conceptos. El repositorio de consumo orquesta la compilación.
El flujo de trabajo reutilizable ejecuta la compilación. Esto reduce la desviación de CI (CI drift),
elimina el código repetitivo de integración de los repositorios y hace que el resultado sea más fácil
de razonar porque el emisor ve un contrato estable en lugar de una gran definición de trabajo personalizada.

