Docker: De Desarrollo a Contenedores en Producción
Guía enfocada en producción para Docker — desde Dockerfiles optimizados y multi-stage builds hasta workflows con Docker Compose, escaneo de seguridad de imágenes, gestión de registries y Kaniko para builds rootless en CI/CD. Cubre volúmenes, healthchecks, BuildKit, modos de networking y .dockerignore. Basada en containerizar 26 microservicios.
Por Jose Nobile | Actualizado 2026-06-11 | 22 min de lectura
Índice
- Buenas Prácticas de Dockerfile
- .dockerignore
- Multi-Stage Builds
- BuildKit
- Docker Compose para Desarrollo Local
- Volúmenes y Bind Mounts
- Healthchecks
- Optimización de Imágenes
- Escaneo de Seguridad
- Gestión de Registries
- Kaniko para Builds en CI/CD
- Networking de Contenedores
- Caso Real: Containerización en Producción
- Últimas Características de Docker (2025-2026)
Buenas Prácticas de Dockerfile
Un Dockerfile es una receta para construir una imagen de contenedor. Cada instrucción crea una capa, y las capas se cachean. El orden de las instrucciones impacta directamente la velocidad de build y el tamaño de imagen. Coloca instrucciones que cambian poco (instalar paquetes del sistema) antes de instrucciones que cambian seguido (copiar código de la aplicación). Esto maximiza los cache hits y reduce los rebuilds de minutos a segundos.
Usa tags específicos de imagen base, nunca latest. Fija a un digest o tag de versión como node:20.11-alpine3.19 para builds reproducibles. Combina instrucciones RUN con && para minimizar capas y limpiar archivos temporales en la misma capa. Cada capa persiste en la imagen final, así que descargar, compilar y limpiar en instrucciones RUN separadas infla la imagen aunque los archivos se borren después.
Siempre incluye un archivo .dockerignore para excluir node_modules/, .git/, *.md, archivos de test y otros artefactos que no deberían estar en el contexto de build. Un contexto de build inflado ralentiza docker build porque todo el contexto se envía al daemon antes de que se ejecute cualquier instrucción. En producción, cada microservicio tiene un .dockerignore curado que reduce el contexto de build de ~500MB a ~20MB.
COPY . .
RUN npm install
# Good: Only re-install when dependencies change
COPY package.json package-lock.json ./
RUN npm ci --production
COPY . .
.dockerignore
El archivo .dockerignore funciona como .gitignore pero para el contexto de build de Docker. Sin él, docker build envía cada archivo del directorio de build al daemon Docker, incluyendo .git/ (frecuentemente cientos de megabytes), node_modules/, fixtures de test, documentación y configuración de IDE. Esto desperdicia tiempo, ancho de banda y puede filtrar secretos a la imagen.
Coloca.dockerignore en la raíz de tu contexto de build (junto al Dockerfile). Lista directorios y patrones de archivos que no tienen por qué estar dentro del contenedor: historial de control de versiones, dependencias de desarrollo, suites de test, configuración de CI, archivos de entorno local y configuración del editor. Un .dockerignore bien mantenido puede reducir el contexto de build de cientos de megabytes a menos de 20MB.
Sé explícito en vez de permisivo. Algunos equipos usan un enfoque de allowlist: ignoran todo con * y luego selectivamente des-ignoran lo que el build realmente necesita con !. Esto previene la inclusión accidental de archivos nuevos agregados al repositorio. En producción, cada microservicio usa el patrón allowlist, asegurando que solo src/, package.json, package-lock.json y tsconfig.json entren al contexto de build.
.git
.gitignore
node_modules
npm-debug.log*
dist
coverage
*.md
.env*
.vscode
.idea
Dockerfile*
docker-compose*
__tests__
*.test.ts
*.spec.ts
.github
.gitlab-ci.yml
# .dockerignore - Allowlist approach (stricter)
*
!src/
!package.json
!package-lock.json
!tsconfig.json
Multi-Stage Builds
Los multi-stage builds son la técnica de mayor impacto para reducir el tamaño de imágenes Docker. Permiten usar una imagen para compilar (con compiladores, dependencias dev, herramientas de build) y una imagen separada y mínima para el runtime final. Solo los artefactos que explícitamente haces COPY --from=build terminan en la imagen de producción. En producción, los multi-stage builds redujeron las imágenes de servicios Node.js de 1.2GB (con dependencias dev) a 180MB (Alpine + deps de producción + código compilado).
Para servicios TypeScript, el patrón es: Etapa 1 compila TypeScript a JavaScript con todas las dependencias dev, Etapa 2 copia solo el JavaScript compilado y los node_modules de producción en una imagen runtime basada en Alpine. Para servicios Go, es aún más dramático: la imagen final puede ser scratch (vacía) ya que Go compila a un binario estático sin dependencias de runtime. Para la menor superficie de ataque, usa imágenes distroless de Google (gcr.io/distroless/nodejs20-debian12) que incluyen el runtime pero sin shell, package manager ni utilidades del SO.
Nombra tus etapas con AS para claridad: FROM node:20-alpine AS build. También puedes apuntar a etapas específicas durante desarrollo con docker build --target=build para obtener una imagen con herramientas dev y test runners. Esto hace que el mismo Dockerfile sirva tanto para desarrollo como para producción.
FROM node:20-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY tsconfig.json ./
COPY src/ ./src/
RUN npm run build
# Stage 2: Production (Alpine)
FROM node:20-alpine AS production
WORKDIR /app
RUN addgroup -g 1001 app && adduser -u 1001 -G app -D app
COPY package.json package-lock.json ./
RUN npm ci --production && npm cache clean --force
COPY --from=build /app/dist ./dist
USER app
EXPOSE 3000
CMD ["node", "dist/index.js"]
# Alternative Stage 2: Distroless (no shell, minimal attack surface)
# FROM gcr.io/distroless/nodejs20-debian12
# WORKDIR /app
# COPY --from=build /app/dist ./dist
# COPY --from=build /app/node_modules ./node_modules
# USER 1000
# CMD ["dist/index.js"]
BuildKit
BuildKit es el motor de build de próxima generación de Docker, habilitado por defecto desde Docker 23.0. Reemplaza al builder legacy con ejecución paralela de builds, mejor caching y nuevas features del Dockerfile. Si estás en una versión anterior de Docker, habilítalo con DOCKER_BUILDKIT=1 docker build o configura { "features": { "buildkit": true } } en la configuración del daemon Docker.
La feature más impactante de BuildKit es la ejecución paralela de etapas. En un Dockerfile multi-stage, las etapas independientes se buildean concurrentemente en vez de secuencialmente, reduciendo significativamente el tiempo total de build. También provee soporte de cache mount vía RUN --mount=type=cache,target=/root/.npm npm ci, que persiste cachés del package manager entre builds sin inflar la capa de imagen. Esto elimina la necesidad de npm cache clean --force y acelera la instalación de dependencias.
BuildKit introduce secret mounts (RUN --mount=type=secret,id=npmrc cat /run/secrets/npmrc) que inyectan secretos en tiempo de build sin escribirlos en ninguna capa de imagen. Esto es crítico para registries npm privados o API keys necesarias durante el build. Otras features incluyen --mount=type=ssh para forwarding del agente SSH (repos Git privados), exportación de cache de build inline (--cache-to y --cache-from), y sintaxis heredoc para instrucciones RUN multilínea.
export DOCKER_BUILDKIT=1
# Cache mount: persist npm cache across builds
# syntax=docker/dockerfile:1
FROM node:20-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
RUN npm run build
# Secret mount: private registry auth without leaking to layers
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
# SSH mount: clone private repos at build time
RUN --mount=type=ssh git clone [email protected]:org/private-lib.git
# Inline cache for CI/CD
docker build --cache-from type=registry,ref=registry/app:cache \
--cache-to type=registry,ref=registry/app:cache \
-t registry/app:latest .
Docker Compose para Desarrollo Local
Docker Compose define aplicaciones multi-contenedor en un solo archivo YAML. Es la herramienta estándar para ambientes de desarrollo local que replican las dependencias de servicios de producción. Un solo docker compose up levanta tu aplicación junto con MySQL, Redis, Elasticsearch o cualquier otro servicio que tu app necesite, con networking ya configurado entre ellos.
Usa volumes para montar tu código fuente en el contenedor para hot-reloading durante desarrollo. Combina con depends_on y health checks para asegurar que los servicios arranquen en el orden correcto. La feature de profiles te permite definir servicios opcionales (como herramientas de debug o bases de datos de test) que solo corren cuando se activan explícitamente con --profile debug.
Mantén archivos Compose separados para diferentes contextos: compose.yaml para servicios core, compose.override.yaml para overrides de desarrollo local (montajes de volúmenes, puertos de debug), y compose.test.yaml para ambientes de test en CI. Compose automáticamente mergea compose.yaml con compose.override.yaml, así que los developers obtienen overrides locales sin modificar el archivo base. Nota: la clave version está deprecada en Compose V2 y puede omitirse.
services:
api:
build:
context: .
target: build
volumes:
- ./src:/app/src
ports:
- "3000:3000"
depends_on:
mysql:
condition: service_healthy
environment:
- DB_HOST=mysql
- REDIS_HOST=redis
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 15s
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: dev
MYSQL_DATABASE: myapp
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
retries: 10
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
retries: 5
volumes:
mysql_data:
Volúmenes y Bind Mounts
Los contenedores Docker son efímeros: cuando se elimina un contenedor, todos los datos dentro de él se pierden. Los volúmenes resuelven esto persistiendo datos fuera de la capa escribible del contenedor. Docker gestiona volúmenes nombrados en /var/lib/docker/volumes/, y sobreviven a la recreación del contenedor, actualizaciones y reinicios. Usa volúmenes nombrados para bases de datos, uploads de archivos y cualquier dato con estado que deba persistir.
Los bind mounts mapean un directorio del host directamente al contenedor. Son esenciales para desarrollo local: monta tu directorio src/ para que los cambios de código aparezcan instantáneamente dentro del contenedor sin reconstruir. Sin embargo, los bind mounts tienen implicaciones de rendimiento en macOS y Windows debido al overhead de traducción del filesystem. Usa los flags de consistencia :cached o :delegated de Docker, o el backend VirtioFS más nuevo, para mejorar el rendimiento en hosts que no sean Linux.
En producción, prefiere volúmenes nombrados sobre bind mounts por portabilidad y gestión. Usa montajes tmpfs para datos sensibles que nunca deberían escribirse en disco (tokens de sesión, secretos temporales). Para bases de datos en contenedores (solo desarrollo), siempre usa un volumen nombrado para evitar perder datos con docker compose down. El comando docker volume prune limpia volúmenes huérfanos, pero úsalo con cuidado para evitar borrar volúmenes de datos.
docker run -v mysql_data:/var/lib/mysql mysql:8.0
# Bind mount (host directory into container)
docker run -v $(pwd)/src:/app/src node:20-alpine
# tmpfs mount (in-memory, never written to disk)
docker run --tmpfs /tmp:rw,noexec,size=100m myapp
# Compose volumes with driver options
volumes:
mysql_data:
driver: local
uploads:
driver: local
driver_opts:
type: none
o: bind
device: /data/uploads
Healthchecks
Los healthchecks le dicen a Docker si un contenedor está funcionando correctamente, no solo corriendo. Un contenedor puede tener su proceso vivo pero estar en deadlock, sin memoria o incapaz de servir requests. La instrucción HEALTHCHECK en un Dockerfile o la clave healthcheck en Compose define un comando que Docker ejecuta periódicamente. Si el chequeo falla consecutivamente, Docker marca el contenedor como unhealthy.
Define healthchecks que prueben la funcionalidad real de tu servicio, no solo la existencia del proceso. Para servicios HTTP, golpea un endpoint /health o /readyz. Para bases de datos, usa el comando ping nativo (mysqladmin ping, redis-cli ping, pg_isready). El parámetro start_period le da tiempo al contenedor para inicializarse antes de que los healthchecks empiecen a fallar, lo que previene falsos negativos durante el arranque.
Los healthchecks habilitan el depends_on: condition: service_healthy de Compose, que asegura que los servicios dependientes solo arranquen después de que sus dependencias estén genuinamente listas, no solo corriendo. Sin healthchecks, tu contenedor API podría arrancar antes de que MySQL esté listo para aceptar conexiones, causando crashes al inicio. En producción, cada servicio de Compose tiene un healthcheck, y el servicio API espera a que MySQL, Redis y Elasticsearch reporten healthy antes de arrancar.
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci --production
HEALTHCHECK --interval=15s --timeout=5s --start-period=10s --retries=3 \
CMD ["node", "-e", "require('http').get('http://localhost:3000/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) })"]
CMD ["node", "dist/index.js"]
# Compose healthchecks
services:
api:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 15s
postgres:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
retries: 10
Optimización de Imágenes
El tamaño de imagen impacta directamente los tiempos de pull, costos de almacenamiento y superficie de ataque. Cada megabyte cuenta cuando estás bajando imágenes de 20+ servicios en cada deployment. Empieza con imágenes basadas en Alpine (node:20-alpine son 50MB vs. node:20 con 350MB). Si tu aplicación tiene dependencias glibc que rompen en musl de Alpine, usa variantes Debian slim (node:20-slim con 80MB).
El caché de capas es tu mejor aliado. Docker cachea cada capa y la reutiliza si la instrucción y todas las capas padre no cambiaron. Estructura tu Dockerfile para que el contenido que cambia más seguido (código fuente) venga al final. Usa npm ci en vez de npm install para instalaciones determinísticas y cache-friendly. Copia solo package.json y package-lock.json antes de correr npm ci, después copia el resto del código fuente.
Para las imágenes más pequeñas posibles, considera las imágenes base distroless de Google (gcr.io/distroless/nodejs20-debian12, gcr.io/distroless/static-debian12). Las imágenes distroless contienen solo el runtime del lenguaje y tu aplicación — sin shell, sin package manager, sin utilidades del SO. Esto elimina clases enteras de vulnerabilidades y reduce las imágenes a su tamaño mínimo absoluto. Usa docker image history y dive (un TUI para explorar capas de imagen) para identificar bloat. En producción, auditorías regulares de imágenes con dive redujeron la imagen promedio de microservicio de 350MB a 140MB, ahorrando ~4.2GB de almacenamiento en registry por deployment en 20 servicios.
Imágenes Base Alpine
Las imágenes Alpine Linux son 5-10x más chicas que las alternativas basadas en Debian. Usa node:20-alpine, python:3.12-alpine. Cuidado con problemas de compatibilidad musl con módulos nativos.
Imágenes Distroless
Las imágenes distroless de Google contienen solo el runtime. Sin shell, sin package manager. Usa gcr.io/distroless/nodejs20-debian12 para Node.js o gcr.io/distroless/static-debian12 para binarios Go. La menor superficie de ataque posible.
Orden de Cache de Capas
Paquetes del sistema primero, luego archivos de dependencias, luego npm ci, luego código fuente. Cambiar un archivo fuente solo reconstruye desde la instrucción COPY en adelante, manteniendo todas las capas de dependencias cacheadas.
Dive para Análisis
Ejecuta dive tu-imagen:tag para explorar interactivamente cada capa, ver espacio desperdiciado e identificar archivos que no deberían estar en la imagen. Apunta a un score de eficiencia de imagen superior al 90%.
Escaneo de Seguridad
Las imágenes de contenedor heredan vulnerabilidades de los paquetes OS base, runtime del lenguaje y dependencias de la aplicación. Un solo CVE sin parchear en una imagen base afecta cada servicio construido sobre ella. Escanea imágenes en tiempo de build (en CI/CD), al pushear (del lado del registry), y continuamente (scans programados de imágenes en ejecución). Herramientas como Trivy, Grype y Snyk Container detectan CVEs conocidos en paquetes OS, librerías del lenguaje e incluso misconfiguraciones del Dockerfile.
Integra el escaneo en tu pipeline de CI como una puerta: falla el build si se encuentran vulnerabilidades críticas o de alta severidad. Trivy corre en menos de 30 segundos y genera formato SARIF para dashboards de seguridad de GitLab/GitHub. Snyk provee análisis más profundo del árbol de dependencias y sugerencias de corrección. En producción, cada pipeline de GitLab CI ejecuta trivy image --severity HIGH,CRITICAL --exit-code 1 antes de pushear a GCR. Esto atrapó 3 CVEs críticos en la imagen base de Node.js en el primer mes.
Más allá del escaneo, sigue la higiene de seguridad de contenedores: corre como usuario no-root (USER app), usa filesystems root de solo lectura donde sea posible, descarta todas las capabilities de Linux y agrega solo las necesarias, y nunca embebas secrets en la imagen. Usa secret mounts de BuildKit para credenciales en tiempo de build. Usa imágenes distroless o scratch para la menor superficie de ataque posible — sin shell significa sin exploits basados en shell.
trivy image --severity HIGH,CRITICAL gcr.io/myproject/api:v2.4.1
# Trivy: fail CI on findings
trivy image --severity HIGH,CRITICAL --exit-code 1 $IMAGE
# Trivy: scan Dockerfile for misconfigurations
trivy config --severity HIGH,CRITICAL ./Dockerfile
# Trivy: generate SARIF report for GitLab/GitHub
trivy image --format sarif --output trivy-results.sarif $IMAGE
# Snyk: scan image with fix suggestions
snyk container test $IMAGE --severity-threshold=high
# Snyk: monitor for new vulnerabilities
snyk container monitor $IMAGE
Gestión de Registries
Un registry de contenedores almacena y distribuye tus imágenes Docker. Google Container Registry (GCR) y su sucesor Artifact Registry, Amazon ECR, y GitHub Container Registry (ghcr.io) son las principales opciones cloud. Elige el registry en el mismo proveedor cloud que tu cluster para minimizar latencia de pull y costos de egress. Los nodos GKE bajan de GCR/Artifact Registry a velocidad de red sin cargos de egress.
Etiqueta imágenes con versiones semánticas y SHA de Git para trazabilidad: gcr.io/myproject/api:v2.4.1 para releases y gcr.io/myproject/api:abc1234 para cada build. Nunca uses :latest en manifiestos Kubernetes de producción — anula el propósito de deployments inmutables y hace imposible los rollbacks. Implementa una política de retención para borrar automáticamente imágenes más viejas de N días o mantener solo los últimos N tags para controlar costos de almacenamiento.
Para imágenes multi-arquitectura (amd64 + arm64), usadocker buildx para buildear y pushear listas de manifiestos. Esto es cada vez más importante a medida que los equipos adoptan nodos basados en ARM (AWS Graviton, GKE Arm) para ahorrar costos. En producción, las imágenes se pushean a Google Artifact Registry con tags de versión y SHA de Git, y una política de lifecycle retiene solo las últimas 30 versiones por servicio.
Google Artifact Registry
Sucesor de GCR. Repositorios regionales con IAM granular, escaneo de vulnerabilidades y políticas de limpieza. Egress gratis a GKE en la misma región. Usado en producción para las 20+ imágenes de servicio.
Amazon ECR
Integrado con ECS/EKS. Políticas de lifecycle para limpieza automática de imágenes. Replicación cross-region para deployments multi-región. Pull gratis desde la misma región.
GitHub Container Registry
ghcr.io se integra con GitHub Actions. Imágenes públicas son gratis. Bueno para proyectos open-source y equipos chicos usando GitHub para CI/CD.
Kaniko para Builds en CI/CD
Kaniko construye imágenes Docker dentro de un contenedor sin requerir un daemon Docker o modo privilegiado. Esto resuelve el problema de seguridad "Docker-in-Docker" en ambientes CI/CD como GitLab CI, donde correr un daemon Docker privilegiado dentro de un job CI es un riesgo de seguridad. Kaniko ejecuta instrucciones Dockerfile en userspace, construyendo la imagen y pusheando directamente a un registry.
La configuración es mínima: monta tu contexto de build, pasa la ruta del Dockerfile y especifica el registry destino. Kaniko soporta cache de capas vía un repositorio de cache remoto, lo cual acelera drásticamente los builds reutilizando capas sin cambios de builds anteriores. En producción, Kaniko con cache remoto redujo los tiempos de build promedio de 4 minutos a 90 segundos en todos los microservicios.
Kaniko soporta todas las instrucciones estándar de Dockerfile, multi-stage builds y build arguments. Los flags --cache=true y --cache-repo habilitan el cache remoto. Usa --snapshot-mode=redo para snapshotting más rápido de capas en imágenes grandes. El flag --use-new-run mejora el rendimiento de instrucciones RUN en 20-30%.
En producción, cada pipeline de GitLab CI usa Kaniko para builds de imágenes. Sin contenedores privilegiados, sin daemon Docker, sin Docker-in-Docker. El pipeline se autentica a GCR vía una service account key montada como secret de Kubernetes. Build, push y scan suceden en menos de 2 minutos por servicio.
build:
stage: build
image:
name: gcr.io/kaniko-project/executor:v1.22.0-debug
entrypoint: [""]
script:
- /kaniko/executor
--context $CI_PROJECT_DIR
--dockerfile $CI_PROJECT_DIR/Dockerfile
--destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
--destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
--cache=true
--cache-repo=$CI_REGISTRY_IMAGE/cache
--snapshot-mode=redo
Networking de Contenedores
Docker provee varios drivers de red, cada uno adecuado para distintos casos de uso. La red bridge por defecto aísla contenedores del host y entre sí a menos que los puertos se publiquen explícitamente. Las redes bridge definidas por el usuario (creadas con docker network create) agregan resolución DNS automática entre contenedores por nombre, razón por la cual Docker Compose crea una por proyecto. Todos los servicios de Compose comparten una red bridge custom automáticamente y pueden alcanzarse entre sí por nombre de servicio.
El modo de red host elimina el aislamiento de red por completo: el contenedor comparte el stack de red del host directamente. Esto elimina el overhead de traducción de direcciones de red y es útil para escenarios de alto rendimiento donde el contenedor necesita máximo throughput de red. Usa --network host o network_mode: host en Compose. La contrapartida es que no hay aislamiento de puertos — los puertos del contenedor se bindean directamente al host.
El driver de red overlay habilita networking multi-host para Docker Swarm y es la base para la comunicación de contenedores entre múltiples máquinas. Las redes overlay encriptan el tráfico entre nodos por defecto y soportan service discovery. En ambientes Kubernetes, el networking overlay lo maneja el plugin CNI (Calico, Cilium, o VPC nativa de GKE) en vez del driver overlay de Docker, pero el concepto es el mismo: contenedores en diferentes hosts se comunican sobre una red virtual.
Para seguridad en desarrollo local, publica puertos con 127.0.0.1:3000:3000 para bindear solo a localhost en vez de todas las interfaces. Para debuggear problemas de networking: docker network inspect bridge muestra IPs y conexiones de contenedores, docker exec container curl other-service:3000 testea conectividad entre contenedores, y docker logs revela errores de conexión.
Bridge (Default)
Red aislada con publicación de puertos. Las bridges definidas por el usuario agregan resolución DNS. Default para Compose. Mejor para la mayoría del desarrollo local y producción en un solo host.
Host
El contenedor comparte el stack de red del host. Sin overhead de NAT. Máximo throughput. Sin aislamiento de puertos. Úsalo para servicios críticos en rendimiento o cuando el contenedor necesita acceso a la red del host.
Overlay
Networking multi-host para Docker Swarm. Tráfico inter-nodo encriptado. Service discovery entre hosts. En Kubernetes, los plugins CNI (Calico, Cilium) cumplen el mismo propósito.
Caso Real: Containerización en Producción
Cada microservicio está containerizado con Docker, buildeado con Kaniko en GitLab CI, y desplegado a GKE vía charts de Helm. La estrategia de containerización evolucionó de Dockerfiles single-stage ingenuos a multi-stage builds optimizados, reduciendo el tamaño de imágenes un 85% y los tiempos de build un 60%.
20+ Servicios Containerizados
Microservicios Node.js/TypeScript, cada uno con Dockerfile multi-stage, base Alpine y usuario no-root. Tamaño promedio de imagen: 140MB. Todos buildeados con Kaniko en GitLab CI, pusheados a Google Artifact Registry.
Kaniko + GitLab CI
Cero daemons Docker en CI. Builds Kaniko con cache de capas remoto redujeron tiempos de build de 4 minutos a 90 segundos. Escaneo de seguridad Trivy bloquea cada imagen antes de llegar al registry.
Docker Compose para Dev
El desarrollo local refleja la topología de producción: servicios API, MySQL, Redis y Elasticsearch definidos en Compose con healthchecks. Developers nuevos pasan de clone a ambiente corriendo en menos de 5 minutos.
Últimas Características de Docker (2025-2026)
Docker Scout: Docker Scout es ahora la herramienta principal de escaneo de seguridad en el ecosistema Docker. Provee detección de CVEs en tiempo real durante builds, evaluación de políticas contra estándares de seguridad organizacionales, y soporte de documentos VEX (Vulnerability Exploitability eXchange) para gestionar excepciones. Scout expone un endpoint Prometheus para métricas de vulnerabilidades, habilitando integración con stacks de monitoreo existentes. A diferencia de scanners externos que corren post-build, Scout se integra directamente en el proceso de build, atrapando vulnerabilidades antes de que las imágenes se pusheen a registries.
Docker Compose v5 ("Mont Blanc") (Dic 2025): Compose v5 elimina el builder interno por completo, delegando todos los builds a Docker Bake. Esto produce builds más rápidos con mejor caching, soporte multi-plataforma nativo y comportamiento de build consistente entre docker compose build e invocaciones standalone de Bake. Compose v5 también incluye un nuevo SDK oficial en Go, habilitando control programático de stacks Compose desde tooling custom y sistemas CI/CD.
Docker Build Cloud: Builds basados en la nube con caches de build compartidos entre equipos. En vez de que cada developer y runner de CI mantenga su propio cache local, Build Cloud provee un cache centralizado que todos los miembros del equipo y pipelines comparten. Esto reduce drásticamente los tiempos de build para equipos distribuidos y elimina las penalidades de cache frío cuando los runners de CI son efímeros.
Docker Engine v29 (Ene 2026): El image store de containerd es ahora el default para instalaciones nuevas, reemplazando el storage driver legacy. Esto alinea a Docker con el ecosistema de contenedores más amplio (Kubernetes ya usa containerd). Engine v29 también agrega soporte de backend nftables para networking, modernizando la dependencia de iptables de Docker. La versión mínima de API es ahora 1.44, requiriendo Docker v25 o posterior como cliente -- clientes más viejos necesitarán actualizarse.
Docker Model Runner y MCP (Desktop 4.40+, Abril 2026): Docker Model Runner, basado en llama.cpp, permite ejecutar LLMs localmente vía una API compatible con OpenAI sin configuración adicional. Aceleración GPU soportada en macOS (Metal), Windows (NVIDIA) y Windows (Qualcomm). Model Runner ahora funciona con Docker Compose y Testcontainers (Java y Go), integrando servicios AI en stacks de microservicios. El Docker AI Agent adopta completamente el Model Context Protocol (MCP), exponiendo capacidades como servidores MCP para Claude Desktop, Cursor o cualquier cliente compatible con MCP. El MCP Toolkit integrado (Desktop 4.42+) descubre y gestiona 100+ servidores MCP sin extensiones. A partir de Docker Desktop 4.69.0 (15 de abril de 2026), Docker publica releases semanales con iteración rápida de herramientas AI -- tarjetas de template MCP, soporte de modelos expandido e inspección de requests de inferencia para debugging de workflows AI.
Docker Scout
Detección de CVEs en tiempo real durante builds. Evaluación de políticas, excepciones VEX y endpoint de métricas Prometheus. La herramienta principal de escaneo de seguridad de Docker.
Compose v5 "Mont Blanc"
Eliminó builder interno, delega a Bake. Builds más rápidos, mejor caching, soporte multi-plataforma. Nuevo SDK oficial en Go para control programático.
Docker Build Cloud
Builds basados en la nube con caches compartidos entre equipos. Elimina penalidades de cache frío en runners CI efímeros. Builds más rápidos para equipos distribuidos.
Docker Engine v29
Estable actual (2026). Image store containerd como default. Soporte backend nftables. IPv6 nativo (dual-stack, solo IPv4 o solo IPv6). Versión mínima de API 1.44 (Docker v25+ requerido). Stack de networking modernizado.
Compose v5.1.4
Última versión de Compose (20 de mayo de 2026). El comando docker-compose (con guión) está completamente deprecado -- usadocker compose (separado con espacio). El campo version en archivos compose ya no es requerido y se ignora.
Model Runner y MCP Toolkit
Ejecuta LLMs localmente vía API compatible con OpenAI (llama.cpp). GPU en macOS, Windows NVIDIA y Qualcomm. Integración con Compose y Testcontainers. MCP Toolkit ahora con tarjetas de template de perfil y tour de onboarding. Model Runner agrega soporte Qwen3.5. Desktop 4.74 (19 de mayo de 2026) hace generalmente disponibles la vista Logs y el asistente AI Gordon. Engine 29.5.3 (3 de junio de 2026) corrige las vulnerabilidades de docker cp CVE-2026-41567 y CVE-2026-41568 y agrega el placeholder .HealthStatus a docker ps --format.