T-CREATOR

Docker で Dev Container を構築:VS Code/Codespaces で即戦力環境を配布

Docker で Dev Container を構築:VS Code/Codespaces で即戦力環境を配布

開発環境の構築は、新しいメンバーがチームに加わるときや、複数のプロジェクトを並行して進めるときに、多くの時間とストレスを生み出す原因となります。「このバージョンの Node.js じゃないと動かない」「Python の環境が壊れた」といった経験は、多くの開発者が一度は経験したことでしょう。

Dev Container(Development Container)は、こうした課題を根本から解決する仕組みです。Docker コンテナ内に開発環境を丸ごとパッケージ化し、VS Code や GitHub Codespaces と連携させることで、誰でも同じ環境で即座に開発を始められます。この記事では、Dev Container の構築方法から実践的な活用法まで、段階的に解説していきます。

背景

開発環境構築の課題

従来の開発環境構築では、以下のような問題が頻繁に発生していました。

開発者のローカルマシンには、さまざまなプログラミング言語のランタイムやツールがインストールされています。しかし、プロジェクトごとに必要なバージョンが異なると、環境の切り替えや管理が複雑になります。

また、「私のマシンでは動くのに」という言葉は、開発現場でよく聞かれるフレーズです。これは、開発者それぞれの環境設定が微妙に異なることが原因で発生します。

以下の図は、従来の開発環境における課題を示しています。

mermaidflowchart TD
  dev1["開発者A<br/>Node 18.x<br/>Python 3.10"]
  dev2["開発者B<br/>Node 16.x<br/>Python 3.9"]
  dev3["開発者C<br/>Node 20.x<br/>Python 3.11"]

  project["プロジェクト要件<br/>Node 18.x<br/>Python 3.10"]

  dev1 -->|環境一致| project
  dev2 -->|バージョン違い| project
  dev3 -->|バージョン違い| project

  style dev2 fill:#ffcccc
  style dev3 fill:#ffcccc

各開発者のマシンにインストールされているツールのバージョンが異なると、コードが正しく動作しない可能性が高まります。

Dev Container の登場

Dev Container は、Docker コンテナ技術を活用して、開発環境そのものをコード化する仕組みです。

プロジェクトのルートディレクトリに .devcontainer フォルダを配置し、その中に設定ファイルを記述するだけで、誰でも同じ環境を再現できます。VS Code や GitHub Codespaces と連携することで、エディタから直接コンテナ内で開発が行えるようになります。

以下は、Dev Container を導入した場合の環境構成です。

mermaidflowchart LR
  devA["開発者A"] -->|VS Code| container
  devB["開発者B"] -->|VS Code| container
  devC["開発者C"] -->|Codespaces| container

  container["Dev Container<br/>Node 18.x<br/>Python 3.10<br/>統一環境"]

  container -->|完全一致| project["プロジェクト要件"]

  style container fill:#ccffcc

すべての開発者が同一のコンテナイメージから生成された環境で作業するため、環境差異による問題が発生しません。

課題

開発環境の属人化

多くのプロジェクトでは、開発環境のセットアップ手順が README ファイルや Wiki に記載されています。しかし、手順書通りに進めても、OS の違いやすでにインストールされているツールとの競合で、環境構築に失敗することがあります。

新しいメンバーが参加するたびに、先輩開発者が環境構築をサポートする時間が必要になり、これが開発効率を下げる要因となっています。

プロジェクト間の環境切り替え

複数のプロジェクトを並行して担当する場合、それぞれのプロジェクトで必要なツールのバージョンが異なることがよくあります。

例えば、プロジェクト A では Node.js 16 系を使い、プロジェクト B では Node.js 20 系を使うといったケースです。nvm や pyenv などのバージョン管理ツールを使うこともできますが、切り替え忘れや設定ミスが発生しやすくなります。

本番環境との乖離

開発環境と本番環境の差異が大きいと、「開発では動いたのに本番でエラー」という問題が発生します。

Dev Container を使えば、本番環境と同じ OS やミドルウェアのバージョンを開発環境でも使用できるため、こうした乖離を最小限に抑えられます。

解決策

Dev Container の仕組み

Dev Container は、以下の要素で構成されています。

#要素役割
1.devcontainer​/​devcontainer.jsonDev Container の設定ファイル(イメージ、拡張機能、ポート転送など)
2Dockerfile または docker-compose.ymlコンテナイメージのビルド定義
3VS Code Remote - Containers 拡張機能VS Code から Dev Container に接続する機能
4GitHub Codespacesクラウド上で Dev Container を実行する環境

これらを組み合わせることで、誰でも同じ開発環境を簡単に起動できます。

以下の図は、Dev Container の起動フローを示しています。

mermaidsequenceDiagram
  participant User as 開発者
  participant VSCode as VS Code
  participant Docker as Docker
  participant Container as Dev Container

  User->>VSCode: プロジェクトを開く
  VSCode->>VSCode: .devcontainer/devcontainer.json を検出
  VSCode->>User: Dev Containerで開きますか?
  User->>VSCode: 承認
  VSCode->>Docker: イメージをビルド/取得
  Docker->>Container: コンテナを起動
  Container->>VSCode: 環境を接続
  VSCode->>User: エディタで開発開始

開発者がプロジェクトを開くと、VS Code が自動的に Dev Container の設定を検出し、コンテナを起動します。その後、エディタからコンテナ内のファイルシステムやターミナルに直接アクセスできるようになります。

Dev Container のメリット

Dev Container を導入することで、以下のメリットが得られます。

環境構築の自動化 設定ファイルをリポジトリに含めるだけで、誰でもワンクリックで開発環境を起動できます。新メンバーのオンボーディング時間が大幅に短縮されます。

環境の一貫性 すべての開発者が同じ Docker イメージから生成された環境で作業するため、「私のマシンでは動く」問題が解消されます。

プロジェクト間の分離 プロジェクトごとに独立したコンテナが起動するため、ツールのバージョン競合が発生しません。プロジェクトを切り替えるだけで、自動的に適切な環境に切り替わります。

本番環境との一致 本番環境で使用する OS やミドルウェアと同じバージョンを開発環境でも使用できるため、環境差異によるバグを未然に防げます。

具体例

基本的な Dev Container の構築

まず、シンプルな Node.js 開発環境の Dev Container を構築してみましょう。

プロジェクト構造の準備

プロジェクトのルートディレクトリに .devcontainer フォルダを作成します。

bashmkdir .devcontainer
cd .devcontainer

devcontainer.json の作成

.devcontainer​/​devcontainer.json ファイルを作成し、Dev Container の基本設定を記述します。

json{
  "name": "Node.js Dev Container",
  "image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}

このファイルでは、Dev Container の名前と使用する Docker イメージを指定しています。mcr.microsoft.com​/​devcontainers​/​javascript-node:18 は、Microsoft が公式に提供する Node.js 18 のイメージです。

VS Code で Dev Container を開く

VS Code でプロジェクトを開き、コマンドパレット(Cmd+Shift+P または Ctrl+Shift+P)から「Dev Containers: Reopen in Container」を選択します。

VS Code がコンテナをビルドして起動し、エディタがコンテナ内の環境に接続されます。ターミナルを開くと、コンテナ内のシェルが表示され、node --version で Node.js のバージョンを確認できます。

カスタム Dockerfile を使った構築

公式イメージだけでは要件を満たせない場合、独自の Dockerfile を作成してカスタマイズできます。

Dockerfile の作成

.devcontainer​/​Dockerfile を作成し、必要なツールをインストールします。

dockerfile# ベースイメージとしてNode.js 18を使用
FROM node:18-bullseye

# 追加のシステムパッケージをインストール
RUN apt-get update && apt-get install -y \
  git \
  curl \
  vim \
  && rm -rf /var/lib/apt/lists/*

この Dockerfile では、Node.js 18 の公式イメージをベースにし、追加で git、curl、vim をインストールしています。

Yarn のインストール

Yarn パッケージマネージャーを有効化します。

dockerfile# Yarnを有効化
RUN corepack enable && corepack prepare yarn@stable --activate

Node.js 16 以降には Corepack が同梱されており、これを使って Yarn を簡単にインストールできます。

ユーザー権限の設定

開発用のユーザーを作成し、適切な権限を設定します。

dockerfile# 開発用ユーザーを作成(rootでの作業を避ける)
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

RUN groupadd --gid $USER_GID $USERNAME \
  && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
  && apt-get update \
  && apt-get install -y sudo \
  && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
  && chmod 0440 /etc/sudoers.d/$USERNAME

USER $USERNAME

この設定により、コンテナ内で root 権限を使わずに開発作業ができるようになります。セキュリティの観点からも推奨される設定です。

devcontainer.json の更新

カスタム Dockerfile を使用するように devcontainer.json を更新します。

json{
  "name": "Node.js Custom Dev Container",
  "build": {
    "dockerfile": "Dockerfile",
    "context": ".."
  },
  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode"
      ]
    }
  }
}

build セクションで Dockerfile を指定し、customizations.vscode.extensions でコンテナ起動時に自動インストールする VS Code 拡張機能を指定しています。

docker-compose を使った複数コンテナ構成

実際のプロジェクトでは、アプリケーションだけでなく、データベースやキャッシュサーバーなど複数のサービスが必要になることがあります。

docker-compose.yml の作成

.devcontainer​/​docker-compose.yml を作成し、複数のサービスを定義します。

yamlversion: '3.8'

services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile
    volumes:
      - ..:/workspace:cached
    command: sleep infinity
    network_mode: service:db

app サービスは、開発用のメインコンテナです。volumes でホストのプロジェクトディレクトリをコンテナ内の ​/​workspace にマウントしています。

データベースサービスの追加

PostgreSQL データベースをサービスとして追加します。

yaml  db:
    image: postgres:15
    restart: unless-stopped
    environment:
      POSTGRES_USER: devuser
      POSTGRES_PASSWORD: devpassword
      POSTGRES_DB: devdb
    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:

データベースのデータは postgres-data という名前付きボリュームに永続化されるため、コンテナを再起動してもデータが失われません。

devcontainer.json の更新

docker-compose を使用するように設定を変更します。

json{
  "name": "Node.js with PostgreSQL",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",
  "forwardPorts": [5432],
  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "ckolkman.vscode-postgres"
      ]
    }
  }
}

dockerComposeFile で docker-compose.yml を指定し、service で開発用のメインサービス名を指定します。forwardPorts で PostgreSQL のポート 5432 をホストに転送し、ローカルのデータベースクライアントから接続できるようにしています。

以下の図は、docker-compose を使った複数コンテナ構成を示しています。

mermaidflowchart TB
  subgraph DevContainer["Dev Container 環境"]
    app["app コンテナ<br/>Node.js + Yarn<br/>開発ツール"]
    db["db コンテナ<br/>PostgreSQL 15"]

    app -->|データベース接続| db
  end

  vscode["VS Code"] -->|Remote接続| app
  vscode -->|ポート転送 5432| db

  workspace["/workspace<br/>プロジェクトファイル"] -.->|マウント| app

VS Code は app コンテナに接続し、app コンテナは db コンテナの PostgreSQL に接続します。プロジェクトファイルは両者で共有されます。

環境変数と設定ファイルの管理

Dev Container では、環境変数や設定ファイルを柔軟に管理できます。

環境変数の設定

devcontainer.json で環境変数を定義できます。

json{
  "name": "Node.js Dev Container",
  "build": {
    "dockerfile": "Dockerfile"
  },
  "containerEnv": {
    "NODE_ENV": "development",
    "API_URL": "http://localhost:3000"
  }
}

containerEnv に定義した環境変数は、コンテナ起動時に自動的に設定されます。

.env ファイルの利用

機密情報を含む環境変数は、.env ファイルで管理し、Git にコミットしないようにします。

.devcontainer​/​.env ファイルを作成します。

bashDATABASE_URL=postgresql://devuser:devpassword@db:5432/devdb
API_KEY=your_api_key_here

この.envファイルは必ず.gitignoreに追加し、リポジトリにコミットされないようにしてください。

docker-compose で .env を読み込む

docker-compose.yml.env ファイルを読み込むように設定します。

yamlversion: '3.8'

services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile
    volumes:
      - ..:/workspace:cached
    env_file:
      - .env
    command: sleep infinity

env_file.env を指定することで、ファイル内の環境変数がコンテナに自動的に設定されます。

GitHub Codespaces での利用

Dev Container の設定は、GitHub Codespaces でもそのまま利用できます。

リポジトリへの設定追加

Dev Container の設定ファイル(.devcontainer​/​devcontainer.json など)を Git リポジトリにコミットします。

bashgit add .devcontainer
git commit -m "Add Dev Container configuration"
git push

これだけで、GitHub Codespaces 上で Dev Container が利用可能になります。

Codespaces の起動

GitHub のリポジトリページで「Code」ボタンをクリックし、「Codespaces」タブから「Create codespace on main」を選択します。

数分でクラウド上に Dev Container 環境が構築され、ブラウザ上の VS Code で開発を開始できます。ローカルマシンに何もインストールすることなく、フル機能の開発環境が手に入ります。

Codespaces の設定カスタマイズ

Codespaces 固有の設定を追加することもできます。

json{
  "name": "Node.js Dev Container",
  "build": {
    "dockerfile": "Dockerfile"
  },
  "customizations": {
    "codespaces": {
      "openFiles": ["README.md", "src/index.ts"]
    }
  }
}

customizations.codespaces.openFiles で、Codespaces 起動時に自動的に開くファイルを指定できます。

以下の図は、GitHub Codespaces を使った Dev Container の利用フローです。

mermaidflowchart LR
  dev["開発者"] -->|ブラウザでアクセス| github["GitHub リポジトリ"]
  github -->|Codespaces起動| cloud["クラウド環境"]
  cloud -->|Dev Container構築| container["Dev Container"]
  container -->|VS Code Web| dev

  style cloud fill:#e1f5ff
  style container fill:#ccffcc

ローカル環境に依存せず、クラウド上で完全な開発環境を利用できます。

実践的な設定例:TypeScript + Next.js プロジェクト

実際のプロジェクトで使える、TypeScript と Next.js を使った Dev Container の設定例を紹介します。

Dockerfile の作成

.devcontainer​/​Dockerfile を作成します。

dockerfileFROM node:18-bullseye

# システムパッケージのインストール
RUN apt-get update && apt-get install -y \
  git \
  curl \
  vim \
  && rm -rf /var/lib/apt/lists/*

# Yarnの有効化
RUN corepack enable && corepack prepare yarn@stable --activate

基本的なツールと Yarn をインストールした Node.js 環境を構築します。

ユーザー設定とグローバルパッケージ

開発用ユーザーを作成し、グローバルパッケージをインストールします。

dockerfile# 開発用ユーザーの作成
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

RUN groupadd --gid $USER_GID $USERNAME \
  && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
  && apt-get update \
  && apt-get install -y sudo \
  && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
  && chmod 0440 /etc/sudoers.d/$USERNAME

# グローバルパッケージのインストール
RUN yarn global add typescript @types/node

USER $USERNAME

TypeScript と型定義をグローバルにインストールすることで、コンテナ内のどこでも TypeScript コマンドが使えるようになります。

docker-compose.yml の作成

.devcontainer​/​docker-compose.yml を作成します。

yamlversion: '3.8'

services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile
    volumes:
      - ..:/workspace:cached
      - node_modules:/workspace/node_modules
    command: sleep infinity
    ports:
      - '3000:3000'

volumes:
  node_modules:

node_modules を名前付きボリュームとして分離することで、ホストとコンテナ間のファイルシステムの違いによるパフォーマンス問題を回避できます。

devcontainer.json の作成

.devcontainer​/​devcontainer.json を作成します。

json{
  "name": "Next.js TypeScript Dev Container",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",
  "forwardPorts": [3000],
  "postCreateCommand": "yarn install",
  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "bradlc.vscode-tailwindcss"
      ],
      "settings": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "esbenp.prettier-vscode",
        "eslint.validate": [
          "javascript",
          "typescript",
          "javascriptreact",
          "typescriptreact"
        ]
      }
    }
  }
}

postCreateCommand でコンテナ作成後に自動的に yarn install が実行され、依存パッケージがインストールされます。また、VS Code の設定でファイル保存時の自動フォーマットを有効化しています。

開発の開始

VS Code でプロジェクトを開き、「Dev Containers: Reopen in Container」を実行します。

コンテナが起動したら、ターミナルで以下のコマンドを実行して開発サーバーを起動できます。

bashyarn dev

Next.js の開発サーバーがポート 3000 で起動し、ブラウザで http:​/​​/​localhost:3000 にアクセスするとアプリケーションが表示されます。

Dev Container の設定を共有する

チーム全体で Dev Container を活用するためのベストプラクティスを紹介します。

README への記載

プロジェクトの README.md に Dev Container の使い方を記載します。

markdown# 開発環境のセットアップ

このプロジェクトは Dev Container に対応しています。

## 必要な環境

- Docker Desktop
- Visual Studio Code
- Remote - Containers 拡張機能

## 起動方法

1. VS Code でこのプロジェクトを開く
2. コマンドパレット(Cmd+Shift+P)を開く
3. 「Dev Containers: Reopen in Container」を選択
4. コンテナのビルドと起動を待つ
5. ターミナルで `yarn dev` を実行

新しいメンバーがプロジェクトに参加したとき、この手順通りに進めるだけで開発を始められます。

テンプレートリポジトリの作成

よく使う構成をテンプレートリポジトリとして保存しておくと、新規プロジェクト立ち上げ時に便利です。

GitHub でリポジトリを作成する際、「Template repository」オプションを有効にすることで、他のプロジェクトからこのリポジトリをテンプレートとして利用できるようになります。

まとめ

Dev Container は、開発環境の構築と共有を劇的に簡素化する強力な仕組みです。

Docker コンテナに開発環境をパッケージ化することで、「私のマシンでは動く」問題を解消し、チーム全体で一貫性のある環境を維持できます。VS Code や GitHub Codespaces との統合により、エディタから直接コンテナ内で開発できる体験は、一度使うと手放せなくなるでしょう。

この記事で紹介した設定例をベースに、プロジェクトの要件に合わせてカスタマイズしてみてください。最初は小さく始めて、徐々に機能を追加していく方法がおすすめです。

Dev Container を導入することで、新メンバーのオンボーディング時間が大幅に短縮され、環境トラブルに費やす時間が減り、本来の開発業務に集中できるようになります。ぜひ、あなたのプロジェクトでも Dev Container を活用してみてください。

関連リンク