Build y Dockerfile en Docker compose
Hasta ahora has aprendido a construir imágenes usando el comando docker build directamente desde la terminal. Sin embargo, Docker Compose permite integrar el proceso de construcción directamente en el archivo compose.yaml, simplificando significativamente el flujo de trabajo de desarrollo.
flowchart LR
YAML["compose.yaml<br/>service: backend<br/>build:<br/> context: ./backend<br/> dockerfile: Dockerfile<br/> target: runtime<br/> args:<br/> NODE_VERSION: 24"] -->|docker compose build| BK["BuildKit<br/>+ buildx"]
BK -->|cache mounts| L1["Layer cache<br/>local"]
BK -->|secret mounts<br/>--mount=type=secret| SEC["("Secrets<br/>./secrets/.npmrc")"]
BK --> IMG["Imagen<br/>proyecto-backend:latest"]
IMG --> UP["docker compose up<br/>arranca contenedor"]
UP --> RUN[Servicio en ejecución]
style BK fill:#1d63ed,color:#fff
style IMG fill:#1d63ed,color:#fff
La integración del build en Docker Compose elimina la necesidad de ejecutar comandos docker build separados, ya que Compose se encarga automáticamente de construir las imágenes cuando es necesario. Esta aproximación es especialmente útil en entornos de desarrollo donde necesitas reconstruir imágenes frecuentemente.
Configuración básica del build
Para integrar el build en tu archivo compose.yaml, utilizas la clave build en lugar de image dentro de la definición del servicio:
services:
web:
build: .
ports:
- "3000:3000"
En este ejemplo básico, Compose buscará un Dockerfile en el directorio actual (indicado por .) y lo utilizará para construir la imagen del servicio web.
Especificando el contexto y Dockerfile
Cuando necesitas mayor control sobre el proceso de build, puedes especificar explícitamente el contexto y la ubicación del Dockerfile:
services:
api:
build:
context: ./backend
dockerfile: Dockerfile.dev
ports:
- "8080:8080"
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
El context define el directorio base que se enviará al daemon de Docker para la construcción, mientras que dockerfile específica qué archivo Dockerfile utilizar dentro de ese contexto.
Integración de build args
Los build arguments que aprendiste anteriormente también se pueden configurar directamente en el archivo Compose:
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
- NODE_VERSION=20
- BUILD_ENV=development
environment:
- APP_ENV=dev
Esto es equivalente a ejecutar:
docker build --build-arg NODE_VERSION=20 --build-arg BUILD_ENV=development .
Variables de entorno en build args
Puedes combinar variables de entorno con build args para mayor flexibilidad:
services:
app:
build:
context: .
args:
- JAVA_VERSION=${JAVA_VERSION:-21}
- BUILD_MODE=${BUILD_MODE:-development}
Con un archivo .env correspondiente:
JAVA_VERSION=21
BUILD_MODE=production
Target para multi-stage builds
Cuando utilizas multi-stage builds, puedes especificar qué stage construir:
services:
app-dev:
build:
context: .
target: development
volumes:
- ./src:/app/src
app-prod:
build:
context: .
target: production
ports:
- "8080:8080"
Esto permite tener diferentes configuraciones del mismo Dockerfile para distintos entornos.
Construcción automática y manual
Por defecto, Compose construye las imágenes automáticamente cuando ejecutas docker compose up si no existen. Sin embargo, puedes controlar este comportamiento:
Forzar reconstrucción:
docker compose up --build
Construir solo las imágenes sin arrancar servicios:
docker compose build
Construir un servicio específico:
docker compose build app
Ejemplo práctico completo
Aquí tienes un ejemplo que integra una aplicación Node.js con una base de datos PostgreSQL:
services:
db:
image: postgres:16
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
app:
build:
context: .
dockerfile: Dockerfile
args:
- NODE_VERSION=20
- BUILD_ENV=development
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://user:password@db:5432/myapp
- NODE_ENV=development
depends_on:
- db
volumes:
- ./src:/app/src
- node_modules:/app/node_modules
volumes:
postgres_data:
node_modules:
El Dockerfile correspondiente podría ser:
ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine
ARG BUILD_ENV=production
ENV NODE_ENV=${BUILD_ENV}
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Ventajas del build integrado
La integración del build en Docker Compose ofrece varias ventajas significativas:
- Flujo simplificado: No necesitas recordar comandos de build separados
- Configuración centralizada: Toda la configuración del proyecto está en un solo archivo
- Gestión automática: Compose maneja las dependencias de construcción
- Reutilización: Los build args y configuraciones se pueden reutilizar fácilmente
- Entornos consistentes: Garantiza que todos los desarrolladores construyen las imágenes de la misma manera
Esta integración hace que el desarrollo con Docker sea mucho más eficiente, especialmente cuando trabajas con aplicaciones que requieren construcción frecuente durante el desarrollo.
Build con BuildKit y cache mounts
Compose v2 invoca BuildKit por defecto, lo que habilita las directivas --mount=type=cache y --mount=type=secret dentro de los Dockerfile. En entornos B2B con runners CI/CD compartidos esto reduce los tiempos de build entre un 40% y un 70% al persistir el caché de paquetes (~/.m2, ~/.npm, ~/.cache/pip) sin contaminar la imagen final:
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
target: runtime
cache_from:
- registry.empresa.es/backend:cache
cache_to:
- type=registry,ref=registry.empresa.es/backend:cache,mode=max
args:
JAVA_VERSION: "21"
secrets:
- github_token
secrets:
github_token:
file: ./secrets/github_token.txt
Las claves cache_from y cache_to permiten compartir el caché entre runners (GitHub Actions self-hosted, GitLab Runner, Jenkins agents) usando el propio registry corporativo como almacén distribuido. El valor mode=max exporta también las capas intermedias del multi-stage para que el siguiente build pueda saltar etapas costosas como mvn dependency:go-offline.
Multi-arch y plataformas con buildx
Cuando el cliente exige imágenes que corran en linux/amd64 y en linux/arm64 (servidores Graviton4 en AWS, Apple Silicon en desarrollo, Raspberry Pi en edge), Compose delega en buildx mediante el campo platforms:
services:
api:
build:
context: .
platforms:
- linux/amd64
- linux/arm64
tags:
- registry.empresa.es/api:1.4.2
- registry.empresa.es/api:1.4
El primer docker compose build genera un manifest list OCI con ambas variantes y lo pública con docker compose push. La consultora puede cubrir multinube heterogéneo con un único pipeline.
Estrategia B2B: Compose para CI, Bake para release
Una pauta extendida en equipos DevOps maduros separa los compose.yaml por propósito. compose.yaml queda como entorno local del desarrollador con builds rápidos y volúmenes de hot reload. compose.ci.yaml se usa en pull requests con target: testing, healthchecks estrictos y sin bind mounts. Para releases productivos se sustituye Compose por Docker Bake (docker buildx bake) declarando los mismos servicios en docker-bake.hcl, lo que añade matrices de plataforma, firmado con cosign y generación de SBOM en una sola invocación. La portabilidad del Dockerfile entre los tres flujos se mantiene porque el contexto y los target son idénticos.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Docker
Documentación oficial de Docker
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Docker es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Docker
Explora más contenido relacionado con Docker y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Comprender cómo configurar la clave build en el archivo compose.yaml para construir imágenes automáticamente. Aprender a especificar el contexto y el Dockerfile para un control detallado del build. Utilizar build args y variables de entorno para parametrizar la construcción de imágenes. Manejar multi-stage builds mediante la opción target en Docker Compose. Conocer los comandos para construir imágenes automática o manualmente con Docker Compose.