System components¶
Workshop is designed to run on Linux systems and is primarily distributed as a snap. It relies on LXD as its containerization backend and ZFS for efficient storage management.
Workshop’s distributed architecture organizes functionality across specialized subsystems, with each handling specific aspects of workshop lifecycle management while maintaining clear separation of concerns and well-defined communication interfaces.
The core subsystems include the workshopd daemon for orchestration, the LXD backend for container management, the state database for transactional jobs, the interface system for resource sharing, and systemd integration for service lifecycle management. Storage is handled through the ZFS storage component with metadata persistence via the state database.
Note
For a description of how these components interact at runtime, see Runtime behavior.
Main components¶
Workshop installation on your host system includes three primary components:
The workshop CLI serves as the main user interface, providing a thin client that translates user commands and communicates with workshopd through a Unix domain socket.
The workshopd daemon runs in the background with elevated privileges. It manages the full workshop lifecycle including container creation, SDK installation, interface coordination, and state persistence through a REST API.
The workshopctl tool runs inside a workshop and has access to a very limited subset of workshopd’s REST API for service-related and reporting tasks.
The communication architecture between these components uses a layered approach where the CLI communicates with workshopd via Unix domain sockets, while workshopd interfaces with LXD through the latter’s native API.
CLI: workshop¶
The workshop CLI provides a comprehensive command-line interface for managing workshops and interacting with workshopd. It is organized into logical command groups for different aspects of Workshop’s operations:
Create, update, and delete operations
Start and stop control
Exploration and troubleshooting
Interface connection management
Workshop utilization
SDK sketching
Miscellaneous utilities
For all operations, the CLI communicates with workshopd through a REST API exposed over Unix domain sockets, using a client library that handles connection management, error handling, and request-response serialization. The client supports both synchronous and asynchronous operations.
For further details, see workshop (CLI).
Control interface: workshopctl¶
The workshopctl tool serves as a secure bridge between workshop containers and the host system, sending control and status messages from inside the workshop back to the host.
The tool is typically invoked by SDK hooks;
it operates with the workshop user’s permissions (UID 1000)
and communicates with workshopd’s REST API
through a dedicated Unix domain socket inside the workshop
at /var/lib/workshop/run/workshop.socket.untrusted.
The tool’s capabilities are intentionally limited to minimize security risks.
Daemon: workshopd¶
The workshopd daemon serves as the central orchestration hub, coordinating all workshop operations and maintaining system state.
The daemon exposes the primary REST API for CLI and external integrations while orchestrating workshop lifecycle through transactional state management. It coordinates interface connections and policy validation.
Key components within the daemon include:
the REST API server for handling HTTP requests,
the state engine as central coordinator,
the task runner for running tasks according to their dependencies,
and specialized state managers for workshops, SDKs, interfaces, commands, and hooks.
During startup, the daemon initializes state managers, establishes an LXD connection, and starts the API server. It supports graceful shutdown with task completion and state persistence. Failure modes are handled through degraded mode operation for LXD unavailability and error detection for connection issues. The daemon provides systemd notification support and structured logging for telemetry.
Authentication occurs via Unix domain socket credentials. Privilege separation exists between trusted and untrusted API endpoints.
REST API¶
The workshopd daemon exposes a versioned REST API (v1) over Unix domain sockets for secure local communication with the CLI. The API provides endpoints for all workshop operations.
Trusted endpoints (require Unix socket credentials):
Workshop lifecycle operations (
/v1/projects/<ID>/workshops)SDK management (
/v1/sdks)Interface connection management (
/v1/connections)Change tracking and monitoring (
/v1/changes)Warning and error reporting (
/v1/warnings)
Untrusted endpoints (accessible from within workshops):
Workshop control interface (
/v1/workshopctl)
The API implements proper access control and supports both synchronous and asynchronous operations.
For data exchange, the API uses JSON with well-defined types for workshop information, SDK details, and interface connections.
LXD backend¶
The workshopd daemon maintains a persistent connection to LXD
through its Unix domain socket at /var/snap/lxd/common/lxd/unix.socket,
managing container operations.
The LXD communication layer handles projects and container lifecycle, storage management, network configuration, and device pass-through.
Its responsibilities also include base image management and caching, providing snapshot and restore capabilities for efficient workshop updates.
Workshop implements user isolation through LXD’s project system,
automatically creating dedicated projects for each user
following the naming pattern workshop.<USERNAME>.
Each user project includes a corresponding snapshots project
(workshop-snapshots.<USERNAME>)
used for temporary storage during workshop rebuild operations.
Note
The term “project” in relation to Workshop can be used in two unrelated senses:
LXD projects, identified by their names (e.g.,
workshop.john). These are created at workshopd’s request to provide isolation in LXD.Workshop projects, identified by Workshop-assigned IDs. These are user-defined directories (e.g.,
my-workshop) used to organize and manage workshops (e.g.,my-workshop). They are referenced in CLI commands and API endpoints.
Storage backends¶
Workshop uses ZFS for storage on Linux, with automatic Btrfs fallback on Windows Subsystem for Linux (WSL). Storage is managed via LXD and requires a minimum pool size of 5 GiB.
The storage backend manages container root filesystems, workshop-specific data volumes, cached base images, and snapshots for efficient workshop updates and rollbacks. This component provides copy-on-write storage utilization, LZ4 compression, and quota management, and is utilized by the LXD backend for container operations.
State database¶
The state.json file is the authoritative database
for workshop metadata, configuration, and operational state.
It enables transactional operations with atomic updates and rollback capabilities.
It uses a model of “changes” (high-level modification to the system state) and “tasks” (operations with Do/Undo handlers that constitute a change) to ensure that requests either complete fully or are rolled back.
Images¶
Workshop containers are created from base operating system images. By default, Workshop fetches base images, such as Ubuntu 22.04 LTS, Ubuntu 24.04 LTS, or Ubuntu 26.04 LTS, from the official Ubuntu cloud image repository.
Interfaces¶
This system handles interface connections, enforces security policies, and also manages the lifecycle of resource connections.
First of all, the interface system validates connections between plugs and slots. Built-in interface declarations enforcement handles auto- and manual connections.
Key components include the interface repository serving as a registry of available interface types, policy validator for enforcing connection rules and security constraints, connection manager handling connection establishment and teardown, and security backends responsible for creating LXD profiles of established interface connections.
For further details, see Interface concepts.
Note
See mount.go in Workshop source code for an elaborate example.
Network¶
Workshop establishes a dedicated network infrastructure
through the workshopbr0 bridge network,
providing isolated networking for workshop containers.
This bridge network includes DNS resolution
configured with the workshop domain.
Diagrams¶
The system components and their interactions:
graph TB
subgraph HOST ["Host system"]
subgraph CLI_SUBSYSTEM ["CLI"]
cli[Workshop CLI]
client[HTTP client library]
end
subgraph LXD ["LXD"]
lxd_daemon[LXD daemon]
containers[(Workshop containers)]
end
subgraph DAEMON_SUBSYSTEM ["workshopd"]
api[REST API server]
daemon[Daemon]
state_mgrs[State managers]
task_runner[Task runner]
hook_manager[Hook manager]
workshop_manager[Workshop manager]
sdk_manager[SDK manager]
end
subgraph BACKEND_SUBSYSTEM ["LXD backend"]
lxd_backend[LXD backend]
end
subgraph STATE_SUBSYSTEM ["State management"]
state_db[(state.json)]
checkpointer[Checkpoint handler]
end
subgraph INTERFACE_SUBSYSTEM ["Interface management"]
repo[Interface repository]
connector[Connection manager]
end
subgraph STORAGE_SUBSYSTEM ["ZFS storage"]
zfs_pool[(ZFS pool)]
snapshot_mgr[Snapshot manager]
volume_mgr[Volume manager]
end
subgraph SYSTEMD_SUBSYSTEM ["systemd integration"]
service_unit[workshopd.service]
socket_activation[Socket activation]
watchdog[Watchdog]
end
end
subgraph EXT_IMG [Image server]
img_server[("cloud-images.ubuntu.com")]
end
api --> daemon
cli --> api
client --> api
connector --> lxd_backend
connector --> repo
daemon --> state_mgrs
hook_manager --> lxd_backend
lxd_backend --> lxd_daemon
lxd_backend <--> img_server
lxd_daemon --> containers
lxd_daemon --> zfs_pool
sdk_manager --> lxd_backend
service_unit --> api
socket_activation --> api
state_mgrs --> checkpointer
state_mgrs --> connector
state_mgrs --> hook_manager
state_mgrs --> sdk_manager
state_mgrs --> state_db
state_mgrs --> task_runner
state_mgrs --> workshop_manager
watchdog --> daemon
workshop_manager --> lxd_backend
zfs_pool --> snapshot_mgr
zfs_pool --> volume_mgr