AIエージェントを使った開発は効率爆上がりだけど
Cursor、Github Copilot、Windsurfなどを使った開発は効率が良いですが、調子に乗って複数プロダクトを並行して開発を行っていると頻繁に事故が発生します。他のAIエージェントが起動したDockerコンテナを削除してしまう、とか。本記事ではそのような悲しい事故を防ぐ方法について考察しました。
はじめに
最近では、Cursor、Github Copilot、WindsurfなどのAIを活用してコード開発を行う「AIエージェント開発」の手法が広がっています。こうしたAIエージェントは複数のプロジェクトを並行して進めるときに便利ですが、特にDockerコンテナを使った開発では様々な競合問題が発生する可能性があります。
この記事では、1台のWindows PCで複数のAIエージェントを使ったコンテナ開発で発生しうる問題と、その対策について体系的に解説します。特にWindowsにおけるDockerとWSL2の関係性を踏まえた分離手法に焦点を当てます。最後に、AIエージェントに与えるプロンプトも付けました。
Windowsにおける Docker と WSL2 の関係
現在のDocker Desktop for Windowsは、デフォルトでWSL2をバックエンドとして使用しています。これは重要なポイントです。
- Windowsで「Docker Desktop」をインストールすると、自動的に「docker-desktop」と「docker-desktop-data」という2つのWSL2ディストリビューションが作成されます。
- Dockerコンテナは実際にはこのWSL2環境内で実行されています。
- Windowsユーザーが明示的にWSL2を使わなくても、Docker Desktop for Windowsを使っていれば、バックグラウンドで自動的にWSL2が使われています。
つまり、WSL2を直接操作していないプロジェクトであっても、Windows上でDockerを使っている限り、WSL2がDockerの実行基盤となっています。この理解は後述する分離手法の選択に重要です。
発生しうる問題
1. ポート競合
- 複数のコンテナが同じポート(80、3000、8080など)を使おうとする
- Webサーバー、データベース、APIサーバーなどで特に発生しやすい
2. リソース競合
- CPU、メモリ、ディスクI/Oの奪い合い
- 一方のコンテナがリソースを大量消費すると他方が遅延・停止する可能性
3. 名前空間の衝突
- 同じコンテナ名、ネットワーク名、ボリューム名の重複
docker: Error response from daemon: Conflict. The container name "xxx" is already in use.
4. 共有リソース削除
- 他のプロジェクトが使用中のボリュームやネットワークを誤って削除
- データ損失やネットワーク接続不能の原因に
5. ホストパス競合
- 同じホストパスをマウントポイントとして使用
- ファイルの上書きや予期せぬ変更が発生
開発環境が壊れる具体例
-
例1: プロジェクトAのクリーンアップ時に
docker system prune -a
を実行し、プロジェクトBのイメージも削除される - 例2: 共有データボリュームを削除し、別プロジェクトのデータが失われる
- 例3: 依存関係のあるコンテナ(データベースなど)を停止/削除し、他プロジェクトの接続先を失わせる
- 例4: 同じネットワーク名を使用することで、コンテナ間の誤った通信が発生
Docker環境の分離レベル体系
WindowsでのDocker開発における分離手法は、保護の強さに応じて以下のように階層化できます。
- WSL2分離(最上位): 別のDockerエンジンによる最強の分離
- Docker Context: 接続設定の分離で操作対象を明確化
- Docker Compose: プロジェクト単位での一貫した命名と管理
- ネットワーク分離: コンテナ間通信の境界を確立
- リソース制限: CPU/メモリ制限による競合防止
- 命名規則(最下層): プレフィックスによる論理的分離
各レベルは異なる問題を解決し、プロジェクトの要件に応じて適切なレベルを選択または組み合わせることができます。
1. WSL2インスタンスによる分離(最強)
- 分離の範囲: Dockerエンジン自体を分離
- 特徴: 別々のDockerエンジンが動作、リソースカタログが完全に独立
- 防げる問題: ボリューム誤削除、イメージ混在、エンジン設定競合など
-
コマンド例:
wsl -d ProjectA-Dev -e docker-compose up
2. Docker Contextによる分離
- 分離の範囲: Docker CLIの接続設定の分離
- 特徴: 同一エンジンへの接続設定を切り替え
- 防げる問題: 操作対象の混同、異なる環境への誤操作
-
コマンド例:
docker context use projectA
3. Docker Composeプロジェクト名による分離
- 分離の範囲: コンテナ、ネットワーク、ボリュームの自動プレフィックス化
- 特徴: プロジェクト単位での一貫した命名
- 防げる問題: リソース名の衝突、関連リソースの識別ミス
-
コマンド例:
docker-compose -p projectA up -d
4. ネットワーク分離
- 分離の範囲: コンテナ間通信の境界
- 特徴: 異なるネットワーク内のコンテナは直接通信不可
- 防げる問題: コンテナ間通信の混線、不正アクセス
-
コマンド例:
docker network create projectA-net
5. リソース制限による分離
- 分離の範囲: CPU、メモリなどの利用リソース
- 特徴: コンテナごとに利用可能なリソースを制限
- 防げる問題: リソース競合、一方のプロジェクトによる資源枯渇
-
コマンド例:
docker run --memory=2g --cpus=2 ‹イメージ名›
6. 命名規則による分離(最弱)
- 分離の範囲: リソース名の視認性
- 特徴: プレフィックスなどで区別するだけの論理的分離
- 防げる問題: 視認性の問題のみ(物理的な保護なし)
-
コマンド例:
docker run --name projectA-web nginx
各分離レベルの詳細と実装方法
1. WSL2インスタンスによる分離
WSL2インスタンスを分離すると、完全に独立したDockerエンジンを使用できます。これにより、他の環境への影響を物理的に防止できます。
防げる問題
- ボリューム・イメージの誤削除
- Docker設定の競合
- リソースカタログの混在
防げない問題
- ホストのポート競合(同じポートを使おうとすると競合)
- 物理リソース(CPU、メモリ)の競合
実装方法
# 新しいWSL2インスタンス作成(Ubuntu 20.04のディストリビューションファイルを使用)
wsl --import ProjectA-Dev C:\WSL\ProjectA-Dev C:\path\to\ubuntu-20.04-server-cloudimg-amd64-wsl.rootfs.tar.gz
# 特定のWSL2インスタンスでDockerコマンド実行
wsl -d ProjectA-Dev -e docker-compose up -d
注意点
- 各WSL2インスタンスにDockerを個別にインストールする必要がある
- 常に
-d
オプションでインスタンスを指定する必要がある -
wsl --set-default
はグローバル設定のため、複数環境を同時に運用する場合は常に明示的に指定する
2. Docker Contextによる分離
Docker Contextは同一エンジン内での接続設定を分離します。主に管理の観点で有用です。
# コンテキスト作成
docker context create projectA
docker context create projectB
# コンテキスト切り替え
docker context use projectA
# 現在のコンテキストでコマンド実行
docker ps
Docker ContextとDocker Composeの組み合わせ
Docker ContextとDocker Composeは組み合わせて使用することも可能です。この組み合わせにより、より強力な分離と管理が実現できます。
# 特定のコンテキストでDocker Composeを実行
docker-compose --context projectA -p projectA up -d
# または環境変数でコンテキストを設定
export DOCKER_CONTEXT=projectA
docker-compose -p projectA up -d
この方法では、Composeプロジェクト名による命名規則の分離と、Contextによる操作対象の分離を組み合わせることで、二重の安全性を確保できます。
3. Docker Composeによるプロジェクト分離
-p
フラグを使用してプロジェクト名を指定し、リソースを分離します。
# プロジェクトA
docker-compose -p projectA up -d
# プロジェクトB
docker-compose -p projectB up -d
docker-compose.yml内でもプロジェクト固有の名前を使用します:
version: '3'
services:
web:
container_name: ${COMPOSE_PROJECT_NAME:-projectA}-web
image: nginx
ports:
- "${WEB_PORT:-8001}:80"
db:
container_name: ${COMPOSE_PROJECT_NAME:-projectA}-db
image: postgres
volumes:
- ${COMPOSE_PROJECT_NAME:-projectA}-data:/var/lib/postgresql/data
volumes:
${COMPOSE_PROJECT_NAME:-projectA}-data:
name: ${COMPOSE_PROJECT_NAME:-projectA}-data
4. ポート割り当ての管理
プロジェクトごとにポート範囲を決めて競合を防ぎます。
プロジェクトA: 8000-8099
プロジェクトB: 8100-8199
プロジェクトC: 8200-8299
マッピング例:
# プロジェクトA
docker run -p 8001:80 -p 8002:3000 -p 8003:5432 --name projectA-stack ...
# プロジェクトB
docker run -p 8101:80 -p 8102:3000 -p 8103:5432 --name projectB-stack ...
5. リソース制限の設定
コンテナごとにリソース使用量を制限して、一つのプロジェクトが全リソースを消費しないようにします。
# メモリとCPU制限の例
docker run --memory=2g --cpus=2 --name projectA-app ...
docker run --memory=1g --cpus=1 --name projectB-app ...
Docker Composeの場合:
services:
web:
image: myapp
deploy:
resources:
limits:
cpus: '2'
memory: 2G
6. 命名規則による分離
すべてのリソース(コンテナ、イメージ、ボリューム、ネットワーク)に一貫したプレフィックスを付けます。
# コンテナ命名例
docker run --name projectA-webserver -d nginx
docker run --name projectB-webserver -d nginx
# ネットワーク命名例
docker network create projectA-network
docker network create projectB-network
分離レベルの選択と実装難易度
以下の表は、各分離手法の実装難易度と提供する保護レベルを比較したものです。これにより、プロジェクトの要件に応じて適切な分離方法を選択できます。
分離手法 | 実装の難易度 | 保護の強さ | 日常操作の手間 | 最適な用途 |
---|---|---|---|---|
WSL2分離 | 高 | ★★★★★ | 高 | ボリューム誤削除防止、完全分離が必要な場合 |
Context | 中 | ★★★☆☆ | 中 | 異なる環境への切り替えが頻繁な場合 |
Compose | 低 | ★★★☆☆ | 低 | 通常の複数プロジェクト管理 |
Context + Compose | 中 | ★★★★☆ | 中 | 複数環境の管理と名前空間の分離が必要な場合 |
ネットワーク | 低 | ★★☆☆☆ | 低 | 通信分離が主目的の場合 |
リソース制限 | 低 | ★★☆☆☆ | 低 | リソース競合が問題になる場合 |
命名規則 | 最低 | ★☆☆☆☆ | 最低 | 簡易的な分離のみ必要な場合 |
分離レベルの組み合わせパターン
実際の開発環境では、複数の分離手法を組み合わせることで、より堅牢な環境を構築できます。特に「Context + Compose」の組み合わせは、実装の難易度と保護の強さのバランスが良く、多くのユースケースで推奨されます。
## 安全なクリーンアップと環境管理
### スクリプトによる安全な管理
開発環境の起動/停止/削除を自動化するスクリプトを作成し、削除前の確認プロセスを組み込むことで、誤操作を防止できます。
```powershell
# 例: PowerShellスクリプト
function Stop-Project {
param (
[Parameter(Mandatory=$true)]
[string]$ProjectName
)
Write-Host "Stopping $ProjectName containers..."
docker-compose -p $ProjectName down
}
function Remove-Project {
param (
[Parameter(Mandatory=$true)]
[string]$ProjectName,
[Parameter(Mandatory=$false)]
[switch]$RemoveVolumes
)
# 対象ボリューム一覧表示
Write-Host "Following volumes will be removed:" -ForegroundColor Yellow
docker volume ls --filter name=$ProjectName
# 確認プロンプト
$confirmation = Read-Host "Are you sure you want to remove project $ProjectName? (y/n)"
if ($confirmation -ne 'y') {
Write-Host "Operation cancelled"
return
}
if ($RemoveVolumes) {
docker-compose -p $ProjectName down -v
} else {
docker-compose -p $ProjectName down
}
}
WSL2全体管理スクリプト
WSL2インスタンスを使った分離環境を管理するためのスクリプト例:
# PowerShellスクリプト: Start-ProjectWSL.ps1
param (
[Parameter(Mandatory=$true)]
[string]$ProjectName
)
# WSL2インスタンスの確認と作成
$wslExists = wsl --list | Select-String $ProjectName
if (-not $wslExists) {
Write-Host "Creating new WSL2 instance for $ProjectName..."
# WSL2インスタンスを作成
wsl --import $ProjectName "C:\WSL\$ProjectName" "C:\path\to\ubuntu-20.04-server-cloudimg-amd64-wsl.rootfs.tar.gz"
# 新しいWSL2インスタンスにDockerをインストール
wsl -d $ProjectName -e bash -c "apt-get update && apt-get install -y docker.io"
wsl -d $ProjectName -e bash -c "systemctl start docker"
}
# プロジェクトディレクトリの作成と設定
wsl -d $ProjectName -e bash -c "mkdir -p /projects/$ProjectName"
# プロジェクトを起動
Write-Host "Starting $ProjectName in its own WSL2 instance..."
wsl -d $ProjectName -e bash -c "cd /projects/$ProjectName && docker-compose -p $ProjectName up -d"
Write-Host "$ProjectName environment is ready!"
Write-Host "To run commands in this environment, use: wsl -d $ProjectName -e docker ..."
推奨される組み合わせパターン
プロジェクトの重要度と分離ニーズに応じて、以下の組み合わせがおすすめです。
初級者向け簡易分離(低保護・低労力)
- Composeプロジェクト名 + 命名規則 + ポート範囲管理
- 例:
docker-compose -p projectA up -d
+ 命名規則に従ったリソース名
中級者向け標準分離(中保護・中労力)
- Composeプロジェクト名 + Context + ネットワーク分離 + リソース制限
- 例: Contextで環境を切り替え + Composeで統一的な管理 + リソース制限
上級者向け完全分離(高保護・高労力)
- WSL2分離 + Composeプロジェクト名 + リソース制限
- 例: 各プロジェクト専用WSL2インスタンス + その中でのCompose管理
AIエージェントに与えるプロンプト例
AIエージェントを使ってコンテナ開発を行う際には、事前に適切な指示を与えることで競合問題を防ぐことができます。分離レベルに応じたプロンプト例を紹介します。
基本的な分離のプロンプト
あなたは私の開発アシスタントです。Dockerコンテナを使用した開発環境を構築するにあたり、以下の点に注意してください:
1. プロジェクト名: [プロジェクト名]
2. 使用ポート範囲: 8100-8199
3. 命名規則: すべてのリソース(コンテナ、ネットワーク、ボリューム)には "[プロジェクト名]-" というプレフィックスを付けること
4. リソース制限: コンテナのメモリ上限は2GB、CPU上限は2コアとすること
5. Docker Composeを使用する場合は、プロジェクト名を明示的に指定すること
これらの条件を守りながら、[具体的な開発タスク]の実装方法を教えてください。
WSL2分離を使用するプロンプト
あなたは私の開発アシスタントです。1台のWindows PCで複数のAIエージェントを使った開発を行うため、WSL2インスタンスを分離して使用します。
1. プロジェクト名: [プロジェクト名]
2. 使用するWSL2インスタンス: [プロジェクト名]-Dev
3. WSL2インスタンス内でのDocker Composeプロジェクト名: [プロジェクト名]
4. ポート範囲: 8200-8299
5. リソース制限: 適切なCPU/メモリ制限を設定
以下のタスクを実行する手順を教えてください:
1. 専用WSL2インスタンスの作成(既存のディストリビューションからコピー)
2. そのWSL2インスタンス内にDockerをインストール
3. WSL2インスタンス内でのDocker Compose環境の構築
4. [具体的な開発タスク]の実装方法
すべてのコマンドは、Windows PowerShellからWSL2インスタンスを指定して実行する形式で示してください。
複数プロジェクト環境での開発プロンプト
私は1台のWindows PCで複数のプロジェクトを同時に開発しています。新しく[プロジェクト名]の開発環境を構築したいと思います。
既存環境との競合を避けるために、以下の条件を守ってDockerコンテナ構成を設計してください:
1. ポート範囲: 82xx番台を使用すること(他のプロジェクトは80xx, 81xxを使用中)
2. リソース名: すべて "[プロジェクト名]-" プレフィックスを付けること
3. 分離方法: Docker Composeで `-p [プロジェクト名]` フラグを使うこと
4. リソース制限: メモリとCPUに適切な制限を設けること
5. 削除方法: 安全にクリーンアップできる手順も含めること
上記を考慮した[必要な技術スタック]の構成と、docker-compose.ymlファイルを提案してください。
Docker Context活用プロンプト
私は複数のDocker環境を切り替えながら開発しています。Docker Contextを使用して、[プロジェクト名]用の環境を設定したいと思います。
1. 新しいContextの名前: [プロジェクト名]
2. Docker Composeプロジェクト名: [プロジェクト名]
3. ポート範囲: 83xx番台
4. リソース命名規則: "[プロジェクト名]-"プレフィックス
以下の手順を教えてください:
1. 新しいContextの作成方法
2. そのContextでの開発環境構築
3. 複数Context間での切り替え方法
4. [具体的な開発タスク]の実装手順
競合防止のためのクリーンアッププロンプト
私の開発環境から[プロジェクト名]を安全に削除したいと思います。同じPC上で他のプロジェクトも動作しているため、それらに影響を与えないよう注意が必要です。
分離レベル: [WSL2分離 / Docker Context / Docker Compose / 命名規則]
以下のリソースを安全に削除する手順を教えてください:
- コンテナ: [プロジェクト名]-*
- イメージ: [プロジェクト名で使用したイメージ]
- ボリューム: [プロジェクト名]-*
- ネットワーク: [プロジェクト名]-*
削除前の確認ステップも含め、他のプロジェクトに影響を与えない安全な削除方法を示してください。
WSL2分離を使用している場合は、WSL2インスタンス自体の削除も含めてください。
実装例: AIエージェント開発プロジェクトの分離
以下に、実際のシナリオにおける分離手法の適用例を紹介します。これらの例は、複数のAIエージェントを使った並行開発の現実的なケースを示しています。
例1: バックエンド・フロントエンド開発の分離
異なるAIエージェントにバックエンドとフロントエンドの開発を依頼する例です。
WSL2分離による実装
# バックエンド用WSL2インスタンス作成
wsl --import Backend-Dev C:\WSL\Backend-Dev C:\path\to\ubuntu-20.04-server-cloudimg-amd64-wsl.rootfs.tar.gz
# フロントエンド用WSL2インスタンス作成
wsl --import Frontend-Dev C:\WSL\Frontend-Dev C:\path\to\ubuntu-20.04-server-cloudimg-amd64-wsl.rootfs.tar.gz
# 各WSL2インスタンスにDockerをインストール
wsl -d Backend-Dev -e bash -c "apt update && apt install -y docker.io docker-compose"
wsl -d Frontend-Dev -e bash -c "apt update && apt install -y docker.io docker-compose"
# バックエンド開発(Claude AIエージェントAに依頼)
wsl -d Backend-Dev -e docker-compose -p backend up -d
# → PostgreSQLデータベース + Node.jsサーバ (ポート8001-8010)
# フロントエンド開発(Claude AIエージェントBに依頼)
wsl -d Frontend-Dev -e docker-compose -p frontend up -d
# → React開発環境 (ポート8101-8110)
この構成では、一方のAIエージェントが誤ってもう一方のリソースを削除することはありません。
例2: マイクロサービスアーキテクチャの並行開発
異なるAIエージェントに複数のマイクロサービスを並行開発させる例です。
Docker Compose分離による実装
# user-service/docker-compose.yml(AIエージェントA担当)
version: '3'
services:
api:
container_name: ${COMPOSE_PROJECT_NAME:-user-service}-api
build: .
ports:
- "8001:3000"
environment:
DB_HOST: ${COMPOSE_PROJECT_NAME:-user-service}-db
networks:
- ${COMPOSE_PROJECT_NAME:-user-service}-network
- shared-network
db:
container_name: ${COMPOSE_PROJECT_NAME:-user-service}-db
image: mongo
volumes:
- ${COMPOSE_PROJECT_NAME:-user-service}-data:/data/db
networks:
- ${COMPOSE_PROJECT_NAME:-user-service}-network
networks:
${COMPOSE_PROJECT_NAME:-user-service}-network:
shared-network:
external: true
volumes:
${COMPOSE_PROJECT_NAME:-user-service}-data:
# payment-service/docker-compose.yml(AIエージェントB担当)
version: '3'
services:
api:
container_name: ${COMPOSE_PROJECT_NAME:-payment-service}-api
build: .
ports:
- "8101:3000"
environment:
DB_HOST: ${COMPOSE_PROJECT_NAME:-payment-service}-db
networks:
- ${COMPOSE_PROJECT_NAME:-payment-service}-network
- shared-network
db:
container_name: ${COMPOSE_PROJECT_NAME:-payment-service}-db
image: postgres
volumes:
- ${COMPOSE_PROJECT_NAME:-payment-service}-data:/var/lib/postgresql/data
networks:
- ${COMPOSE_PROJECT_NAME:-payment-service}-network
networks:
${COMPOSE_PROJECT_NAME:-payment-service}-network:
shared-network:
external: true
volumes:
${COMPOSE_PROJECT_NAME:-payment-service}-data:
# 共有ネットワーク作成
docker network create shared-network
# サービス起動
cd user-service && docker-compose -p user-service up -d
cd payment-service && docker-compose -p payment-service up -d
この例では、明確なプロジェクト名とポート範囲の分離でサービスを分けつつ、shared-network
で必要な通信を可能にしています。
例3: 本番環境とテスト環境のシミュレーション
AIエージェントに本番に近い環境とテスト環境を同時に構築させる例です。
Context + Compose分離による実装
# Context作成
docker context create production
docker context create testing
# 各Contextでの環境構築 - Composeプロジェクト名も併用
docker context use production
docker-compose -p production-env -f docker-compose.production.yml up -d
docker context use testing
docker-compose -p testing-env -f docker-compose.testing.yml up -d
# 環境の切り替え
docker context use production
docker ps # 本番環境のコンテナのみ表示
docker context use testing
docker ps # テスト環境のコンテナのみ表示
この方法では、Contextの切り替えによって操作対象の環境を明確に分離しつつ、Composeプロジェクト名による命名規則でリソースを整理できます。Context + Composeの組み合わせは、多環境開発での誤操作防止に特に効果的です。
シェルスクリプトによる環境管理の自動化
複数環境の操作を簡略化するシェルスクリプト例:
#!/bin/bash
# 使用法: ./manage-env.sh [production|testing] [up|down|status]
ENV_NAME=$1
ACTION=$2
# コンテキストの存在確認と切り替え
if ! docker context inspect $ENV_NAME > /dev/null 2>&1; then
echo "Error: Context '$ENV_NAME' does not exist"
exit 1
fi
# コンテキストを切り替え
docker context use $ENV_NAME > /dev/null
# 指定されたアクションを実行
case $ACTION in
up)
echo "Starting $ENV_NAME environment..."
docker-compose -p $ENV_NAME-env -f docker-compose.$ENV_NAME.yml up -d
;;
down)
echo "Stopping $ENV_NAME environment..."
docker-compose -p $ENV_NAME-env -f docker-compose.$ENV_NAME.yml down
;;
status)
echo "Status of $ENV_NAME environment:"
docker ps
;;
*)
echo "Usage: $0 [production|testing] [up|down|status]"
exit 1
;;
esac
このスクリプトにより、./manage-env.sh production up
のようなシンプルなコマンドで、コンテキストの切り替えとComposeコマンドの実行を一度に行えます。
まとめ
1台のWindows PCで複数のAIエージェントを使ったコンテナ開発では、様々な競合問題が発生する可能性があります。これらの問題は、適切な分離レベルを選択することで効果的に防止できます。
分離レベルの選択
-
最強の分離(WSL2インスタンス分離)
- 完全に別のDockerエンジンを使用
- ボリューム誤削除などの深刻な問題を確実に防止
- 操作がやや煩雑になるデメリットあり
-
中程度の分離(Docker Context + Compose)
- 同一エンジン内での管理面・リソース名の分離
- 日常操作の手間と保護のバランスが良好
- 特に複数環境(開発/テスト/本番)を扱う場合に効果的
-
基本的な分離(命名規則 + ポート管理)
- 最も実装が簡単で運用コストが低い
- 人的ミスによる問題は防ぎきれない
重要なポイント
- WindowsのDockerはデフォルトでWSL2上で動作している。
- 分離レベルは保護の必要性に応じて選択する。
- AIエージェントには明確な分離条件を事前に指示する。
- 安全なクリーンアップのためのスクリプトを用意する。
- 複数の分離手法を組み合わせることで、より堅牢な環境を構築できる。
これらの対策を実施することで、1台のPCで複数のAIエージェントを活用した効率的かつ安全なコンテナ開発が可能になります。特にAIエージェントの特性を考慮し、適切な分離レベルと明確なプロンプトを組み合わせることで、開発効率を落とさずに競合問題を回避しましょう。