UbuntuのWorkshopでClaude Codeをサンドボックス化された開発環境で実行してみる
はじめに
皆様こんにちは、あかいけです。
Claude Codeのようなコーディングエージェントは便利ですが、危険な操作(rmや得体の知れないcurl | sh)でホストのファイルや認証情報まで触られると怖いので、隔離した環境で動かしたいですよね。
そして先日CanonicalがUbuntuの新機能である「Workshop」を発表されたのですが、まさにこのようなユースケースに使えそうです。
というわけで今回は、WorkshopでClaude Codeのサンドボックス環境を構築してみました。
Workshopとは
Workshopは、Canonicalが2026年5月に公開したUbuntu向けの開発環境管理ツールであり、YAMLファイルでサンドボックス化された開発環境を構築することができます。
実体はsnapアプリで、内部ではCanonical製のLXD(システムコンテナ/VMマネージャー)を使っています。
Canonicalの公式ブログでは、Workshopの特徴として「再現性・隔離・権限制御」が挙げられています。
- 再現性
- YAMLファイルに環境を宣言する形なので、テキストとしてGit管理・チーム共有でき、別マシンでも同じ環境を作れます
- 隔離
- Dockerの「アプリケーションコンテナ」ではなく、LXDの非特権システムコンテナで動きます
- 1台のマシンに近い感覚で、それでいてホストとは分離されています
- 権限制御
- snapd由来のPlug/Slot(インターフェース)で、ホスト資源へのアクセスを明示的に許可します
- 何も指定しなければ遮断されたままです
この「デフォルトは遮断、必要なものだけ明示的に許可」という考え方が、AIエージェントを安心して走らせたいニーズと相性が良さそうだなと思いました。
WorkshopはLXDを開発環境向けに使いやすくするツール
まず整理しておくと、Workshopの土台はLXDです。
DockerやDev Containerが基本的に1プロセスを動かす「アプリケーションコンテナ」なのに対し、LXDのシステムコンテナはinit(systemd)が動いて複数サービスを常駐でき、中身も通常のUbuntuとほぼ同等です。1台のマシンに近い感覚で扱えます。
では、Workshopは何をしてくれるのかと言うと、このLXDを「開発環境」として手軽に扱えるようにするレイヤーです。
具体的には以下のような特徴があります。
- YAMLファイルで環境を定義し、
workshop init/launch/refreshで構築・更新できる - 利用したいプログラミング言語やツールを「SDK」という再利用可能な部品としてSDK Storeから追加できる
- ホスト資源(GPU・ssh-agent・ポートなど)へのアクセスを「インターフェース」で明示的に制御できる
LXD単体でも同じことはできますが、それを「YAMLファイル」で使いやすくしてくれているのがWorkshop、という位置づけと言えそうです。
前提条件
前述の通り、WorkshopはLXDに依存するため、動かせるのはLinux系の環境になります。
とはいえ対応範囲は意外と広く、Ubuntuに限らずsnapが使えるLinuxディストリビューションでサポートされていますし、WSL2でも利用できます。
本記事は以下の環境を前提にしています。
- Ubuntu 24.04 LTSなど、snapが使えるLinux環境(他のsnap対応ディストリビューションやWSL2でも可)
- LXD 6.8以降
- Claude Codeを使える何らかのサブスクリプション契約をしていること
試してみる
セットアップ
細かいオプションは公式ドキュメントが詳しいので、あわせて参照してください。
インストール
まずはLXDとWorkshop本体を入れます。
# LXD 6.8 以降をインストール (6/stable チャンネル)
sudo snap install --channel=6/stable lxd
# Workshop 本体をインストール
sudo snap install --classic workshop
インストール後、バージョン確認ができればOKです。
# バージョン確認
workshop --version
0.9.2
利用できるSDKを確認する
Workshopは「SDK」という単位で、言語ランタイムやAIツールを環境に追加します。
SDKの検索や情報表示は、workshopではなくsdkコマンドで行います
- SDK Store から SDK を検索
sdk find claude-code
NAME VERSION PUBLISHER SUMMARY
claude-code 2.1.179 Dmitry Lyfar Claude Code CLI
hermes-agent 2026.5.29.2 Matias Piipari Hermes Agent — self-improving AI agent from Nous Research
- 特定 SDK のチャンネルや対応ベースを確認
sdk info claude-code
name: claude-code
publisher: Dmitry Lyfar (dlyfar)
license: https://www.anthropic.com/legal/commercial-terms
website: https://github.com/canonical/claude-code-sdk
This SDK provides the Claude Code CLI for AI-assisted coding within a
workshop. The agent is sandboxed in the workshop container. Credentials are
persisted between workshop updates.
CHANNELS
CHANNEL VERSION BUILD BASE REV SIZE
latest/stable 2.1.179 2026-06-25 all 27 62.16MB
latest/candidate ↑
latest/beta ↑
latest/edge ↑
なお、目的のSDKが存在するか・正確な名前は、必ずsdk find <名前>で確認してください(例えばClaude Code用ならsdk find claude-code)。
本記事の設定例も、実行前に一度チェックしておくと安心です。
なおどんなSDKがあるかを一覧で眺めたいときは、GitHubのcanonical/reference-sdksにカタログがあるのでこちらを参照するのが良さそうです。
Claude Codeのサンドボックスを立ち上げる
Claude Codeには確認なしで動く自動承認モードがあり、便利な反面、ホストでそのまま全権を渡すのは少し怖いところです。SDKにClaude Code(claude-code)が用意されているので、これを使ってみます。
まずはプロジェクトを用意します。
mkdir -p ~/claude-code-workshop && cd ~/claude-code-workshop
git init
workshop initで、claude-code SDK入りの定義を作成します。
環境の定義は、プロジェクト直下の.workshop/<名前>.yamlに置かれます。
workshop init dev --sdks claude-code/latest/stable --base ubuntu@24.04
生成される.workshop/dev.yamlはこんな形です。
name: dev
base: ubuntu@24.04
sdks:
- name: claude-code
channel: latest/stable
以下コマンドでWorkshopが定義を認識していることを確認できます。
workshop list
WORKSHOP STATUS NOTES
dev Off -
WARNING: There is 1 new warning. See "workshop warnings".
あとは起動するだけです。
初回はベースイメージとSDKのダウンロードが走ります。
(WARNINGが出ていますが、これは後で解説します)
- 定義を読んで環境を構築・起動
workshop launch
"dev" launched
WARNING: There is 1 new warning. See "workshop warnings".
- 起動後の状態を確認
workshop info
name: dev
base: ubuntu@24.04
project: ~/claude-code-workshop
hostname: dev.claude-code-workshop.wp
status: ready
notes: –
sdks:
system:
installed: (2)
claude-code:
tracking: latest/stable
installed: 2.1.179 2026-06-25 (27)
mounts:
claude-config:
host-source: …/97c30ea5/dev/mount/claude-code/claude-config
workshop-target: /home/workshop/.claude
WARNING: There is 1 new warning. See "workshop warnings".
- マシンに保存されているSDKボリュームの確認
sdk list
NAME VERSION REV SIZE
claude-code 2.1.179 27 115.23MB
system - 2 25.09kB
- Claude Code が使えるか確認
workshop exec dev -- claude --version
2.1.179 (Claude Code)
WARNING: There is 1 new warning. See "workshop warnings".
- .workshop.lockを.gitignoreに追加
echo ".workshop.lock" >> .gitignore
起動できたら、シェルに入って中を覗いてみます。
workshop shell
workshop@dev:/project$ pwd
/project
workshop@dev:/project$ whoami
workshop
workshop@dev:/project$ ls -la
total 18
drwxrwxr-x 4 workshop workshop 4096 Jun 28 20:03 .
drwxr-xr-x 22 root root 26 Jun 28 20:06 ..
drwxrwxr-x 7 workshop workshop 4096 Jun 28 20:00 .git
drwxr-xr-x 2 workshop workshop 4096 Jun 28 20:01 .workshop
-rw-r--r-- 1 workshop workshop 8 Jun 28 20:03 .workshop.lock
workshop@dev:/project$ ls -la /
total 25
drwxr-xr-x 22 root root 26 Jun 28 20:06 .
drwxr-xr-x 22 root root 26 Jun 28 20:06 ..
lrwxrwxrwx 1 root root 7 Apr 22 2024 bin -> usr/bin
drwxr-xr-x 2 root root 2 Feb 26 2024 bin.usr-is-merged
drwxr-xr-x 2 root root 2 Jun 15 22:50 boot
drwxr-xr-x 9 root root 540 Jun 28 20:06 dev
drwxr-xr-x 104 root root 196 Jun 28 20:06 etc
drwxr-xr-x 4 root root 4 Jun 28 20:06 home
lrwxrwxrwx 1 root root 7 Apr 22 2024 lib -> usr/lib
drwxr-xr-x 2 root root 2 Apr 8 2024 lib.usr-is-merged
lrwxrwxrwx 1 root root 9 Apr 22 2024 lib64 -> usr/lib64
drwxr-xr-x 2 root root 2 Jun 15 22:43 media
drwxr-xr-x 2 root root 2 Jun 15 22:43 mnt
drwxr-xr-x 2 root root 2 Jun 15 22:43 opt
dr-xr-xr-x 574 nobody nogroup 0 Jun 28 20:06 proc
drwxrwxr-x 4 workshop workshop 4096 Jun 28 23:08 project
drwx------ 3 root root 5 Jun 15 22:46 root
drwxr-xr-x 20 root root 640 Jun 28 20:06 run
lrwxrwxrwx 1 root root 8 Apr 22 2024 sbin -> usr/sbin
drwxr-xr-x 2 root root 2 Mar 31 2024 sbin.usr-is-merged
drwxr-xr-x 2 root root 3 Jun 28 20:06 snap
drwxr-xr-x 2 root root 2 Jun 15 22:43 srv
dr-xr-xr-x 13 nobody nogroup 0 Jun 28 23:12 sys
drwxrwxrwt 11 root root 220 Jun 28 23:04 tmp
drwxr-xr-x 12 root root 12 Jun 15 22:43 usr
drwxr-xr-x 13 root root 16 Jun 28 20:06 var
workshop@dev:/project$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04.4 LTS
Release: 24.04
Codename: noble
この実行結果から、次のことがわかります。
- カレントディレクトリが
/projectになっている、ホスト側のプロジェクトディレクトリがここに自動でマウントされている - 実行ユーザーは
workshopという非rootユーザー
ls -la /で見えている/は、コンテナ自身のOS一式です。ホストのファイルシステムとは完全に分離されており、/homeの中身もコンテナのworkshopユーザーのものだけで、ホストのホームディレクトリではありません。
ホスト側とつながっているのは、自動マウントされた/projectだけです。
そのため仮にコーディングエージェントが危険な操作を実行しても、被害はコンテナの中で済みます。
あとは任意の方法でログインすれば、Claude Codeが使えるようになります。
超簡単ですね。
claude login
補足:WARNINGについて
セットアップ時に出ていたWARNINGについて確認してみます。
workshop warnings
どうやら「ネットワーク通信が遮断されているかもしれない」という警告のようで、メッセージにあるとおり、原因はDockerと思われます。
last-occurrence: today at 22:57 JST
warning: |
firewall rules may be blocking network traffic on the workshopbr0 bridge: the FORWARD chain policy
is set to DROP with no rules allowing traffic through the bridge. This is likely caused by Docker.
To resolve, run: sudo nft insert rule ip filter DOCKER-USER iifname workshopbr0 accept \; sudo nft
insert rule ip filter DOCKER-USER oifname workshopbr0 ct state related,established accept (see
https://documentation.ubuntu.com/lxd/latest/howto/network_bridge_firewalld/)
DockerはnftablesのFORWARDチェーンのポリシーをDROPにするため、Workshop(LXD)が使うworkshopbr0ブリッジ経由の通信までブロックされ、コンテナの中から外部に出られなくなることがあるようです。
対処は、警告に書かれているとおり、DOCKER-USERチェーンにworkshopbr0の通行を許可するルールを追加するだけです。
# workshopbr0 からの通信を許可
sudo nft insert rule ip filter DOCKER-USER iifname workshopbr0 accept
# workshopbr0 への戻りの通信(確立済み・関連)を許可
sudo nft insert rule ip filter DOCKER-USER oifname workshopbr0 ct state related,established accept
再度execコマンドを実行しても前述のWARNINGが出ないので、解消していそうです。
workshop exec dev -- claude --version
2.1.179 (Claude Code)
YAML定義をカスタマイズする
サンドボックスが立ち上がったら、あとは.workshop/dev.yamlを編集して環境を育てていきます。
ベースイメージを変える、SDKを足す、チャンネルを切り替える、といった調整はすべてこのファイルで宣言します。
たとえば、Pythonツールのuvを足してみます。
name: dev
base: ubuntu@24.04
sdks:
- name: claude-code
channel: latest/stable
- name: uv
定義を変えたら、workshop refreshで環境に反映します。
launchと違ってrefreshは、途中で失敗しても直前の状態にロールバックして環境を壊さないようになっています。
workshop refresh
更新完了後、uvがインストールされていることが確認できます。
workshop exec dev -- uv --version
uv 0.11.24 (1e11c3925 2026-06-26 x86_64-unknown-linux-gnu)
WARNING: There is 1 new warning. See "workshop warnings".
ここまでにWorkshopが行った操作は、workshop changesで履歴として確認できます。
workshop changes
ID STATUS SPAWN READY SUMMARY
1 Done yesterday at 20:04 JST yesterday at 20:06 JST Launch "dev" workshop
2 Done yesterday at 20:08 JST yesterday at 20:08 JST Execute command "claude"
3 Done yesterday at 22:57 JST yesterday at 23:07 JST Execute command "bash"
4 Done yesterday at 23:07 JST yesterday at 23:08 JST Execute command "bash"
5 Done yesterday at 23:10 JST yesterday at 23:16 JST Execute command "bash"
6 Done yesterday at 23:17 JST yesterday at 23:18 JST Refresh "dev" workshop
7 Done yesterday at 23:18 JST yesterday at 23:18 JST Execute command "uv"
8 Done yesterday at 23:56 JST yesterday at 23:56 JST Execute command "curl"
9 Done yesterday at 23:57 JST yesterday at 23:57 JST Refresh "dev" workshop
10 Done yesterday at 23:58 JST yesterday at 23:58 JST Execute command "claude"
最初のlaunchから、claudeやbashの実行、uvを足したときのrefreshまで、これまでの操作が時系列で並んでいます。
1行がchangeという操作の単位で、STATUSがDoneになっていれば正常に完了しています。
Workshopは変更をアトミックに適用し、失敗時は元の状態へ巻き戻すので、この履歴が「いつ何をして環境がどう変わったか」の記録になります。
個々の操作をさらに掘り下げたいときは、workshop tasks <ID>を使うと、その変更の中で実際に走った細かいタスク(ベースイメージのダウンロード、SDKの取得、フックの実行など)まで追えます。
workshop tasks 7
STATUS DURATION SUMMARY
Done 129ms Exec command "uv"
Plug/Slotでホスト資源へのアクセスを制御する
Workshopの重要なセキュリティ機能の一つが、「インターフェース」の仕組みです。
これは、SDKが資源をslotとして公開し、それをplugとして消費する形で接続するというものです。
例えばカメラやGPUといったホスト側の機能は、systemというSDKを通じてslotとして公開されます。
- plug
- SDK側が要求する側(例:
gpu,mount,ssh-agent,tunnel)
- SDK側が要求する側(例:
- slot
- 資源を提供する側(
systemSDKやほかのSDKが提供)
- 資源を提供する側(
どのplug/slotを持つかはSDK側で定義されており、接続状態はコマンドで確認・変更します。
# 現在の接続状態を一覧
workshop connections
INTERFACE PLUG SLOT NOTES
mount dev/claude-code:claude-config dev/system:mount -
mount dev/uv:cache dev/system:mount -
以下のコマンドで接続を有効化したり無効化したりできます。
# 接続 / 切断 (plug と slot を指定)
workshop connect dev/<sdk>:<plug> :<slot>
workshop disconnect dev/<sdk>:<plug>
ポイントは、すべてが自動でつながるわけではないことです。
さきほどのclaude-code:claude-config(認証情報のmount)のように起動時に自動接続されるものもあれば、ssh-agentのように明示的に接続しないと使えないものもあります。
デフォルトで全部入りにしない、という安全に配慮した設計になっています。
ssh-agentでGithubの認証を通す
Claude Codeを使うならGitHubが欠かせないので、ssh-agentを足してみます。
まず、claude-code SDKにssh-agent plugを足します。
name: dev
base: ubuntu@24.04
sdks:
- name: claude-code
channel: latest/stable
plugs:
ssh-agent:
interface: ssh-agent
- name: uv
定義を反映しても、ssh-agentは自動では接続されません。workshop connectで手動接続します。
workshop refresh
workshop connect dev/claude-code:ssh-agent
接続できたかはworkshop connections --allで確認できます。ssh-agentの行がmanual付きで出ていればOKです。
workshop connections --all
INTERFACE PLUG SLOT NOTES
mount - dev/uv:venv -
mount dev/claude-code:claude-config dev/system:mount -
mount dev/uv:cache dev/system:mount -
ssh-agent dev/claude-code:ssh-agent dev/system:ssh-agent manual
接続すると、workshopユーザーの$SSH_AUTH_SOCKにホストのSSHエージェントへ橋渡しするソケットが設定されます。コンテナの中から確認してみます。
workshop shell
echo $SSH_AUTH_SOCK
/var/lib/workshop/run/ssh-agent.sock
ssh-add -l
(ホスト側でロード済みの鍵が一覧表示される)
鍵が一覧表示されれば、コンテナの中からも同じエージェント経由でgit pushなどができます。
秘密鍵そのものはコンテナにコピーされず、エージェント越しに使うだけなので、コンテナ内に鍵を置かずに済むのがポイントです。
不要になったらworkshop disconnect dev/claude-code:ssh-agentで切断できます。
またGPUを使いたい場合も仕組みは同じです。
たとえばollamaSDKはgpu plugを持っていて、これはsystem:gpuへ自動接続されるので、対応チャンネル(cuda/stableなど)を選ぶだけでGPUが使えます。
VS Codeから接続できるようにする
コマンドラインだけでなく、使い慣れたVS Codeからサンドボックスにつないで開発することもできます。あらかじめVS Code側にRemote Development拡張(Remote-SSH)を入れておき、定義にvscode-remote SDKを足すと、Remote-SSH越しにコンテナの/projectを開けるようになります。
定義にvscode-remote SDKを追加します。
name: dev
base: ubuntu@24.04
sdks:
- name: claude-code
channel: latest/stable
plugs:
ssh-agent:
interface: ssh-agent
- name: uv
- name: vscode-remote
あとは更新してタスクを見てみると、
workshop refresh
workshop tasks
以下のように接続用のアドレスとガイダンスが表示されます。
2026-06-29T00:51:58+09:00 INFO VS Code → Open Remote Window → Connect to host → workshop@XX.XX.XX.XX
or from the terminal,
code --folder-uri vscode-remote://ssh-remote+workshop@XX.XX.XX.XX/project
2種類ありますが、どちらでも繋げるので好きな方で繋いでください。
- VS Codeの画面コマンドパレットで「Open Remote Window」→「Connect to Host」を選び、表示されたアドレスを指定する
- ターミナルで
code --folder-uri vscode-remote://ssh-remote+workshop@XX.XX.XX.XX/projectを実行する
接続すると、VS Codeのウィンドウがコンテナ側につながり、/projectをそのまま開けます。
エディタもターミナルも拡張機能もコンテナの中で動くので、ここからClaude Codeを起動すれば、いつものエディタの中でサンドボックス化されたエージェントを使えます。

所感
Workshopが向いていそうなケース
- LinuxやWSL2上で、Claude Codeなどのエージェントを自動承認で気軽に回したい
workshop initとlaunchだけで、Claude Code入りの環境がすぐ立ち上がって手軽でした- ホスト資源は
workshop connectなどで明示的につながないと使えないので比較的安全そう - 認証情報などの永続化はSDK側で指定されていて、利用する側はマウント設定を気にせず済みます
- GPUを使ったML/LLMの実験を、ホストを汚さずに始めたい(CUDA/ROCm)
- 複数プロセスを常駐させる開発環境には、システムコンテナのLXDを土台にしているのが合っていると感じました
- 取得済みのSDKはキャッシュされるためか、
workshop refreshでの作り直しも早かった気がします
Workshopが向いていなさそうなケース
- いろいろなOSで同じように使いたい
- WorkshopはLinux(やWSL2)が前提なので、macOSなどでも広く使いたいなら、mac/Windowsでも動くDocker / Dev Containerのほうが汎用性で勝ります(Workshopをmacで使う場合はVMやリモートのLinux環境越しになります)
- とにかく最軽量で隔離したい
- 1台のシステムコンテナを立てるぶん、プロセス単位で隔離する手段よりは重めです
- SDKが用意されていないツールも使いたい
- SDKのラインナップはまだ少なめで、無いツールは自分でSDKを定義することになります(作り方はチュートリアルのsketch SDK・SDKcraftの章にあります)
sdk infoで分かるのは概要やpublisher程度で、信頼してよいSDKか判断に迷う場面がありました
さいごに
以上、WorkshopでClaude Codeのサンドボックス環境を作ってみました。
触ってみた感想として、WorkshopはDocker / Dev Containerと比べると、「安全に開発するマシンを1台まるごと立てる」ためのツールだと感じました。
そのためAIエージェントを隔離して走らせる用途とは特に相性が良さそうで、数コマンドでClaude Code入りの環境が立ち上がる手軽さも魅力でしょう。
一方で、その手軽さはSDKが用意されている範囲の話で、SDKに無いツールを足したいときは自分でSDKを作る必要があり、ここはちょっと面倒だなと感じました。
リリースされて日が浅いため、SDKのラインナップやエコシステムが充実してくればもっと使いやすくなりそうなので、今後に期待していきたいです。







