Dev Containers
Language Overview¶
Dev Containers provide consistent, reproducible development environments using container technology.
This guide covers standards for .devcontainer configuration files used with VS Code, GitHub Codespaces,
and other compatible IDEs.
Key Characteristics¶
- File Name:
devcontainer.json(in.devcontainer/directory) - Format: JSON with Comments (JSONC)
- Primary Use: Defining containerized development environments
- Key Principles: Reproducibility, consistency, zero-setup onboarding, cloud portability
This Style Guide Covers¶
- Dev Container configuration structure and naming
- GitHub Codespaces-specific settings
- Feature selection and tool installation
- VS Code extension recommendations
- Port forwarding and networking
- Secret management
- Multi-container development environments
- Lifecycle scripts and commands
- Performance optimization
- Security best practices
Quick Reference¶
| Category | Convention | Example | Notes |
|---|---|---|---|
| Directory Structure | |||
| Standard location | .devcontainer/ |
.devcontainer/devcontainer.json |
Required directory |
| Multi-config | Named subdirs | .devcontainer/python/ |
For multiple configs |
| Docker Compose | Alongside config | .devcontainer/docker-compose.yml |
Multi-container |
| Configuration | |||
| Name | Descriptive | "My Project Dev" |
Shows in UI |
| Image | Pinned version | mcr.microsoft.com/devcontainers/python:3.11 |
Use specific tags |
| Features | Official registry | ghcr.io/devcontainers/features/... |
Prefer official |
| Lifecycle | |||
| postCreateCommand | Initial setup | pip install -r requirements.txt |
After container creation |
| postStartCommand | On every start | echo 'Ready!' |
After container starts |
| postAttachCommand | On attach | git fetch |
When user attaches |
| Extensions | |||
| Format | Extension ID | ms-python.python |
Use full ID |
| Required | In array | ["ms-python.python"] |
Always install |
| Ports | |||
| Forward | Port number | "forwardPorts": [8000] |
Expose to host |
| Attributes | Labels & behavior | "portsAttributes": {...} |
Configure per port |
| Codespaces | |||
| Host requirements | CPU/memory | "hostRequirements": {...} |
Machine sizing |
| Secrets | Variable names | "secrets": {...} |
Environment secrets |
| Prebuild | Boolean | "codespaces": {"prebuild": true} |
Enable prebuilds |
Basic Structure¶
Minimal Configuration¶
{
"name": "My Project",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu"
}
Standard Project Configuration¶
{
"name": "My Project Dev Environment",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.black-formatter",
"charliermarsh.ruff"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python"
}
}
},
"forwardPorts": [8000],
"postCreateCommand": "pip install -r requirements.txt",
"remoteUser": "vscode"
}
Directory Structure¶
Standard Layout¶
.devcontainer/
├── devcontainer.json # Main configuration
├── Dockerfile # Custom image (optional)
├── docker-compose.yml # Multi-container (optional)
├── scripts/
│ ├── setup-dev.sh # Setup script
│ └── post-create.sh # Post-create hook
└── .env.example # Environment template
Multiple Configurations¶
.devcontainer/
├── devcontainer.json # Default configuration
├── python/
│ └── devcontainer.json # Python-specific
├── node/
│ └── devcontainer.json # Node.js-specific
└── full-stack/
├── devcontainer.json # Full stack
└── docker-compose.yml # With services
Base Images¶
Official Microsoft Dev Container Images¶
{
"name": "Python Development",
"image": "mcr.microsoft.com/devcontainers/python:3.11-bookworm"
}
{
"name": "Node.js Development",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20-bookworm"
}
{
"name": "Go Development",
"image": "mcr.microsoft.com/devcontainers/go:1.21-bookworm"
}
{
"name": "Universal Development",
"image": "mcr.microsoft.com/devcontainers/universal:2"
}
Pin Image Versions¶
{
"name": "Production-Grade Environment",
"image": "mcr.microsoft.com/devcontainers/python:1.1.3-3.11-bookworm"
}
{
"name": "Avoid Unpinned Versions",
"image": "mcr.microsoft.com/devcontainers/python:latest"
}
Features¶
Installing Dev Container Features¶
{
"name": "Feature-Rich Environment",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"version": "latest",
"moby": true
},
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {
"kubectl": "latest",
"helm": "latest",
"minikube": "none"
},
"ghcr.io/devcontainers/features/terraform:1": {
"version": "latest",
"tflint": "latest",
"terragrunt": "latest"
},
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
}
}
Common Feature Combinations¶
{
"name": "Python Data Science",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": true,
"configureZshAsDefaultShell": true
},
"ghcr.io/devcontainers/features/git:1": {
"ppa": true
},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.11"
},
"ghcr.io/rocker-org/devcontainer-features/quarto-cli:1": {}
}
}
{
"name": "Full Stack JavaScript",
"image": "mcr.microsoft.com/devcontainers/javascript-node:20",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers-contrib/features/pnpm:2": {},
"ghcr.io/devcontainers/features/azure-cli:1": {}
}
}
{
"name": "DevOps/Platform Engineering",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {},
"ghcr.io/devcontainers/features/terraform:1": {},
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/azure-cli:1": {},
"ghcr.io/devcontainers/features/python:1": {},
"ghcr.io/devcontainers/features/go:1": {}
}
}
VS Code Customizations¶
Extensions Configuration¶
{
"name": "Python Project",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"ms-python.black-formatter",
"charliermarsh.ruff",
"ms-python.debugpy",
"ms-toolsai.jupyter",
"tamasfe.even-better-toml",
"redhat.vscode-yaml",
"eamodio.gitlens",
"streetsidesoftware.code-spell-checker"
]
}
}
}
Settings Configuration¶
{
"name": "Python with Full Settings",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.black-formatter",
"charliermarsh.ruff"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.analysis.typeCheckingMode": "standard",
"python.analysis.autoImportCompletions": true,
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
"editor.rulers": [88, 100],
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true
}
}
}
}
TypeScript/Node.js Extensions¶
{
"name": "TypeScript Project",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss",
"prisma.prisma",
"orta.vscode-jest",
"yoavbls.pretty-ts-errors",
"christian-kohler.path-intellisense",
"streetsidesoftware.code-spell-checker"
],
"settings": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "explicit"
},
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.updateImportsOnFileMove.enabled": "always"
}
}
}
}
Terraform/IaC Extensions¶
{
"name": "Infrastructure as Code",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/terraform:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"hashicorp.terraform",
"hashicorp.hcl",
"redhat.vscode-yaml",
"timonwong.shellcheck",
"foxundermoon.shell-format",
"ms-azuretools.vscode-docker",
"ms-kubernetes-tools.vscode-kubernetes-tools"
],
"settings": {
"terraform.languageServer.enable": true,
"terraform.experimentalFeatures.validateOnSave": true,
"[terraform]": {
"editor.defaultFormatter": "hashicorp.terraform",
"editor.formatOnSave": true
},
"[terraform-vars]": {
"editor.defaultFormatter": "hashicorp.terraform",
"editor.formatOnSave": true
}
}
}
}
}
Port Forwarding¶
Basic Port Configuration¶
{
"name": "Web Application",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"forwardPorts": [3000, 5000, 8000, 5432],
"portsAttributes": {
"3000": {
"label": "Frontend",
"onAutoForward": "notify"
},
"5000": {
"label": "API Server",
"onAutoForward": "openBrowser"
},
"8000": {
"label": "Django",
"onAutoForward": "silent"
},
"5432": {
"label": "PostgreSQL",
"onAutoForward": "ignore"
}
}
}
Advanced Port Attributes¶
{
"name": "Full Stack Application",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"forwardPorts": [3000, 3001, 5432, 6379, 9000],
"portsAttributes": {
"3000": {
"label": "Next.js Frontend",
"onAutoForward": "openBrowser",
"protocol": "http",
"requireLocalPort": false
},
"3001": {
"label": "API Server",
"onAutoForward": "notify",
"protocol": "http"
},
"5432": {
"label": "PostgreSQL",
"onAutoForward": "ignore",
"requireLocalPort": true
},
"6379": {
"label": "Redis",
"onAutoForward": "ignore"
},
"9000": {
"label": "MinIO S3",
"onAutoForward": "silent",
"protocol": "http"
}
},
"otherPortsAttributes": {
"onAutoForward": "notify"
}
}
Lifecycle Scripts¶
Post-Create Command¶
{
"name": "Python Project",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"postCreateCommand": "pip install -r requirements.txt && pre-commit install"
}
Multiple Lifecycle Commands¶
{
"name": "Full Lifecycle Configuration",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"initializeCommand": "echo 'Initializing on host machine...'",
"onCreateCommand": "echo 'Container created for first time'",
"updateContentCommand": "pip install -e .[dev]",
"postCreateCommand": {
"install-deps": "pip install -r requirements.txt",
"setup-pre-commit": "pre-commit install",
"setup-db": "python manage.py migrate"
},
"postStartCommand": "echo 'Container started - ready for development!'",
"postAttachCommand": "git fetch --all"
}
External Script Reference¶
{
"name": "Script-Based Setup",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"postCreateCommand": "bash .devcontainer/scripts/setup-dev.sh",
"postStartCommand": "bash .devcontainer/scripts/on-start.sh"
}
#!/bin/bash
# .devcontainer/scripts/setup-dev.sh
set -e
echo "Installing Python dependencies..."
pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
echo "Setting up pre-commit hooks..."
pre-commit install
pre-commit install --hook-type commit-msg
echo "Initializing database..."
python manage.py migrate
python manage.py loaddata fixtures/dev_data.json
echo "Development environment ready!"
#!/bin/bash
# .devcontainer/scripts/on-start.sh
set -e
echo "Pulling latest changes..."
git fetch --all --prune
echo "Checking for dependency updates..."
pip check || echo "Warning: Some dependencies have issues"
echo "Container started at $(date)"
Custom Dockerfile¶
Using a Custom Dockerfile¶
{
"name": "Custom Image Project",
"build": {
"dockerfile": "Dockerfile",
"context": "..",
"args": {
"PYTHON_VERSION": "3.11",
"NODE_VERSION": "20"
}
},
"customizations": {
"vscode": {
"extensions": ["ms-python.python"]
}
}
}
# .devcontainer/Dockerfile
ARG PYTHON_VERSION=3.11
FROM mcr.microsoft.com/devcontainers/python:${PYTHON_VERSION}
ARG NODE_VERSION=20
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g pnpm
# Install additional tools
RUN apt-get update && apt-get install -y --no-install-recommends \
postgresql-client \
redis-tools \
&& rm -rf /var/lib/apt/lists/*
# Install Python packages globally
COPY requirements-dev.txt /tmp/
RUN pip install --no-cache-dir -r /tmp/requirements-dev.txt
# Create workspace directory
WORKDIR /workspace
# Set up shell customizations
COPY .devcontainer/shell-config.sh /home/vscode/.shell-config.sh
RUN echo 'source ~/.shell-config.sh' >> /home/vscode/.bashrc
USER vscode
Multi-Stage Dev Container Build¶
# .devcontainer/Dockerfile
# Build stage for compiled dependencies
FROM python:3.11-slim AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt
# Development stage
FROM mcr.microsoft.com/devcontainers/python:3.11
# Copy pre-built wheels
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels
# Install development tools
RUN pip install --no-cache-dir \
pytest \
pytest-cov \
black \
ruff \
mypy \
pre-commit
USER vscode
WORKDIR /workspace
Multi-Container Environments¶
Docker Compose Configuration¶
{
"name": "Full Stack with Services",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"shutdownAction": "stopCompose",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-azuretools.vscode-docker"
]
}
},
"forwardPorts": [8000, 5432, 6379]
}
# .devcontainer/docker-compose.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ../..:/workspace:cached
- ~/.ssh:/home/vscode/.ssh:ro
- ~/.gitconfig:/home/vscode/.gitconfig:ro
command: sleep infinity
environment:
DATABASE_URL: postgresql://postgres:postgres@db:5432/devdb
REDIS_URL: redis://redis:6379/0
depends_on:
- db
- redis
db:
image: postgres:15-alpine
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
- ./init-db.sql:/docker-entrypoint-initdb.d/init.sql:ro
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: devdb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
mailhog:
image: mailhog/mailhog:latest
ports:
- "8025:8025"
volumes:
postgres-data:
redis-data:
-- .devcontainer/init-db.sql
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- Create test user
CREATE USER testuser WITH PASSWORD 'testpass';
GRANT ALL PRIVILEGES ON DATABASE devdb TO testuser;
Full Stack Application Example¶
{
"name": "Next.js + FastAPI Full Stack",
"dockerComposeFile": "docker-compose.yml",
"service": "workspace",
"workspaceFolder": "/workspace",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"prisma.prisma",
"ms-azuretools.vscode-docker"
],
"settings": {
"python.defaultInterpreterPath": "/workspace/backend/.venv/bin/python"
}
}
},
"forwardPorts": [3000, 8000, 5432, 6379, 9000],
"portsAttributes": {
"3000": {"label": "Next.js Frontend"},
"8000": {"label": "FastAPI Backend"},
"5432": {"label": "PostgreSQL", "onAutoForward": "ignore"},
"6379": {"label": "Redis", "onAutoForward": "ignore"},
"9000": {"label": "MinIO S3", "onAutoForward": "silent"}
},
"postCreateCommand": "bash .devcontainer/scripts/setup-workspace.sh"
}
# .devcontainer/docker-compose.yml
version: '3.8'
services:
workspace:
build:
context: .
dockerfile: Dockerfile
volumes:
- ../..:/workspace:cached
- node-modules:/workspace/frontend/node_modules
- venv:/workspace/backend/.venv
command: sleep infinity
environment:
DATABASE_URL: postgresql://postgres:postgres@db:5432/app
REDIS_URL: redis://redis:6379/0
S3_ENDPOINT: http://minio:9000
S3_ACCESS_KEY: minioadmin
S3_SECRET_KEY: minioadmin
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
db:
image: postgres:15-alpine
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: app
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 10
minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
volumes:
- minio-data:/data
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
volumes:
postgres-data:
redis-data:
minio-data:
node-modules:
venv:
GitHub Codespaces¶
Basic Codespaces Configuration¶
{
"name": "GitHub Codespaces Environment",
"image": "mcr.microsoft.com/devcontainers/universal:2",
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"hostRequirements": {
"cpus": 4,
"memory": "8gb",
"storage": "32gb"
},
"customizations": {
"vscode": {
"extensions": [
"github.copilot",
"github.copilot-chat",
"github.vscode-pull-request-github"
]
},
"codespaces": {
"openFiles": [
"README.md"
]
}
}
}
Codespaces with Secrets¶
{
"name": "Codespaces with AWS Access",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"secrets": {
"AWS_ACCESS_KEY_ID": {
"description": "AWS Access Key for development"
},
"AWS_SECRET_ACCESS_KEY": {
"description": "AWS Secret Key for development"
},
"AWS_DEFAULT_REGION": {
"description": "AWS Region (e.g., us-east-1)"
},
"DATABASE_URL": {
"description": "Database connection string"
}
},
"containerEnv": {
"AWS_DEFAULT_REGION": "${localEnv:AWS_DEFAULT_REGION:us-east-1}"
}
}
Prebuild Configuration¶
{
"name": "Codespaces with Prebuild",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
}
},
"hostRequirements": {
"cpus": 4,
"memory": "8gb"
},
"waitFor": "onCreateCommand",
"updateContentCommand": "pip install -e .[dev] && npm install",
"postCreateCommand": "pre-commit install && npm run build",
"postStartCommand": "npm run dev",
"customizations": {
"codespaces": {
"prebuild": {
"enabled": true
},
"repositories": {
"my-org/shared-config": {
"permissions": "read"
}
}
}
}
}
Machine Type Recommendations¶
{
"name": "Small Project (2-core)",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"hostRequirements": {
"cpus": 2,
"memory": "4gb",
"storage": "32gb"
}
}
{
"name": "Standard Project (4-core)",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"hostRequirements": {
"cpus": 4,
"memory": "8gb",
"storage": "32gb"
}
}
{
"name": "Large Project (8-core)",
"image": "mcr.microsoft.com/devcontainers/universal:2",
"hostRequirements": {
"cpus": 8,
"memory": "16gb",
"storage": "64gb"
}
}
{
"name": "ML/Data Science (GPU)",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"hostRequirements": {
"cpus": 8,
"memory": "32gb",
"storage": "64gb",
"gpu": true
}
}
Environment Variables¶
Container Environment¶
{
"name": "Environment Configuration",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"containerEnv": {
"ENVIRONMENT": "development",
"DEBUG": "true",
"LOG_LEVEL": "debug",
"DATABASE_URL": "postgresql://postgres:postgres@db:5432/devdb",
"REDIS_URL": "redis://redis:6379/0"
},
"remoteEnv": {
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}",
"CONTAINER_WORKSPACE_FOLDER": "${containerWorkspaceFolder}"
}
}
Using .env Files¶
{
"name": "Environment File Project",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"runArgs": ["--env-file", ".devcontainer/.env"],
"postCreateCommand": "cp .env.example .env"
}
# .devcontainer/.env
ENVIRONMENT=development
DEBUG=true
LOG_LEVEL=debug
SECRET_KEY=dev-secret-key-not-for-production
# .env.example (committed to repository)
ENVIRONMENT=development
DEBUG=true
LOG_LEVEL=debug
SECRET_KEY=change-me-in-local-env
DATABASE_URL=postgresql://user:pass@localhost:5432/db
REDIS_URL=redis://localhost:6379/0
Volume Mounts¶
Standard Mounts¶
{
"name": "Project with Mounts",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"mounts": [
"source=${localWorkspaceFolder}/.aws,target=/home/vscode/.aws,type=bind,readonly",
"source=${localWorkspaceFolder}/.ssh,target=/home/vscode/.ssh,type=bind,readonly",
"source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,readonly"
]
}
Named Volumes for Performance¶
{
"name": "Project with Named Volumes",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"mounts": [
"source=project-node-modules,target=${containerWorkspaceFolder}/node_modules,type=volume",
"source=project-pnpm-store,target=/home/vscode/.local/share/pnpm,type=volume"
],
"postCreateCommand": "pnpm install"
}
Docker Socket Mount¶
{
"name": "Docker-in-Docker Alternative",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
"postCreateCommand": "sudo chmod 666 /var/run/docker.sock"
}
Run Arguments¶
Common Run Arguments¶
{
"name": "Project with Run Args",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"runArgs": [
"--name", "my-dev-container",
"--hostname", "dev-machine",
"--privileged",
"--cap-add=SYS_PTRACE",
"--security-opt", "seccomp=unconfined"
]
}
Network Configuration¶
{
"name": "Custom Network",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"runArgs": [
"--network", "host"
]
}
{
"name": "Bridge Network with DNS",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"runArgs": [
"--dns", "8.8.8.8",
"--dns", "8.8.4.4"
]
}
Language-Specific Configurations¶
Python Data Science¶
{
"name": "Python Data Science",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": true,
"configureZshAsDefaultShell": true
}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"ms-toolsai.jupyter",
"ms-toolsai.jupyter-keymap",
"ms-toolsai.jupyter-renderers",
"ms-toolsai.vscode-jupyter-cell-tags",
"mechatroner.rainbow-csv",
"GrapeCity.gc-excelviewer"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.analysis.typeCheckingMode": "basic",
"jupyter.askForKernelRestart": false,
"notebook.cellToolbarLocation": {
"default": "right",
"jupyter-notebook": "left"
}
}
}
},
"postCreateCommand": "pip install --upgrade pip && pip install -r requirements.txt",
"forwardPorts": [8888],
"portsAttributes": {
"8888": {
"label": "Jupyter Lab",
"onAutoForward": "openBrowser"
}
}
}
Go Microservices¶
{
"name": "Go Microservices",
"image": "mcr.microsoft.com/devcontainers/go:1.21",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"golang.go",
"zxh404.vscode-proto3",
"ms-azuretools.vscode-docker",
"ms-kubernetes-tools.vscode-kubernetes-tools",
"redhat.vscode-yaml"
],
"settings": {
"go.toolsManagement.autoUpdate": true,
"go.useLanguageServer": true,
"go.lintTool": "golangci-lint",
"go.lintFlags": ["--fast"],
"[go]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
"gopls": {
"usePlaceholders": true,
"staticcheck": true
}
}
}
},
"postCreateCommand": "go mod download && go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest",
"forwardPorts": [8080, 9090],
"portsAttributes": {
"8080": {"label": "HTTP API"},
"9090": {"label": "gRPC"}
}
}
Rust Development¶
{
"name": "Rust Development",
"image": "mcr.microsoft.com/devcontainers/rust:1",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"customizations": {
"vscode": {
"extensions": [
"rust-lang.rust-analyzer",
"tamasfe.even-better-toml",
"serayuzgur.crates",
"vadimcn.vscode-lldb",
"fill-labs.dependi"
],
"settings": {
"rust-analyzer.checkOnSave.command": "clippy",
"rust-analyzer.cargo.features": "all",
"[rust]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "rust-lang.rust-analyzer"
}
}
}
},
"postCreateCommand": "rustup component add clippy rustfmt && cargo fetch",
"forwardPorts": [8080]
}
Java/Spring Boot¶
{
"name": "Java Spring Boot",
"image": "mcr.microsoft.com/devcontainers/java:17",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/java:1": {
"version": "17",
"installMaven": true,
"installGradle": true
}
},
"customizations": {
"vscode": {
"extensions": [
"vscjava.vscode-java-pack",
"vmware.vscode-boot-dev-pack",
"vscjava.vscode-gradle",
"redhat.vscode-xml",
"ms-azuretools.vscode-docker"
],
"settings": {
"java.server.launchMode": "Standard",
"java.configuration.updateBuildConfiguration": "automatic",
"spring-boot.ls.java.home": "/usr/local/sdkman/candidates/java/current"
}
}
},
"postCreateCommand": "./mvnw dependency:go-offline",
"forwardPorts": [8080, 5005],
"portsAttributes": {
"8080": {"label": "Spring Boot App"},
"5005": {"label": "Debug Port", "onAutoForward": "ignore"}
}
}
Testing Dev Containers¶
Container Structure Tests¶
# tests/devcontainer-test.yaml
schemaVersion: 2.0.0
commandTests:
- name: "Python is installed"
command: "python"
args: ["--version"]
expectedOutput: ["Python 3.11"]
- name: "pip is available"
command: "pip"
args: ["--version"]
exitCode: 0
- name: "Git is installed"
command: "git"
args: ["--version"]
exitCode: 0
- name: "Required packages installed"
command: "pip"
args: ["list"]
expectedOutput: ["pytest", "black", "ruff"]
fileExistenceTests:
- name: "Workspace directory exists"
path: "/workspace"
shouldExist: true
- name: "VS Code extensions directory"
path: "/home/vscode/.vscode-server"
shouldExist: true
metadataTest:
user: "vscode"
workdir: "/workspace"
Automated Testing Script¶
#!/bin/bash
# .devcontainer/test-container.sh
set -e
echo "Testing Dev Container configuration..."
# Test Python installation
echo "Checking Python..."
python --version
pip --version
# Test required packages
echo "Checking required packages..."
python -c "import pytest; print(f'pytest {pytest.__version__}')"
python -c "import black; print(f'black installed')"
# Test VS Code extensions (if applicable)
echo "Checking VS Code extensions..."
if command -v code &> /dev/null; then
code --list-extensions | grep -E "ms-python|charliermarsh"
fi
# Test database connectivity
echo "Checking database connectivity..."
if [ -n "$DATABASE_URL" ]; then
python -c "
import psycopg2
from urllib.parse import urlparse
url = urlparse('$DATABASE_URL')
conn = psycopg2.connect(
host=url.hostname,
port=url.port,
user=url.username,
password=url.password,
database=url.path[1:]
)
print('Database connection successful')
conn.close()
"
fi
echo "All tests passed!"
CI/CD Integration¶
# .github/workflows/devcontainer-test.yml
name: Dev Container CI
on:
push:
paths:
- '.devcontainer/**'
pull_request:
paths:
- '.devcontainer/**'
jobs:
test-devcontainer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Install Dev Container CLI
run: npm install -g @devcontainers/cli
- name: Build Dev Container
run: devcontainer build --workspace-folder .
- name: Test Dev Container
run: |
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . python --version
devcontainer exec --workspace-folder . pip list
devcontainer exec --workspace-folder . bash .devcontainer/test-container.sh
- name: Validate devcontainer.json
run: |
devcontainer read-configuration --workspace-folder . \
--include-features-configuration \
--output json
Security Best Practices¶
Secure Configuration¶
{
"name": "Security-Hardened Environment",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"remoteUser": "vscode",
"containerUser": "vscode",
"updateRemoteUserUID": true,
"runArgs": [
"--security-opt", "no-new-privileges:true",
"--cap-drop", "ALL",
"--cap-add", "NET_BIND_SERVICE"
],
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"postCreateCommand": "git config --global init.defaultBranch main"
}
Secret Management¶
{
"name": "Secrets Best Practices",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"secrets": {
"API_KEY": {
"description": "API key for external service"
},
"DATABASE_PASSWORD": {
"description": "Database password"
}
},
"mounts": [
"source=${localEnv:HOME}/.aws,target=/home/vscode/.aws,type=bind,readonly"
],
"containerEnv": {
"ENVIRONMENT": "development"
}
}
{
"name": "No Hardcoded Secrets",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"containerEnv": {
"API_KEY": "sk_live_abc123xyz"
}
}
Non-Root User Configuration¶
{
"name": "Non-Root Development",
"build": {
"dockerfile": "Dockerfile",
"args": {
"USER_UID": "1000",
"USER_GID": "1000"
}
},
"remoteUser": "vscode",
"containerUser": "vscode",
"updateRemoteUserUID": true
}
# .devcontainer/Dockerfile
FROM mcr.microsoft.com/devcontainers/python:3.11
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Update vscode user UID/GID if needed
RUN if [ "$USER_GID" != "1000" ]; then \
groupmod --gid $USER_GID vscode; \
fi && \
if [ "$USER_UID" != "1000" ]; then \
usermod --uid $USER_UID --gid $USER_GID vscode; \
fi
USER vscode
WORKDIR /workspace
Performance Optimization¶
Caching Dependencies¶
{
"name": "Optimized Caching",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"mounts": [
"source=project-node-modules,target=${containerWorkspaceFolder}/node_modules,type=volume",
"source=pnpm-store,target=/home/vscode/.local/share/pnpm,type=volume",
"source=pip-cache,target=/home/vscode/.cache/pip,type=volume"
],
"postCreateCommand": "pnpm install --frozen-lockfile"
}
Prebuild Scripts¶
{
"name": "Prebuild Optimized",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"waitFor": "onCreateCommand",
"onCreateCommand": "pip install --no-cache-dir -r requirements.txt",
"updateContentCommand": "pip install --no-cache-dir -r requirements.txt",
"postCreateCommand": "pip install -e .[dev]",
"postStartCommand": "echo 'Ready for development'"
}
Minimal Feature Installation¶
{
"name": "Minimal Features",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/git:1": {}
}
}
{
"name": "Heavy Features",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {},
"ghcr.io/devcontainers/features/terraform:1": {},
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/azure-cli:1": {},
"ghcr.io/devcontainers/features/gcloud:1": {},
"ghcr.io/devcontainers/features/python:1": {},
"ghcr.io/devcontainers/features/node:1": {},
"ghcr.io/devcontainers/features/go:1": {},
"ghcr.io/devcontainers/features/rust:1": {}
}
}
Common Pitfalls¶
Missing Workspace Folder Configuration¶
Issue: Container starts but VS Code opens an empty or wrong directory.
{
"name": "Missing workspaceFolder",
"dockerComposeFile": "docker-compose.yml",
"service": "app"
}
{
"name": "Correct workspaceFolder",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace"
}
Incorrect Volume Mounts¶
Issue: Changes not persisting or wrong permissions.
{
"name": "Wrong Volume Mount",
"mounts": [
"source=./local-dir,target=/container-dir,type=bind"
]
}
{
"name": "Correct Volume Mount",
"mounts": [
"source=${localWorkspaceFolder}/local-dir,target=/container-dir,type=bind"
]
}
Feature Ordering Issues¶
Issue: Features failing due to dependencies.
{
"name": "Wrong Feature Order",
"features": {
"ghcr.io/devcontainers/features/python:1": {},
"ghcr.io/devcontainers/features/common-utils:2": {}
}
}
{
"name": "Correct Feature Order",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {},
"ghcr.io/devcontainers/features/python:1": {}
}
}
Lifecycle Command Errors¶
Issue: Commands failing silently or blocking container startup.
{
"name": "Blocking Command",
"postCreateCommand": "npm run dev"
}
{
"name": "Non-blocking Commands",
"postCreateCommand": "npm install",
"postStartCommand": "npm run dev &"
}
Anti-Patterns¶
Using Latest Tags¶
{
"name": "Unpredictable Image",
"image": "mcr.microsoft.com/devcontainers/python:latest"
}
{
"name": "Pinned Image",
"image": "mcr.microsoft.com/devcontainers/python:1.1.3-3.11-bookworm"
}
Hardcoded Secrets¶
{
"name": "Exposed Secrets",
"containerEnv": {
"DATABASE_PASSWORD": "super-secret-password",
"API_KEY": "sk_live_12345"
}
}
{
"name": "Secure Secrets",
"secrets": {
"DATABASE_PASSWORD": {
"description": "Database password"
},
"API_KEY": {
"description": "API key"
}
}
}
Monolithic Configurations¶
{
"name": "Everything Installed",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/python:1": {},
"ghcr.io/devcontainers/features/node:1": {},
"ghcr.io/devcontainers/features/go:1": {},
"ghcr.io/devcontainers/features/rust:1": {},
"ghcr.io/devcontainers/features/java:1": {},
"ghcr.io/devcontainers/features/dotnet:1": {},
"ghcr.io/devcontainers/features/ruby:1": {},
"ghcr.io/devcontainers/features/php:1": {}
}
}
{
"name": "Python Project Only",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/git:1": {}
}
}
Missing Remote User¶
{
"name": "Running as Root",
"image": "mcr.microsoft.com/devcontainers/python:3.11"
}
{
"name": "Non-Root User",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"remoteUser": "vscode"
}
Over-Permissive Run Arguments¶
{
"name": "Too Permissive",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"runArgs": [
"--privileged",
"--cap-add=ALL"
]
}
{
"name": "Minimal Permissions",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"runArgs": [
"--cap-add=SYS_PTRACE"
]
}
IDE Integration¶
JetBrains Gateway¶
{
"name": "JetBrains Compatible",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"customizations": {
"jetbrains": {
"plugins": [
"com.intellij.plugins.vscodekeymap"
]
},
"vscode": {
"extensions": [
"ms-python.python"
]
}
},
"forwardPorts": [8000],
"remoteUser": "vscode"
}
Multi-IDE Support¶
{
"name": "Multi-IDE Development",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.black-formatter"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python"
}
},
"jetbrains": {
"backend": "PyCharm"
},
"codespaces": {
"openFiles": ["README.md", "src/main.py"]
}
}
}
Template Repository Configuration¶
Organization Default¶
{
"name": "${localWorkspaceFolderBasename}",
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.black-formatter",
"charliermarsh.ruff",
"eamodio.gitlens",
"streetsidesoftware.code-spell-checker"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true
}
}
}
},
"postCreateCommand": "pip install -r requirements.txt 2>/dev/null || true",
"remoteUser": "vscode"
}
Starter Template¶
{
"$schema": "https://raw.githubusercontent.com/devcontainers/spec/main/schemas/devContainer.schema.json",
"name": "Project Template",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {},
"customizations": {
"vscode": {
"extensions": [],
"settings": {}
}
},
"forwardPorts": [],
"postCreateCommand": "",
"remoteUser": "vscode"
}
References¶
Official Documentation¶
Tools¶
Related Guides¶
Status: Active