jocker scaffolds a minimal Juju Kubernetes charm tree for an ad-hoc OCI
image (from Docker Hub or any other registry) -- the closest thing to
docker run for Juju.
MVP: only jocker init is implemented. It generates the charm tree; you
pack and deploy it yourself with charmcraft and juju. A jocker deploy
command that automates packing/deploying is planned for later.
- uv -- to run jocker itself, and because
jocker uses it to generate the charm's
uv.lockas a final step. - skopeo (optional but recommended) -- jocker uses it to prefill each container's command and environment config defaults from the image. Without it, those defaults are left empty and jocker prints a warning.
Run directly from GitHub with uv, no local install needed:
uv tool run --from git+https://github.com/<your-org>/jocker jocker init my-app --image my-app=docker.io/library/nginx:latest
Note that jocker appears twice: --from git+https://.../jocker tells uv
which package to fetch, and the second jocker tells it which command from
that package to run (uv tool run doesn't infer the command name from
--from). Dropping the second jocker -- e.g. running uv tool run --from git+https://.../jocker init my-app ... -- makes uv try to run a program
literally called init from your PATH (usually your system's init/pid 1
binary), which fails with a confusing init: unrecognized option error.
Or install it as a persistent tool:
uv tool install --from git+https://github.com/<your-org>/jocker jocker
If you have a local clone of this repo (e.g. at /home/user/code/jocker)
and want to use it from somewhere else, like /tmp/some-k8s-operator, point
uv run at the checkout with --project -- you don't need to cd into it
or install anything globally:
cd /tmp/some-k8s-operator
uv run --project /home/user/code/jocker jocker init my-app --image my-app=docker.io/library/nginx:latest
uv run --project <path> uses that path's environment (installing/syncing
it on first use) but still runs the command with your current directory as
the working directory, so jocker init scaffolds into /tmp/some-k8s-operator
as expected.
If you'll be doing this often, install it as a tool from the local path
instead, which puts a jocker command on your PATH:
uv tool install --from /home/user/code/jocker jocker
After editing jocker's source, re-sync with uv tool upgrade jocker (or
uv tool install --reinstall --from /path/to/jocker jocker) to pick up the
changes.
jocker init <charm-name> --image NAME=IMAGE [--image NAME=IMAGE ...] [--storage NAME=PATH ...] [--ports PORT,PORT,...] [--summary TEXT] [--description TEXT] [--base ubuntu@24.04]
- Must be run in an empty directory (created if it doesn't exist yet). jocker aborts if the target directory already has files in it.
--image NAME=IMAGEis repeatable and required at least once. Each entry adds a workload container namedNAME(also used as its Pebble service name), runningIMAGEas theupstream-sourceof itsoci-imageresource (namedNAME-image) incharmcraft.yaml.--storage NAME=PATHcan be repeated to declare filesystem storage. Every storage entry is mounted atPATHin every container declared via--image.- Each container gets its own namespaced config options:
NAME-commandandNAME-environment. If skopeo is installed, jocker usesskopeo inspect --configon each image to prefill these options' defaults from the image'sEntrypointandEnv. If skopeo is missing, or inspection fails for a given image, jocker leaves that container's defaults empty and prints a warning -- it does not abort. portsis a single, shared config option (ports are per-pod, not per-container). Use--ports PORT,PORT,...(e.g.--ports 8123,8080,4317,4318) to set its default in the generatedcharmcraft.yaml; it's empty by default.- As a final step, jocker runs
uv lock --upgrade --no-cachein the new directory to generateuv.lock(required by the charm'suvbuild plugin). This requiresuvto be installed and onPATH; if it isn't, jocker still leaves the charm tree in place but reports the error so you can run the lock command yourself.
Single container:
mkdir clickhouse-k8s && cd clickhouse-k8s
jocker init clickhouse \
--image clickhouse=docker.io/clickhouse/clickhouse-server:latest \
--storage db=/data/db \
--storage logs=/var/log/clickhouse-server
This creates:
.
├── charmcraft.yaml
├── pyproject.toml
├── uv.lock
├── README.md
├── .gitignore
└── src/
└── charm.py
Then, as usual:
charmcraft pack
juju deploy ./clickhouse_*.charm --resource clickhouse-image=docker.io/clickhouse/clickhouse-server:latest
Multiple containers (e.g. an app plus a sidecar), sharing the same
storage mounts and a default ports list:
jocker init my-app \
--image clickhouse=clickhouse/clickstack-all-in-one:latest \
--image other-sidecar=some/other-sidecar \
--storage db=/data/db \
--ports 8123,8080,4317,4318
- It inspects each image's
Entrypoint/Env(via skopeo) only to prefill config defaults -- always double checkcharmcraft.yamland adjustNAME-command/NAME-environmentif a default is missing or wrong. - It does not run
charmcraft packorjuju deployfor you (jocker deployis planned).
uv sync --extra dev
uv run pytest
To test jocker in a clean, reproducible environment without installing
anything on your host, use Canonical's Workshop
tool. This repo ships a .workshop/dev.yaml definition with a uv SDK
and two ready-made actions.
sudo snap install --channel=6/stable lxd # skip if LXD is already installed
sudo snap install --classic workshop
From the repo root, launch the workshop once:
workshop launch
Then run the actions:
workshop run -- test # uv sync --extra dev && uv run pytest, sandboxed
workshop run -- smoke # runs `jocker init` end-to-end in a scratch dir
After editing jocker's source, no refresh is needed to pick up code
changes -- only .workshop/dev.yaml itself (SDKs/actions) requires a
workshop refresh. Drop into an interactive shell with workshop shell if
you want to poke around manually.