Dev Container — Mac / Windows / Linux 統一開発環境
VS Code Dev Containers で OS 差異を消す。Docker ベースで再現可能な開発環境を devcontainer.json 1ファイルでチーム全員が共有できる。
「自分の環境では動く(It works on my machine)」問題は、たいていOS差異から始まる。Mac には brew と Apple Silicon があり、Windows には PowerShell と UTF-16 があり、Linux マシンには systemd がある。全員が同じバージョンの Node とパッケージをインストールしても、微妙なズレは必ず生まれる。
Dev Containers(VS Code Dev Containers + 標準の devcontainer.json)は、OS 差異を Docker コンテナの中に封じ込める。チーム全員が同じ Linux 環境の内側で作業し、IDE だけがホスト側で動く。このガイドでは、Mac・Windows・Linux どのホストでも同じように動く単一の Dev Container をセットアップする。
TL;DR
- Docker ランタイムをインストール(Mac:OrbStack/Docker Desktop、Win:Docker Desktop/WSL Docker、Linux:docker)
- VS Code + Dev Containers 拡張機能(
ms-vscode-remote.remote-containers) - プロジェクトルートに
.devcontainer/devcontainer.jsonを1ファイル置く Cmd/Ctrl+Shift+P→ Dev Containers: Reopen in Container — IDE がコンテナ内で再起動- チームメンバー:clone → そのコマンドを1回実行 → 同一環境
前提条件
- VS Code 1.95+
- Docker ランタイム — OS 別ガイド:mac/docker-setup · windows/docker-wsl2
- Git 管理下のプロジェクト(devcontainer.json を共有するため)
1. Dev Container を使う理由
解決する問題
- 「自分の環境では動く」問題 — コンテナ内では OS とツールチェーンが同一
- オンボーディングの速さ — 新メンバーが30行の README を読まなくても1クリックで環境が揃う
- バージョン衝突の解消 — プロジェクト A は Node 18、B は Node 22 — ホストの mise/nvm なしで分離できる
- OS 固有のビルド問題 — Apple Silicon ARM 問題、Windows の長いパス問題などを回避
- CI との一致 — GitHub Actions ワークフローと同じベースイメージを使えばギャップがなくなる
Dev Container が弱い場面
- GUI アプリ開発 — Mac ネイティブや Windows ネイティブの UI ビルドはコンテナに向かない
- GPU 負荷の高いワークロード — GPU パススルーは可能だが、ホストで直接動かす方が安定
- 低スペックマシン — Docker 自体が 1〜2GB 余分に RAM を消費する(16GB なら問題なし)
2. 最小構成の devcontainer.json
.devcontainer/devcontainer.json:
{
"name": "My Project Dev",
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm",
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"postCreateCommand": "npm install",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
},
"forwardPorts": [3000, 5173],
"remoteUser": "node"
}主要フィールド:
| フィールド | 役割 |
|---|---|
image | Docker ベースイメージ(Node / Python / Go / Rust など) |
features | 追加ツール(git、gh、docker-in-docker、awscli など — カタログから選択) |
postCreateCommand | コンテナ作成後に1回実行(依存関係インストールなど) |
customizations.vscode.extensions | コンテナ内に自動インストールされる VS Code 拡張機能 |
forwardPorts | ホストに公開するポート |
remoteUser | コンテナ内のユーザー(セキュリティ上 non-root 推奨) |
3. 初回起動
VS Code コマンドパレット(Cmd/Ctrl+Shift+P)→ Dev Containers: Reopen in Container。
- 初回:〜1〜3分(イメージ取得 +
postCreateCommand) - VS Code の左下に
Dev Container: My Project Devと表示される
# コンテナ内ターミナル(VS Code Terminal)
uname -a
# Linux 1234abcd 6.10.x #1 SMP Debian ...
which node
# /usr/local/share/nvm/versions/node/v22.x/bin/nodeホスト OS に関係なく同じ Linux 環境になる。
4. ベースイメージの選び方
devcontainer.json の image:。公式カタログ:
| 言語 / スタック | イメージ |
|---|---|
| Node.js | mcr.microsoft.com/devcontainers/javascript-node:1-{18,20,22}-bookworm |
| Python | mcr.microsoft.com/devcontainers/python:1-{3.11,3.12,3.13}-bookworm |
| Go | mcr.microsoft.com/devcontainers/go:1-{1.22,1.23} |
| Rust | mcr.microsoft.com/devcontainers/rust:1-bookworm |
| Java | mcr.microsoft.com/devcontainers/java:1-{17,21}-bookworm |
| .NET | mcr.microsoft.com/devcontainers/dotnet:1-9.0-bookworm |
| Universal(多言語) | mcr.microsoft.com/devcontainers/universal:2-linux |
推奨:単一言語プロジェクト → その言語のイメージ。多言語 → ベースイメージ + features。
独自の Dockerfile を使うことも可能:
{
"name": "My Custom Dev",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
}
}5. features — 1行でツールを追加
features ブロックは公式カタログ(https://containers.dev/features)のモジュールを使う。1行でツールがインストールされる。
よく使う選択肢:
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}, // コンテナ内で docker を実行
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/terraform:1": {},
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {}
}6. Docker-in-Docker — コンテナ内のコンテナ
Dev Container 内で docker run が必要な場合(docker-compose のテスト、ビルド検証など):
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"version": "latest",
"dockerDashComposeVersion": "v2"
}
}あるいは、ホストの Docker ソケットを共有する方法もある(軽量だがセキュリティが低下する):
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
]7. ホスト ↔ コンテナのファイルマウント
ワークスペースフォルダは /workspaces/{project} に自動マウントされる。
追加マウント:
"mounts": [
"source=${localEnv:HOME}/.aws,target=/home/node/.aws,type=bind,readonly",
"source=${localEnv:HOME}/.gitconfig,target=/home/node/.gitconfig,type=bind"
]macOS のマウントパフォーマンスについては docker-setup §5.2 を参照(VirtioFS 推奨)。
8. 環境変数とシークレット
静的な環境変数
"containerEnv": {
"NODE_ENV": "development",
"LOG_LEVEL": "debug"
}シークレット(絶対にコミットしない)
.env ファイルをマウントするか、localEnv 経由で渡す:
"containerEnv": {
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}",
"OPENAI_API_KEY": "${localEnv:OPENAI_API_KEY}"
}ホストシェルの環境変数がコンテナに注入される。.env は .gitignore に追加しておくこと。
9. マルチコンテナ(docker-compose 統合)
DB / Redis などの依存関係がある場合:
.devcontainer/docker-compose.yml:
services:
app:
image: mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm
volumes:
- ..:/workspaces/myapp
command: sleep infinity
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: dev
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:.devcontainer/devcontainer.json:
{
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/myapp"
}VS Code が app コンテナにアタッチし、db は自動的に起動される。
10. CI と同じ環境 — devcontainer-cli
CI で devcontainer.json を再利用する:
npm install -g @devcontainers/cli
# コンテナをビルドしてコマンドを実行
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . npm testGitHub Actions:
# .github/workflows/test.yml
- name: Test in dev container
uses: devcontainers/ci@v0.3
with:
runCmd: npm testCI がグリーンならローカルでも同じ結果が得られる。
11. 検証
# ホスト
docker --version
# コンテナ内(VS Code Terminal)
uname -a # Linux ...
which node # /usr/local/share/...
echo $NODE_ENV # development(containerEnv が効いている)
node --version # コンテナの Node バージョン
git --version # features でインストール済み5つすべてがコンテナ内で正しく応答すればセットアップ完了。
12. トラブルシューティング
"Failed to connect" / コンテナが起動しない
- Docker ランタイムは起動している?(Docker Desktop のメニューバー、
orb status、colima status) docker psでポート/名前の衝突を確認- VS Code → コマンドパレット → 「Dev Containers: Rebuild Without Cache」
ビルドが終わらない
- 初回ビルドはベースイメージ(数GB)を取得するため時間がかかる — 想定内
- 2回目以降はキャッシュが効く。
postCreateCommandはキャッシュ対象外(リビルドごとに再実行) onCreateCommand(初回のみ)とpostCreateCommand(リビルドごと)の使い分けを意識する
ファイルに Permission denied
- コンテナの UID とホストの UID が一致していない(Linux ホストで特に発生しやすい)
remoteUserとupdateRemoteUserUIDをセット:"remoteUser": "vscode", "updateRemoteUserUID": true
forwardPorts が動かない
- コンテナ内のアプリが
0.0.0.0または::にバインドしているか(127.0.0.1ではなく)? - 例:Next.js は
next dev -H 0.0.0.0が必要
ホストの Git 設定が反映されない
.gitconfigの自動マウントはオプション —mountsに明示的に追加する- または
featuresの git が使うgitconfigのコピーに頼る
node_modules が大きくて IDE が遅い
- VS Code のウォッチャーから
node_modulesを除外する(files.watcherExclude) - または
node_modulesをホストマウントではなくコンテナ専用ボリュームに置く:"mounts": [ "source=${localWorkspaceFolderBasename}-node-modules,target=/workspaces/${localWorkspaceFolderBasename}/node_modules,type=volume" ]
13. 次のステップ
- Mac Docker — /mac/docker-setup(ランタイム比較)
- Windows Docker WSL2 — /windows/docker-wsl2
- リモート開発 — /multi-os/remote-development — リモートマシンを開発環境として使う
- Dotfiles 同期 — /mac/dotfiles — chezmoi で Dev Container 内にも dotfiles を適用
参考資料
更新履歴
- 2026-05-16:初稿。devcontainer.json の基本 · ベースイメージ選択 · features · docker-compose 統合 · CI 統合 · 6つのトラブルシューティング事例。