Status
[!NOTE] This project is in early development and not ready for production use.
The goal of Caisson is to provide an update workflow for predefined Docker services on air-gapped or offline devices. In 0.1.0, operators should only need to point the CLI at a local package file and apply the update. The backend handles validation, image import, service restart, health checks, rollback, and local audit history.
Why the name
A caisson is a controlled chamber used to move work safely through difficult or isolated environments. That is the idea behind this project: a controlled path for getting updates onto an edge device and applying them safely.
What the project is about
Caisson is focused on:
- accept an offline update package
- work through a CLI-first operator flow in
0.1.0 - validate it
- load the Docker image
- update a predefined service
- run health checks
- roll back automatically if the update fails
- keep a local history of what happened
- support predefined services that use either direct Docker control or developer-provided Docker Compose definitions
What it is not
Caisson is not:
- a fleet manager
- a registry
- a cloud update system
- a general Docker dashboard
Alternatives
Hauler describes itself as an “Airgap Swiss Army Knife” for fetching, storing, packaging, and distributing artifacts across disconnected environments.
Mender supports standalone deployments for devices without network connectivity, including updates triggered manually or through external storage, and it also has Docker Compose update support.
Portainer is a broader container management UI for Docker and other environments, positioned as a toolset for building and managing containers.
Caisson exists because I wanted something smaller and more opinionated than those options: a local updater focused specifically on offline Docker service updates on one device, with a simple operator experience. It is not always that the human closest to the end device has the technical knowlege to safely update its services.
Current direction
The first release is focused on getting the baseline workflow working:
- offline package intake
- validation
- Docker image import
- service update
- health checks
- rollback
- local audit/history
[!NOTE] Current roadmap:
0.1.0: cli for offline updater0.2.0: minimal GUI on top of the same application logic0.3.0: self-updater support0.4.0: encryption and signatures
Current CLI
That command shows the predefined services from services.toml together with the locally known image state and the last recorded update result.
Validate a package without changing anything:
That command:
- stages the package locally
- validates the
.edgepkgtar structure - parses
manifest.toml - checks target service compatibility against
services.toml - persists validation records and audit events under the chosen state directory
Load a package:
That command validates the package first, asks for confirmation, imports the staged image.tar into Docker, applies the update to the target service, runs health checks, and rolls back automatically if the update does not stay healthy.
If you want the same flow without the confirmation prompt:
To inspect local update history after a run:
If you want to remove leftover local package artifacts created under the updater state directory:
That command currently cleans only the local package workspace. It does not remove validation records, audit history, candidate releases, or service state.
Quick way to build a local package for manual testing is:
tmpdir=
If you want to test the full package load path, start the managed service first so there is something to replace:
||
Then run:
hello-world is still fine for the earlier image-import smoke test, but it exits immediately, so it is not a good fit for the full apply + health check.
For a one-shot local smoke test, run:
To build just the lightweight demo package used in local docs and demos:
Test fixtures live under tests/fixtures/.