DevContainer上にClaude Codeをセットアップする

DevContainer上にClaude Codeをセットアップする

2025.12.09

クラスメソッドではAI駆動開発を推進するための取り組みを行っており、クラスメソッド社員も実際に日常的にAIを使って開発を行っています。

弊社メンバーが日常的に実践するAI駆動開発のナレッジやTipsを共有するために、AI駆動開発 Advent Calendar 2025を開催しています。

本ブログは、この企画の9日目の記事になります。

もしAI駆動開発の最先端を知りたい方は、この1ヶ月間、ぜひ本アドベントカレンダーをチェックしてみてください。

https://adventar.org/calendars/11778

本エントリでは、私が現在参画しているプロジェクトにおいて、Claude CodeのDevContainer上へのインストール方法を試行錯誤した内容を共有します。

背景

プロジェクトでは多数のGitリポジトリを利用しています。各リポジトリでClaude Codeを使い始めるにあたり、そのガイドラインを策定しました。その結果 DevContainer上での利用を推奨するという結論になり、そのサンプル実装を検討しました。

案1: Claude Code 公式のサンプルを利用する

Claude Code公式ドキュメントにDevContainerについてのページがあります。

上記ページからリンクされている .devcontainer/ 以下のサンプルコードがあり、参考になります。

特徴的な実装はファイアウォール設定です。ホワイトリストに登録されたドメインのみへの送信(アウトバウンド通信)が可能になっています。

サンプルコードに設定されているホワイトリストドメインは以下です。

  • registry.npmjs.org
  • api.anthropic.com
  • sentry.io
  • statsig.anthropic.com
  • statsig.com
  • marketplace.visualstudio.com
  • vscode.blob.core.windows.net
  • update.code.visualstudio.com
  • 参照元: https://github.com/anthropics/claude-code/blob/main/.devcontainer/init-firewall.sh#L67
  • ※ GitHub関連のドメインについては別途設定があります。ドメインベースではなく、GitHub Meta API を使ってGitHub関連のIPレンジを全て取得して送信許可しています。

使ってみた

  1. https://github.com/anthropics/claude-code をクローン
  2. VSCodeで上記クローンしたリポジトリを開く
    • code コマンドが使えるのであれば クローンコマンド後に code claude-code を実行すればいけるはず
  3. Cmd+Shift+P → 「DevContainers: Reopen in Container」
  4. claudeコマンド実行

簡単に Claude Codeを使い始めることができました。

Welcome to Claude Code

ファイアウォール設定も動作していることが確認できました。

confirm firewall

課題

とても簡単かつセキュアにClaude Codeを使い始められるこの案ですが、以下の点が課題になり採用には至りませんでした。

既存の設定に移植するのが大変

これから DevContainer使い始めますというリポジトリであれば、このサンプルコードをベースに設定を始めるのはありだと思います。が、私の現在のプロジェクトではすでにDevContainerを設定して日常的に利用しているリポジトリもあり、その場合は設定移植が大変です。できれば修正箇所を最小限に抑えたいです。

Dockerfileではなくdevcontainer.json 側で定義したい

このサンプルコードでは Dockerfile 上にも多数の記述が含まれています。しかし、Claude Codeの設定はできる限り Dockerfile ではなく devcontainer.json上に寄せたいと考えました。Claude Codeは開発中に利用するツールであり、作成するアプリケーション自体に必要なものではありません。 Dockerfile にはアプリの実行環境に関する設定のみを含めたい、 反対にClaude Codeをはじめとした開発ツールの設定はdevcontainer.json側でしたい、と考えました。

ネイティブインストーラーを使っていない = Node.js に依存

ネイティブインストーラー以前は npm install -g claude-code 等のコマンドでClaude Codeをインストールしていました。つまり Node.jsがインストールされていないと Claude Codeが利用できませんでした。

Node.js非採用のプロジェクトでは環境構築の複雑化やコンテナサイズの増加が、採用プロジェクトではバージョン競合のリスクなどが課題となります。

そんな中 2025/11/1に Claude CodeのネイティブインストーラーがGAされました。

https://x.com/claudeai/status/1984304957353243061

これにより Node.js への依存が解消されました。

ただこの Claude Code公式の DevContainer サンプルコードはネイティブインストーラーのGA前に公開されていますので、 Node.jsに依存する構成になります。

(ファイアウォールの制限が厳しい)

前述の通りホワイトリストに登録されたドメインにしか送信できません。サンプルコードで設定されているホワイトリストが不十分であればドメインを追加すればよいです。とはいえ開発途中段階ではそのドメインの特定が難しい、煩雑であるという状況もあるでしょう。

ただ、この点に関してはファイアウォールの設定をやっている該当コードをコメントアウトして利用すれば良いです。大きな問題ではありません。

案2: Claude Code 公式の DevContainer Featureを利用する

DevContainer Featureとは

DevContainer Featureとは、DevContainerの構成(devcontainer.json)に対して、再利用可能なインストールスクリプトや設定をパッケージ化したものです。これを利用することで、Dockerfileを直接編集して複雑なインストールコマンドを書くことなく、features プロパティに記述するだけでツールや言語ランタイムをコンテナに追加できます。

Claude Code 公式の DevContainer Feature

Anthropic社は Claude Code用のDevContainer Featureを提供しています。

ただ、あまりメンテナンスはされていないようです。下記ページによると最新版 v1.05は2025/3/12にリリースされてますね。…ということは Claude Code のGA前ですね!

devcontainer.jsonfeatures プロパティにClaude CodeとNode.jsのFeatureを記述するだけで、Claude Codeが利用可能になります。簡単!

devcontainer.json
{
    // 他の設定
    "features": {
        "ghcr.io/devcontainers/features/node:1": {},
        "ghcr.io/anthropics/devcontainer-features/claude-code:1": {}
    },
    // 他の設定
}

使ってみた

DevContainerの公式サンプルに追加してみましょう。まずは追加前のDevContainerを立ち上げます。

  1. https://github.com/microsoft/vscode-remote-try-python をクローン
  2. VSCodeで上記クローンしたリポジトリを開く
    • code コマンドが使えるのであれば クローンコマンド後に code vscode-remote-try-python を実行すればいけるはず
  3. Cmd+Shift+P → 「DevContainers: Reopen in Container」

コンテナのビルドが始まるのでしばらく待ちます。Done. Press any key to close the terminal. という表記がターミナルに出力されたら コンテナビルド完了、DevContainer利用可です。

ここからClaude Codeインストール設定を追加します。devcontainer.jsonを修正します。

devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
	"name": "Python 3",
	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
	"image": "mcr.microsoft.com/devcontainers/python:1-3.12",

	// Features to add to the dev container. More info: https://containers.dev/features.
-	// "features": {},
+    "features": {
+        "ghcr.io/devcontainers/features/node:1": {},
+        "ghcr.io/anthropics/devcontainer-features/claude-code:1": {}
+    },
+
	// Configure tool-specific properties.
	"customizations": {
		// Configure properties specific to VS Code.
		"vscode": {
			"settings": {},
			"extensions": [
				"streetsidesoftware.code-spell-checker"
			]
		}
	},

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// "forwardPorts": [9000],

	// Use 'portsAttributes' to set default properties for specific forwarded ports. 
	// More info: https://containers.dev/implementors/json_reference/#port-attributes
	"portsAttributes": {
		"9000": {
			"label": "Hello Remote World",
			"onAutoForward": "notify"
		}
	},

	// Use 'postCreateCommand' to run commands after the container is created.
	"postCreateCommand": "pip3 install -r requirements.txt"

	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
}

再び Cmd+Shift+Pでコマンドパレットを開き、Dev Container: Rebuild Containerを選択します。
rebuild.png

コンテナの再ビルドが始まるのでしばらく待ちます。Done. Press any key to close the terminal. という表記の出力でビルド完了です。claudeコマンド実行してみます。

おなじみの画面が表示されました。
claude-install-complete.png

このfeatureはClaude Code VSCode extensionも併せてインストールしてくれます。

ext.png
(私はまだこのextensionを使ったことありません…)

課題

前案で課題に挙げた以下はクリアできます。

  • 既存の設定に移植するのが大変
  • Dockerfileではなくdevcontainer.json 側で定義したい

一方、以下の課題はクリアできません。

  • ネイティブインストーラーを使っていない = Node.js に依存

前述の通り、このDevContainer featureはネイティブインストーラーGA前のものなので、Node.jsに依存する構成になります。

案3: ネイティブインストーラーを使ったスクリプトを自分で書く

せっかくネイティブインストーラーが出たので、使ってNode.js依存から脱却したいですね。

やってみた

案2と同じくDevContainerの公式サンプル(Python)に追加してみます。

「スクリプトを自分で書く」といっても、ネイティブインストーラーがシンプルなのであまりやることはありません。

.devcontainer/scripts/install-claude-code.sh
#!/bin/bash
set -e

curl -fsSL https://claude.ai/install.sh | bash

postCreateCommandすなわちコンテナ作成後に実行されるコマンドに、このスクリプトを追加します。

devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
	"name": "Python 3",
	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
	"image": "mcr.microsoft.com/devcontainers/python:1-3.12",

	// Features to add to the dev container. More info: https://containers.dev/features.
	// "features": {},

	// Configure tool-specific properties.
	"customizations": {
		// Configure properties specific to VS Code.
		"vscode": {
			"settings": {},
			"extensions": [
				"streetsidesoftware.code-spell-checker"
			]
		}
	},

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// "forwardPorts": [9000],

	// Use 'portsAttributes' to set default properties for specific forwarded ports. 
	// More info: https://containers.dev/implementors/json_reference/#port-attributes
	"portsAttributes": {
		"9000": {
			"label": "Hello Remote World",
			"onAutoForward": "notify"
		}
	},

	// Use 'postCreateCommand' to run commands after the container is created.
-	"postCreateCommand": "pip3 install -r requirements.txt"
+	"postCreateCommand": "bash ${containerWorkspaceFolder}/.devcontainer/scripts/install-claude-code.sh && pip3 install -r requirements.txt"

	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
}

再び Cmd+Shift+P→Dev Container: Rebuild Containerです。

エラー

err.png

上記キャプチャのように bash: line 142: 692 Killedというエラーになります。インストール中にメモリ不足(OOM - Out Of Memory)でプロセスが強制終了されたことを示しています。

私は Rancher Desktopを利用しており、コンテナホスト環境のVMへのメモリ割り当てを4GBにしていました。これでは足りないようです。(他のコンテナは起動させていません)

「Claude Code のセットアップ」ページの「システム要件」項によると、「ハードウェア: 4GB 以上の RAM」が必要とのこと。その後、VMへのメモリ割り当てを6GBにしても変わらず。8GBにしてみたところインストールは成功しました。(ただし、8GBでも時折失敗します。余裕があるならもっと割り当てたほうが良さそうです…)

8GBは多い気がしますがインストールが失敗する以上仕方がありません。 devcontainer.jsonに以下の設定を入れておきます。

  "hostRequirements": {
    "memory": "8gb"
  },

上記設定を入れておくと、ホストがメモリを8GB持っていない場合に警告がでます。
caution.png
ただし、警告が出るタイミングはビルド(再ビルドを含む)の際ではなく既存コンテナを開くときのようです。

デメリット

メモリ消費量が多い

前述のとおりです。貧弱なホスト環境や、そうでなくても複数コンテナを並行で起動させたい場合は不便になりそうです。とはいえインストール処理にメモリ消費量が多いだけで、その後ずっと8GBメモリを消費するわけではなさそうです。

インストール時間が長い

案1や案2に比べてインストールにかかる時間が長いです。8分ほどかかる場合もありました。

また、Dockerfile内でインストールする場合はレイヤーキャッシュが効くため再ビルド時には時間が短くなるのですが、devcontainer.json内でインストールする場合はその効果は期待できません。

追加設定

案3で進めることに決めました。追加の設定をいろいろ加えます。

VSCode extensionを追加

前述の VSCode extensionも追加しておきます。

devcontainer.json
	"customizations": {
		// Configure properties specific to VS Code.
		"vscode": {
			"settings": {},
			"extensions": [
-				"streetsidesoftware.code-spell-checker"
+				"streetsidesoftware.code-spell-checker",
+				"anthropic.claude-code"
			]
		}
	},

ログイン永続化

再ビルドのたびに Claude Codeのログインが必要になります。/resumeで過去のセッション(conversation)を再開できません。これを解消します。案1の実装を参考にしました。

~/.claude 以下を永続化することで、ログイン情報も永続化されます。

devcontainer.json
  "mounts": [
    "source=claude-code-config-${devcontainerId},target=/home/vscode/.claude,type=volume"
  ],

ただし、mountsでマウントされたディレクトリの所有者はrootになり、Claude Codeインストールスクリプト(マウント後に実行されます)が Permission denied で失敗します。postCreateCommandのスクリプトは remoteUser値(デフォルトはvscode)権限で実行されるためです。

そのため、install-claude-code.shスクリプトに sudo chown -R $USER:$USER ~/.claudeを追加して、所有権を変更する必要があります。

.devcontainer/scripts/install-claude-code.sh
#!/bin/bash
set -e

+ # Avoid permission error in installing
+ # This directory is already created with mounts property in devcontainer.json, but sometimes its owner is root
+ sudo chown -R $USER:$USER ~/.claude

curl -fsSL https://claude.ai/install.sh | bash

ただ、これだけではうまくいきませんでした。どうやら ~/.claude.json というファイル(先程永続化した~/.claudeに含まれていない)も永続化する必要がある、ということがわかりました。このファイル、案1と案2では存在していないのですが… ネイティブインストーラー経由だと作成される、ということなのでしょうか。(推測です。)

そこで、以下の処理を追加しました。

  1. ~/.claude.json があれば、それを ~/.claude/config.json に移動する(永続化するため)
  2. ~/.claude/config.json がなければ、空のファイルを作成する
  3. ~/.claude.json~/.claude/config.json にシンボリックリンクを張る
.devcontainer/scripts/install-claude-code.sh
#!/bin/bash
set -e

+ # Setup symlink for .claude.json to persist settings in volume-mounted directory
+ # This ensures that Claude Code settings (theme, tips history, etc.) are preserved across container rebuilds
+ setup_claude_config_persistence() {
+ 	local claude_dir="$HOME/.claude"
+ 	local settings_in_volume="$claude_dir/config.json"
+ 	local settings_link="$HOME/.claude.json"
+ 
+ 	# If .claude.json exists as a regular file, move it to volume
+ 	if [ -f "$settings_link" ] && [ ! -L "$settings_link" ]; then
+ 		mv "$settings_link" "$settings_in_volume"
+ 	fi
+ 
+ 	# Create initial config.json in volume if it doesn't exist
+ 	if [ ! -f "$settings_in_volume" ]; then
+ 		echo '{}' > "$settings_in_volume"
+ 	fi
+ 
+ 	# Create symlink from ~/.claude.json to ~/.claude/config.json
+ 	if [ -L "$settings_link" ] || [ -f "$settings_link" ]; then
+ 		rm -f "$settings_link"
+ 	fi
+ 	ln -s "$settings_in_volume" "$settings_link"
+ }

# Avoid permission error in installing
# This directory is already created with mounts property in devcontainer.json, but sometimes its owner is root
sudo chown -R $USER:$USER ~/.claude

+ setup_claude_config_persistence

# Install Claude Code
# refs: https://docs.claude.com/en/docs/claude-code/setup
curl -fsSL https://claude.ai/install.sh | bash

Bashの履歴を保持する

こちらも案1の実装を参考にしました。

devcontainer.json
	"mounts": [
+	    "source=claude-code-bashhistory-${devcontainerId},target=/commandhistory,type=volume",
		"source=claude-code-config-${devcontainerId},target=/home/vscode/.claude,type=volume"
	],
    (他の設定)
-	"postCreateCommand": "bash ${containerWorkspaceFolder}/.devcontainer/scripts/install-claude-code.sh && pip3 install -r requirements.txt",
+   "postCreateCommand": "bash ${containerWorkspaceFolder}/.devcontainer/scripts/install-claude-code.sh && bash ${containerWorkspaceFolder}/.devcontainer/scripts/persist-bash-history.sh && pip3 install -r requirements.txt",

.devcontainer/scripts/persist-bash-history.sh
#!/bin/bash
set -e

sudo mkdir -p /commandhistory
sudo chown -R $USER:$USER /commandhistory
touch /commandhistory/.bash_history
echo "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" >> ~/.bashrc

# this script works with mounts property in devcontainer.json
# refs: https://code.visualstudio.com/remote/advancedcontainers/persist-bash-history

いらない GitHub Copilot関連の機能を無効化する

GitHub Copilotの機能は不要ですが、(ユーザー設定次第では)デフォルトで表示されてしまいます。
copilot-features.png
表示位置は設定により異なる場合があります。

邪魔ですし、Copilotに意図せずコード情報を与えてしまっていないかも不安です。以下設定を追加して無効化しておきましょう。

devcontainer.json
  "customizations": {
    "vscode": {
      "settings": {
        "chat.disableAIFeatures": true
      }
    }
  }    

インストールが終わるまで待つ

デフォルトではインストール処理を行なう postCreateCommand 実行完了を待たずともDevContainerを使用開始できます。ただ postCreateCommandの処理が完了しないと claudeコマンドは使えません。そのため、"waitFor": "postCreateCommand"を設定し、完了まで待つことにしました。

ワークスペースマウント設定

devcontainer.jsonmountsworkspaceMountを以下のように修正しました。こちらも案1を参考にしました。

devcontainer.json
	"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated",
	"workspaceFolder": "/workspace",

マウント先パスを /workspaces/<プロジェクト名> から /workspaceと固定に変更しました。これにより、プロジェクト名が変わっても影響を受けませんし、プロジェクト間での設定の展開が容易になります。特に今回は複数リポジトリ間で共通で採用できるサンプル実装を作成する、という状況でしたのでこちらの方が理にかなっていると判断しました。

また、 consistency=delegated としています。これは「コンテナ内で行われた更新がホストに反映されるまでに遅延が生じる場合がある」という設定です。これによりコンテナ内での書き込み性能の向上を狙っています。

最終的な設定

.devcontainer/scripts/install-claude-code.sh
#!/bin/bash
set -e

# Setup symlink for .claude.json to persist settings in volume-mounted directory
# This ensures that Claude Code settings (theme, tips history, etc.) are preserved across container rebuilds
setup_claude_config_persistence() {
	local claude_dir="$HOME/.claude"
	local settings_in_volume="$claude_dir/config.json"
	local settings_link="$HOME/.claude.json"

	# If .claude.json exists as a regular file, move it to volume
	if [ -f "$settings_link" ] && [ ! -L "$settings_link" ]; then
		mv "$settings_link" "$settings_in_volume"
	fi

	# Create initial config.json in volume if it doesn't exist
	if [ ! -f "$settings_in_volume" ]; then
		echo '{}' > "$settings_in_volume"
	fi

	# Create symlink from ~/.claude.json to ~/.claude/config.json
	if [ -L "$settings_link" ] || [ -f "$settings_link" ]; then
		rm -f "$settings_link"
	fi
	ln -s "$settings_in_volume" "$settings_link"
}

# Avoid permission error in installing
# This directory is already created with mounts property in devcontainer.json, but sometimes its owner is root
sudo chown -R $USER:$USER ~/.claude

setup_claude_config_persistence

# Install Claude Code
# refs: https://docs.claude.com/en/docs/claude-code/setup
curl -fsSL https://claude.ai/install.sh | bash
.devcontainer/scripts/persist-bash-history.sh
#!/bin/bash
set -e

sudo mkdir -p /commandhistory
sudo chown -R $USER:$USER /commandhistory
touch /commandhistory/.bash_history
echo "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" >> ~/.bashrc

# this script works with mounts property in devcontainer.json
# refs: https://code.visualstudio.com/remote/advancedcontainers/persist-bash-history
.devcontainer/devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
	"name": "Python 3",
	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
	"image": "mcr.microsoft.com/devcontainers/python:1-3.12",
	"hostRequirements": {
		"memory": "8gb"
	},	
	// Features to add to the dev container. More info: https://containers.dev/features.
	// "features": {},

	// Configure tool-specific properties.
	"customizations": {
		// Configure properties specific to VS Code.
		"vscode": {
			"settings": {
				"chat.disableAIFeatures": true
			},
			"extensions": [
				"streetsidesoftware.code-spell-checker",
				"anthropic.claude-code"
			]
		}
	},

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// "forwardPorts": [9000],

	// Use 'portsAttributes' to set default properties for specific forwarded ports. 
	// More info: https://containers.dev/implementors/json_reference/#port-attributes
	"portsAttributes": {
		"9000": {
			"label": "Hello Remote World",
			"onAutoForward": "notify"
		}
	},

	"mounts": [
	    "source=claude-code-bashhistory-${devcontainerId},target=/commandhistory,type=volume",
		"source=claude-code-config-${devcontainerId},target=/home/vscode/.claude,type=volume"
	],

	"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated",
	"workspaceFolder": "/workspace",
	"postCreateCommand": "bash ${containerWorkspaceFolder}/.devcontainer/scripts/install-claude-code.sh && bash ${containerWorkspaceFolder}/.devcontainer/scripts/persist-bash-history.sh && pip3 install -r requirements.txt",
	"waitFor": "postCreateCommand"

	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
}

検証環境(私のローカル端末)情報

  • OS: macOS 26.1(25B78)
  • Rancher Desktop: Version 1.20.1
  • VSCode: Version 1.106.3 (Universal)
    • Dev Containers Extension: Version 0.431.1
  • Claude Code: v2.0.60

参考情報

この記事をシェアする

FacebookHatena blogX

関連記事