「お兄ちゃん、それ開発用の箱だよ」──Dev Container を妹に教えてもらう
この記事で分かること
- Dev Container が「環境のブレ」をどう減らそうとしているか
-
devcontainer.jsonのimage/features/postCreateCommand/customizationsの役割の違い - リポジトリをコンテナで開くまでの操作イメージ
- 認証まわりをイメージに焼かない考え方(例: AWS の bind mount)
前提
兄: 俺、Docker は入れたんだけどさ。Dev Container って単語だけ聞いてて中身が曖昧なんだよね。
妹: 大丈夫。Docker が動いて、Cursor か VS Code に Dev Containers 拡張が入ってればスタートラインはクリア。あとこの記事の例は Ubuntu 24.04 ベースで Python 3.12 と Node LTS 想定だから、手元の devcontainer.json はバージョンだけ読み替えてね、お兄ちゃん。
Dev Container って、何するの?
兄: 開発コンテナって、本番サーバーと同じイメージ?
妹: 必ずしも同じじゃないことが多いよ。狙いは開発環境をそろえること。.devcontainer/devcontainer.json を置いておくと、エディタが Docker でコンテナを起動して、ワークスペースをコンテナにマウントした状態で開発するの。
兄: つまり、俺の Mac の中を汚さずに、決まった Python とか Node が使える?
妹: そういう理解で OK。「自分のマシンでは動くのに他の人のでは動かない」を減らすのが主目的。仕様の中心はオープンな Development Containers(containers.dev) で、VS Code も Cursor もだいたいそれに沿ってるよ。
devcontainer.json、地図みたいなもん?
兄: JSON だけ見ると頭がこんがらがるんだけど。
妹: よく出るキーだけつかまえよう。これ説明用の抜粋だから、プロジェクトによって値は違うかも。
{
"name": "Development Standard Package",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04",
"features": {
"ghcr.io/devcontainers/features/python:1": { "version": "3.12" },
"ghcr.io/devcontainers/features/node:1": { "version": "lts" }
},
"postCreateCommand": "bash .devcontainer/postCreate.sh",
"customizations": {
"vscode": {
"extensions": ["ms-python.python", "charliermarsh.ruff"],
"settings": { "editor.formatOnSave": true }
}
},
"remoteUser": "vscode",
"mounts": []
}
兄: image が土台の OS で、features がその上に乗せる道具、って感じ?
妹: 合ってる。features で Python とか Node とか AWS CLI を宣言的に足せる。バージョンが JSON に残るから、誰がいつコンテナを作っても同じに寄せやすいの。
兄: postCreateCommand は何するやつ?
妹: コンテナが初めて作られたあとに 1 回だけ実行されるコマンド。Features だけだと足りない分——例えば uv のインストールとか npm install -g prettier とか——を .devcontainer/postCreate.sh にまとめるパターンがよくあるよ。
兄: customizations はエディタの話?
妹: うん。コンテナ内に入れる拡張機能と、保存時フォーマットとか Python を Ruff にするとか、エディタ設定をコードとして固定する。README で「みんな同じ拡張入れて」と書くよりズレにくい。
鍵とか AWS、コンテナに直コピーしていい?
兄: AWS のキーとか、コンテナの中にコピーするのはアウトでしょ。
妹: その感覚で正解。イメージに秘密を焼き込まないのが原則。このリポジトリの例だと、ホストの ~/.aws をコンテナの vscode ユーザー配下に bind mount してる。
"mounts": [
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.aws,target=/home/vscode/.aws,type=bind,consistency=cached"
]
兄: HOME と USERPROFILE が両方あるの、なんで?
妹: Unix 系と Windows のホスト両方でパスを組み立てやすくするための定番パターン。会社によっては SSO とか別の渡し方のほうが適切なこともある。一番きついのは平文キーをリポジトリにコミットすることだから、そこだけは絶対やめて。
じゃあ実際どうやって開くの
兄: 操作だけ手短に。手順が欲しい。
妹: 3 ステップ。
- リポジトリをクローンして Cursor / VS Code で開く
-
Reopen in Container か、コマンドパレットの
Dev Containers: Reopen in Container - 初回はイメージ取得と Features で数分かかることがある。終わればターミナルも拡張もコンテナ側に揃う
兄: 初回だけ長いのは、環境を揃える処理が走ってるから?
妹: そう捉えていい。2 回目以降はキャッシュが効いてだいぶマシになることが多いよ。
よくある誤解
兄: コンテナに入ったら、プロジェクトのファイル全部コピーされるイメージなんだけど。
妹: 基本はマウント。編集してるのはいつものフォルダのまま、実行環境だけがコンテナ側に寄る感じ。Git の履歴も普通はホスト側のリポジトリに残る。厳密にはマウントの設定次第で挙動は変わるから、変なときはログを見てね。
まとめ
兄: ……なんか、お前いつからそんな詳しかったんだ。
妹: お兄ちゃんが聞くから説明しただけ。要点はこの 3 つ。
- Dev Container は containers.dev の仕様を軸に、エディタと Docker で開発環境を揃える仕組み
-
image+featuresで土台とランタイム、postCreateCommandで追加分、と分けると読みやすい - 秘密はイメージに入れない。マウントや会社の認証方針で扱う
Discussion