Dev Containers para Entornos de Desarrollo Reproducibles
Los Dev Containers permiten definir entornos de desarrollo completos en un fichero de configuración, garantizando que todos los miembros del equipo trabajen con exactamente las mismas herramientas, versiones y dependencias independientemente de su sistema operativo. Con soporte nativo en VS Code, GitHub Codespaces y la CLI oficial, son la solución más efectiva para eliminar el clásico problema de "en mi máquina funciona".
Requisitos Previos
- Docker instalado en el sistema anfitrión
- VS Code con la extensión "Dev Containers" (ms-vscode-remote.remote-containers)
- O la CLI oficial de Dev Containers
- Git para clonar repositorios
Estructura de devcontainer.json
El fichero .devcontainer/devcontainer.json es el corazón de la configuración:
{
"name": "Entorno de Desarrollo Node.js",
// Imagen base del contenedor
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-20-bullseye",
// Características adicionales a instalar
"features": {
"ghcr.io/devcontainers/features/git:1": {
"version": "latest",
"ppa": false
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"version": "latest",
"dockerDashComposeVersion": "v2"
},
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
}
},
// Extensiones de VS Code a instalar automáticamente
"customizations": {
"vscode": {
"extensions": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"ms-vscode.vscode-typescript-next",
"eamodio.gitlens",
"ms-azuretools.vscode-docker"
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"terminal.integrated.defaultProfile.linux": "bash"
}
}
},
// Puertos a exponer automáticamente
"forwardPorts": [3000, 8080, 5432],
// Etiquetar los puertos expuestos
"portsAttributes": {
"3000": {
"label": "Aplicación web",
"onAutoForward": "notify"
},
"5432": {
"label": "PostgreSQL",
"onAutoForward": "silent"
}
},
// Comando que se ejecuta tras crear el contenedor
"postCreateCommand": "npm install && npm run prepare",
// Comando que se ejecuta al iniciar el contenedor
"postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
// Variables de entorno para el contenedor
"containerEnv": {
"NODE_ENV": "development"
},
// Montar el agente SSH del anfitrión
"mounts": [
"source=${localEnv:SSH_AUTH_SOCK},target=/ssh-agent,type=bind,consistency=delegated"
],
// Variables de entorno del agente SSH
"remoteEnv": {
"SSH_AUTH_SOCK": "/ssh-agent"
}
}
Features: Herramientas Preconfiguradas
Los Features son componentes reutilizables que añaden herramientas al contenedor:
{
"name": "Entorno Backend Python + Go",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-22.04",
"features": {
// Python con versión específica
"ghcr.io/devcontainers/features/python:1": {
"version": "3.11",
"installTools": true
},
// Go
"ghcr.io/devcontainers/features/go:1": {
"version": "1.22"
},
// kubectl y Helm para trabajo con Kubernetes
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {
"version": "latest",
"helm": "latest",
"minikube": "none"
},
// Terraform para infraestructura como código
"ghcr.io/devcontainers/features/terraform:1": {
"version": "latest",
"tflint": "latest"
},
// AWS CLI
"ghcr.io/devcontainers/features/aws-cli:1": {},
// GitHub CLI
"ghcr.io/devcontainers/features/github-cli:1": {}
}
}
Crear tu propio Feature personalizado:
# Estructura de un Feature personalizado
mkdir -p .devcontainer/features/mi-herramienta/
tee .devcontainer/features/mi-herramienta/devcontainer-feature.json << 'EOF'
{
"id": "mi-herramienta",
"version": "1.0.0",
"name": "Mi Herramienta Personalizada",
"description": "Instala herramientas específicas del equipo",
"options": {
"version": {
"type": "string",
"default": "latest",
"description": "Versión a instalar"
}
}
}
EOF
tee .devcontainer/features/mi-herramienta/install.sh << 'EOF'
#!/bin/bash
# Script de instalación del Feature
VERSION=${VERSION:-latest}
# Instalar dependencias del sistema
apt-get update && apt-get install -y jq curl
# Instalar la herramienta
curl -fsSL "https://ejemplo.com/install.sh" | bash -s -- "$VERSION"
echo "Mi herramienta instalada correctamente"
EOF
chmod +x .devcontainer/features/mi-herramienta/install.sh
Integración con Docker Compose
Para entornos con múltiples servicios (base de datos, Redis, etc.):
# .devcontainer/docker-compose.yml
version: "3.8"
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/workspace:cached
- ~/.gitconfig:/root/.gitconfig:ro
command: sleep infinity
environment:
DATABASE_URL: postgresql://postgres:postgres@db:5432/devdb
REDIS_URL: redis://redis:6379
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: devdb
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
restart: unless-stopped
mailhog:
image: mailhog/mailhog
# Captura emails en desarrollo
ports:
- "8025:8025"
volumes:
postgres_data:
// .devcontainer/devcontainer.json con Docker Compose
{
"name": "Entorno Full Stack",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/devcontainers/features/node:1": {"version": "20"},
"ghcr.io/devcontainers/features/git:1": {}
},
"customizations": {
"vscode": {
"extensions": ["ms-azuretools.vscode-docker"]
}
},
"forwardPorts": [3000, 5432, 6379, 8025],
"postCreateCommand": "npm install && npm run db:migrate",
"shutdownAction": "stopCompose"
}
# .devcontainer/Dockerfile
FROM mcr.microsoft.com/devcontainers/javascript-node:1-20-bullseye
# Instalar herramientas adicionales del sistema
RUN apt-get update && apt-get install -y \
postgresql-client \
redis-tools \
&& rm -rf /var/lib/apt/lists/*
# Instalar herramientas globales de Node
RUN npm install -g \
typescript \
ts-node \
@prisma/cli \
knex
Uso con VS Code
# Abrir el repositorio en VS Code
code /ruta/al/proyecto
# VS Code detectará el .devcontainer/ automáticamente y mostrará
# una notificación para "Reabrir en contenedor"
# También puedes usar el Command Palette:
# Ctrl+Shift+P → "Dev Containers: Reopen in Container"
# Para ver los logs de construcción del contenedor:
# Ctrl+Shift+P → "Dev Containers: Show Container Log"
# Para reconstruir el contenedor (tras cambios en devcontainer.json):
# Ctrl+Shift+P → "Dev Containers: Rebuild Container"
Atajos útiles dentro del Dev Container:
# Dentro del contenedor, ejecutar tareas
# El terminal de VS Code ya está dentro del contenedor
# Verificar que estás dentro del contenedor
cat /etc/hostname # Mostrará el ID del contenedor
# Ver los servicios disponibles (si usas Docker Compose)
docker ps
# Conectar a la base de datos
psql $DATABASE_URL
# Ejecutar migraciones
npm run db:migrate
Dev Container CLI
Para usar Dev Containers sin VS Code:
# Instalar la CLI
npm install -g @devcontainers/cli
# Verificar la instalación
devcontainer --version
# Construir e iniciar el contenedor
cd /ruta/al/proyecto
devcontainer up --workspace-folder .
# Ejecutar un comando dentro del contenedor
devcontainer exec --workspace-folder . npm test
# Ejecutar una shell interactiva
devcontainer exec --workspace-folder . bash
# Parar y eliminar el contenedor
devcontainer down --workspace-folder .
# Construir sin iniciar (útil para CI/CD)
devcontainer build --workspace-folder . \
--image-name mi-devcontainer:latest
Integración en pipelines CI/CD:
# .github/workflows/ci.yml - Pruebas dentro del Dev Container
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar Dev Container CLI
run: npm install -g @devcontainers/cli
- name: Ejecutar pruebas en el Dev Container
run: |
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . npm test
Estandarización del Equipo
Buenas prácticas para usar Dev Containers en equipo:
// Configuración orientada al equipo
{
"name": "Proyecto MiEmpresa",
// Versionar la imagen para reproducibilidad exacta
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-20.12-bullseye",
// Documentar las variables de entorno requeridas
"containerEnv": {
"NODE_ENV": "development",
"TZ": "Europe/Madrid"
},
// Tarea de bienvenida al abrir el proyecto
"postCreateCommand": {
"instalar": "npm install",
"preparar": "npm run prepare",
"mensaje": "echo '\\n✓ Entorno listo. Ejecuta: npm run dev\\n'"
},
// Extensiones obligatorias para el proyecto
"customizations": {
"vscode": {
"extensions": [
// Linting y formato - obligatorias
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
// Colaboración
"ms-vsliveshare.vsliveshare"
]
}
}
}
# Añadir guía de inicio rápido en el README
# Asegúrate de documentar los requisitos previos del equipo:
# 1. Instalar Docker Desktop (Windows/Mac) o Docker Engine (Linux)
# 2. Instalar VS Code + extensión "Dev Containers"
# 3. Clonar el repositorio
# 4. Abrir en VS Code → aceptar "Reabrir en contenedor"
# 5. Esperar a que se construya el contenedor (primera vez: ~5 minutos)
Solución de Problemas
El contenedor no se construye:
# Ver los logs detallados de construcción
# En VS Code: Ctrl+Shift+P → "Dev Containers: Show Container Log"
# Desde la CLI
devcontainer up --workspace-folder . --log-level debug 2>&1 | tail -50
Cambios en devcontainer.json no se aplican:
# Forzar reconstrucción completa del contenedor
# VS Code: Ctrl+Shift+P → "Dev Containers: Rebuild Container Without Cache"
# CLI:
devcontainer up --workspace-folder . --remove-existing-container
Permisos de ficheros incorrectos:
# El usuario dentro del contenedor suele ser 'vscode' con UID 1000
# Si los ficheros montados tienen permisos incorrectos:
sudo chown -R 1000:1000 /ruta/al/proyecto
# O ajustar en devcontainer.json:
# "remoteUser": "root" (solo para depuración)
Conclusión
Los Dev Containers eliminan la fricción de configurar entornos de desarrollo al codificar toda la infraestructura necesaria en un fichero de configuración versionado. La integración con Docker Compose permite replicar entornos de producción completos localmente, mientras que la compatibilidad con GitHub Codespaces facilita el trabajo en la nube cuando es necesario. Adoptar Dev Containers es especialmente valioso en equipos grandes donde la consistencia del entorno impacta directamente en la productividad.


