Dev Container の features を使う理由：Dockerfile との使い分けを理解する

# はじめに

Dev Container を使い始めたとき、こんな疑問を持ったことはありませんか？

「Dockerfile でツールをインストールできるのに、なぜ devcontainer.json の features を使うの？」

今回は、この疑問に答えながら、features と Dockerfile の使い分けについて詳しく解説します。

# 結論：役割が違います

簡単に言うと：
- **Dockerfile** = アプリケーションの実行環境を構築
- **features** = 開発者の作業環境を拡張

この違いを理解すると、適切な使い分けができるようになります。

# features とは何か？

features は、Dev Container の開発環境に機能を追加するための仕組みです。

```json
{
  "features": {
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/devcontainers/features/azure-cli:1": {},
    "ghcr.io/devcontainers/features/node:1": {
      "version": "18"
    }
  }
}
```

このように書くだけで、GitHub CLI、Azure CLI、Node.js が自動的にインストールされます。

# なぜ features が生まれたのか？

## 1. 開発環境の標準化

Dockerfile だけで開発環境を構築すると、チームメンバーごとに微妙な差異が生まれがちです。

```dockerfile
# 開発者A の Dockerfile
RUN apt-get update && apt-get install -y git vim

# 開発者B の Dockerfile  
RUN apt-get update && apt-get install -y git nano curl
```

features を使えば、必要なツールセットを標準化できます。

## 2. 再利用性の向上

よく使う開発ツールの組み合わせを、プロジェクト間で簡単に共有できます。

```json
// Python プロジェクトの定番セット
{
  "features": {
    "ghcr.io/devcontainers/features/python:1": {},
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/devcontainers-contrib/features/poetry:2": {},
    "ghcr.io/devcontainers-contrib/features/pre-commit:2": {}
  }
}
```

## 3. メンテナンスの簡素化

features は自動的に更新され、最新のベストプラクティスが反映されます。Dockerfile で手動管理する必要がありません。

# 具体的な使い分け

## features を使うべき場合

### 1. 一般的な開発ツール

```json
{
  "features": {
    // Git 関連
    "ghcr.io/devcontainers/features/github-cli:1": {},
    
    // クラウド CLI
    "ghcr.io/devcontainers/features/aws-cli:1": {},
    
    // 言語ランタイム
    "ghcr.io/devcontainers/features/go:1": {},
    
    // コンテナツール
    "ghcr.io/devcontainers/features/docker-in-docker:2": {}
  }
}
```

### 2. VS Code 拡張機能との連携

```json
{
  "features": {
    "ghcr.io/devcontainers/features/java:1": {
      "version": "17",
      "installMaven": true
    }
  },
  "customizations": {
    "vscode": {
      "extensions": [
        "vscjava.vscode-java-pack"
      ]
    }
  }
}
```

### 3. チーム共通の開発ツール

```json
{
  "features": {
    // チーム標準のリンター・フォーマッター
    "ghcr.io/devcontainers-contrib/features/prettier:1": {},
    "ghcr.io/devcontainers-contrib/features/eslint:1": {},
    
    // チーム標準の開発支援ツール
    "ghcr.io/devcontainers-contrib/features/jq:1": {},
    "ghcr.io/devcontainers-contrib/features/yq:1": {}
  }
}
```

## Dockerfile を使うべき場合

### 1. アプリケーション固有の依存関係

```dockerfile
# 特定バージョンのライブラリが必要
FROM node:18-alpine

# アプリケーションに必要な特殊なパッケージ
RUN apk add --no-cache \
    libc6-compat \
    python3 \
    make \
    g++

# カスタムビルドツール
RUN npm install -g custom-build-tool@2.3.4
```

### 2. OS レベルの設定

```dockerfile
# タイムゾーン設定
ENV TZ=Asia/Tokyo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime

# システムユーザーの作成
RUN useradd -m -s /bin/bash appuser

# カーネルパラメータの調整
RUN echo "vm.max_map_count=262144" >> /etc/sysctl.conf
```

### 3. 複雑なセットアップ手順

```dockerfile
# 外部リポジトリからのインストール
RUN curl -fsSL https://example.com/install.sh | bash

# 複数ステップのビルドプロセス
WORKDIR /tmp
RUN git clone https://github.com/example/tool.git && \
    cd tool && \
    ./configure --prefix=/usr/local && \
    make && \
    make install
```

# 実践的な例：フルスタックアプリケーション

## devcontainer.json

```json
{
  "name": "Full Stack App",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",
  
  // 開発に必要なツールは features で
  "features": {
    "ghcr.io/devcontainers/features/node:1": {
      "version": "18"
    },
    "ghcr.io/devcontainers/features/python:1": {
      "version": "3.11"
    },
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/devcontainers/features/aws-cli:1": {},
    "ghcr.io/devcontainers/features/docker-in-docker:2": {}
  },
  
  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "ms-python.python"
      ]
    }
  },
  
  "postCreateCommand": "npm install && pip install -r requirements.txt"
}
```

## Dockerfile

```dockerfile
FROM ubuntu:22.04

# アプリケーション実行に必要な環境のみ
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

# アプリケーション固有の設定
ENV NODE_ENV=development
ENV PYTHONUNBUFFERED=1

WORKDIR /workspace

# アプリケーションの依存関係
COPY package.json package-lock.json ./
RUN npm ci --only=production

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

EXPOSE 3000
```

# features の高度な使い方

## 1. カスタム features の作成

組織固有のツールセットを features として定義できます。

```json
{
  "features": {
    "./local-features/company-tools": {}
  }
}
```

## 2. features の設定カスタマイズ

```json
{
  "features": {
    "ghcr.io/devcontainers/features/node:1": {
      "version": "lts",
      "nodeGypDependencies": true,
      "nvmInstallPath": "/usr/local/share/nvm"
    }
  }
}
```

## 3. 条件付き features

```json
{
  "features": {
    "ghcr.io/devcontainers/features/powershell:1": {
      "version": "latest"
    }
  },
  "overrideFeatureInstallOrder": [
    "ghcr.io/devcontainers/features/common-utils",
    "ghcr.io/devcontainers/features/powershell"
  ]
}
```

# ベストプラクティス

## 1. レイヤーの分離を意識する

```
アプリケーション層（Dockerfile）
  ├── OS設定
  ├── システムパッケージ
  └── アプリケーション依存関係

開発ツール層（features）
  ├── CLI ツール
  ├── 言語ランタイム
  └── 開発支援ツール
```

## 2. チーム間での共有を前提に設計

```json
{
  // 必須の features
  "features": {
    "ghcr.io/devcontainers/features/common-utils:2": {
      "installZsh": true,
      "username": "vscode",
      "upgradePackages": true
    }
  },
  
  // オプションの features はコメントで提供
  // "ghcr.io/devcontainers/features/rust:1": {}
}
```

## 3. パフォーマンスを考慮

```json
{
  // 必要最小限の features のみインストール
  "features": {
    "ghcr.io/devcontainers/features/git:1": {
      "version": "latest",
      "ppa": false  // 不要なリポジトリ追加を避ける
    }
  }
}
```

# トラブルシューティング

## features が動かない場合

1. **互換性の確認**
   ```json
   {
     "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
     // この base イメージは features 対応
   }
   ```

2. **features のバージョン指定**
   ```json
   {
     "features": {
       "ghcr.io/devcontainers/features/node:1": {
         // 明示的なバージョン指定で問題を回避
         "version": "18.17.0"
       }
     }
   }
   ```

3. **ログの確認**
   Dev Container の作成ログで features のインストール状況を確認できます。

# まとめ

- **features** は開発環境の拡張に特化した仕組み
- **Dockerfile** はアプリケーションの実行環境構築に集中
- 適切に使い分けることで、保守性と再利用性が向上

Dev Container を使いこなすには、この使い分けが重要です。チームで開発環境を統一したい場合は、積極的に features を活用しましょう。

# 参考リンク

- [Dev Container Features 公式リポジトリ](https://github.com/devcontainers/features)
- [利用可能な features 一覧](https://containers.dev/features)
- [カスタム features の作成方法](https://containers.dev/implementors/features/)