Dominar los contenedores de desarrollo en VS Code
Cree entornos de desarrollo consistentes, portables y reproducibles usando Dev Containers.
Los desarrolladores a menudo enfrentan el dilema “funciona en mi máquina” debido a desacuerdos en dependencias, versiones de herramientas o diferencias en el sistema operativo.
Dev Containers en Visual Studio Code (VS Code) resuelven esto elegantemente — permitiendo desarrollar dentro de un entorno contenedorizado configurado específicamente para su proyecto.
El desarrollo de software moderno requiere entornos consistentes y reproducibles que funcionen en todas las máquinas y sistemas operativos. Ya sea que estés trabajando en un proyecto de ciencia de datos en Python, una aplicación web en Node.js o un microservicio en Go, garantizar que cada miembro del equipo tenga una configuración de desarrollo idéntica puede ser un desafío.
Esta guía completa recorre qué son los Dev Containers, por qué son valiosos y cómo configurarlos en VS Code para flujos de trabajo de desarrollo portables y suaves. Aprenderás todo, desde la configuración básica hasta configuraciones avanzadas con Docker Compose y buenas prácticas para la colaboración en equipo.
🧩 ¿Qué son los Dev Containers?
Los Dev Containers son una característica proporcionada por la extensión VS Code Remote - Containers (ahora parte de VS Code Remote Development).
Permiten abrir tu proyecto en un contenedor Docker que está preconfigurado con todas tus dependencias, lenguajes y herramientas.
Píntalo así:
“Un entorno de desarrollo completamente configurado, definido como código.”
En lugar de instalar Python, Node.js, bases de datos y diversas herramientas directamente en tu máquina, las defines en archivos de configuración. Cuando abres el proyecto en VS Code, automáticamente se levanta un contenedor con todo instalado y configurado exactamente como se especificó.
Una configuración de Dev Container típicamente incluye:
- Un Dockerfile o referencia a una imagen base (definiendo el sistema operativo, lenguajes y herramientas del contenedor)
- Un archivo
devcontainer.json
(configurando ajustes del espacio de trabajo, extensiones de VS Code, reenvío de puertos, variables de entorno y comandos de inicio) - Opcional docker-compose.yml si tu proyecto depende de múltiples servicios (como bases de datos, Redis, colas de mensajes, etc.)
⚙️ ¿Por qué usar Dev Containers?
Aquí está lo que los hace poderosos:
-
Reproducibilidad: Cada desarrollador y sistema de CI usa exactamente el mismo entorno. No más problemas como “funciona en mi máquina pero no en la tuya”. Lo que funciona en tu laptop funcionará de forma idéntica en la máquina de tu compañero, en Windows, Mac o en una estación de trabajo Linux.
-
Aislamiento: No es necesario contaminar tu máquina local con dependencias conflictivas. Trabaja en múltiples proyectos que requieren versiones diferentes de Python, Node.js u otras herramientas sin conflictos de versiones o ajustes de entornos virtuales.
-
Portabilidad: Funciona en cualquier sistema operativo que admita Docker. Tu entorno de desarrollo viaja con tu código. Clona un repositorio, ábrelo en VS Code y estarás listo para codificar en minutos — independientemente de tu sistema operativo.
-
Consistencia en equipo: Una configuración compartida en toda tu equipe. Los nuevos miembros del equipo pueden estar operativos en minutos en lugar de pasar horas (o días) configurando su entorno de desarrollo con las herramientas y versiones correctas.
-
Automatización: Instala automáticamente extensiones de VS Code, dependencias de lenguaje y herramientas cuando abres el proyecto. Los comandos post-creación pueden ejecutar migraciones de base de datos, sembrar datos o realizar otras tareas de configuración sin intervención manual.
-
Seguridad: Aisla dependencias potencialmente riesgosas en contenedores. Si necesitas probar con una versión más antigua y vulnerable de una biblioteca, permanece contenida y no afecta tu sistema anfitrión.
Ejemplo real: Imagina unirte a un equipo que trabaja en un proyecto de microservicios que usa Python 3.11, PostgreSQL 15, Redis y Elasticsearch. Sin Dev Containers, pasarías horas instalando y configurando cada componente. Con Dev Containers, abres el proyecto en VS Code, le dejas que construya el contenedor y estarás escribiendo código dentro de 5 a 10 minutos.
🧱 Configuración de un Dev Container en VS Code
Vamos paso a paso.
1. Instalar las herramientas necesarias
Antes de comenzar, asegúrate de tener instalado lo siguiente:
-
Docker Desktop (o un entorno de contenedores equivalente como Podman)
- Para Windows/Mac: Descarga e instala Docker Desktop
- Para Linux: Instala Docker Engine y asegúrate de que tu usuario esté en el grupo docker
-
VS Code (recomendado la última versión)
-
La extensión Dev Containers (por Microsoft)
- Abre VS Code
- Ve a Extensiones (
Ctrl+Shift+X
oCmd+Shift+X
en macOS) - Busca “Dev Containers”
- Instala la extensión con ID:
ms-vscode-remote.remote-containers
Verifica tu configuración:
# Verifica que Docker esté en ejecución
docker --version
docker ps
# Debería mostrar la versión de Docker y los contenedores en ejecución (si hay alguno)
2. Inicializar el Dev Container
Abre tu carpeta de proyecto en VS Code
y abre el Panel de Comandos (Ctrl+Shift+P
o Cmd+Shift+P
en macOS), luego escribe y selecciona:
Dev Containers: Add Dev Container Configuration Files...
VS Code presentará una lista de plantillas de entorno predefinidas. Elige la que coincida con tu proyecto:
- Node.js — proyectos de JavaScript/TypeScript
- Python — ciencia de datos, aplicaciones web, scripts
- Go — aplicaciones y servicios en Go
- .NET — aplicaciones en C#/F#
- Java — proyectos Spring Boot, Maven, Gradle
- Docker-in-Docker — cuando necesitas Docker dentro de tu contenedor
- Y muchos más…
También puedes seleccionar características adicionales como:
- Utilidades comunes (git, curl, wget)
- Clientes de base de datos
- Herramientas de CLI de la nube (AWS, Azure, GCP)
Este asistente crea una carpeta .devcontainer
con:
devcontainer.json
— archivo de configuración principalDockerfile
— definición de imagen personalizada (o referencia a una imagen base preconstruida)
3. Personalizar devcontainer.json
El archivo devcontainer.json
es donde ocurre la magia. Aquí hay un ejemplo bien documentado para un proyecto de Node.js:
{
// Nombre de visualización del contenedor en VS Code
"name": "Node.js Development Container",
// Configuración de construcción — puede usar Dockerfile o una imagen preconstruida
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
// Alternativa: usar una imagen preconstruida en lugar de Dockerfile
// "image": "mcr.microsoft.com/devcontainers/javascript-node:18",
// Configuración del espacio de trabajo
"customizations": {
"vscode": {
// Configuraciones de VS Code que se aplican en el contenedor
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// Extensiones para instalar automáticamente
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"eamodio.gitlens",
"ms-azuretools.vscode-docker"
]
}
},
// Reenvío de puertos — hacer disponibles los puertos del contenedor en el host
"forwardPorts": [3000, 5432],
"portsAttributes": {
"3000": {
"label": "Aplicación",
"onAutoForward": "notify"
}
},
// Comandos para ejecutar en diferentes etapas
"postCreateCommand": "npm install", // Después de crear el contenedor
"postStartCommand": "npm run dev", // Después de iniciar el contenedor
// Variables de entorno
"containerEnv": {
"NODE_ENV": "development",
"PORT": "3000"
},
// Ejecutar el contenedor como usuario no root (recomendado para seguridad)
"remoteUser": "node",
// Montar volúmenes adicionales
"mounts": [
"source=${localEnv:HOME}/.ssh,target=/home/node/.ssh,readonly,type=bind"
]
}
Explicación de opciones clave:
name
— nombre de visualización mostrado en la barra de estado de VS Codebuild
/image
— usar un Dockerfile o una imagen preconstruidacustomizations.vscode.extensions
— extensiones de VS Code para instalar automáticamenteforwardPorts
— puertos para exponer del contenedor al hostpostCreateCommand
— se ejecuta una vez cuando se crea el contenedor (ej. instalar dependencias)postStartCommand
— se ejecuta cada vez que se inicia el contenedorcontainerEnv
— variables de entorno disponibles en el contenedorremoteUser
— cuenta de usuario para usar dentro del contenedormounts
— archivos o carpetas adicionales para montar (como claves SSH)
💡 Consejos profesionales:
- Usa
postCreateCommand
para operaciones lentas (npm install, pip install) - Usa
postStartCommand
para tareas de inicio rápido (migraciones de base de datos) - Siempre especifique las extensiones que necesita tu proyecto — esto asegura una herramienta consistente
- Usa variables de entorno para configuraciones que varían entre desarrolladores
4. Construir y abrir en el contenedor
Una vez que tu configuración esté lista, es hora de lanzar tu entorno de desarrollo:
Abrir el Panel de Comandos (Ctrl+Shift+P
/ Cmd+Shift+P
) y ejecutar:
Dev Containers: Reopen in Container
¿Qué sucede a continuación:
-
Construcción de la imagen — VS Code construye la imagen Docker basada en tu Dockerfile o extrae una imagen preconstruida. Esto puede tomar unos minutos la primera vez.
-
Creación del contenedor — Docker crea un nuevo contenedor a partir de la imagen construida.
-
Montaje de volúmenes — Tu carpeta de proyecto se monta en el contenedor, haciendo accesible tu código dentro de él.
-
Instalación de extensiones — Todas las extensiones de VS Code especificadas se instalan automáticamente en el contenedor.
-
Comandos post-creación — Tu
postCreateCommand
se ejecuta (ej.npm install
,pip install -r requirements.txt
). -
¡Listo! — VS Code se reconecta al contenedor y ahora estás desarrollando dentro de él.
Verifica que estés en el contenedor:
Puedes confirmar que estás trabajando dentro del contenedor abriendo un terminal y ejecutando:
# Verificar el sistema operativo
uname -a
# Salida: Linux ... (kernel del contenedor)
# Verificar el nombre del host (normalmente el ID del contenedor)
hostname
# Salida: abc123def456
# Verificar procesos en ejecución
ps aux
# Verás procesos del contenedor, no de tu sistema anfitrión
Nota que la barra de estado de VS Code (inferior izquierda) ahora muestra: Dev Container: [Nombre de tu contenedor]
Comandos del ciclo de vida del contenedor:
- Reconstruir el contenedor —
Dev Containers: Rebuild Container
(cuando cambias el Dockerfile) - Reconstruir sin caché —
Dev Containers: Rebuild Container Without Cache
(para una construcción fresca) - Reabrir localmente —
Dev Containers: Reopen Folder Locally
(salir del contenedor, trabajar en el host)
5. Añadir servicios adicionales (opcional)
Las aplicaciones reales suelen depender de bases de datos, capas de caché, colas de mensajes u otros servicios. Puedes usar Docker Compose para orquestar múltiples contenedores.
Ejemplo: Aplicación full-stack con Node.js, PostgreSQL y Redis
Crea un docker-compose.yml
en tu carpeta .devcontainer
:
version: "3.8"
services:
# Contenedor de desarrollo principal
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
# Montar carpeta del proyecto
- ..:/workspace:cached
# Usar volumen con nombre para node_modules (mejor rendimiento)
- node_modules:/workspace/node_modules
# Mantener el contenedor en ejecución
command: sleep infinity
# Acceso de red a otros servicios
depends_on:
- db
- redis
environment:
DATABASE_URL: postgresql://dev:secret@db:5432/appdb
REDIS_URL: redis://redis:6379
# Base de datos PostgreSQL
db:
image: postgres:15-alpine
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_USER: dev
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
ports:
- "5432:5432"
# Cache Redis
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- redis-data:/data
ports:
- "6379:6379"
volumes:
postgres-data:
redis-data:
node_modules:
Luego, actualiza tu devcontainer.json
para usar Docker Compose:
{
"name": "Entorno de desarrollo full-stack",
// Usar docker-compose en lugar de un solo contenedor
"dockerComposeFile": "docker-compose.yml",
// ¿Qué servicio usar como contenedor de desarrollo?
"service": "app",
// Ruta a la carpeta de trabajo dentro del contenedor
"workspaceFolder": "/workspace",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-azuretools.vscode-docker",
"ckolkman.vscode-postgres" // Cliente de PostgreSQL
]
}
},
"forwardPorts": [3000, 5432, 6379],
"postCreateCommand": "npm install && npm run db:migrate",
"remoteUser": "node"
}
¿Qué ofrece esta configuración:
app
— Tu contenedor de desarrollo con Node.jsdb
— Base de datos PostgreSQL, accesible endb:5432
desde tu aplicaciónredis
— Cache Redis, accesible enredis:6379
- Volúmenes con nombre — Persistir datos de la base de datos entre reinicios del contenedor
- Reenvío de puertos — Acceder a todos los servicios desde tu máquina anfitriona
Conectar a servicios desde tu código:
// En tu aplicación de Node.js
const { Pool } = require('pg');
const redis = require('redis');
// Conexión a PostgreSQL
const pool = new Pool({
connectionString: process.env.DATABASE_URL
// Resuelve a: postgresql://dev:secret@db:5432/appdb
});
// Conexión a Redis
const redisClient = redis.createClient({
url: process.env.REDIS_URL
// Resuelve a: redis://redis:6379
});
Acceder a servicios desde tu máquina anfitriona:
- App:
http://localhost:3000
- PostgreSQL:
localhost:5432
(usando cualquier cliente de PostgreSQL) - Redis:
localhost:6379
(usandoredis-cli
o herramientas gráficas)
Ahora, cuando abras el proyecto en VS Code, todos los servicios se iniciarán automáticamente!
🧠 Consejos avanzados y buenas prácticas
Usar imágenes preconstruidas
Ahorra tiempo de construcción significativo empezando desde las imágenes oficiales de devcontainer de Microsoft:
{
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
}
}
Features son scripts de instalación reutilizables para herramientas comunes (Git, GitHub CLI, Node, AWS CLI, etc.).
Buenas prácticas de control de versiones
Siempre comita tu carpeta .devcontainer
:
git add .devcontainer/
git commit -m "Añadir configuración de Dev Container"
git push
Esto asegura:
- ✅ Nuevos miembros del equipo obtienen el entorno automáticamente
- ✅ Los cambios del entorno se rastrean y revisan
- ✅ Todos desarrollan en la misma configuración
Consejo profesional: Añade una sección README que explique la configuración del contenedor de desarrollo:
## Configuración de desarrollo
Este proyecto usa Dev Containers de VS Code. Para comenzar:
1. Instalar Docker Desktop y VS Code
2. Instalar la extensión "Dev Containers"
3. Clonar este repositorio
4. Abrir en VS Code
5. Hacer clic en "Reopen in Container" cuando se le pida
Depuración en contenedores
La depuración funciona de forma inmediata. Configura tu launch.json
como de costumbre:
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Node.js",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/index.js",
"skipFiles": ["<node_internals>/**"]
}
]
}
Establece puntos de interrupción y depura normalmente — VS Code maneja automáticamente la conexión al contenedor.
Paridad con Continuous Integration
Usa la misma imagen de contenedor en tu pipeline de CI/CD:
# Ejemplo de GitHub Actions
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/devcontainers/javascript-node:18
steps:
- uses: actions/checkout@v3
- run: npm install
- run: npm test
Esto asegura paridad entre desarrollo y producción — si las pruebas pasan localmente, pasarán en CI.
Optimización de rendimiento
Para usuarios de macOS/Windows — usa volúmenes con nombre para dependencias:
{
"mounts": [
"source=myproject-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
]
}
Esto mejora significativamente el rendimiento de E/S para node_modules
, venv
, etc.
Desarrollo multi-estadio
Crea configuraciones diferentes para diferentes roles de equipo:
.devcontainer/
├── devcontainer.json # Default (full-stack)
├── frontend/
│ └── devcontainer.json # Solo frontend (más ligero)
└── backend/
└── devcontainer.json # Solo backend (con DB)
Los miembros del equipo pueden elegir su entorno cuando abran el proyecto.
Trabajar con claves SSH y Git
Monta tus claves SSH para operaciones de Git:
{
"mounts": [
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/node/.ssh,readonly,type=bind"
],
"postCreateCommand": "ssh-add ~/.ssh/id_ed25519 || true"
}
Archivos de entorno personalizados
Carga configuración específica del entorno:
{
"runArgs": ["--env-file", ".devcontainer/.env"]
}
.devcontainer/.env
:
API_KEY=dev_key_here
DEBUG=true
LOG_LEVEL=debug
🔧 Problemas comunes de solución
El contenedor no inicia
Error: No se puede conectar al demonio de Docker
Solución:
- Asegúrate de que Docker Desktop esté en ejecución
- En Linux, verifica:
sudo systemctl status docker
- Verifica que Docker esté en tu PATH:
docker --version
Rendimiento lento en macOS/Windows
Problema: Las operaciones de archivos son lentas
Soluciones:
-
Usa volúmenes con nombre para
node_modules
,venv
, etc. -
Habilita el compartir archivos en la configuración de Docker Desktop
-
Considera usar opciones de montaje
cached
odelegated
:"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached"
Extensiones no se instalan
Problema: Las extensiones especificadas en devcontainer.json
no se instalan
Soluciones:
- Reconstruye el contenedor:
Dev Containers: Rebuild Container
- Verifica que los IDs de las extensiones sean correctos
- Asegúrate de que las extensiones admitan contenedores remotos (la mayoría lo hacen)
Puerto ya en uso
Error: El puerto 3000 ya está asignado
Soluciones:
- Detén los contenedores conflictivos:
docker ps
ydocker stop <container>
- Cambia el mapeo de puertos en
forwardPorts
- Usa puertos dinámicos: VS Code asignará automáticamente puertos disponibles
Cambios en Dockerfile no aplicados
Problema: Modificaste el Dockerfile pero los cambios no se aplican
Solución: Reconstruye sin caché:
Dev Containers: Rebuild Container Without Cache
El contenedor se cierra inmediatamente
Problema: El contenedor inicia y luego se cierra
Solución: Añade un comando para mantenerlo en ejecución en docker-compose.yml
:
command: sleep infinity
O en devcontainer.json
:
{
"overrideCommand": true
}
✅ Conclusión
Los Dev Containers en VS Code traen consistencia, simplicidad y automatización a tu flujo de trabajo de desarrollo. Transforman configuraciones complejas y frágiles en entornos definidos por código que simplemente funcionan, independientemente de tu máquina o sistema operativo.
Conclusión clave:
- 🎯 Eliminar problemas de “funciona en mi máquina” — Todos usan entornos idénticos
- 🚀 Mayor velocidad de onboarding — Nuevos miembros del equipo productivos en minutos, no en días
- 🔒 Mejor seguridad — Aislar dependencias del sistema anfitrión
- 📦 Portabilidad — Tu entorno viaja con tu código
- 🤝 Consistencia en equipo — No más conflictos de versiones de dependencias
- 🔄 Paridad con CI/CD — Usa la misma imagen en desarrollo y en integración continua
Ya sea que estés trabajando en un simple script de Python o en una arquitectura compleja de microservicios con múltiples bases de datos, los Dev Containers ofrecen una base sólida para el desarrollo moderno.
Si colaboras en proyectos multilenguaje, contribuyes a repositorios de código abierto, onboards nuevos desarrolladores con frecuencia o simplemente deseas entornos de desarrollo limpios y reproducibles — los Dev Containers son una herramienta esencial en tu pila.
Empieza pequeño: prueba Dev Containers en tu próximo proyecto. Una vez que experimentes los beneficios, te preguntarás cómo desarrollaste sin ellos.
📚 Recursos útiles y artículos relacionados
Documentación oficial:
- Documentación de Dev Containers de Microsoft
- Repositorio de imágenes de Dev Containers — imágenes preconstruidas para varios lenguajes y frameworks
- Funciones de Dev Containers — snippets de configuración reutilizables de contenedores de desarrollo
Artículos relacionados en este sitio:
- Guía de atajos de VSCode — atajos y comandos esenciales de VS Code
- Guía de comandos de Docker — referencia de comandos de Docker
- Guía de comandos de Docker Compose — orquestación de múltiples contenedores
- Guía de Python — referencia del lenguaje Python
- Guía de instalación de Node.js — guía de instalación de Node.js
- Guía de Go — referencia del lenguaje Go
- Popularidad de lenguajes y frameworks de programación — tendencias y rankings tecnológicos