0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Canonical Workshopを使って再現可能な開発環境を作ってみた

0
Posted at

はじめに

つい先日の 2026 年 5 月 26 日に、Canonical から Workshop という新しい開発環境管理ツールが公開されました。

公式には、Workshop は sandboxed development environment を single command で起動するためのツールとして紹介されています。開発環境を一度定義しておけば、別のマシンでも同じ環境を再現しやすくなる、という方向性のツールです。

内部的には LXD を使っており、リポジトリに workshop.yaml や project-local SDK を置くことで、そのプロジェクト専用の開発環境を定義できます。

この記事では、リリース直後の Workshop を試しながら、基本的な使い方を確認しつつ、実際に筆者が開発している自作カーネルプロジェクトで使ってみた構成を紹介します。

Workshop とは

Canonical Workshop は、プロジェクトごとに開発用 sandbox を定義して起動できるツールです。

ざっくり言うと、リポジトリに workshop.yaml や .workshop/ 配下の SDK 定義を置いておくことで、開発に必要な環境を再現できます。

筆者の感覚だと、Docker Compose が「コンテナ群をどう起動するか」に寄っているのに対して、Workshop は「このリポジトリで開発するための作業環境」を定義するみたいな感じに近いです。

特に以下のような用途と相性が良さそうです。

  • 開発ツールチェーンを固定したい
  • QEMU やクロスコンパイラを使う
  • ホスト環境との差分を減らしたい
  • リポジトリを clone したあと、少ない手順で build / test / run したい
  • プロジェクト固有のセットアップを .workshop/ に閉じ込めたい

基本的な使い方

ここでは、Workshop の基本的なライフサイクルとして、定義、起動、更新、コマンド実行、shell 接続、actions、ログ確認を見ていきます。

この章は 公式 Tutorial: Part 1 をベースにしています。

Workshop は、プロジェクトディレクトリをコンテナ内の開発環境に対応づける仕組みです。プロジェクト側には workshop.yaml を置き、そこに base image、SDK、actions などを定義します。

インストール

Workshop は snap でインストールできます。

sudo snap install --classic workshop

内部では LXD を利用するため、LXD 6.8 以降が必要です。snap で LXD を入れる場合は次のようになります。

sudo snap install --channel=6/stable lxd

既に LXD を使っている場合は、必要に応じて refresh します。

sudo snap refresh --channel=6/stable lxd

workshop.yaml を定義する

Workshop の定義は、プロジェクトディレクトリに置く YAML ファイルです。

最小構成のイメージは次のようになります。

name: dev
base: ubuntu@24.04

sdks:
  - name: ollama

name は Workshop の名前です。

base には Ubuntu の base image を指定します。

sdks には、その Workshop に含めたい SDK を指定します。SDK は独自に作成できるほか、公開されている SDK を利用することもできます。

たとえば、Go 環境の SDK を探す場合は次のようにできます。

sdk find go
# NAME     VERSION  PUBLISHER     SUMMARY
# go       1.26.3   Dmitry Lyfar  The Go programming language

Workshop を起動する

定義を書いたら、プロジェクトディレクトリで次を実行します。

workshop launch

起動後は、Workshop 内にプロジェクトディレクトリが /project として mount されます。

Workshop の状態は次のコマンドで確認できます。

workshop list
# WORKSHOP  STATUS  NOTES
# dev       Ready   -

workshop info
# name:     dev
# base:     ubuntu@24.04
# project:  ~/code/project
# status:   ready
#   :

workshop info では、base、project path、status、SDK、mount などの情報を確認できます。

start / stop

launch は Workshop を作成して起動する操作です。

一度 launch した Workshop は、必要に応じて stop / start できます。

workshop stop
workshop start

stop は Workshop を削除するわけではなく、起動中の環境を停止する操作です。再び使うときは start で戻せます。

refresh

workshop.yaml や SDK 定義を変更した場合は、Workshop を refresh します。

workshop refresh

base や SDK の定義を変更した場合は、refresh して環境へ反映します。

一方で、後述する actions は workshop run のたびに読み込まれるため、actions の中身だけを変更した場合は refresh なしで試せます。

Workshop 内でコマンドを実行する

Workshop 内でコマンドを直接実行するには workshop exec を使います。

workshop exec dev -- ls /project

単一 Workshop のプロジェクトでは、Workshop 名を省略できる場面もあります。

workshop exec -- ls /project

shell に入る

複数の操作を手動で実行したい場合は、Workshop 内の shell に入れます。

workshop shell

shell に入ると、作業ディレクトリは /project になります。

workshop@dev-xxxx:/project$ pwd
/project

actions を定義する

よく使うコマンドは actions として workshop.yaml に定義できます。

たとえば、Ollama のモデル追加と一覧確認を行うコマンドを、以下のように定義しておくことができます。

actions:
  pull: ollama pull "$@"

  list: ollama list

こうすると、ホスト側から次のように実行できます。

workshop run -- pull <MODEL>
workshop run -- list

actions は workshop run のたびに読み込まれるため、actions: の内容を少し修正して試すだけなら workshop refresh は不要です。

プロジェクトディレクトリの同期

Workshop では、ホスト側のプロジェクトディレクトリが Workshop 内の /project に mount されます。

そのため、ホスト側で作成したファイルは Workshop 内から見えますし、Workshop 内で作成したファイルもホスト側から見えます。

touch created_outside.txt
workshop exec -- ls /project
workshop exec -- touch /project/created_inside.txt
ls

この挙動のおかげで、ソースコードはホスト側のエディタで編集しつつ、build / test / run だけを Workshop 内で実行する、という使い方ができます。

tasks / changes でログを見る

Workshop では、launch や refresh のような操作が change として記録され、その中の細かい処理が task として確認できます。

workshop changes
# ID  STATUS  SPAWN               READY               SUMMARY
# 5   Done    today at 14:25 JST  today at 14:25 JST  Launch "dev" workshop
# 6   Done    today at 14:26 JST  today at 14:27 JST  Execute action "setup"
# 7   Done    today at 14:28 JST  today at 14:28 JST  Execute action "build"
# 8   Done    today at 14:29 JST  today at 14:29 JST  Remove "dev" workshop

特定の change の task を確認するには、change ID を指定します。

workshop tasks <CHANGE_ID>
# STATUS  DURATION  SUMMARY
# Done       108ms  Disconnect interfaces of "system" SDK
# Done        76ms  Discard "dev" undesired connections
# Done      3.114s  Stop "dev" workshop
# Done       350ms  Uninstall "system" SDK
#   :

hook が失敗した場合も、workshop tasks <CHANGE_ID> でログを確認できます。

SDK hooks

Workshop では、環境を準備するための hook を定義できます。

特に基本になるのが、setup-base と setup-project です。

setup-base は、Workshop の base 環境を準備するための hook です。system package のインストールや開発ツールの導入など、プロジェクトディレクトリに依存しない初期設定に向いています。

一方で、setup-project は project directory が mount された後に実行される hook です。そのため、/project 配下のファイルを前提にした処理や、プロジェクト固有の初期化に向いています。

たとえば、一般的な CLI / Web アプリ開発環境なら、次のように分けられます。

setup-base:
  - apt package のインストール
  - Node.js / Python / Go などの開発ツール導入
  - OS package として必要なライブラリの導入

setup-project:
  - /project に移動
  - npm install / pip install / go mod download などの依存取得
  - .env.example から .env を作る
  - database migration の準備
  - project-local な cache directory の作成

setup-base の例です。

#!/usr/bin/env bash
set -euxo pipefail

apt-get update
apt-get install -y \
  ca-certificates \
  curl \
  git \
  make \
  python3 \
  python3-venv \
  nodejs \
  npm

このように、base 環境そのものに入れておきたいものは setup-base に置くと分かりやすいです。

次に setup-project の例です。

#!/usr/bin/env bash
set -euxo pipefail

cd /project

if [ -f package.json ]; then
  npm install
fi

if [ -f requirements.txt ]; then
  python3 -m venv .venv
  . .venv/bin/activate
  pip install -r requirements.txt
fi

if [ -f .env.example ] && [ ! -f .env ]; then
  cp .env.example .env
fi

mkdir -p .cache

setup-project は /project が見える状態で実行されるため、リポジトリ内のファイルを見ながら初期化できます。

この分け方にしておくと、次のように整理できます。

  • setup-base: sandbox の土台を作る
  • setup-project: その repository を開発できる状態にする

Workshop はこのように、system-level な準備と project-level な準備を hook として分けて書けるのが便利です。

Workshop で起動されるコンテナの特徴

Workshop は内部的に LXD を利用しており、workshop launch を実行すると、プロジェクトごとの開発用コンテナが作成されます。

実際に起動されたコンテナは、通常のアプリケーションコンテナというより、開発作業用の sandbox に近い性質を持っています。

プロジェクトディレクトリが /project に mount される

Workshop の大きな特徴は、ホスト側のプロジェクトディレクトリがコンテナ内の /project に mount される点です。

そのため、エディタや Git 操作はホスト側で行い、build / test / run は Workshop 内で実行する、という使い方ができます。

workshop shell

で shell に入ると、基本的には /project を作業ディレクトリとして開発できます。

workshop@dev-xxxx:/project$ pwd
/project

この mount は双方向なので、コンテナ内で生成したファイルはホスト側からも見えます。たとえば build artifacts や generated files をそのままホスト側のエディタや Git から確認できます。

一方で、これはコンテナ内の処理がホスト側の作業ツリーを書き換えられるということでもあります。Workshop は開発環境としては非常に便利ですが、未信頼コードを強く隔離するための sandbox として使う場合は、この点を意識しておいた方がよさそうです。

SDK は読み取り専用で mount される

Workshop では、base image の上に SDK を追加して開発環境を構成します。

起動後のコンテナを見ると、SDK は /var/lib/workshop/sdk/<sdk-name> のような場所に mount されます。

/var/lib/workshop/sdk/system
/var/lib/workshop/sdk/rkc-base

SDK は基本的に読み取り専用で mount されるため、Workshop 内で作業していても SDK 本体を直接書き換える形にはなりません。

この構造のおかげで、SDK は「開発環境の部品」として扱いやすくなっています。プロジェクト固有のセットアップは .workshop/<sdk-name>/hooks/ に書き、実際の作業は /project 側で行う、という分離がしやすいです。

apt cache などは Workshop 側で管理される

コンテナ内では apt package をインストールすることもあります。

Workshop では apt cache などの一部ディレクトリが Workshop 側の管理領域から mount されます。これにより、同じ環境を何度も作り直す場合でも、ある程度キャッシュを活用できます。

開発用途では、パッケージインストールの時間を減らせるので便利です。

dev container としての性格が強い

全体として、Workshop のコンテナは「本番アプリケーションを隔離して動かすコンテナ」というより、開発に必要な道具をまとめておく dev container に近い印象です。

  • ホストのプロジェクトディレクトリを /project に mount する
  • SDK を読み取り専用で mount する
  • actions 経由で build / test / run を実行する
  • 必要に応じて tunnel interface でポートを公開できる
  • hook の結果や health check を workshopctl 経由で返せる

このあたりの設計を見ると、Workshop は「ホスト環境を完全に隠す」というより、ホストの開発作業とコンテナ内の再現可能なツールチェーンをうまくつなぐための仕組みだと感じました。

実際の使い方を紹介してみる

ここからは、実際に自作 OS プロジェクト Rk-C の開発環境を Workshop で定義した例を紹介します。
GitHubリポジトリはこちら: Rk-C microkernel for RISC-V 64bit

Rk-C の開発では、Nim、clang / lld、QEMU、OpenSBI、RISC-V GNU toolchain、TAP networking などを使います。

これらをホストに直接入れてもよいのですが、特に QEMU / OpenSBI / networking 周りは環境差分が出やすく、README に手順を書く方式だと少し管理しづらさがありました。

そこで、Workshop を使って開発環境をリポジトリ内に定義し、次のような操作で build / test / run できるようにしました。

workshop launch
workshop run -- build
workshop run -- test
workshop run -- run

以降では、その構成を順番に紹介します。

基本構成

今回の構成は次のようにしました。

.
├── workshop.yaml
└── .workshop/
    └── rkc-base/
        ├── sdk.yaml
        └── hooks/
            ├── setup-base
            └── setup-project

workshop.yaml には、Workshop 本体の設定と actions を書きます。

.workshop/rkc-base/ は project-local SDK です。

今回は、Rk-C 専用の SDK として、必要なパッケージのインストール、Nim の配置、OpenSBI の clone / build、TAP interface の準備などをまとめました。

workshop.yaml

例として、以下のような定義にしています。

name: rkcdev
base: ubuntu@24.04

sdks:
  - name: project-rkc-base

actions:
  build: |
    set -eux
    cd /project
    make build

  build-bins: |
    set -eux
    cd /project
    make build-bins

  test: |
    set -eux
    cd /project
    make test-apps

  run: |
    set -eux
    cd /project
    make run

  debug: |
    set -eux
    cd /project
    make qemu-debug

  clean: |
    set -eux
    cd /project
    make clean

これで、ホスト側から次のように実行できます。

workshop run -- build
workshop run -- test
workshop run -- run

/project にはリポジトリが mount されるので、Workshop 内では /project に移動して make を実行しています。

SDK 定義

.workshop/rkc-base/sdk.yaml は最小限だと次のような形です。

name: rkc-base
version: "0.1.0"
summary: Rk-C development environment
description: |
  Development environment for building, testing, and running Rk-C.
license: MIT

プロジェクト固有の SDK として使うので、外部公開用というより、リポジトリに含める開発環境定義という位置づけです。

setup-base

setup-base には、root 権限が必要な初期設定を書きました。

たとえば、apt package のインストールです。

#!/usr/bin/env bash
set -euxo pipefail

apt-get update
apt-get install -y \
  ca-certificates \
  curl \
  git \
  make \
  python3 \
  clang \
  lld \
  llvm \
  qemu-system-misc \
  qemu-utils \
  device-tree-compiler \
  build-essential \
  libglib2.0-dev \
  libpixman-1-dev \
  gcc-riscv64-linux-gnu \
  binutils-riscv64-linux-gnu

Rk-C では OpenSBI を build するために riscv64-linux-gnu- toolchain が必要なので、gcc-riscv64-linux-gnu と binutils-riscv64-linux-gnu もここで入れています。

そのほかにも必要となる Nim のインストールや OpenSBI のビルドなども setup-base で行っています。

setup-project

setup-project には、project mount 後に実行したい処理を書きました。

今回の場合は、OpenSBI の build や TAP interface のセットアップなど、プロジェクトに依存する処理をこちらに置いています。

TAP networking も Workshop 内で準備できるようにしたことで、ホスト側で次のような作業をしなくて済むようになりました。

sudo ip tuntap add dev tap0 mode tap user "$USER"
sudo ip link set tap0 up
sudo ip addr add 10.0.1.1/24 dev tap0
sudo sysctl -w net.ipv4.ip_forward=1

QEMU / TAP 周りは環境差分が出やすいので、ここを Workshop 側に閉じ込められるのはかなり便利でした。

GDB port を公開する

qemu-debug では QEMU が GDB server を localhost:1234 で待ちます。

ただし、Workshop 内の localhost:1234 はそのままだとホストから見えません。

この場合は tunnel interface を使って、Workshop 内の port を host に公開できます。

sdks:
  - name: project-rkc-base
    slots:
      gdb:
        interface: tunnel
        endpoint: localhost:1234

  - name: system
    plugs:
      gdb:
        interface: tunnel
        endpoint: localhost:1234

イメージとしては、

  • コンテナ内[SLOT]に対して
  • ホスト側[PLUGIN]を接続する

という感じです。

これで workshop run -- debug 後に、ホスト側から次のように接続できるようになります。

gdb-multiarch bin/kernel.elf
(gdb) target remote localhost:1234

実際に使う

最終的に、Rk-C の開発では次のような流れになります。

workshop launch
workshop run -- build
workshop run -- test
workshop run -- run

デバッグする場合は次のようにします。

workshop run -- debug

Docker Compose との違い

今回触ってみて、Workshop は Docker Compose よりも「リポジトリに紐づいた開発環境」として使いやすい印象でした。

Docker Compose は、複数サービスを起動する用途では非常に便利です。

一方で、今回のように、

  • QEMU を動かす
  • クロスコンパイラを入れる
  • OpenSBI を build する
  • TAP interface を準備する
  • project directory を前提に build / test / run action を定義する

といった用途では、Workshop の方が自然に感じました。

特に project-local SDK と actions の組み合わせがよく、環境構築 / 動作確認の手順をかなり短くできます。

よかったところ

実際に使ってみてよかった点は以下です。

  • リポジトリ内に開発環境定義を置ける
  • workshop launch で環境を起動できる
  • workshop run -- build/test/run のように操作を actions として定義できる
  • QEMU や OpenSBI などの環境差分を吸収しやすい
  • project-local SDK でプロジェクト固有のセットアップを管理できる
  • tunnel interface で debug port を host に公開できる
  • task log が見やすく、hook 失敗時の調査がしやすい

まとめ

Canonical Workshop を使って、Rk-C の開発環境をリポジトリ内に定義してみました。

結果として、従来 README に書いていた host setup 手順の多くを Workshop SDK に移せました。

特に QEMU / OpenSBI / RISC-V toolchain / TAP networking のような、環境差分が出やすい部分を sandbox 側に閉じ込められたのが大きかったです。

自作 OS や低レイヤー系プロジェクトのように、開発環境の再現が難しくなりがちなプロジェクトでは、Workshop はかなり相性が良いと感じました。

ぜひ皆さんも workshop を使ってみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?