Mastery dei Dev Container in VS Code

Crea ambienti di sviluppo coerenti, portabili e riproducibili utilizzando i Dev Containers

Indice

Gli sviluppatori spesso si trovano di fronte al dilemma “funziona sul mio computer” a causa di incompatibilità delle dipendenze, versioni degli strumenti o differenze tra i sistemi operativi.
Dev Containers in Visual Studio Code (VS Code) risolvono questo problema in modo elegante — permettendo di sviluppare all’interno di un ambiente containerizzato configurato specificamente per il proprio progetto.

Lo sviluppo software moderno richiede ambienti coerenti e riproducibili che funzionino su diversi computer e sistemi operativi. Che si stia lavorando su un progetto di data science in Python, un’applicazione web in Node.js o un microservizio in Go, garantire che ogni membro del team abbia un’identica configurazione di sviluppo può essere un compito complesso.

vs code dev containers

Questo completo guida illustra cos’è un Dev Container, perché sono utili e come configurarli in VS Code per flussi di lavoro di sviluppo portabili e fluidi. Imparerai tutto, dall’installazione base alle configurazioni avanzate con Docker Compose e alle migliori pratiche per la collaborazione in team.


🧩 Cosa sono i Dev Containers?

I Dev Containers sono una funzionalità fornita dall’estensione VS Code Remote - Containers (ora parte di VS Code Remote Development).
Permettono di aprire il progetto in un container Docker preconfigurato con tutte le dipendenze, le lingue e gli strumenti necessari.

Pensaci come:

“Un ambiente di sviluppo completamente configurato, definito come codice.”

Invece di installare Python, Node.js, database e vari strumenti direttamente sul tuo computer, li definisci in file di configurazione. Quando apri il progetto in VS Code, automaticamente viene avviato un container con tutto preinstallato e configurato esattamente come specificato.

Una configurazione di Dev Container include tipicamente:

  • Un Dockerfile o un riferimento a un’immagine base (definendo il sistema operativo, le lingue e gli strumenti del container)
  • Un file devcontainer.json (configurando le impostazioni del workspace, le estensioni di VS Code, il forwarding delle porte, le variabili d’ambiente e i comandi di avvio)
  • Opzionalmente un docker-compose.yml se il progetto dipende da più servizi (come database, Redis, code di messaggistica, ecc.)

⚙️ Perché utilizzare i Dev Containers?

Ecco perché sono potenti:

  • Riproducibilità: Ogni sviluppatore e ogni sistema CI utilizza lo stesso ambiente. Non più problemi come “funziona sul mio computer ma non su quello tuo”. Ciò che funziona sul tuo laptop funzionerà in modo identico sul computer del tuo collega, su un Mac, su un Windows o su un workstation Linux.

  • Isolamento: Non è necessario inquinare il tuo computer locale con dipendenze conflittuali. Lavora su diversi progetti che richiedono versioni diverse di Python, Node.js o altri strumenti senza conflitti di versione o gestione di ambienti virtuali.

  • Portabilità: Funziona su qualsiasi sistema operativo che supporta Docker. Il tuo ambiente di sviluppo viaggia con il tuo codice. Clona un repository, aprilo in VS Code e sarai pronto a codificare in pochi minuti — indipendentemente dal sistema operativo.

  • Coerenza del team: Una configurazione condivisa per l’intero team. I nuovi membri del team possono iniziare a lavorare in pochi minuti invece di spendere ore (o giorni) per configurare l’ambiente di sviluppo con gli strumenti e le versioni corrette.

  • Automazione: Installa automaticamente le estensioni di VS Code, le dipendenze linguistiche e gli strumenti quando apri il progetto. I comandi post-creazione possono eseguire migrazioni del database, popolare dati o eseguire altre attività di configurazione senza intervento manuale.

  • Sicurezza: Isolare le dipendenze potenzialmente rischiose nei container. Se devi testare con una versione più vecchia e vulnerabile di una libreria, rimane contenuta e non influisce sul sistema host.

Esempio reale: Immagina di unirti a un team che lavora su un progetto di microservizi che utilizza Python 3.11, PostgreSQL 15, Redis e Elasticsearch. Senza Dev Containers, spendiresti ore per installare e configurare ogni componente. Con Dev Containers, apri il progetto in VS Code, lascia che costruisca il container e sarai pronto a scrivere codice in 5-10 minuti.


🧱 Configurare un Dev Container in VS Code

Andiamo passo passo.

1. Installare gli strumenti necessari

Prima di iniziare, assicurati di aver installato i seguenti strumenti:

  • Docker Desktop (o un runtime container equivalente come Podman)

    • Per Windows/Mac: Scarica e installa Docker Desktop
    • Per Linux: Installa Docker Engine e assicurati che l’utente sia nel gruppo docker
  • VS Code (versione più recente consigliata)

  • L’estensione Dev Containers (di Microsoft)

    • Apri VS Code
    • Vai alle Estensioni (Ctrl+Shift+X o Cmd+Shift+X su macOS)
    • Cerca “Dev Containers”
    • Installa l’estensione con ID: ms-vscode-remote.remote-containers

Verifica la tua configurazione:

# Verifica che Docker sia in esecuzione
docker --version
docker ps

# Dovrebbe visualizzare la versione di Docker e i container in esecuzione (se presenti)

2. Inizializzare il Dev Container

Apri la cartella del progetto in VS Code e apri il Palette dei comandi (Ctrl+Shift+P o Cmd+Shift+P su macOS), quindi digita e seleziona:

Dev Containers: Add Dev Container Configuration Files...

VS Code ti presenterà un elenco di modelli di ambiente predefiniti. Scegli quello che corrisponde al tuo progetto:

  • Node.js — Progetti JavaScript/TypeScript
  • Python — Applicazioni di data science, web e script
  • Go — Applicazioni e servizi in Go
  • .NET — Applicazioni in C#/F#
  • Java — Progetti Spring Boot, Maven, Gradle
  • Docker-in-Docker — Quando hai bisogno di Docker all’interno del container
  • E molti altri…

Puoi anche selezionare funzionalità aggiuntive come:

  • Utilità comuni (git, curl, wget)
  • Client per database
  • Strumenti CLI per il cloud (AWS, Azure, GCP)

Questo wizard crea una cartella .devcontainer con:

  • devcontainer.json — File di configurazione principale
  • Dockerfile — Definizione dell’immagine personalizzata (o un riferimento a un’immagine base pre-costruita)

3. Personalizzare devcontainer.json

Il file devcontainer.json è dove avviene la magia. Ecco un esempio ben documentato per un progetto Node.js:

{
  // Nome del container visualizzato in VS Code
  "name": "Node.js Development Container",
  
  // Configurazione di costruzione - puoi usare Dockerfile o un'immagine pre-costruita
  "build": {
    "dockerfile": "Dockerfile",
    "context": ".."
  },
  
  // Alternativa: usa un'immagine pre-costruita invece di Dockerfile
  // "image": "mcr.microsoft.com/devcontainers/javascript-node:18",
  
  // Configurazione del workspace
  "customizations": {
    "vscode": {
      // Impostazioni di VS Code applicabili nel container
      "settings": {
        "terminal.integrated.defaultProfile.linux": "bash",
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "esbenp.prettier-vscode"
      },
      
      // Estensioni da installare automaticamente
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "eamodio.gitlens",
        "ms-azuretools.vscode-docker"
      ]
    }
  },
  
  // Forwarding delle porte - rende disponibili le porte del container sull'host
  "forwardPorts": [3000, 5432],
  "portsAttributes": {
    "3000": {
      "label": "Application",
      "onAutoForward": "notify"
    }
  },
  
  // Comandi da eseguire a diversi stadi
  "postCreateCommand": "npm install",     // Dopo la creazione del container
  "postStartCommand": "npm run dev",      // Dopo l'avvio del container
  
  // Variabili d'ambiente
  "containerEnv": {
    "NODE_ENV": "development",
    "PORT": "3000"
  },
  
  // Esegui il container come utente non root (consigliato per la sicurezza)
  "remoteUser": "node",
  
  // Monta volumi aggiuntivi
  "mounts": [
    "source=${localEnv:HOME}/.ssh,target=/home/node/.ssh,readonly,type=bind"
  ]
}

Spiegazione delle opzioni di configurazione principali:

  • name — Nome visualizzato nella barra di stato di VS Code
  • build / image — Usa un Dockerfile o un’immagine pre-costruita
  • customizations.vscode.extensions — Estensioni di VS Code da installare automaticamente
  • forwardPorts — Porte da esporre dal container all’host
  • postCreateCommand — Esegue una volta quando il container viene creato per la prima volta (es. installa dipendenze)
  • postStartCommand — Esegue ogni volta che il container viene avviato
  • containerEnv — Variabili d’ambiente disponibili nel container
  • remoteUser — Account utente da utilizzare all’interno del container
  • mounts — File/cartelle aggiuntive da montare (es. chiavi SSH)

💡 Consigli professionali:

  • Usa postCreateCommand per operazioni lente (npm install, pip install)
  • Usa postStartCommand per compiti di avvio veloci (migrazioni del database)
  • Specifica sempre le estensioni necessarie per il tuo progetto — questo garantisce uno strumento coerente
  • Usa le variabili d’ambiente per la configurazione che varia tra gli sviluppatori

4. Costruisci e apri nel container

Una volta pronta la configurazione, è il momento di lanciare l’ambiente di sviluppo:

Apri la Palette dei comandi (Ctrl+Shift+P / Cmd+Shift+P) e esegui:

Dev Containers: Reopen in Container

Cosa succede successivamente:

  1. Costruzione dell’immagine — VS Code costruisce l’immagine Docker in base al tuo Dockerfile o carica un’immagine pre-costruita. Questo potrebbe richiedere alcuni minuti la prima volta.

  2. Creazione del container — Docker crea un nuovo container dall’immagine costruita.

  3. Montaggio dei volumi — La tua cartella del progetto viene montata nel container, rendendo accessibile il tuo codice all’interno.

  4. Installazione delle estensioni — Tutte le estensioni di VS Code specificate vengono installate automaticamente nel container.

  5. Comandi post-creazione — Il tuo postCreateCommand viene eseguito (es. npm install, pip install -r requirements.txt).

  6. Pronto! — VS Code si riconnette al container e ora stai sviluppando all’interno di esso.

Verifica che tu stia nel container:

Puoi confermare che stai lavorando all’interno del container aprendo un terminale e eseguendo:

# Verifica il sistema operativo
uname -a
# Output: Linux ... (kernel del container)

# Verifica l'hostname (solitamente l'ID del container)
hostname
# Output: abc123def456

# Verifica i processi in esecuzione
ps aux
# Vedrai i processi del container, non quelli del tuo sistema host

Noterai che la barra di stato di VS Code (in basso a sinistra) ora mostra: Dev Container: [Nome del tuo container]

Comandi del ciclo di vita del container:

  • Ricostruisci il containerDev Containers: Rebuild Container (quando modifichi il Dockerfile)
  • Ricostruisci senza cacheDev Containers: Rebuild Container Without Cache (per un build pulito)
  • Riapri localmenteDev Containers: Reopen Folder Locally (esci dal container, lavora sull’host)

5. Aggiungi servizi aggiuntivi (opzionale)

Le applicazioni reali dipendono spesso da database, strati di caching, code di messaggistica o altri servizi. Puoi utilizzare Docker Compose per orchestrare diversi container.

Esempio: Applicazione full-stack con Node.js, PostgreSQL e Redis

Crea un docker-compose.yml nella tua cartella .devcontainer:

version: "3.8"

services:
  # Container principale per lo sviluppo
  app:
    build: 
      context: ..
      dockerfile: .devcontainer/Dockerfile
    
    volumes:
      # Monta la cartella del progetto
      - ..:/workspace:cached
      # Usa un volume nominato per node_modules (migliore prestazione)
      - node_modules:/workspace/node_modules
    
    # Mantieni il container in esecuzione
    command: sleep infinity
    
    # Accesso di rete ad altri servizi
    depends_on:
      - db
      - redis
    
    environment:
      DATABASE_URL: postgresql://dev:secret@db:5432/appdb
      REDIS_URL: redis://redis:6379

  # Database 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:

Poi, aggiorna il tuo devcontainer.json per utilizzare Docker Compose:

{
  "name": "Full-stack Dev Environment",
  
  // Usa docker-compose invece di un singolo container
  "dockerComposeFile": "docker-compose.yml",
  
  // Quale servizio utilizzare come container di sviluppo
  "service": "app",
  
  // Percorso della cartella del workspace all'interno del container
  "workspaceFolder": "/workspace",
  
  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "ms-azuretools.vscode-docker",
        "ckolkman.vscode-postgres"  // Client PostgreSQL
      ]
    }
  },
  
  "forwardPorts": [3000, 5432, 6379],
  
  "postCreateCommand": "npm install && npm run db:migrate",
  
  "remoteUser": "node"
}

Cosa offre questa configurazione:

  • app — Il container di sviluppo con Node.js
  • db — Database PostgreSQL, accessibile a db:5432 dall’app
  • redis — Cache Redis, accessibile a redis:6379
  • Volumi nominati — Persistenza dei dati del database tra i riavvii del container
  • Forwarding delle porte — Accesso a tutti i servizi dalla macchina host

Connetti i servizi dal tuo codice:

// Nel tuo'applicazione Node.js
const { Pool } = require('pg');
const redis = require('redis');

// Connessione PostgreSQL
const pool = new Pool({
  connectionString: process.env.DATABASE_URL
  // Risolve a: postgresql://dev:secret@db:5432/appdb
});

// Connessione Redis
const redisClient = redis.createClient({
  url: process.env.REDIS_URL
  // Risolve a: redis://redis:6379
});

Accedi ai servizi dalla tua macchina host:

  • App: http://localhost:3000
  • PostgreSQL: localhost:5432 (utilizzando qualsiasi client PostgreSQL)
  • Redis: localhost:6379 (utilizzando redis-cli o strumenti GUI)

Ora, quando apri il progetto in VS Code, tutti i servizi vengono avviati automaticamente!


🧠 Consigli avanzati e buone pratiche

Utilizza immagini pre-costruite

Risparmia tempo significativo partendo dalle immagini ufficiali di Microsoft per devcontainer:

{
  "image": "mcr.microsoft.com/devcontainers/python:3.11",
  "features": {
    "ghcr.io/devcontainers/features/git:1": {},
    "ghcr.io/devcontainers/features/github-cli:1": {}
  }
}

Features sono script di installazione riutilizzabili per strumenti comuni (Git, GitHub CLI, Node, AWS CLI, ecc.).

Buone pratiche per il controllo versione

Commit sempre la tua cartella .devcontainer:

git add .devcontainer/
git commit -m "Aggiungi configurazione Dev Container"
git push

Questo garantisce:

  • ✅ I nuovi membri del team ottengono automaticamente l’ambiente
  • ✅ Le modifiche all’ambiente vengono tracciate e revisionate
  • ✅ Tutti sviluppano nello stesso setup

Consiglio professionale: Aggiungi una sezione README che spiega la configurazione del dev container:


## Configurazione dello sviluppo

Questo progetto utilizza VS Code Dev Containers. Per iniziare:

1. Installa Docker Desktop e VS Code
2. Installa l'estensione "Dev Containers"
3. Clona questo repository
4. Apri in VS Code
5. Clicca su "Reopen in Container" quando richiesto

Debugging nei container

Il debugging funziona senza problemi. Configura il tuo launch.json come di consueto:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch Node.js",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/index.js",
      "skipFiles": ["<node_internals>/**"]
    }
  ]
}

Imposta i punti di interruzione e debugga normalmente — VS Code gestisce automaticamente la connessione al container.

Parità con Continuous Integration

Utilizza la stessa immagine del container nel tuo pipeline CI/CD:

# Esempio 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

Questo garantisce parità tra sviluppo e produzione — se i test passano localmente, passeranno anche in CI.

Ottimizzazione delle prestazioni

Per gli utenti macOS/Windows — utilizza volumi nominati per le dipendenze:

{
  "mounts": [
    "source=myproject-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
  ]
}

Questo migliora significativamente le prestazioni di I/O per node_modules, venv, ecc.

Sviluppo multi-stage

Crea diverse configurazioni per diversi ruoli del team:

.devcontainer/
├── devcontainer.json          # Default (full-stack)
├── frontend/
│   └── devcontainer.json      # Solo frontend (più leggero)
└── backend/
    └── devcontainer.json      # Solo backend (con DB)

I membri del team possono scegliere l’ambiente quando aprono il progetto.

Lavorare con chiavi SSH e Git

Monta le tue chiavi SSH per le operazioni Git:

{
  "mounts": [
    "source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/node/.ssh,readonly,type=bind"
  ],
  "postCreateCommand": "ssh-add ~/.ssh/id_ed25519 || true"
}

File di ambiente personalizzati

Carica la configurazione specifica dell’ambiente:

{
  "runArgs": ["--env-file", ".devcontainer/.env"]
}

.devcontainer/.env:

API_KEY=dev_key_here
DEBUG=true
LOG_LEVEL=debug

🔧 Problemi comuni e risoluzione

Il container non si avvia

Errore: Non è possibile connettersi al demone Docker

Soluzione:

  • Assicurati che Docker Desktop sia in esecuzione
  • Su Linux, verifica: sudo systemctl status docker
  • Verifica che Docker sia nel tuo PATH: docker --version

Prestazioni lente su macOS/Windows

Problema: Le operazioni sui file sono lente

Soluzioni:

  1. Usa volumi nominati per node_modules, venv, ecc.

  2. Abilita il condivisione file in Docker Desktop

  3. Considera l’uso di opzioni di montaggio cached o delegated:

    "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached"
    

Estensioni non installate

Problema: Le estensioni specificate in devcontainer.json non vengono installate

Soluzioni:

  1. Ricostruisci il container: Dev Containers: Rebuild Container
  2. Verifica che gli ID delle estensioni siano corretti
  3. Assicurati che le estensioni supportino i container remoti (la maggior parte lo fa)

Porta già in uso

Errore: La porta 3000 è già allocata

Soluzioni:

  1. Ferma i container in conflitto: docker ps e docker stop <container>
  2. Modifica il mapping delle porte in forwardPorts
  3. Usa porte dinamiche: VS Code assegnerà automaticamente porte disponibili

Modifiche al Dockerfile non applicate

Problema: Dockerfile modificato ma le modifiche non vengono applicate

Soluzione: Ricostruisci senza cache:

Dev Containers: Rebuild Container Without Cache

Il container si ferma immediatamente

Problema: Il container si avvia e poi si ferma

Soluzione: Aggiungi un comando per mantenerlo in esecuzione in docker-compose.yml:

command: sleep infinity

O in devcontainer.json:

{
  "overrideCommand": true
}

✅ Conclusione

I Dev Containers in VS Code portano coerenza, semplicità e automazione al tuo flusso di lavoro di sviluppo. Trasformano configurazioni complesse e fragili in ambienti definiti come codice che funzionano, indipendentemente dal tuo computer o sistema operativo.

Punti chiave:

  • 🎯 Elimina i problemi “funziona sul mio computer” — Tutti utilizzano ambienti identici
  • 🚀 Onboarding più rapido — I nuovi membri del team produttivi in pochi minuti, non in giorni
  • 🔒 Migliore sicurezza — Isola le dipendenze dal sistema host
  • 📦 Portabilità — L’ambiente viaggia con il tuo codice
  • 🤝 Coerenza del team — Nessun conflitto di versione delle dipendenze
  • 🔄 Parità con CI/CD — Usa la stessa immagine in sviluppo e in integrazione continua

Che tu stia lavorando su un semplice script Python o su un’architettura complessa di microservizi con diversi database, i Dev Containers offrono una solida base per lo sviluppo moderno.

Se collabori su progetti multilingua, contribuisci a repository open source, onbordi frequentemente nuovi sviluppatori o semplicemente desideri ambienti di sviluppo puliti e riproducibili — i Dev Containers sono uno strumento essenziale nel tuo stack.

Inizia da piccolo: prova i Dev Containers sul tuo prossimo progetto. Una volta che avrai sperimentato i benefici, ti chiederai come hai mai sviluppato senza di loro.

📚 Risorse utili e articoli correlati

Documentazione ufficiale:

Articoli correlati su questo sito: