Dev Container 入門:VS Code で“開発環境そのもの”をコード化し、チームの足並みを揃える

はじめに

チーム開発で地味に時間を奪うのが、環境差分です。
「Node のバージョンが違う」「ローカルに入ってる CLI が古い」「Mac では動くけど Windows だと…」「インストール手順が README にあるけど、いつの間にかズレてる」。こういう“ややこしさ”は、バグより発見しにくいのに、確実に生産性を落とします。

Docker でアプリを動かすのは一般的になりましたが、実は “開発環境そのもの” まで揃えきれていないケースが多いです。
そこで効いてくるのが Dev Container(VS Code の Development Containers)
これは「このリポジトリを開くときは、このコンテナを開発環境として使ってね」という宣言を devcontainer.json と Dockerfile / Compose で管理する仕組みです。

  • 新しいメンバーが参加 → リポジトリを開くだけで同じ環境が立ち上がる
  • CI だけでなく、ローカルの“開発体験”まで統一できる
  • 依存ツール(formatter, linter, DB クライアント, Cloud SDK…)もまとめられる
  • “プロジェクトの開発環境”がコードとしてレビュー可能になる

この記事では、Dev Container の概念を押さえつつ、実際に Node.js + Postgres の開発環境を Dev Container 化して、VS Code でそのまま開発できるところまでをハンズオンで作ります。


座学

1) Dev Container は何を解決するのか

Dev Container は、ざっくり言うと **「IDE がコンテナに入って開発する」**仕組みです。
正確には VS Code がローカルの UI として動き、プロジェクトのファイル操作・ターミナル・拡張機能の一部を コンテナ側で動かします。

これにより、開発者のPCに以下を“直接”入れなくてもよくなります。

  • 言語ランタイム(Node / Python / Go…)
  • ビルドツール(make, gcc, java…)
  • CLI(psql, awscli, gcloud, terraform…)
  • lint/format ツール(eslint, prettier, golangci-lint…)

つまり、README の環境構築手順が“実行可能な形”で /.devcontainer に移るのが Dev Container の価値です。


2) 仕組みの全体像(最低限ここだけ)

Dev Container は主に以下の部品で構成されます。

  • devcontainer.json:VS Code が参照する設定(どのコンテナで開くか、拡張機能、ポート転送、初期コマンドなど)
  • Dockerfile または docker-compose.yml:開発環境のコンテナ定義
  • (任意)postCreateCommand / initializeCommand:初回セットアップの自動化
  • (任意)features:よくあるツールを簡単に追加できる仕組み(Git, Node, Docker CLI 等)

ここで重要なのは、Dev Container は「コンテナを立てる」だけではなく、“開発体験(拡張機能やポート転送)”まで含めて設定化できる点です。


3) Dockerfile 方式と Compose 方式、どっちがいい?

どちらも使えます。使い分けの感覚はこうです。

  • Dockerfile 方式:単体サービス(アプリだけ)で完結しやすい。軽量。
  • Compose 方式:DB や Redis など複数サービスが必要なとき強い。現場はこっちが多い。

今回は “開発環境の統一” の旨味が分かりやすいように、**Compose(アプリ + DB)**でいきます。


4) よく使う devcontainer.json の設定(使い所込み)

  • service / workspaceFolder:どのサービスに入るか、作業ディレクトリをどこにするか
  • forwardPorts:ホスト側へ転送するポート(Webサーバ、DB、Storybook など)
  • customizations.vscode.extensions:チームで入れる拡張機能を固定化
  • postCreateCommand:初回に npm ci などを自動実行
  • remoteUser:root を避ける(権限トラブルやファイル所有者問題を避ける)
  • mounts:キャッシュや SSH キーなどを必要に応じてマウント

特に postCreateCommand は効きます。
「開いた瞬間に依存が入り、すぐ動く」状態を作れるので、オンボーディングが劇的に短くなります。


ハンズオン

目標:このリポジトリを VS Code で開いたら、同じ Node 環境 + Postgres が立ち上がり、即開発できる状態を作る。

0) ディレクトリ構成

プロジェクト直下に以下を作ります。

.
├─ .devcontainer/
│ ├─ devcontainer.json
│ ├─ docker-compose.yml
│ └─ Dockerfile
├─ package.json
├─ server.js
└─ .dockerignore

1) 最小アプリを用意(Node + Express)

package.json

{
"name": "devcontainer-demo",
"version": "1.0.0",
"type": "commonjs",
"scripts": {
"dev": "node server.js"
},
"dependencies": {
"express": "^4.19.2",
"pg": "^8.11.5"
}
}

server.js(DB 接続して / で表示)

const express = require("express");
const { Client } = require("pg");const app = express();app.get("/", async (_req, res) => {
const client = new Client({
host: process.env.PGHOST || "db",
port: Number(process.env.PGPORT || 5432),
user: process.env.PGUSER || "postgres",
password: process.env.PGPASSWORD || "postgres",
database: process.env.PGDATABASE || "app",
}); try {
await client.connect();
const r = await client.query("SELECT NOW() as now");
res.send(`Hello Dev Container! DB time: ${r.rows[0].now}`);
} catch (e) {
res.status(500).send(`DB error: ${e.message}`);
} finally {
await client.end().catch(() => {});
}
});app.listen(3000, () => console.log("listening on :3000"));

.dockerignore

node_modules
.git
.DS_Store

2) 開発用コンテナ(Dockerfile)を作る

.devcontainer/Dockerfile

FROM node:20-bookworm# 開発で使いがちなツール(例)
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
git curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*WORKDIR /workspace

入門としては、ここでは「開発に必要な最低限だけ入れる」方針でOKです。
(このあと Features を使うと、もっと楽に増やせます)


3) Compose で “アプリ + DB” を立てる

.devcontainer/docker-compose.yml

version: "3.9"
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/workspace:cached
command: sleep infinity
environment:
PGHOST: db
PGPORT: "5432"
PGUSER: postgres
PGPASSWORD: postgres
PGDATABASE: app
ports:
- "3000:3000"
depends_on:
- db db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: app
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/datavolumes:
pgdata:

ポイント:

  • volumes: ..:/workspace でソースコードをコンテナに見せる
  • command: sleep infinity で VS Code が “開発用シェル”として使える状態にする
  • db は永続ボリューム pgdata を持たせて再起動でもデータ保持

4) devcontainer.json を書く(VS Code に“開き方”を教える)

.devcontainer/devcontainer.json

{
"name": "DevContainer Demo (Node + Postgres)",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace", "forwardPorts": [3000, 5432], "customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-azuretools.vscode-docker"
],
"settings": {
"editor.formatOnSave": true
}
}
}, "postCreateCommand": "npm ci || npm install",
"remoteUser": "node"
}

ポイント:

  • service: app により、VS Code は app コンテナに入る
  • forwardPorts でブラウザアクセスやDB接続がしやすくなる
  • postCreateCommand で初回セットアップを自動化
  • remoteUser: node により root 運用を避け、ファイル権限トラブルを減らす

5) VS Code で Dev Container を起動

  1. VS Code でプロジェクトを開く
  2. コマンドパレット → “Dev Containers: Reopen in Container”
  3. コンテナが立ち上がったら、VS Code のターミナルで:
npm run dev

ブラウザで http://localhost:3000 にアクセスし、DB時刻が出れば成功です。


6) “統一” が効く瞬間(チームでの使い方)

この状態をリポジトリにコミットすると、チームメンバーはこうなります。

  • リポジトリを開く
  • “Reopen in Container” を押す
  • 依存が自動で入り、DB も立ち、すぐ動く

「環境構築の差分」ではなく「コードの差分」に集中できます。
さらに、customizations.vscode.extensions によって Lint/Format が揃うので、PR のノイズも減ります。


まとめ

Dev Container は Dockerfile を“実行環境のため”に書くのではなく、**開発環境を“共有資産としてコード化する”**ための仕組みです。

  • devcontainer.json で IDE の体験(拡張、ポート、初期セットアップ)まで統一
  • Compose を使えば、DB/Redis など依存サービスも一緒に揃う
  • 新規参加者のオンボーディングが短くなり、環境差分のバグが減る
  • 開発環境がレビュー可能になり、いつの間にか手順が壊れる事故を防げる

「README の環境構築が長くなってきた」「個人のPC依存が増えてきた」と感じたら、Dev Container はかなり強い選択肢になります。


投稿日

カテゴリー:

投稿者:

タグ:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です