🥊

devcontainer で Claude Code を安全に大暴れさせるためのレシピを考える

に公開

AIが自律的に働いているとき「破壊的な処理を実行してしまわないか」という心配事があります。その対策のひとつとして、プロジェクトをサンドボックスで隔離して、外界に影響を与えない環境で安全に開発をさせたい。それを可能にする技術のひとつが devcontainer であるわけで、今回は devcontainer + Claude Code の開発環境を試してみました。

devcontainer とは

devcontainer は devcontainer.json という設定ファイルで開発環境のコンテナを定義・構築する仕組みです。もともとは VS Code の一機能だったのが、VS Code の外でも使えるように仕様が標準化されたものらしいです。

devcontainer は設定ファイルの記述に沿って Docker コンテナをビルドし、起動します。ローカルにあるプロジェクトのコードベースをコンテナにマウントし、コンテナの中にはいって開発をおこないます。コンテナの中からはホストOSのあれこれは触れないので、安全に開発がおこなえます。

Dev Container CLI

VS Code ではUIで簡単に利用できるので、はじめて試す場合はそちらがちょうど良いかもしれませんが、今回は Claude Code と一緒に使う前提です。せっかく CLI で完結しているところなので、 devcontainer もコマンドで起動させようと思います。

npm パッケージなので node が動く環境であれば使えます。導入もいつもの様に。

npm i -g @devcontainers/cli

基本的な使い方は、まず up サブコマンドでコンテナをビルドして起動し、 exec サブコマンドでコンテナの中に入ります。

devcontainer up --workspace-folder the/path/to/project

up サブコマンドはデフォルトで workspace folder の中にある .devcontainer/devcontainer.json を探して使いますが、別の場所にある devcontainer.json--config オプションで指定して使わせることもできます。 --config を使うことで、複数の workspace で共通の設定の devcontainer を立ち上げることができます。共通なのは設定だけであって、コンテナ自体は workspace ごとに作成されます。

devcontainer up --workspace-folder the/path/to/project \
                --config ~/.config/devcontainer/devcontainer.json

コンテナを立ち上げたら exec で中に入ります。 execdocker exec と似た要領で、何のコマンドで起動するかを渡します。(下の例では /bin/bashexec--workspace-folder--config を手がかりにしてコンテナを探すので、 up した時と同じオプションを渡さなければいけません。

devcontainer exec --workspace-folder the/path/to/project \
                  --config ~/.config/devcontainer/devcontainer.json \
                  /bin/bash

devcontainer.json のレシピ

さて次は、Claude Code のコンテナを立ち上げるための devcontainer.json のレシピです。色々試してみた結果、次のような形に辿り着きました。

{
  "name": "Node.js & TypeScript",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm",
  "remoteUser": "node",
  "features": {
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {}
  },
  "mounts": [
    "type=bind,src=${localEnv:HOME}/.claude,dst=/home/node/.claude_host,readonly"
  ],
  "postCreateCommand": "mkdir -p ~/.claude && cp -r ~/.claude_host/agents ~/.claude_host/commands ~/.claude_host/CLAUDE.md ~/.claude"
}

ghcr.io/anthropics/devcontainer-features/claude-code:1.0 というのが Anthropic 公式から提供されている devcontainer 用の feature です。

mounts ではホストOSのホームディレクトリにある .claude ディレクトリを別名 .claude_host としてマウントし、 postCreateCommand でその中の一部をコンテナの .claude ディレクトリにコピーしています。こうすることで、いままで手塩にかけて育ててきたサブエージェントやカスタムスラッシュコマンドといった Claude Code の共有資産をコンテナの中でも活用することができます。

.claude ディレクトリを同名でマウントしてそのまま使う方法もあるのですが、これは推奨できません。 Claude Code は .claude に色々と書き込みをするものです。せっかくサンドボックスに隔離しているのに、ホストOSの環境を汚染することができる穴を残しておいては道理にあいません。

この devcontainer.json を、自分は ~/.config/devcontainer/claude/devcontainer.json に保存して共有で使うことにしました。

devclaude コマンド

毎度毎度長いオプションをつけて up して exec するのは面倒なので、シェルコマンドにまとめてしまうことにしました。 devclaude という名前で作ります。

#!/bin/bash

# devclaude - DevContainer for Claude
# Usage: devclaude <workspace-folder-path>

WORKSPACE_FOLDER="$1"
CONFIG_FILE="$HOME/.config/devcontainer/claude/devcontainer.json"

# Start DevContainer
echo "Starting DevContainer..."
echo "Workspace: $WORKSPACE_FOLDER"
echo "Config: $CONFIG_FILE"

devcontainer up \
    --workspace-folder "$WORKSPACE_FOLDER" \
    --config "$CONFIG_FILE"

# Check result
if [ $? -eq 0 ]; then
    echo "DevContainer started successfully!"

    # Connect to container
    echo "Connecting to container..."
    devcontainer exec \
        --workspace-folder "$WORKSPACE_FOLDER" \
        --config "$CONFIG_FILE" \
        /bin/bash
else
    echo "Error: Failed to start DevContainer" >&2
    exit 1
fi

この devclaude コマンドは引数に workspace folder を受け取ります。つまりプロジェクトルートディレクトリを渡せば、そのプロジェクト専用の Claude Code コンテナが立ち上がります。

devclaude projects/my-project
node ➜ /workspaces/my-project $

コンテナの中はどうなっているか、中に入ってどうしたらいいか

コンテナの中身は Debian Linux のようです。開発者が関心を持つのは主にホームディレクトリと workspaces ディレクトリです。

/
├── home/
│   └── node/
│       └── .claude
└── workspaces/
    └── myproject/
        └── <Project Code Base>

コンテナに入った時は /workspaces/myproject に居ます。そこでそのまま claude を実行すれば開発が開始できます。あとは、いつも通りです。

devcontainer + Claude Code 環境の注意点

試してみていくつか気になった点があったので記録しておきます。問題の解消方法が見つかったら追記しておこうと思います。もし知ってるよ!という方いたら是非教えて下さい。

1. 入ってる Claude Code のバージョンがやや古く、オートアップデートが働かない

公式の devcontainer feature で入る Claude Code のバージョンは、執筆時点では 1.0.57 でした。この時の最新バージョンは 1.0.72 です。

node ➜ /workspaces/sandbox $ claude --version
1.0.57 (Claude Code)

バージョンアップをしようにも、 auto update はうまく動きません。 claude update も試しましたが失敗しました。

node ➜ /workspaces/sandbox $ claude update
Current version: 1.0.57
Checking for updates...
New version available: 1.0.72 (current: 1.0.57)
Installing update...
Warning: Could not determine installation type
Attempting global update based on file detection...
Using global installation update method...
Error: Failed to install update
Or consider migrating to a local installation with:
  claude migrate-installer

結局のところ npm で入れ直すのが一番手っ取り早かったです。もう少しスマートにできるとうれしい。

sudo npm i -g @anthropics-ai/claude-code

2. MCPがうまく動かない

あまり多くのMCPは試していないのですが、少なくとも docker ベースのものは動かせないのでは、と踏んでいます。(使えるようにするにはコンテナ内で docker を使えるようにしなければならなそう)

それから Atlassian MCP(公式)のようにリモートのSSEで動くタイプについては、それ自体は動きそうな気はしますが認証がパスできません。 Claude Code の認証のようにハッシュをコピー&ペーストするタイプならいけますが、Atlassian は loalhost にコールバックを飛ばす方式で、どうしてもホストの localhost に着地してしまい、コンテナ内まで到達しません。

色々試してみようとは思いますが、 devcontainer を使いたい理由に回帰してみると、MCPに依存せずに閉じた世界で Claude Code に大暴れしてもらう運用でも良いのかなと。

おわりに

まだちゃんと実運用はしてないのでなんとも言えないですが、取り敢えず起動して運用することが出来るレシピまで到達しました。また課題など見つけたら改善していきましょう。

Discussion