Mestre os contêineres de desenvolvimento no VS Code

Crie ambientes de desenvolvimento consistentes, portáveis e reprodutíveis usando Dev Containers.

Conteúdo da página

Os desenvolvedores frequentemente enfrentam o dilema “funciona no meu computador” devido a incompatibilidades de dependências, versões de ferramentas ou diferenças no sistema operacional.
Contêineres de Desenvolvimento no Visual Studio Code (VS Code) resolvem isso de forma elegante — permitindo que você desenvolva dentro de um ambiente contêinerizado configurado especificamente para seu projeto.

O desenvolvimento de software moderno exige ambientes consistentes e reprodutíveis que funcionem em diferentes máquinas e sistemas operacionais. Seja você trabalhando em um projeto de ciência de dados com Python, uma aplicação web com Node.js ou um microserviço com Go, garantir que cada membro da equipe tenha uma configuração de desenvolvimento idêntica pode ser desafiador.

vs code dev containers

Este guia abrangente passa por tudo sobre os Contêineres de Desenvolvimento, por que eles são valiosos e como configurá-los no VS Code para fluxos de trabalho de desenvolvimento portáveis e suaves. Você aprenderá desde a configuração básica até configurações avançadas com Docker Compose e práticas recomendadas para colaboração em equipe.


🧩 O que são Contêineres de Desenvolvimento?

Contêineres de Desenvolvimento são uma funcionalidade fornecida pela extensão VS Code Remote - Containers (agora parte do VS Code Remote Development).
Eles permitem que você abra seu projeto em um contêiner Docker que está pré-configurado com todas as suas dependências, linguagens e ferramentas.

Pense nisso como:

“Um ambiente de desenvolvimento totalmente configurado, definido como código.”

Em vez de instalar Python, Node.js, bancos de dados e várias ferramentas diretamente em sua máquina, você define-as em arquivos de configuração. Quando você abre o projeto no VS Code, ele automaticamente inicia um contêiner com tudo pré-instalado e configurado exatamente como especificado.

Uma configuração de Contêiner de Desenvolvimento geralmente inclui:

  • Um Dockerfile ou referência a uma imagem base (definindo o sistema operacional, linguagens e ferramentas do contêiner)
  • Um arquivo devcontainer.json (configurando configurações do workspace, extensões do VS Code, encaminhamento de portas, variáveis de ambiente e comandos de inicialização)
  • docker-compose.yml opcional, se seu projeto depender de múltiplos serviços (como bancos de dados, Redis, filas de mensagens, etc.)

⚙️ Por que usar Contêineres de Desenvolvimento?

Aqui está o que os torna poderosos:

  • Reprodutibilidade: Cada desenvolvedor e sistema CI usa o mesmo ambiente exatamente. Não mais problemas como “funciona no meu computador, mas não no seu”. O que funciona no seu laptop funcionará exatamente da mesma forma no computador do seu colega, no Windows, Mac ou no Linux.
  • Isolamento: Não é necessário poluir sua máquina local com dependências conflitantes. Trabalhe em múltiplos projetos que exigem versões diferentes de Python, Node.js ou outras ferramentas sem conflitos de versão ou manipulação de ambientes virtuais.
  • Portabilidade: Funciona em qualquer OS que suporte Docker. Seu ambiente de desenvolvimento viaja com seu código. Clone um repositório, abra-o no VS Code e você estará pronto para codificar em minutos — independentemente do seu sistema operacional.
  • Consistência em equipe: Uma configuração compartilhada por toda a sua equipe. Novos membros da equipe podem estar operacionais em minutos, em vez de passar horas (ou dias) configurando seu ambiente de desenvolvimento com as ferramentas e versões certas.
  • Automação: Instala automaticamente extensões do VS Code, dependências de linguagem e ferramentas ao abrir o projeto. Comandos pós-criação podem executar migrações de banco de dados, semente de dados ou outras tarefas de configuração sem intervenção manual.
  • Segurança: Isolam dependências potencialmente arriscadas em contêineres. Se você precisar testar com uma versão mais antiga e vulnerável de uma biblioteca, ela permanece contida e não afeta seu sistema anfitrião.

Exemplo real: Imagine se juntar a uma equipe trabalhando em um projeto de microserviços que usa Python 3.11, PostgreSQL 15, Redis e Elasticsearch. Sem Contêineres de Desenvolvimento, você passaria horas instalando e configurando cada componente. Com Contêineres de Desenvolvimento, você abre o projeto no VS Code, deixa-o construir o contêiner e você está escrevendo código dentro de 5 a 10 minutos.


🧱 Configurando um Contêiner de Desenvolvimento no VS Code

Vamos passo a passo.

1. Instale as ferramentas necessárias

Antes de começar, certifique-se de ter instalado o seguinte:

  • Docker Desktop (ou um runtime de contêiner equivalente como Podman)

    • Para Windows/Mac: Faça o download e instale o Docker Desktop
    • Para Linux: Instale o Docker Engine e certifique-se de que seu usuário está no grupo docker
  • VS Code (versão mais recente recomendada)

  • A extensão Dev Containers (por Microsoft)

    • Abra o VS Code
    • Vá para Extensões (Ctrl+Shift+X ou Cmd+Shift+X no macOS)
    • Procure por “Dev Containers”
    • Instale a extensão com ID: ms-vscode-remote.remote-containers

Verifique sua configuração:

# Verifique se o Docker está em execução
docker --version
docker ps

# Deve exibir a versão do Docker e os contêineres em execução (se houver)

2. Inicialize o Contêiner de Desenvolvimento

Abra a pasta do seu projeto no VS Code e abra o Palette de Comandos (Ctrl+Shift+P ou Cmd+Shift+P no macOS), depois digite e selecione:

Dev Containers: Adicionar Arquivos de Configuração de Contêiner de Desenvolvimento...

O VS Code apresentará uma lista de modelos de ambiente pré-definidos. Escolha o que corresponde ao seu projeto:

  • Node.js — Projetos JavaScript/TypeScript
  • Python — Ciência de dados, aplicações web, scripts
  • Go — Aplicações e serviços Go
  • .NET — Aplicações C#/F#
  • Java — Projetos Spring Boot, Maven, Gradle
  • Docker-in-Docker — Quando você precisa de Docker dentro do seu contêiner
  • E muitos outros…

Você também pode selecionar recursos adicionais, como:

  • Utilitários comuns (git, curl, wget)
  • Clientes de banco de dados
  • Ferramentas de CLI de nuvem (AWS, Azure, GCP)

Este assistente cria uma pasta .devcontainer com:

  • devcontainer.json — Arquivo de configuração principal
  • Dockerfile — Definição de imagem personalizada (ou referência a uma imagem base pré-construída)

3. Personalize devcontainer.json

O arquivo devcontainer.json é onde a mágica acontece. Aqui está um exemplo bem documentado para um projeto Node.js:

{
  // Nome de exibição do contêiner no VS Code
  "name": "Node.js Development Container",
  
  // Configuração de construção - pode usar Dockerfile ou imagem pré-construída
  "build": {
    "dockerfile": "Dockerfile",
    "context": ".."
  },
  
  // Alternativa: use uma imagem pré-construída em vez de Dockerfile
  // "image": "mcr.microsoft.com/devcontainers/javascript-node:18",
  
  // Configuração do workspace
  "customizations": {
    "vscode": {
      // Configurações do VS Code que se aplicam no contêiner
      "settings": {
        "terminal.integrated.defaultProfile.linux": "bash",
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "esbenp.prettier-vscode"
      },
      
      // Extensões para instalar automaticamente
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "eamodio.gitlens",
        "ms-azuretools.vscode-docker"
      ]
    }
  },
  
  // Encaminhamento de portas - torna as portas do contêiner disponíveis no host
  "forwardPorts": [3000, 5432],
  "portsAttributes": {
    "3000": {
      "label": "Aplicação",
      "onAutoForward": "notify"
    }
  },
  
  // Comandos para executar em diferentes estágios
  "postCreateCommand": "npm install",     // Após o contêiner ser criado
  "postStartCommand": "npm run dev",      // Após o contêiner iniciar
  
  // Variáveis de ambiente
  "containerEnv": {
    "NODE_ENV": "development",
    "PORT": "3000"
  },
  
  // Execute o contêiner como usuário não root (recomendado para segurança)
  "remoteUser": "node",
  
  // Montar volumes adicionais
  "mounts": [
    "source=${localEnv:HOME}/.ssh,target=/home/node/.ssh,readonly,type=bind"
  ]
}

Explicação das opções de configuração principais:

  • name — Nome de exibição mostrado na barra de status do VS Code
  • build / image — Use um Dockerfile ou imagem pré-construída
  • customizations.vscode.extensions — Extensões do VS Code para instalar automaticamente
  • forwardPorts — Portas para expor do contêiner para o host
  • postCreateCommand — Executa uma vez quando o contêiner é criado pela primeira vez (ex: instalar dependências)
  • postStartCommand — Executa toda vez que o contêiner inicia
  • containerEnv — Variáveis de ambiente disponíveis no contêiner
  • remoteUser — Conta de usuário a ser usada dentro do contêiner
  • mounts — Arquivos/pastas adicionais para montar (como chaves SSH)

💡 Dicas profissionais:

  • Use postCreateCommand para operações lentas (npm install, pip install)
  • Use postStartCommand para tarefas de inicialização rápidas (migrações de banco de dados)
  • Sempre especifique as extensões necessárias para o seu projeto — isso garante ferramentas consistentes
  • Use variáveis de ambiente para configurações que diferem entre desenvolvedores

4. Construa e abra no contêiner

Uma vez que sua configuração estiver pronta, é hora de lançar seu ambiente de desenvolvimento:

Abra o Palette de Comandos (Ctrl+Shift+P / Cmd+Shift+P) e execute:

Dev Containers: Reabrir no Contêiner

O que acontece em seguida:

  1. Construção da imagem — O VS Code constrói a imagem Docker com base no seu Dockerfile ou puxa uma imagem pré-construída. Isso pode levar alguns minutos na primeira vez.

  2. Criação do contêiner — O Docker cria um novo contêiner a partir da imagem construída.

  3. Montagem de volumes — Sua pasta de projeto é montada no contêiner, tornando seu código acessível dentro dele.

  4. Instalação de extensões — Todas as extensões do VS Code especificadas são instaladas automaticamente no contêiner.

  5. Comandos pós-criação — Seu postCreateCommand é executado (ex: npm install, pip install -r requirements.txt).

  6. Pronto! — O VS Code se reconecta ao contêiner, e agora você está desenvolvendo dentro dele.

Verifique se você está no contêiner:

Você pode confirmar que está trabalhando dentro do contêiner abrindo um terminal e executando:

# Verifique o sistema operacional
uname -a
# Saída: Linux ... (núcleo do contêiner)

# Verifique o nome do host (geralmente o ID do contêiner)
hostname
# Saída: abc123def456

# Verifique os processos em execução
ps aux
# Você verá processos do contêiner, não do seu sistema anfitrião

Note que a barra de status do VS Code (inferior esquerdo) agora mostra: Dev Container: [Nome do seu Contêiner]

Comandos do ciclo de vida do contêiner:

  • Reconstruir o contêinerDev Containers: Reconstruir o Contêiner (quando você alterar o Dockerfile)
  • Reconstruir sem cacheDev Containers: Reconstruir o Contêiner sem Cache (para uma construção limpa)
  • Reabrir localmenteDev Containers: Reabrir Pasta Localmente (sair do contêiner, trabalhar no host)

5. Adicionar serviços adicionais (opcional)

Aplicações reais geralmente dependem de bancos de dados, camadas de cache, filas de mensagens ou outros serviços. Você pode usar Docker Compose para orquestrar múltiplos contêineres.

Exemplo: Aplicação full-stack com Node.js, PostgreSQL e Redis

Crie um docker-compose.yml na pasta .devcontainer:

version: "3.8"

services:
  # Contêiner de desenvolvimento principal
  app:
    build: 
      context: ..
      dockerfile: .devcontainer/Dockerfile
    
    volumes:
      # Montar pasta do projeto
      - ..:/workspace:cached
      # Usar volume nomeado para node_modules (melhor desempenho)
      - node_modules:/workspace/node_modules
    
    # Manter o contêiner em execução
    command: sleep infinity
    
    # Acesso de rede a outros serviços
    depends_on:
      - db
      - redis
    
    environment:
      DATABASE_URL: postgresql://dev:secret@db:5432/appdb
      REDIS_URL: redis://redis:6379

  # Banco de dados 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:

Em seguida, atualize seu devcontainer.json para usar Docker Compose:

{
  "name": "Ambiente de Desenvolvimento Full-stack",
  
  // Use docker-compose em vez de um único contêiner
  "dockerComposeFile": "docker-compose.yml",
  
  // Qual serviço usar como contêiner de desenvolvimento
  "service": "app",
  
  // Caminho para a pasta do workspace dentro do contêiner
  "workspaceFolder": "/workspace",
  
  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "ms-azuretools.vscode-docker",
        "ckolkman.vscode-postgres"  // Cliente PostgreSQL
      ]
    }
  },
  
  "forwardPorts": [3000, 5432, 6379],
  
  "postCreateCommand": "npm install && npm run db:migrate",
  
  "remoteUser": "node"
}

O que esta configuração fornece:

  • app — Seu contêiner de desenvolvimento com Node.js
  • db — Banco de dados PostgreSQL, acessível em db:5432 do seu app
  • redis — Cache Redis, acessível em redis:6379
  • Volumes nomeados — Persistência de dados do banco entre reinícios do contêiner
  • Encaminhamento de portas — Acesso a todos os serviços da sua máquina anfitriã

Conectar-se aos serviços do seu código:

// Em sua aplicação Node.js
const { Pool } = require('pg');
const redis = require('redis');

// Conexão com PostgreSQL
const pool = new Pool({
  connectionString: process.env.DATABASE_URL
  // Resolve para: postgresql://dev:secret@db:5432/appdb
});

// Conexão com Redis
const redisClient = redis.createClient({
  url: process.env.REDIS_URL
  // Resolve para: redis://redis:6379
});

Acessar serviços da sua máquina anfitriã:

  • App: http://localhost:3000
  • PostgreSQL: localhost:5432 (usando qualquer cliente PostgreSQL)
  • Redis: localhost:6379 (usando redis-cli ou ferramentas gráficas)

Agora, quando você abrir o projeto no VS Code, todos os serviços iniciarão automaticamente!


🧠 Dicas avançadas e melhores práticas

Use imagens pré-construídas

Economize tempo significativo começando das imagens oficiais do Microsoft devcontainer:

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

Features são scripts de instalação reutilizáveis para ferramentas comuns (Git, GitHub CLI, Node, AWS CLI, etc.).

Práticas recomendadas de controle de versão

Sempre comite sua pasta .devcontainer:

git add .devcontainer/
git commit -m "Adicionar configuração de contêiner de desenvolvimento"
git push

Isso garante:

  • ✅ Novos membros da equipe obtêm o ambiente automaticamente
  • ✅ Alterações no ambiente são rastreadas e revisáveis
  • ✅ Todos desenvolvem no mesmo setup

Dica profissional: Adicione uma seção README explicando a configuração do contêiner de desenvolvimento:


## Configuração de Desenvolvimento

Este projeto usa VS Code Dev Containers. Para começar:

1. Instale o Docker Desktop e o VS Code
2. Instale a extensão "Dev Containers"
3. Clone este repositório
4. Abra no VS Code
5. Clique em "Reabrir no Contêiner" quando solicitado

Depuração em contêineres

A depuração funciona de forma perfeita. Configure seu launch.json como de costume:

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

Defina pontos de interrupção e depure normalmente — o VS Code lida automaticamente com a conexão do contêiner.

Paridade com CI/CD

Use a mesma imagem de contêiner em sua pipeline de CI/CD:

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

Isso garante paridade entre desenvolvimento e produção — se os testes passarem localmente, eles passarão no CI.

Otimização de desempenho

Para usuários de macOS/Windows — use volumes nomeados para dependências:

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

Isso melhora significativamente o desempenho de E/S para node_modules, venv, etc.

Desenvolvimento multi-estágio

Crie diferentes configurações para diferentes papéis da equipe:

.devcontainer/
├── devcontainer.json          # Padrão (full-stack)
├── frontend/
│   └── devcontainer.json      # Apenas frontend (mais leve)
└── backend/
    └── devcontainer.json      # Apenas backend (com DB)

Membros da equipe podem escolher seu ambiente ao abrir o projeto.

Trabalhando com chaves SSH e Git

Monte suas chaves SSH para operações de Git:

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

Arquivos de ambiente personalizados

Carregue configurações específicas do ambiente:

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

.devcontainer/.env:

API_KEY=dev_key_here
DEBUG=true
LOG_LEVEL=debug

🔧 Problemas comuns de solução

O contêiner não inicia

Erro: Não é possível conectar ao daemon do Docker

Solução:

  • Certifique-se de que o Docker Desktop está em execução
  • No Linux, verifique: sudo systemctl status docker
  • Verifique se o Docker está no seu PATH: docker --version

Desempenho lento em macOS/Windows

Problema: Operações de arquivo são lentas

Soluções:

  1. Use volumes nomeados para node_modules, venv, etc.

  2. Ative o compartilhamento de arquivos nas configurações do Docker Desktop

  3. Considere usar opções de montagem cached ou delegated:

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

Extensões não instaladas

Problema: Extensões especificadas em devcontainer.json não instaladas

Soluções:

  1. Reconstrua o contêiner: Dev Containers: Reconstruir o Contêiner
  2. Verifique se os IDs das extensões estão corretos
  3. Certifique-se de que as extensões suportam contêineres remotos (a maioria suporta)

Porta já alocada

Erro: A porta 3000 já está alocada

Soluções:

  1. Pare os contêineres conflitantes: docker ps e docker stop <container>
  2. Mude o mapeamento de porta em forwardPorts
  3. Use portas dinâmicas: o VS Code atribuirá automaticamente portas disponíveis

Alterações no Dockerfile não aplicadas

Problema: Dockerfile modificado, mas as alterações não aparecem

Solução: Reconstrua sem cache:

Dev Containers: Reconstruir o Contêiner sem Cache

O contêiner sai imediatamente

Problema: O contêiner inicia e depois para

Solução: Adicione um comando para mantê-lo em execução no docker-compose.yml:

command: sleep infinity

Ou em devcontainer.json:

{
  "overrideCommand": true
}

✅ Conclusão

Os Contêineres de Desenvolvimento no VS Code trazem consistência, simplicidade e automação ao seu fluxo de trabalho de desenvolvimento. Eles transformam configurações complexas e frágeis em ambientes definidos por código que simplesmente funcionam, independentemente da sua máquina ou sistema operacional.

Principais lições aprendidas:

  • 🎯 Elimine o problema “funciona no meu computador” — Todos usam ambientes idênticos
  • 🚀 Onboarding mais rápido — Novos membros da equipe produtivos em minutos, não em dias
  • 🔒 Melhor segurança — Isolam dependências do seu sistema anfitrião
  • 📦 Portabilidade — Seu ambiente viaja com seu código
  • 🤝 Consistência em equipe — Nenhuma mais conflitos de versão de dependência
  • 🔄 Paridade com CI/CD — Use a mesma imagem em desenvolvimento e integração contínua

Seja você trabalhando em um simples script Python ou em uma complexa arquitetura de microserviços com múltiplos bancos de dados, os Contêineres de Desenvolvimento oferecem uma base sólida para o desenvolvimento moderno.

Se você colabora em projetos multilínguas, contribui para repositórios de código aberto, onboarding de novos desenvolvedores com frequência ou simplesmente deseja ambientes de desenvolvimento limpos e reprodutíveis — os Contêineres de Desenvolvimento são uma ferramenta essencial no seu stack.

Comece pequeno: tente os Contêineres de Desenvolvimento no seu próximo projeto. Uma vez que você experimente os benefícios, você se perguntará como você desenvolveu sem eles.

📚 Recursos Úteis e Artigos Relacionados

Documentação Oficial:

Artigos Relacionados Neste Site: