プログラミング ソフトウェア 公開日 2026.04.04 更新日 2026.10.18

Dev Containersとは?ローカル開発を汚さない開発環境の作り方を初心者向けに解説

Dev Containers とは何か、なぜローカル開発を汚しにくくできるのか、最初の作り方とハマりやすい点を初心者向けに整理した記事です。

目次(37項目)

先に要点

  • Dev Containers は、開発環境をコンテナでそろえて、ローカルPCを汚しにくくするやり方です。中心になるのは devcontainer.json で、どのイメージ・拡張・設定を使うかを定義します。
  • 初心者が必ず詰まるのは「Windowsでマウントが遅い」「Linuxで生成ファイルが root 所有になる」「シェルスクリプトが \r で動かない」の3点です。本文で 現象→原因→確認→回避 の形で先回りします。
  • 導入する価値があるラインは数値で見えます。目安は「参加者3人以上」「セットアップ手順がREADMEで10行を超える」「言語ランタイムが2つ以上混ざる」。逆に単発スクリプトや1人開発では uv 等の軽い仮想環境で十分なことが多いです。
  • 始め方は、Docker を入れて、既存イメージ + 最小の devcontainer.json で1プロジェクト動かすところから。Windowsならソースを WSL2 側に置くのが速度面の前提条件です。

Dev Containers(開発コンテナ)は、プロジェクトに必要な言語ランタイムやツールを Docker コンテナの中にまとめ、エディタからそのコンテナに入って開発する仕組みです。設定はリポジトリの .devcontainer/devcontainer.json に書くので、clone した人は同じ環境を数分で再現できます。

ここまでは定義なので、この記事ではその先を扱います。最小の設定ファイルと「正しく立ち上がったか」を確かめるコマンド、Windows・Linux で必ず踏む3つの落とし穴と回避策、そして uv や venv で足りるケースとの境目を数値で示します。確認したのは 2026年10月時点の VS Code の Dev Containers ドキュメント、Improve disk performance ガイド、containers.dev の devcontainer.json リファレンス、devcontainers/images と devcontainers/cli の公式リポジトリです。

Dev Containersとは何か

仕様は containers.dev で公開されていて、VS Code のほか GitHub Codespaces などが同じ devcontainer.json を読みます。構造は次の図のとおりです。

手元のPC ソースコード 開発用の依存は 入れなくてよい コンテナ 言語ランタイム DBクライアント OSパッケージ 拡張機能 マウント 境界で詰まる:マウント速度・権限・改行
ソースは手元、実行環境はコンテナ。両者をマウントでつなぐのが既定の動作

初心者向けにかなりざっくり言うと、アプリを動かすための開発環境を、手元のOSへ直接いろいろ入れずにコンテナ側へまとめるやり方 です。
そのため、ローカルPCを開発用の依存で汚しにくくなります。ただし「ソースコードまでコンテナに閉じ込める」わけではなく、後述するようにソースは手元に残してマウントで共有するのが既定の動作です。この前提が、後で出てくる「マウントが遅い」「権限でハマる」の根っこになります。

何が便利なのか

ローカルPCを汚しにくい

言語ランタイムやDBクライアント、OSパッケージをコンテナ側に寄せることで、PC本体をきれいに保てます。プロジェクトごとに環境が混ざりません。

チームで環境が揃う

devcontainer.json をリポジトリに入れれば「自分のPCだけ動かない」を減らせます。新メンバーのセットアップは、手順書を読みながらの手作業から「コンテナのビルドを待つだけ」に変わります。

作り直しが簡単

コンテナが壊れても Rebuild Container するだけ。ローカルのソースコードはマウント側に残るので消えません。

3つの中で実務の効き目が大きいのは2つ目です。「macOS では動くが Windows では詰まる」「誰かのローカルだけ設定が増えている」といった環境差は、口頭や README では揃いきりません。Dev Containers では「このプロジェクトはこの環境で開く」を定義ファイルとしてリポジトリに持てるので、差分がレビューの対象になります。設定を変えたら Pull Request で誰でも確認できる、という点が手順書との一番の違いです。

何でできているのか

中心になるのは次の3つです。

土台

Docker

コンテナを動かす土台。

設定ファイル

devcontainer.json

開発環境の設定ファイル。

中身と構成

Dockerfile / Docker Compose

コンテナの中身や複数サービス構成を定義するときに使う。

つまり Dev Containers は単独の新しいコンテナ技術というより、Docker ベースの開発環境を扱いやすくするための定義と仕組み と考えると分かりやすいです。

devcontainer.json は何をするのか

devcontainer.json は開発環境の入口になる設定ファイルです。たとえば次を書けます。

土台

どのイメージ / Dockerfile / Docker Compose 構成を使うか

拡張機能

どの拡張機能を入れるか

ポート

どのポートを開けるか

作成後の処理

コンテナ作成後に何を実行するか(postCreateCommand)

初心者向けには このプロジェクトをどういう開発環境で開くかを書いた設計メモ と考えると入りやすいです。

実務でよく使う項目を1つにまとめると、次のような形になります。features は「GitHub CLI を足す」「Docker を中で使う」のような追加ツールを、Dockerfile を書かずに部品として足す仕組みです。

{
  "name": "web-app",
  "image": "mcr.microsoft.com/devcontainers/javascript-node:24-bookworm",
  "features": {
    "ghcr.io/devcontainers/features/github-cli:1": {}
  },
  "forwardPorts": [3000],
  "postCreateCommand": "npm ci",
  "customizations": {
    "vscode": {
      "extensions": ["dbaeumer.vscode-eslint"]
    }
  }
}

迷いやすいのが、コンテナ作成時や起動時に自動で走るコマンドの使い分けです。containers.dev のリファレンスでは次のように定義されています。

項目どこで・いつ走るか向いている処理
initializeCommandホスト側。作成時と起動時ホスト側で必要なファイルの準備
postCreateCommandコンテナ内。初回作成時に1回npm ci などの依存インストール
postStartCommandコンテナ内。起動のたび開発用サーバーやワーカーの起動
postAttachCommandコンテナ内。エディタが接続するたび接続時に表示したい情報など

依存インストールを postStartCommand に書くと、起動のたびに走って遅くなります。逆に開発サーバーを postCreateCommand に書くと、2回目以降の起動で立ち上がりません。なお、途中のコマンドが失敗すると、その後のコマンドは実行されません。

最初の作り方はどうするのか

いちばん入りやすいのは、VS Code で既存テンプレートやイメージを使って始めるやり方です。4ステップで動かせます。

Dev Containers 初回セットアップ4ステップ

  1. 1
    Docker を入れる

    Dev Containers はコンテナ前提。まず Docker Desktop(または Docker Engine)を入れる。Windowsはこのとき WSL2 バックエンドを有効にしておく。

  2. 2
    .devcontainer/devcontainer.json を作る

    プロジェクト直下に .devcontainer フォルダを作り、devcontainer.json を置く。最初は既存イメージを指定するだけでよく、自前 Dockerfile は不要。

  3. 3
    VS Code でコンテナとして開く

    VS Code で Dev Containers: Reopen in Container を実行。コンテナ作成、拡張機能の導入、postCreateCommand が自動で走る。

  4. 4
    必要なら Dockerfile / Compose へ広げる

    依存が増えたら Dockerfile を書き、複数サービス(DB、Redis 等)が必要なら docker-compose.yml を追加して devcontainer.json から参照する。

手順1: Docker を入れる

まず Docker が必要です。Dev Containers はコンテナ前提なので、ここがないと始まりません。Windowsの場合はこの時点で Docker Desktop の WSL2 バックエンドを有効にしておくのが後の速度問題の予防になります(理由は後述)。

手順2: .devcontainer/devcontainer.json を作る

最小例なら次の形です。

{
  "name": "sample-app",
  "image": "mcr.microsoft.com/devcontainers/javascript-node:24-bookworm",
  "customizations": {
    "vscode": {
      "extensions": ["dbaeumer.vscode-eslint"]
    }
  }
}

既存イメージで Node.js 開発環境を開く形です。最初は自前 Dockerfile を書かず、イメージ指定だけで十分です。

イメージのタグは公式の一覧から選ぶ

タグの 24 は Node.js のバージョン、bookworm は土台の Debian のバージョンです。2026年10月時点で公式の README に載っているのは Node.js 22・24・26 と、Debian の bookworm・trixie の組み合わせです。設定例でよく見かける 1-22-bookworm のような先頭に数字が付いたタグは「イメージ自体の版」を固定する書き方で、公式は「セキュリティ修正は最新の版にだけ入れる」としています。古い版のまま固定し続けないようにします。

手順3: VS Code でコンテナとして開く

VS Code で Dev Containers: Reopen in Container を選ぶと、その設定で開発環境が立ち上がります。初回はイメージの取得とビルドが走るため、回線とマシン次第で数分かかります。2回目以降はキャッシュが効くので、待ち時間はかなり短くなります。

立ち上がったら、本当にコンテナの中で動いているかを VS Code のターミナルで確かめます。ホスト側の Node.js を見ていた、というのはよくある勘違いです。

$ cat /etc/os-release | head -1
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
$ node -v
v24.x.x
$ whoami
node
$ pwd
/workspaces/sample-app

OS がイメージの Debian になっていて、ユーザーが root ではなく node(このイメージの一般ユーザー)、作業フォルダが /workspaces/ 配下なら想定どおりです。VS Code を使わずに同じ設定を立ち上げたいときは、公式の devcontainers/cli が使えます。CI やエディタ以外のツールから同じ環境を使うときに便利です(Push ごとの自動テストの組み方は GitHub Actionsとは? で扱っています)。

npm install -g @devcontainers/cli   # npm で入れる場合、環境によっては Python と C/C++ のビルドツールが要る
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . node -v

devcontainer up は最後に {"outcome":"success","containerId":"…","remoteUser":"node","remoteWorkspaceFolder":"/workspaces/sample-app"} のような1行の JSON を出します。outcome が success 以外なら、その上に出ているビルドログを読みます。

手順4: 必要なら Dockerfile へ広げる

依存が増えたら自前 Dockerfile へ広げます。

FROM mcr.microsoft.com/devcontainers/base:ubuntu

RUN apt-get update && apt-get install -y git curl

そして devcontainer.json 側で参照します。

{
  "name": "sample-app",
  "build": { "dockerfile": "Dockerfile" }
}

複数サービスがあるときはどうするか

アプリ本体だけでなく DB や Redis も一緒に立てたいことがあります。このときは Docker Compose を使う形が分かりやすいです。アプリ・PostgreSQL・Redis のように複数コンテナが必要なら、Compose でまとめて定義し、devcontainer.json からどの service を開発対象にするか指定します。

ざっくり言うと、単体で足りるなら image / Dockerfile、複数サービスなら Compose、で考えると入りやすいです。Compose ファイル自体の書き方は Docker Composeとは?複数コンテナをまとめて動かす基本 で整理しています。

単体か、複数サービスか

image / Dockerfile

アプリ本体だけで足りるとき

  • 最初は既存イメージの指定だけ
  • 依存が増えたら自前の Dockerfile へ広げる

実務で必ず詰まる3つの落とし穴と回避策

ここがこの記事の本題です。Dev Containers は「ソースは手元、実行環境はコンテナ、両者をマウントでつなぐ」という構造のため、その境界で確実にハマります。代表的な3つを 現象→原因→確認→回避 の形でまとめます。

落とし穴1

Windowsでマウントが遅い

回避の最優先は、ソースを WSL2 のLinuxファイルシステムへ置くこと。

落とし穴2

生成ファイルが root 所有

Linuxホストで起きる。UID/GIDをホストに合わせ、非rootユーザーで動かす。

落とし穴3

CRLFでスクリプトが落ちる

.gitattributes で改行を LF に固定する。

落とし穴1: Windowsでマウントが致命的に遅い

現象: Windows + Docker Desktop で、npm install やテスト実行、ファイル保存時の再ビルドが体感で数倍〜10倍遅い。VS Code のファイル監視(ホットリロード)が効かないこともある。

原因: プロジェクトを C:\Users...(Windows側ファイルシステム)に置いたまま開いていると、ファイルI/Oが Windows ↔ WSL2 の境界を毎回越えます。この /mnt/c 経由のアクセスは Linux ネイティブのファイルシステムより大幅に遅く、ファイル数の多い node_modules や .git で顕著に効きます。

確認手順: コンテナ内ターミナルで pwd を実行し、パスが /mnt/c/... や /workspaces/... でもホスト実体が C: 配下なら遅い構成です。time npm ci を Windows側配置と WSL2側配置で計測すると差がはっきり出ます。

回避:

  • 最優先: ソースを WSL2 のLinuxファイルシステムへcloneしてから開く。\wsl$\Ubuntu\home\you\project 配下に置き、VS Code から WSL 経由で開けば、マウントが Linux ネイティブになり速くなります。
  • node_modules など大量の小ファイルだけ名前付きボリュームに逃がす。これは VS Code 公式の Improve disk performance ガイドにある手法で、Docker が VM の中で動く macOS でも効きます。名前付きボリュームの性質は Dockerのvolumeとは? を参照してください。
"mounts": [
  "source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
],
"remoteUser": "node",
"postCreateCommand": "sudo chown node node_modules"
  • I/Oが重すぎるなら、ソースツリー全体を名前付きボリュームに置く Clone Repository in Container Volume を使う。バインドマウントを介さないぶん Windows / macOS で速度が出ます。
"workspaceMount": "source=your-volume-name,target=/workspace,type=volume",
"workspaceFolder": "/workspace"

落とし穴2: Linuxホストで生成ファイルが root 所有になる

現象: Linux(または WSL2 上の Docker Engine)で開発中、コンテナ内で生成したファイルがホストから編集・削除できない。rm しようとすると Permission denied、Git が dubious ownership を出すこともある。

原因: Linux のバインドマウントはホストのUID/GIDをそのまま使います。コンテナ内のユーザーがホストのあなた(多くは UID 1000)と違うUIDだと、生成物の所有者がずれます。とくにコンテナが root(UID 0)で動いていると、生成ファイルは全部 root 所有になります。

確認手順: ホスト側で ls -n して所有UIDを見る。コンテナ内で id を実行し、UID/GIDがホストの id と一致しているか比べます。

回避: devcontainer.json でイメージ・Dockerfile・Compose を参照していれば、Dev Containers はコンテナユーザーのUID/GIDをホストに自動で合わせます(updateRemoteUserUID の既定は有効)。明示するなら非rootユーザーを指定します。

{
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "remoteUser": "vscode"
}

ポイントは、イメージ内にUIDを書き換えてよい一般ユーザーをちょうど1人だけ用意すること。同じUIDのユーザーが複数いるとUID更新に失敗します。すでに root 所有で散らかしてしまったら、コンテナ内で sudo chown -R vscode:vscode /workspaces/プロジェクト名 で一括修正できます。

落とし穴3: Windowsの改行(CRLF)でシェルスクリプトが動かない

現象: Windowsでcloneしたリポジトリの entrypoint.sh や postCreateCommand から呼ぶスクリプトが、コンテナ内で no such file or directory や bad interpreter で落ちる。中身は明らかに存在するのに失敗する。

原因: Windowsの Git は既定で core.autocrlf=true のことが多く、checkout時に改行を CRLF に変換します。Linuxのシェルは行末の \r をパスやインタプリタ名の一部と解釈するため、#!/bin/bash\r が「/bin/bash\r というファイルが無い」と判定されます。Windowsのパス区切り </code> をそのままスクリプトに書いている場合も同様に壊れます。

確認手順: コンテナ内で file entrypoint.sh を実行し、with CRLF line terminators と出たらこれです。cat -A スクリプト で行末に ^M$ が見えても同じ。

回避: 個人設定ではなくリポジトリの .gitattributes で改行を固定するのが確実です(GitHub公式も推奨)。

* text=auto eol=lf
*.sh text eol=lf

これでチームの誰がcloneしても、シェルスクリプトはコンテナ内で LF に揃います。すでに混入していれば git add --renormalize . で正規化できます。応急処置としてコンテナ内で sed -i 's/\r$//' スクリプト でも直りますが、根本対策は .gitattributes です。

どの規模・構成なら導入する価値があるか

「何でも Dev Containers にすればよい」わけではありません。コンテナの起動・ビルド・ディスク使用というコストが常にかかるからです。uv などの軽量な仮想環境との一番の違いは、Dev Containers はOSレベルの依存とサービス群まで丸ごと揃える点にあります。逆に言えば、そこまで要らない規模ではオーバーキルです。判断ラインを数値と条件で示します。

条件導入の判断代わりの選択肢
開発者が1〜2人 / 全員同じOS不要寄り。環境差が起きにくい言語標準の仮想環境(venv + uv 等)
開発者が3人以上 / OSが混在導入価値が高い—(Dev Containers が有力)
READMEのセットアップ手順が10行以内不要寄りセットアップスクリプト1本
セットアップ手順が10行超 / 30分以上かかる導入価値が高い—
言語ランタイムが1つだけ場合による仮想環境で足りることが多い
言語ランタイムが2つ以上混在導入価値が高い—
DB / Redis など常駐サービスが必要導入価値が非常に高い(Compose連携)—
単発スクリプト / 使い捨て検証不要その場で実行、または uv run
当てはまる条件を数える 参加者3人以上 セットアップ手順がREADMEで10行超 言語ランタイムが2つ以上、または常駐サービス 2つ以上 導入の損益分岐を超える 1つも無い 仮想環境が軽くて速い
導入の目安

ざっくりした目安として、「参加者3人以上」「セットアップ手順がREADMEで10行超」「言語ランタイムが2つ以上、または常駐サービスあり」のうち2つ以上に当てはまるなら導入の損益分岐を超えると考えてよいです。逆に1つも当てはまらない単発作業なら、仮想環境のほうが軽くて速いです。

マシン要件も判断材料

Docker Desktop はコンテナ稼働中にメモリを数GB単位で確保します。実務で複数サービスを立てるなら、目安としてRAM 16GB以上が快適ラインで、8GBだとブラウザやエディタと取り合って厳しくなります。古い・低メモリのPCしか無いチームでは、導入価値があってもまず Docker Desktop のリソース割り当て調整から入ります。

初心者がハマりやすい考え方

devcontainer.json を直したのに反映されない

devcontainer.json や Dockerfile を書き換えても、VS Code のウィンドウを開き直すだけでは既存のコンテナがそのまま使われます。設定を変えたら Dev Containers: Rebuild Container を実行して作り直します。ソースはマウント側にあるので作り直しても消えませんが、コンテナの中だけに置いたファイル(ホームディレクトリに作った設定や、手で apt-get install したもの)は消えます。手で入れて動いたものは、その場で Dockerfile か features に書き戻しておくと、次の作り直しで困りません。

開発用と本番用の Dockerfile は分ける

開発用の設定を本番に持ち込まない

開発コンテナに入れた便利ツールやデバッグ設定を、そのまま本番に持ち込むのは安全ではありません。本番用は最小・セキュリティ重視(multi-stage build、非root実行)、開発用はデバッグしやすさ重視、と役割を分けるのが定石です。

よくある誤解

よくある誤解

Dev Containers を使えば環境差や不具合が全部消えるわけではありません。実際には Docker の理解、マウント、権限、改行コード、ネットワーク、ボリュームの扱いといった別の見どころが出てきます。本記事の3つの落とし穴は、その代表例です。

もう一つ多いのは ローカルに何も入れなくてよくなる という誤解です。実際には Docker やエディタの準備は必要で、Git や補助ツールの考え方も要ります。

Dev Containersに関するよくある質問

Q. Windowsでとにかく遅いです。最初に試すべきことは?

A. ソースを C: 配下から WSL2 のLinuxファイルシステム(\wsl$...)へ移して開き直すことです。これだけで npm install やテストが体感で数倍速くなることがあります。次に node_modules を名前付きボリュームへ逃がします。詳しくは本文「落とし穴1」を参照。

Q. コンテナで作ったファイルがホストから消せません。

A. Linuxホスト特有の権限ずれです。devcontainer.json に "remoteUser": "vscode" 等を指定し、UID/GIDをホストに合わせます。すでに root 所有なら sudo chown -R vscode:vscode で一括修正。本文「落とし穴2」参照。

Q. シェルスクリプトが「no such file or directory」で落ちます。中身はあるのに。

A. CRLF改行が原因のことがほとんどです。.gitattributes に *.sh text eol=lf を書き、git add --renormalize . で正規化してください。本文「落とし穴3」参照。

Q. uv や venv で足りるのに Dev Containers を使う意味は?

A. ランタイムが1つでサービスも無いなら、多くの場合 uv / venv のほうが軽くて速いです。Dev Containers の価値はOSレベルの依存や DB / Redis などの常駐サービスまで丸ごと揃える点にあります。「導入判断ライン」の表で2つ以上当てはまるかを確認してください。

Q. VS Code 以外でも使える?

A. containers.dev の仕様は VS Code 以外にも開かれており、JetBrains IDEs(IntelliJ、PyCharm 等)、GitHub Codespaces、DevPod などで対応が進んでいます。実装が最も進んでいるのは VS Code です。

Q. Docker Desktop は有料?

A. 個人利用・教育・小規模事業者(従業員250人未満かつ年商1000万ドル未満)は無料、それ以上の規模では有料サブスクが必要です。無料の代替として Colima(macOS)、Rancher Desktop、Podman Desktop も選択肢です。

Q. マシンが重いときの対策は?

A. Docker Desktop のリソース割り当て(CPU・メモリ・ディスク)を調整し、不要なコンテナ・イメージを docker system prune で定期削除、ボリュームマウントを最小限に、拡張機能はコンテナ内で必要なものだけに絞ります。複数サービスを常用するなら RAM 16GB以上が快適ラインです。

まとめ

Dev Containers は、コンテナで開発環境をそろえ、ローカルPCを開発依存で汚しにくくするやり方です。中心は devcontainer.json で、必要に応じて Dockerfile や Docker Compose を組み合わせます。

始めるときは、既存イメージを指定しただけの最小の設定で立ち上げ、whoami や node -v でコンテナの中にいることを確かめてから、Dockerfile や Compose へ広げます。Windows ならソースを WSL2 側に置くこと、Linux なら一般ユーザーで動かすこと、どの OS でも .gitattributes で改行を LF に固定することを最初に済ませておけば、3つの落とし穴の大半は避けられます。

参考リンク

あとで見返すならここで保存

読み終わったあとに残しておきたい記事は、お気に入りからまとめて辿れます。