Workshop internals¶
This topic speaks about what goes into building and running a workshop.
What a workshop is¶
A workshop is a development environment running in a container, mapping your project to its contained dependencies. It is fully described in a definition file.
Workshop currently uses LXD as its container engine, communicating to it via the socket-activated workshopd backend, but that is an implementation detail and potential subject to change.
When you launch a workshop, you create and start a container with a base image. The image is downloaded from the container engine server and cached locally.
On top of the base image, one or more SDKs are usually applied, which provide tools for development and runtime tasks. SDKs are downloaded from the SDK Store that is specific to Workshop.
SDKs are installed in the order dictated by the workshop definition:
first system, then user-listed SDKs, and finally sketch.
Each SDK’s setup-base hook runs immediately after that SDK is installed;
this serves to customize the workshop
and prepare each SDK for use before proceeding further.
After all SDKs are installed,
the following hooks execute sequentially in the same deterministic order:
setup-project hooks run first to prepare the project environment,
followed by check-health hooks to verify the workshop is ready for use.
The host user running Workshop is mapped to the default workshop user,
named workshop in the container,
with uid=1000 and gid=1000.
This ensures that files and directories changed by the workshop user
inside the container map back to the same user on the host,
preserving consistent ownership and permissions.
User sessions and ID mapping¶
By default, all commands that execute something inside a workshop
(exec, run, shell)
run login shells as uid=1000 and gid=1000,
unless you explicitly change the IDs.
This ensures files created inside the container map back to the host user.
By default, $XDG_RUNTIME_DIR is set to /run/user/1000/,
and a user-scoped session bus address is created at /run/user/1000/bus.
Using other IDs can break sessions.
Finally, it’s worth mentioning that having an active session doesn’t prevent refresh or any other change from running. However, you may need to restart the session to see the effect.
How workshops are built¶
At the container launch, Workshop does the following:
Reads the workshop definition to see which base image and SDKs are needed.
Fetches the required images and SDKs from the image server and the Store, if they aren’t already cached locally.
Reads definitions of local SDKs, such as the sketch SDK, and copies them to a read-only location.
Spins up the container with mapped user and group IDs, configures basic devices like the root disk and network bridge.
Installs the SDKs, then runs their
setup-basehooks in the container.Configures the container’s time zone to match the host.
Maps the project directory on the host to
/projectin the container; this allows to transparently work on the host-based files using the tools provided by the SDKs.Sets up interface plugs and slots defined by the workshop and its SDKs for extra devices and capabilities.
Runs
setup-projectandcheck-healthhooks for all SDKs.
Thus, the container is built, or launched in Workshop terms. All subsequent start and stop operations affect an already built container; any rebuilds occur only with a refresh.
After a successful start, you have a running container named for your workshop, accessible via the regular container engine capabilities. From a user’s perspective, it behaves like a custom Ubuntu environment tailored to a specific project.
How workshops are updated¶
Workshop has a refresh manager that tracks all updates in a workshop (changes to the base image, adding or removing SDKs, updates to the definition) and builds an update plan to decide whether a refresh is needed.
Some changes don’t cause a refresh by their nature; for example, updated actions in the definition are copied inside the workshop. Larger ones, like switching base images or changing the SDK layout, trigger the refresh mechanism:
A snapshot of the current container is stashed as a fallback.
A new container is built based on the updated setup.
If the build succeeds, the old container is dropped. If it fails, the system reverts to the previous snapshot.
After a successful refresh, the stash is cleaned up.
This prevents broken states during major refreshes.
To explicitly revert to the state after the last successful launch or refresh, use the workshop restore command. It restores the container filesystem from the most recent snapshot and resets all connections and mounts to their defaults. Unlike the automatic rollback during a failed refresh, restore is a deliberate user action to discard all changes made to a workshop since it was last set up.
Storage pools and drivers¶
Workshop stores its containers and data on a storage pool. On Linux, Workshop uses ZFS, while on Windows Subsystem for Linux it automatically uses Btrfs. This approach consolidates container images, apt caches, SDKs and other workshop content under a single system.
If you need more space or different performance,
you can resize or tune the storage pool (it’s named workshop),
using the lxc storage command
as suggested in this LXD documentation section.
However, day-to-day usage requires little manual intervention.
Attention
Don’t use storage driver utilities (such as zfs or btrfs) directly to alter the LXD-managed storage pool, as this may cause issues with LXD.
Additionally, Workshop ensures the LXD storage pool itself is at least 5 GiB. Otherwise, LXD allocates 20% of the available disk space by default. If the total disk space is under 14 GiB, this would result in a pool size of only about 2 GiB per workshop, making it more likely to run out of space.
Details of the apt cache¶
To speed up repeated software installations,
each workshop maintains a package cache at /var/cache/apt/archives.
Because the container is single-user,
only the mapped user and root can access that cache.
When a workshop is removed, the apt cache directory is removed as well.
Interfaces¶
As a reminder, Workshop enforces resource access with plugs and slots. A plug requests a resource (for example, the GPU or a socket), and a slot provides it.
However, only the default workshop user can access the host resources that interfaces expose inside the container. Other users may exist (for example, those hard-coded in an SDK), but they do not have that access and are not intended to.
In particular, this includes interface-based SSH or desktop sessions, which are also limited to the default workshop user.
See also¶
Explanation:
Reference: