Dev Container入門 - チームで統一された開発環境を構築する


Dev Container(Development Container)は、Dockerコンテナ内に完全な開発環境を構築する仕組みです。VS CodeやJetBrains IDE、GitHub Codespacesと連携し、「自分の環境では動く」問題を根本的に解決します。

本記事では、Dev Containerの基本概念からdevcontainer.jsonの書き方、チームでの運用方法まで解説します。

Dev Containerとは?

Dev Containerは、開発環境をコードとして管理するための仕様(Dev Container Specification)です。プロジェクトに.devcontainer/devcontainer.jsonを置くことで、誰でも同じ環境で開発を始められます。

主な特徴

  • 再現可能: 全員が同じツール、同じバージョンで開発
  • 分離された環境: ホストOSを汚さない
  • 即座にセットアップ: cloneしたらすぐ開発開始
  • GitHub Codespaces対応: ブラウザから即座に開発可能
  • Feature: 再利用可能な機能モジュールで拡張

従来の方法との比較

方法セットアップ時間環境の一貫性ホストへの影響
ローカルインストール数時間低い大きい
Docker Compose中程度高い小さい
Vagrant長い高い小さい
Dev Container短い最も高いなし
GitHub Codespaces即座最も高いなし

セットアップ

前提条件

  • Docker Desktop または Podman
  • VS Code + Dev Containers拡張機能
# VS Code拡張機能のインストール
code --install-extension ms-vscode-remote.remote-containers

最小構成

プロジェクトルートに.devcontainer/devcontainer.jsonを作成します。

// .devcontainer/devcontainer.json
{
  "name": "My Project",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:22",
  "postCreateCommand": "npm install"
}

VS CodeでCmd+Shift+P → 「Dev Containers: Reopen in Container」でコンテナ内の開発環境が起動します。

devcontainer.jsonの書き方

基本構造

{
  // 表示名
  "name": "Node.js & TypeScript",

  // ベースイメージ(image または build を指定)
  "image": "mcr.microsoft.com/devcontainers/typescript-node:22",

  // Features(追加ツール)
  "features": {
    "ghcr.io/devcontainers/features/git:1": {},
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/devcontainers/features/docker-in-docker:2": {}
  },

  // ポートフォワーディング
  "forwardPorts": [3000, 5432],

  // VS Code設定
  "customizations": {
    "vscode": {
      "settings": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
        "editor.formatOnSave": true
      },
      "extensions": [
        "esbenp.prettier-vscode",
        "dbaeumer.vscode-eslint",
        "bradlc.vscode-tailwindcss"
      ]
    }
  },

  // ライフサイクルコマンド
  "postCreateCommand": "npm install",
  "postStartCommand": "npm run dev",
  "postAttachCommand": "echo 'Welcome to the dev container!'"
}

カスタムDockerfileを使う

より細かいカスタマイズが必要な場合は、Dockerfileを使います。

// .devcontainer/devcontainer.json
{
  "name": "Custom Environment",
  "build": {
    "dockerfile": "Dockerfile",
    "context": "..",
    "args": {
      "NODE_VERSION": "22"
    }
  }
}
# .devcontainer/Dockerfile
ARG NODE_VERSION=22
FROM mcr.microsoft.com/devcontainers/typescript-node:${NODE_VERSION}

# 追加ツールのインストール
RUN apt-get update && apt-get install -y \
    postgresql-client \
    redis-tools \
    && rm -rf /var/lib/apt/lists/*

# グローバルnpmパッケージ
RUN npm install -g tsx prisma turbo

Docker Composeとの連携

データベースなど複数のサービスが必要な場合:

// .devcontainer/devcontainer.json
{
  "name": "Full Stack",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",
  "forwardPorts": [3000, 5432, 6379],
  "postCreateCommand": "npm install && npx prisma migrate dev"
}
# .devcontainer/docker-compose.yml
version: '3.8'

services:
  app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile
    volumes:
      - ..:/workspace:cached
    command: sleep infinity
    environment:
      - DATABASE_URL=postgresql://postgres:password@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=myapp
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine

volumes:
  pgdata:

Features

Dev Container Featuresは、再利用可能な機能モジュールです。Dockerfileを書かなくても、必要なツールを宣言的に追加できます。

よく使うFeatures

{
  "features": {
    // Git
    "ghcr.io/devcontainers/features/git:1": {
      "version": "latest"
    },
    // GitHub CLI
    "ghcr.io/devcontainers/features/github-cli:1": {},
    // Docker in Docker
    "ghcr.io/devcontainers/features/docker-in-docker:2": {},
    // AWS CLI
    "ghcr.io/devcontainers/features/aws-cli:1": {},
    // Terraform
    "ghcr.io/devcontainers/features/terraform:1": {},
    // Python
    "ghcr.io/devcontainers/features/python:1": {
      "version": "3.12"
    },
    // Rust
    "ghcr.io/devcontainers/features/rust:1": {
      "version": "latest"
    },
    // Go
    "ghcr.io/devcontainers/features/go:1": {
      "version": "1.22"
    }
  }
}

カスタムFeatureの作成

チーム固有のツールセットをFeatureとしてパッケージ化できます。

// src/my-feature/devcontainer-feature.json
{
  "id": "my-team-tools",
  "version": "1.0.0",
  "name": "My Team Tools",
  "options": {
    "version": {
      "type": "string",
      "default": "latest"
    }
  }
}
#!/bin/bash
# src/my-feature/install.sh
set -e

# チーム固有のツールをインストール
npm install -g @team/cli-tool@${VERSION:-latest}

# 設定ファイルのコピー
cp /tmp/team-config.json /home/vscode/.team-config.json

実践例: フルスタックプロジェクト

Next.js + Prisma + PostgreSQL

// .devcontainer/devcontainer.json
{
  "name": "Next.js Full Stack",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",
  "features": {
    "ghcr.io/devcontainers/features/github-cli:1": {}
  },
  "forwardPorts": [3000, 5555],
  "customizations": {
    "vscode": {
      "settings": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
          "source.fixAll.eslint": "explicit"
        },
        "typescript.preferences.importModuleSpecifier": "non-relative"
      },
      "extensions": [
        "esbenp.prettier-vscode",
        "dbaeumer.vscode-eslint",
        "bradlc.vscode-tailwindcss",
        "prisma.prisma",
        "ms-azuretools.vscode-docker"
      ]
    }
  },
  "postCreateCommand": "npm install && npx prisma generate && npx prisma migrate dev",
  "postStartCommand": "npx prisma studio &"
}

Rust + WebAssembly

{
  "name": "Rust + WASM",
  "image": "mcr.microsoft.com/devcontainers/rust:1",
  "features": {
    "ghcr.io/devcontainers/features/node:1": {
      "version": "22"
    }
  },
  "customizations": {
    "vscode": {
      "extensions": [
        "rust-lang.rust-analyzer",
        "tamasfe.even-better-toml",
        "vadimcn.vscode-lldb"
      ]
    }
  },
  "postCreateCommand": "rustup target add wasm32-unknown-unknown && cargo install wasm-pack trunk"
}

Python + FastAPI + ML

{
  "name": "Python ML",
  "image": "mcr.microsoft.com/devcontainers/python:3.12",
  "features": {
    "ghcr.io/devcontainers/features/node:1": {}
  },
  "customizations": {
    "vscode": {
      "settings": {
        "python.defaultInterpreterPath": "/usr/local/bin/python",
        "python.formatting.provider": "black"
      },
      "extensions": [
        "ms-python.python",
        "ms-python.vscode-pylance",
        "ms-toolsai.jupyter"
      ]
    }
  },
  "postCreateCommand": "pip install -r requirements.txt && pip install -e '.[dev]'"
}

GitHub Codespacesとの連携

Dev Containerの設定は、GitHub Codespacesでそのまま使えます。

Codespaces用の最適化

{
  "name": "Optimized for Codespaces",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:22",

  // Codespacesのマシンタイプ指定
  "hostRequirements": {
    "cpus": 4,
    "memory": "8gb",
    "storage": "32gb"
  },

  // プリビルドの最適化
  "updateContentCommand": "npm install",
  "postCreateCommand": "npm run build",

  // GitHub Codespaces固有の設定
  "customizations": {
    "codespaces": {
      "openFiles": ["README.md", "src/index.ts"]
    }
  }
}

Prebuild設定

# .github/workflows/codespaces-prebuild.yml
name: Codespaces Prebuild
on:
  push:
    branches: [main]
    paths:
      - '.devcontainer/**'
      - 'package-lock.json'

jobs:
  prebuild:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: devcontainers/ci@v0.3
        with:
          push: always
          imageName: ghcr.io/${{ github.repository }}/devcontainer

チーム運用のベストプラクティス

1. 設定をリポジトリにコミットする

# .devcontainerディレクトリをGitに含める
git add .devcontainer/
git commit -m "Add dev container configuration"

2. 環境変数の管理

// .devcontainer/devcontainer.json
{
  // 開発用のデフォルト値
  "containerEnv": {
    "NODE_ENV": "development",
    "LOG_LEVEL": "debug"
  },
  // シークレットはファイルで管理(.gitignoreに追加)
  "runArgs": ["--env-file", ".devcontainer/.env.local"]
}
# .devcontainer/.env.local(.gitignoreに追加)
API_KEY=your-api-key
DATABASE_URL=postgresql://...

3. パフォーマンスの最適化

{
  // ボリュームマウントのキャッシュ
  "mounts": [
    "source=node-modules-cache,target=${containerWorkspaceFolder}/node_modules,type=volume",
    "source=pnpm-store,target=/home/vscode/.local/share/pnpm/store,type=volume"
  ],

  // .gitやnode_modulesの除外
  "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached"
}

4. マルチプラットフォーム対応

{
  "build": {
    "dockerfile": "Dockerfile",
    "args": {
      "TARGETPLATFORM": "${localArch}"
    }
  }
}

ライフサイクルコマンド

Dev Containerのライフサイクルに合わせて、適切なタイミングでコマンドを実行できます。

initializeCommand      → コンテナ作成前(ホスト側で実行)
onCreateCommand        → コンテナ初回作成時のみ
updateContentCommand   → コンテナ作成時 + コンテンツ更新時
postCreateCommand      → コンテナ作成後(初回 + リビルド時)
postStartCommand       → コンテナ起動時(毎回)
postAttachCommand      → VS Code接続時(毎回)
{
  "initializeCommand": "echo 'ホスト側の準備...'",
  "onCreateCommand": "git config --global core.editor 'code --wait'",
  "updateContentCommand": "npm ci",
  "postCreateCommand": {
    "db-setup": "npx prisma migrate dev",
    "seed": "npx prisma db seed"
  },
  "postStartCommand": "npm run dev &",
  "postAttachCommand": "echo '開発環境の準備が完了しました'"
}

トラブルシューティング

コンテナが起動しない

# Dev Containerのログ確認
# VS Code: Cmd+Shift+P → "Dev Containers: Show Container Log"

# Docker側のログ
docker logs <container-id>

ビルドが遅い

{
  // レイヤーキャッシュの活用
  "build": {
    "cacheFrom": "ghcr.io/your-org/devcontainer:latest"
  }
}

拡張機能が動作しない

{
  "customizations": {
    "vscode": {
      // コンテナ内にインストールする拡張機能
      "extensions": ["ms-python.python"],
      "settings": {
        // コンテナ内のパスを指定
        "python.defaultInterpreterPath": "/usr/local/bin/python"
      }
    }
  }
}

ファイル権限の問題

{
  // コンテナ内ユーザーの指定
  "remoteUser": "vscode",
  "containerUser": "vscode",

  // UID/GIDのマッピング
  "updateRemoteUserUID": true
}

まとめ

Dev Containerは開発環境の標準化に最適な仕組みです。

導入すべきケース

  • チーム開発: 新メンバーの環境構築を数分に短縮
  • OSS開発: コントリビューターがすぐに開発を始められる
  • マルチプロジェクト: プロジェクトごとに異なる環境を分離
  • CI/CD統合: ローカルとCIで同じ環境を使用

学習リソース

まずは既存プロジェクトに.devcontainer/devcontainer.jsonを1つ追加することから始めてみてください。チーム全体の開発体験が大きく向上します。

関連記事