Kamu pernah ngalamin ini: laptop baru, clone repo lama, terus npm install atau pip install gagal karena versi Node atau Python beda. Atau lebih parah — kode jalan di laptop kamu, tapi di laptop teman satu tim hasilnya beda. Classic "works on my machine" problem.
Solusi paling umum biasanya bikin README panjang berisi langkah setup manual. Tapi README itu basi dalam seminggu karena nggak ada yang update.
Gue udah pakai devcontainer sejak setahun lalu buat semua project solo maupun kolaborasi kecil, dan ini yang paling bikin hidup lebih tenang: environment-nya ikut di-commit bareng kode.
Apa Itu Devcontainer?
Devcontainer adalah spesifikasi open source (awalnya dari Microsoft, sekarang di bawah devcontainers.org) yang mendefinisikan dev environment kamu dalam sebuah file JSON dan Dockerfile. VS Code, Cursor, bahkan GitHub Codespaces bisa baca spesifikasi ini dan otomatis spin up container yang sudah siap pakai.
Intinya: kamu define environment sekali, semua orang (atau semua laptop kamu) dapat environment yang sama persis.
Bukan cuma soal dependency — devcontainer juga bisa define:
- Extension VS Code yang harus ter-install
- Port forwarding otomatis
- Script yang jalan setelah container up (
postCreateCommand) - Environment variable
Struktur File yang Perlu Kamu Buat
Minimal kamu butuh satu file: .devcontainer/devcontainer.json. Kalau mau custom lebih dalam, tambah Dockerfile.
Struktur folder:
project-root/
├── .devcontainer/
│ ├── devcontainer.json
│ └── Dockerfile # opsional
├── src/
└── ...
Contoh paling sederhana buat project Node.js:
// .devcontainer/devcontainer.json
{
"name": "Node.js Dev",
"image": "mcr.microsoft.com/devcontainers/javascript-node:22",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss"
]
}
},
"forwardPorts": [3000],
"postCreateCommand": "npm install"
}
Simpan file ini, commit ke repo, dan siapapun yang clone repo kamu + punya Docker + VS Code bisa langsung Reopen in Container dan langsung kerja. Tanpa setup manual.
Setup dari Nol: Project Python FastAPI
Gue akan tunjukin setup yang lebih realistis — project FastAPI dengan PostgreSQL sebagai database.
Langkah 1: Buat Dockerfile custom
# .devcontainer/Dockerfile
FROM mcr.microsoft.com/devcontainers/python:3.12
# Install system dependencies
RUN apt-get update && apt-get install -y \
libpq-dev \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Install Poetry
RUN pip install poetry==1.8.2
# Set Poetry config: jangan buat virtualenv, install langsung ke system
RUN poetry config virtualenvs.create false
Langkah 2: devcontainer.json dengan Docker Compose
Karena kita butuh PostgreSQL, kita pakai dockerComposeFile bukan image langsung:
// .devcontainer/devcontainer.json
{
"name": "FastAPI + PostgreSQL",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"mtxr.sqltools",
"mtxr.sqltools-driver-pg"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"editor.formatOnSave": true,
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
}
}
}
},
"forwardPorts": [8000, 5432],
"postCreateCommand": "poetry install",
"remoteUser": "vscode"
}
Langkah 3: Docker Compose untuk dev
# .devcontainer/docker-compose.yml
version: '3.8'
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/workspace:cached
command: sleep infinity
environment:
DATABASE_URL: postgresql://devuser:devpass@db:5432/devdb
depends_on:
- db
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: devuser
POSTGRES_PASSWORD: devpass
POSTGRES_DB: devdb
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
Setelah tiga file ini ada di repo kamu, buka VS Code, tekan Ctrl+Shift+P, ketik Dev Containers: Reopen in Container. VS Code akan build image, spin up container, install extension, dan jalankan poetry install — semuanya otomatis.
Gotcha yang Gue Kena
Beberapa hal yang bikin gue buang waktu waktu pertama kali setup:
1. Volume mount dan permission issue
Kalau kamu pakai Linux sebagai host, file yang dibuat di dalam container kadang punya owner root, bukan user kamu. Solusinya: pastikan remoteUser di devcontainer.json di-set ke user non-root (biasanya vscode di image Microsoft). Image official Microsoft sudah handle ini dengan baik.
2. postCreateCommand gagal karena dependency belum ada
Kalau postCreateCommand kamu butuh service lain (misalnya database buat run migration), jangan taruh migration di sini. Pisahkan jadi script manual atau pakai postStartCommand yang jalan setiap container start — tapi tetap hati-hati karena service mungkin belum ready.
Gue biasanya bikin script scripts/setup-dev.sh yang harus dijalankan manual setelah container up:
#!/bin/bash
# scripts/setup-dev.sh
set -e
echo "Waiting for database..."
until pg_isready -h db -U devuser; do
sleep 1
done
echo "Running migrations..."
alembic upgrade head
echo "Seeding dev data..."
python scripts/seed_dev.py
echo "Dev environment ready!"
3. Build ulang image kalau Dockerfile berubah
Devcontainer nggak otomatis rebuild kalau kamu ubah Dockerfile. Kamu harus manual: Ctrl+Shift+P → Dev Containers: Rebuild Container. Ini sering bikin bingung kalau kamu tambah dependency di Dockerfile tapi lupa rebuild.
4. .env file dan secrets
Jangan taruh secrets di devcontainer.json. Gunakan fitur localEnv untuk forward environment variable dari host:
"remoteEnv": {
"OPENAI_API_KEY": "${localEnv:OPENAI_API_KEY}"
}
Jadi kamu set OPENAI_API_KEY di .bashrc atau .zshrc di laptop kamu, dan otomatis tersedia di dalam container.
Pakai Devcontainer Tanpa VS Code
Kalau kamu lebih suka terminal atau pakai editor lain (Neovim, misalnya), ada CLI resminya:
# Install
npm install -g @devcontainers/cli
# Spin up container dari folder project
devcontainer up --workspace-folder .
# Jalankan command di dalam container
devcontainer exec --workspace-folder . bash
# Atau langsung jalankan script
devcontainer exec --workspace-folder . -- poetry run pytest
Ini berguna banget buat CI/CD juga. Kamu bisa jalankan test suite di dalam devcontainer yang sama persis dengan yang kamu pakai lokal — eliminasi "test pass di lokal, gagal di CI" problem.
Contoh GitHub Actions yang pakai devcontainer CLI:
# .github/workflows/test.yml
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install devcontainer CLI
run: npm install -g @devcontainers/cli
- name: Build devcontainer
run: devcontainer up --workspace-folder .
- name: Run tests
run: devcontainer exec --workspace-folder . -- poetry run pytest --tb=short
Tips Tambahan buat Solo Dev
Kalau kamu kerja solo dan punya beberapa laptop (misalnya desktop di rumah dan laptop buat mobile), devcontainer ini killer feature-nya adalah kamu nggak perlu sync environment manual.
Beberapa hal yang gue lakuin:
Bikin devcontainer template per stack. Gue punya repo devcontainer-templates yang isinya template untuk Python, Node, Go, dan Rust. Waktu mulai project baru, tinggal copy folder .devcontainer yang relevan.
Commit lock file. poetry.lock, package-lock.json, go.sum — selalu di-commit. Devcontainer jalankan install dari lock file, jadi versi dependency persis sama di semua environment.
Pisahkan dev dan prod Dockerfile. Devcontainer Dockerfile boleh gemuk — install semua dev tools, debugger, profiler. Dockerfile buat production harus lean. Jangan campur keduanya.
Forward port yang kamu butuhkan. Kalau kamu pakai tools seperti Adminer atau Mailhog buat development, tambahkan ke forwardPorts dan docker-compose.yml. Akses dari browser host kamu langsung.
"forwardPorts": [8000, 5432, 8080],
"portsAttributes": {
"8000": { "label": "FastAPI", "onAutoForward": "openBrowser" },
"8080": { "label": "Adminer" }
}
Yang Gue Lakuin Sekarang
Semua project baru gue langsung mulai dengan .devcontainer. Workflow-nya sekarang jadi:
git clonerepo- Buka di VS Code
- Klik "Reopen in Container"
- Tunggu 2-3 menit (build pertama), habis itu langsung bisa coding
Kalau ganti laptop, proses yang sama. Nggak ada lagi sesi debugging "kenapa di laptop gue nggak jalan" yang makan waktu berjam-jam.
Satu hal yang masih gue eksplor: pakai devcontainer dengan Orbstack di macOS sebagai pengganti Docker Desktop. Orbstack jauh lebih ringan dan volume mount-nya lebih cepat — ini penting karena salah satu keluhan utama devcontainer di Mac adalah I/O performance yang lambat karena filesystem virtualization.
Kalau kamu mau mulai, clone salah satu repo project kamu yang sudah ada, buat folder .devcontainer, taruh devcontainer.json paling sederhana dulu (pakai image bukan custom Dockerfile), dan coba Reopen in Container. Dari situ kamu bisa iterasi.
Spesifikasi lengkap devcontainer ada di containers.dev — dokumentasinya cukup bagus dan ada banyak reference implementation yang bisa kamu jadiin starting point.