Dev Container(devcontainer)は、開発に使うOS・言語ランタイム・ツール・エディタ設定を1つのコンテナとして定義し、その定義ファイル(.devcontainer/devcontainer.json)をリポジトリに置く仕組みです。クローンしてコンテナで開けば全員が同じ定義から環境を作れるので、環境設定の違いによる不具合や、新メンバーが手作業で環境を構築する負担を減らせます。
この記事では、メリットと向かない場面を先に整理し、devcontainer.jsonの配置場所と書き方、docker-compose.yamlとの違い、devcontainer-lock.jsonの役割を、Dev Container CLI 0.89.0(2026年8月31日公開)で実際に動かした結果とあわせて解説します。
まとめ
- 最大のメリットは環境の再現性。開発環境をdevcontainer.jsonとしてバージョン管理し、ローカルを汚さずにプロジェクト単位で作り直せる。
- devcontainer.jsonの置き場所は
.devcontainer/devcontainer.jsonが基本。ルートの.devcontainer.jsonと両方あれば、フォルダ側が使われる(CLIで確認)。 - docker-compose.yamlとの違い:Composeは「どのコンテナを並べて動かすか」、devcontainer.jsonは「そのうちどれに接続し、何を入れて、どう開くか」を決める。DBなどを併用するときや、既存のCompose構成を開発にも使うときに両方を組み合わせる。
- devcontainer-lock.jsonはFeaturesの解決済みバージョンとダイジェストを記録するロックファイル。CLI 0.87.0(2026年5月)で安定版になり、
build/upで既定で生成される。リポジトリにコミットする。 - 向かないのは依存の少ない単発スクリプト、GPUやネイティブGUIをホスト直結で使う開発、macOS/Windowsで巨大な依存フォルダをホスト共有する構成(対策なしの場合)。
Dev Containerの仕組み|devcontainer.jsonによる開発環境の定義
Dev Containerは、アプリを配布するためのコンテナではなく、コードを書くための環境そのものをコンテナにしたものです。プロジェクトに .devcontainer フォルダを作り、devcontainer.jsonに「使うイメージ」「追加するツール」「入れる拡張機能」「起動時に実行するコマンド」を書きます。エディタやCLIはこのファイルを読んでコンテナを作り、その中に接続します。
始まりはVS Codeの拡張機能でしたが、現在はDevelopment Container Specificationとしてオープン仕様になっています。devcontainer.jsonはコメントを書けるJSON(JSONC)で、プロパティの一覧は公式のJSONリファレンスにまとまっています。
本番用Dockerイメージとの違い
本番用のイメージはアプリを動かす最小構成を目指し、コンパイラやデバッガを削ります。Dev Containerは逆で、開発に要るツールを積極的に入れます。土台は同じDockerでも役割が反対なので、1つのDockerfileで両方を兼ねようとせず、共通部分をベースイメージに置き、開発用ツールはFeaturesや起動時コマンドで足すのが扱いやすい分け方です。Docker自体の前提はDockerとは|仮想マシンとの違い・必要スペック・Desktop/Engineの違いとインストール手順【2026年10月】で確認できます。
Dev Container対応ツールと設定ファイル生成ツール
仕様サイトの対応ツール一覧(2026年10月時点)には、エディタとしてVS Code・Visual Studio・IntelliJ IDEA・Emacs、ツールとしてDev Container CLI、サービスとしてGitHub Codespaces・CodeSandbox・DevPod・Ona(旧Gitpod)が載っています。Cachix devenvとJetify Devboxは、Nixで作った環境からDev Container用の設定ファイルを生成する連携として掲載されています。同じdevcontainer.jsonをローカルのVS Code、クラウドのCodespaces、CIのCLIで使い回せるのはこのためです。Nixで環境を固定する方式と比べたい場合はDevboxとは?Nixを使う開発環境構築ツールの仕組み・インストール・使い方【2026年版】も参考になります。
Dev Containerを導入するメリットと向かない場面
メリットはすべて「環境をコードにして再現できる」ことから派生します。一方で、導入しても得をしない場面もはっきりあります。
環境の再現性とオンボーディングの短縮
環境定義がリポジトリに入っているので、クローンして「コンテナーで再度開く」を実行すれば、必要なランタイム・ライブラリ・拡張機能が揃った状態から始められます。手順書を見て各自がインストールする方式では、Node.jsのマイナー版やOSパッケージのわずかな差が「その人の環境だけで出るバグ」を生みます。Dev Containerでは環境定義を共有して差を減らせます。ただし、可変のイメージタグやFeaturesが取得するツールの版は、別途固定が必要です。後述のdevcontainer-lock.jsonをコミットすれば、Featuresの版まで揃います。
言語ランタイムの分離とプロジェクト単位の環境切り替え
言語ランタイムやデータベースをホストに入れないため、プロジェクトAはNode.js 24、プロジェクトBはPython 3.13とPostgreSQL 17、という要求がぶつかりません。フォルダを開き直すだけで環境が切り替わり、不要になればコンテナとイメージを削除できます。ただし、名前付きボリュームやバインドマウント先のファイルなどは別に残ります。環境が壊れても再ビルドで戻せます。
採用を見送るべきケース
- 依存が少ない単発のスクリプト:コンテナのビルドと接続の手間のほうが大きくなります。
- GPUやネイティブGUIをホスト直結で使う開発:GPU・GUIの対応はホストOS、ランタイム、デバイスに依存します。必要な機能をコンテナ経由で利用できない構成では、ホスト上の開発環境を選びます。
- macOS/Windowsで巨大な依存フォルダをホストと共有する構成:ファイル共有がボトルネックになり、ビルドやファイル監視が重くなります。後述のボリューム退避で改善できますが、「入れれば速くなる」道具ではありません。
判断の目安は「環境構築の手順書がある、または2人以上が同じリポジトリを触る」かどうかです。どちらも当てはまらない個人の小さなツールなら、無理に入れる必要はありません。
devcontainer.jsonの書き方|配置場所と主要プロパティ
環境の起点は3つあります。既製イメージを使う(image)、Dockerfileからビルドする(build)、Docker Composeを使う(dockerComposeFile)です。まず置き場所から決めます。
devcontainer.jsonの3種類の配置場所と探索の優先順位
仕様で認められている置き場所は、.devcontainer/devcontainer.json、リポジトリ直下の .devcontainer.json(先頭にドット)、構成を複数持つための .devcontainer/<フォルダ名>/devcontainer.json の3通りです。CLIのヘルプには「既定では .devcontainer/devcontainer.json を使い、無ければ .devcontainer.json を使う」とあります。両方を置いた状態で devcontainer read-configuration を実行すると、実際にフォルダ側が選ばれました。
$ ls -a
.devcontainer .devcontainer.json
$ devcontainer read-configuration --workspace-folder . \
| jq -r '.configuration.name, .configuration.configFilePath.path'
in-folder
/.../ws1/.devcontainer/devcontainer.json
ルート直下の1ファイル形式は手軽ですが、Dockerfileやcompose.yamlを並べるとリポジトリ直下が散らかります。迷ったら .devcontainer/ フォルダに置いてください。
image指定によるdevcontainer.jsonの最小構成
公式イメージを指定すれば、Dockerfileを書かずに始められます。次の例は、ワークスペース直下に内容の整合したpackage.jsonとpackage-lock.jsonがあるnpmプロジェクトを前提にしています。Node.js 20は2026年4月30日でサポートが終わっているので、例ではサポート期間内のLTS版である24を使います(javascript-nodeイメージには 24 タグがあります)。
{
// コメントを書ける(JSONC)
"name": "my-app",
"image": "mcr.microsoft.com/devcontainers/javascript-node:24",
"forwardPorts": [3000],
"postCreateCommand": "npm ci"
}
このタグ指定ではNode.jsのメジャー版を揃えられますが、イメージは更新されます。同一のイメージを再現するにはダイジェストで固定します。Node.js 26は2026年10月28日にLTSへ移る予定なので、切り替えるならその後にタグを書き換えます。
buildによるDockerfileの指定
OSパッケージを足すなど細かい制御が要るときは、Dockerfileを用意して build から参照します。パスはdevcontainer.jsonからの相対です。
{
"name": "my-app",
"build": { "dockerfile": "Dockerfile", "context": ".." },
"forwardPorts": [8000]
}
本番と共有したい土台だけをDockerfileに書き、エディタ拡張や開発専用ツールはFeaturesと postCreateCommand で足すと、開発の都合がDockerfileに混ざりません。
Featuresによるツール追加とメジャー版の指定
Node.jsやGitHub CLI、AWS CLIなどは、Dockerfileにインストール手順を書く代わりに features へ宣言するだけで入ります。各Featureは ghcr.io/devcontainers/features/<名前>:<メジャー版> の形で参照し、オプションで中身の版を指定します。
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/node:1": { "version": "24" },
"ghcr.io/devcontainers/features/github-cli:1": {}
}
}
注意したいのは、:1 のようなタグは「そのメジャー版の最新」を指すことです。2026年10月20日時点で node:1 は1.7.1で止まり、Featureの最新は2.1.1でした(後述の devcontainer outdated で確認)。メジャー版が上がっても自動では追従しないので、ときどき outdated で差を確認し、変更点を読んでからタグを書き換えます。
customizations.vscodeによる拡張機能と設定の指定
入れるVS Code拡張やエディタ設定は customizations.vscode の下に置きます。古い記事にあるトップレベルの extensions/settings は旧形式です。
{
"image": "mcr.microsoft.com/devcontainers/javascript-node:24",
"customizations": {
"vscode": {
"extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"],
"settings": { "editor.formatOnSave": true }
}
}
}
よく使うプロパティの早見表
| プロパティ | 用途 | 既定値・注意 |
|---|---|---|
image / build |
イメージ指定/Dockerfileでビルド | どちらか一方 |
features |
ツールの宣言的追加 | 版はlockfileで固定 |
forwardPorts |
ホストへ転送するポート | "db:5432" 形式も可 |
postCreateCommand |
作成後に1回実行 | 依存の取得向き |
remoteUser |
ツールやターミナルの実行ユーザー | コンテナ全体は変えない |
containerUser |
コンテナ全体の実行ユーザー | 既定はrootかDockerfileのUSER |
mounts |
追加のマウント | --mount と同じ書式 |
privileged |
特権モード | 既定false・Docker in Dockerで必要 |
capAdd |
ケーパビリティ追加 | デバッガ用の SYS_PTRACE など |
shutdownAction |
ウィンドウを閉じたときの停止 | image系はstopContainer |
各項目の定義はJSONリファレンスの記述に合わせています。remoteUser と containerUser の実際の違い(作られるファイルの所有者など)は、VS Codeで開発コンテナを作る(Create Dev Container)|devcontainer.jsonの書き方・root実行・複数コンテナで実行結果つきで解説しています。
devcontainer.jsonとdocker-compose.yamlの違い
2つは競合する設定ではなく、担当が違います。Composeは「どのコンテナを、どのネットワークとボリュームで並べて動かすか」を決めるDockerの設定です。devcontainer.jsonは「そのうちどのコンテナに接続し、何をインストールし、どのフォルダを開くか」を決める開発環境の設定です。アプリ用のコンテナ1つで足りるならdevcontainer.jsonだけでよく、データベースやキャッシュを一緒に動かすときにComposeを足します。
devcontainer.jsonとComposeの役割比較
| 観点 | devcontainer.json | docker-compose.yaml |
|---|---|---|
| 読むもの | VS Code・Codespaces・CLI | Docker Compose |
| 定義するもの | 接続先・Features・拡張・起動時処理 | サービス・ネットワーク・ボリューム |
| 単独で使えるか | 使える(image/build) | 使えるが開発環境の設定は持たない |
| ソースのマウント | image/buildでは自動 | Compose連携時は自分で書く |
| 開くフォルダ | workspaceFolder |
なし |
Compose連携で見落としやすいのが最後の2行です。image や build の構成ではソースコードが自動でマウントされますが、Composeを使う構成では volumes でマウントを自分で書き、workspaceFolder を指定します。JSONリファレンス上、Compose構成の workspaceFolder の既定値は / なので、書き忘れるとルートが開きます。
Compose連携の書き方とrunServicesの挙動
開発用コンテナをComposeの1サービスとして定義し、service で接続先を指定します。次の構成でCLIの devcontainer up を実行しました。
# .devcontainer/compose.yaml
services:
app:
image: mcr.microsoft.com/devcontainers/base:ubuntu
command: sleep infinity
volumes:
- ..:/workspaces/ws2:cached
db:
image: postgres:17-alpine
environment:
POSTGRES_PASSWORD: postgres
cache:
image: redis:8-alpine
{
"name": "compose-test",
"dockerComposeFile": "compose.yaml",
"service": "app",
"runServices": ["app", "db"],
"workspaceFolder": "/workspaces/ws2",
"shutdownAction": "stopCompose"
}
$ docker ps --filter label=com.docker.compose.project=ws2_devcontainer \
--format '{{.Names}} {{.Image}}'
ws2_devcontainer-db-1 postgres:17-alpine
ws2_devcontainer-app-1 mcr.microsoft.com/devcontainers/base:ubuntu
$ devcontainer exec --workspace-folder . bash -lc 'getent hosts db; getent hosts cache; echo "getent cache exit=$?"'
172.21.0.3 db
getent cache exit=2
結果から分かることは3つあります。runServices に書かなかった cache は起動せず、コンテナ一覧に無く、名前解決も失敗しました(getent の終了コード2は「見つからない」)。runServices を省略すると全サービスが起動します。アプリからDBへは localhost ではなくサービス名 db で接続します。Composeのプロジェクト名は「フォルダ名_devcontainer」になりました。重いサービスを普段は止めておきたいときは runServices で絞ります。
devcontainer-lock.jsonとは|Featuresの版を固定するロックファイル
devcontainer-lock.jsonは、devcontainer.jsonに書いたFeaturesが「どの版・どのダイジェストに解決されたか」を記録するファイルです。npmの package-lock.json に相当します。node:1 のようなタグは時間とともに中身が変わるため、ロックファイルが無いと、半年後に参加したメンバーやCIが別の版でビルドすることになります。
CLIの変更履歴によると、ロックファイルは0.87.0(2026年5月12日公開)で実験機能から安定版になり、build と up で既定で生成されるようになりました。VS CodeのDev Containers拡張(0.469.0)にも dev.containers.lockfile 設定があり、既定値はtrue(ロックファイルを書き出す)です。VS Code 1.118で既定化された経緯はVS Code 1.118の新機能|codebase semantic indexが使えない原因・devcontainer-lock.json・Copilot設定の変更点にまとめています。
生成されるタイミングと中身
Featuresを2つ書いた構成で devcontainer build を実行すると、devcontainer.jsonの隣に次のファイルができました(ダイジェストは途中を省略しています)。Featureが1つも無い構成(先ほどのCompose例)では作られません。
{
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {
"version": "1.1.3",
"resolved": "ghcr.io/devcontainers/features/github-cli@sha256:bd7ab48a...",
"integrity": "sha256:bd7ab48a..."
},
"ghcr.io/devcontainers/features/node:1": {
"version": "1.7.1",
"resolved": "ghcr.io/devcontainers/features/node@sha256:8c0de469...",
"integrity": "sha256:8c0de469..."
}
}
}
version が実際に使われたFeatureの版、resolved と integrity がレジストリ上のダイジェストです。ファイル名は置き場所で変わり、ルート直下の .devcontainer.json を使う構成では先頭にドットの付いた .devcontainer-lock.json になります(CLIのソースで確認)。どちらの場合もリポジトリにコミットします。コミットしないと、手元で固定しても他の人とCIには効きません。
outdated・upgrade・–frozen-lockfileの使い方
更新の確認と反映には3つのコマンドを使います。
$ devcontainer outdated --workspace-folder .
Feature Current Wanted Latest
ghcr.io/devcontainers/features/node 1.7.1 1.7.1 2.1.1
ghcr.io/devcontainers/features/github-cli 1.1.3 1.1.3 1.1.3
Wanted は今のタグ(:1)で取れる最新、Latest はFeature自体の最新です。node の行は「タグを :2 に変えない限り1.7.1のまま」と読みます。
次に、devcontainer.jsonの node:1 を node:2 に書き換え、ロックファイルを更新しないまま --frozen-lockfile 付きでビルドすると、終了コード1で止まりました。
$ devcontainer build --workspace-folder . --frozen-lockfile
Error: Lockfile does not match.
CIではこのオプションを付けておくと、「devcontainer.jsonだけ変えてロックファイルのコミットを忘れた」変更を検出できます。ロックファイルの更新は devcontainer upgrade で行い、--dry-run を付けると書き込まずに新しい内容(この例では node:2 が2.1.1に解決)を表示します。生成そのものを止めたい場合は --no-lockfile を使います。
VS CodeでDev Containersを使う手順
必要なのは、Dockerが動く環境とVS Codeの拡張「Dev Containers」(ID:ms-vscode-remote.remote-containers、旧名Remote – Containers)です。2026年10月20日時点の安定版は0.469.0(2026年9月8日公開・VS Code 1.101以降)です。
Dev Containers拡張の導入とコンテナへの接続
拡張を入れ、.devcontainer/devcontainer.json のあるフォルダを開き、コマンドパレットで「Dev Containers: Reopen in Container(コンテナーで再度開く)」を実行します。定義どおりにイメージがビルドされ、VS Codeがコンテナ内に接続します。初回はビルドに時間がかかり、2回目以降はキャッシュで速くなります。devcontainer.jsonを変えたら「Dev Containers: Rebuild Container」で作り直します。ゼロから構成ファイルを追加する手順は開発コンテナを作る記事で扱っています。
forwardPortsによるWebアプリへのアクセス
コンテナ内で起動したWebアプリには、forwardPorts に書いたポートでホストのブラウザからアクセスできます。portsAttributes でラベルや通知の挙動も指定できます。
{
"image": "mcr.microsoft.com/devcontainers/javascript-node:24",
"forwardPorts": [3000],
"portsAttributes": {
"3000": { "label": "web", "onAutoForward": "notify" }
}
}
ライフサイクルコマンドによる作成時・起動時の処理
依存の取得は作成時に1回だけ走る postCreateCommand、毎回実行したい処理は起動のたびに走る postStartCommand に置きます。依存の取得を postStartCommand に置くと、起動のたびに待たされます。次の db:migrate は、package.jsonに同名のスクリプトがあり、接続先DBの準備が完了している場合の例です。
{
"image": "mcr.microsoft.com/devcontainers/javascript-node:24",
"postCreateCommand": "npm ci",
"postStartCommand": "npm run db:migrate"
}
コンテナ内のDocker利用|docker-in-dockerとdocker-outside-of-docker
Dev Containerの中でイメージをビルドしたり、Testcontainersを動かしたりするには、2つの方式があります。どちらも公式Featureで入ります。
docker-in-dockerによる独立Dockerデーモンの起動
コンテナの中で別のDockerデーモンを動かす方式です。ホストのDockerとは分離されますが、特権モードが必要です。Featureの定義自体に privileged: true と、/var/lib/docker 用の名前付きボリュームが含まれているので、devcontainer.jsonに privileged を自分で書く必要はありません。
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:4": {}
}
}
古い記事に多い docker-in-docker:2 は、devcontainer outdated で見ると2.17.0止まりで、最新は4.1.3でした。3.0.0(2026年5月)では、Codespacesなどでcontainerdがerofsスナップショッターを読み込もうとしてdockerdが起動しない不具合が修正されています(PR #1645)。:2 のまま使っているなら、変更点を確認したうえで :4 へ上げてください。
docker-outside-of-dockerによるホスト側Dockerの共有
ホストのDockerソケットをコンテナに渡し、ホスト側のDockerを操作する方式です。コンテナの特権モード指定は不要ですが、ソケットを使えるユーザーはホスト側のDockerを自由に操作でき、rootfulのDockerではホストのroot相当の権限になります(Dockerのドキュメントも docker グループはroot相当と注意しています)。作られるコンテナとイメージキャッシュはホスト側で共有されます。
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
}
}
このFeatureは定義の中でホストの /var/run/docker.sock をコンテナの /var/run/docker-host.sock にマウントします。よく見かける「mounts で docker.sock を自分でマウントする」書き方は、Featureを使うなら不要です。Dockerデーモンやイメージ管理を分けるならdocker-in-docker、ホスト側のDocker操作を許可してキャッシュを共有するならdocker-outside-of-dockerを選びます。どちらも信頼できないコードを安全に隔離するための選択肢ではありません。コンテナの隔離の仕組みはDockerの仕組みを図解|コンテナ隔離・アーキテクチャ・VMとの違いを実機コマンドで確認で確認できます。
Dev Containerが遅い・重いときの改善策
macOSとWindowsでは、ホストとコンテナ間のファイル共有が処理を遅くする原因の1つになります。ソースをホストに置いてバインドマウントすると、OSをまたぐファイルアクセスが遅く、小さなファイルを大量に読み書きする node_modules やビルド出力で差が出ます。対策は、重いパスを共有マウントから外すことです。
名前付きボリュームによるnode_modulesの分離
書き込みが集中するフォルダだけをDockerの名前付きボリュームに載せると、コンテナ内のファイルシステムで動くため速くなります。
{
"image": "mcr.microsoft.com/devcontainers/javascript-node:24",
"mounts": [
"source=${localWorkspaceFolderBasename}-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
],
"postCreateCommand": "sudo chown node node_modules && npm ci"
}
この書き方はVS Codeのパフォーマンス改善ガイドの例に沿っています。ボリュームは作成直後rootの所有になるため、postCreateCommand で所有者を変えてから依存を入れます。フォルダ名を含めると区別しやすくなりますが、別の場所にある同名フォルダでは衝突します。構成ごとに分けたい場合は、ボリューム名に${devcontainerId}を使います。
WindowsでのWSL2ファイルシステムへのリポジトリ配置
Windowsでは、リポジトリを /mnt/c 配下ではなくWSL2のLinuxファイルシステム(~/repos など)に置くと、Windows側とのファイル共有を避けられます。Docker DesktopのバックエンドがWSL2なら、Linux側のファイルはネイティブに近い速度で扱えます。WSL2の導入はWSL2とは?WSL1との違い・仕組み・インストール手順【WSL 3.0対応・2026年10月】で確認できます。
CI・GitHub Codespacesでの環境定義の再利用
1つのdevcontainer.jsonをローカル・クラウド・CIで共有すると、「ローカルでは通るのにCIで落ちる」を減らせます。
GitHub Codespacesでの利用条件と無料枠
GitHub Codespacesは、リポジトリの .devcontainer を読んでクラウド上に環境を作るサービスです。ローカルにDockerが無くても、ブラウザやVS Codeから同じ環境に接続できます。個人アカウントには無料枠があり、GitHubの課金ドキュメントではFreeプランで月120コア時間(2コアのマシンなら実質60時間)とストレージ15GB-month、Proプランで180コア時間と20GB-monthです。組織のプランには無料枠がありません。なお、Codespacesはバインドマウントを(Dockerソケットを除き)無視し、shutdownAction も適用されないと対応ツール一覧に書かれています。ローカル専用のマウントに頼った定義は、Codespacesでは動きが変わります。
devcontainers/ciとCLIによるビルド・テスト
GitHub Actionsなら devcontainers/ci アクション、その他のCIならDev Container CLI(@devcontainers/cli)の devcontainer build/up/exec で、devcontainer.jsonから環境を作ってテストできます。
- uses: actions/checkout@v7
- uses: devcontainers/[email protected]
with:
runCmd: npm test
ロックファイルを使っているなら、CLIで動かすCIでは --frozen-lockfile を付けてロックファイルとの不一致を落とします。ビルド済みイメージをghcr.ioなどに公開し、環境定義の参照先やCIのキャッシュ取得元に指定すると、各開発者とCIのビルド時間を短縮できます。ワークフローの組み方はGitHub Actionsでビルド・自動テストを設定する方法|CI/CDワークフローの作り方、開発環境の標準化とCI/CDの整備を外部に任せたい場合はDevOps・CI/CD導入支援も検討してください。
Dev Containerに関するよくある質問
Dev ContainerとDockerの違いは何ですか?
Dockerはコンテナを作って動かす基盤です。Dev ContainerはDockerの上で「開発環境をコンテナとして定義し、エディタから接続して開発する」ための仕様(devcontainer.json)と、それを読むツール群を指します。Dev Containerを使うにはDockerか互換のランタイムが必要です。
devcontainer.jsonとDockerfileはどちらが必要ですか?
必須なのはdevcontainer.jsonだけです。既製イメージを image で指定すればDockerfileは要りません。OSパッケージの追加など細かい制御が要るようになったら、build からDockerfileを参照します。追加ツールの多くはFeaturesで足ります。
Dev Containersを使うのにDocker Desktopは必須ですか?
必須ではありません。Docker Desktopは利用規約上、従業員250人未満かつ年間売上1,000万ドル未満の事業者、個人、教育、非商用OSSでは無料で、それ以外は有料サブスクリプションが必要です。VS Codeの公式ドキュメントはmacOSのColima、Podman 5以降(dev.containers.dockerPath を podman に変更)、Rancher Desktopを代替として案内しています。ただしDocker以外のCLIは「動く場合もあるが公式サポート外」とされています。
devcontainer-lock.jsonはGitにコミットすべきですか?
コミットします。ロックファイルの目的は、他のメンバーやCIが同じ版のFeaturesでビルドすることなので、手元にだけあっても意味がありません。版を上げるときは devcontainer upgrade でロックファイルを更新し、devcontainer.jsonと一緒にコミットします。
Dev ContainerとGitHub Codespacesはどう違いますか?
Dev Containerは環境の定義(仕様とdevcontainer.json)で、Codespacesはその定義をGitHubのクラウドで動かすサービスです。同じ .devcontainer を読むので定義を書き分ける必要はありませんが、バインドマウントなど一部のプロパティはCodespacesでは効きません。