encapsule
CLI tool to run developer containers, isolating your home directory and host from container side effects:
"encapsules" a project and/or temp home dir together with select "capabilities".
Originally derived from toolbox-constrained tool.
Run a (toolbox) container or image as
an isolated podman container. Unlike with toolbox enter, this does not
bind-mount your home directory or integrate with the host by default.
You can explicitly choose what dir(s) to mount or features to enable,
selecting user-configured "capabilities" that the encapsule container can access.
encapsule TOOLBOX [options] [CMD...]
if TOOLBOX is a container it will be committed (saved) to an "encapsule" container image from the named toolbox container using buildah.
Examples
# Isolated shell without host fs access
$ encapsule my-toolbox
# Mount current (project) directory in / and set it as the working directory
# (also names the container after the project, e.g. encapsule-my-toolbox-myproject)
$ encapsule my-toolbox -p .
# Bind mount a volume
$ encapsule my-toolbox -v ~/data:/data
# Mount a temp "home" directory (created if it doesn't exist)
$ encapsule my-toolbox --home /tmp/somedir
# Use capabilities from config
$ encapsule my-toolbox --cap ssh --cap git
# Read-only container filesystem
$ encapsule my-toolbox --readonly
# Remove the saved image
$ encapsule my-toolbox --delete-image
# Set environment variables and prepend to PATH
$ encapsule my-toolbox -e MY_VAR=hello -P ~/.local/bin
# Run a specific command
$ encapsule my-toolbox -- ls /
# Dry run: print the full podman command without running it
$ encapsule my-toolbox --dryrun
# run directly from an image
$ encapsule fedora:44 --home tmphome
Encapsule containers are ephemeral by default: use --keep to leave the encapsule container around for reuse. Note the saved image will be reused next time unless using --refresh.
Usage
$ encapsule --version
0.3
$ encapsule --help
encapsule
Usage: encapsule [--version] [TOOLBOX] [-v|--volume HOST:CONTAINER[:opts]]
[-e|--env KEY[=VALUE]] [-P|--path DIR] [-i|--init CMD]
[--cap NAME] [--home DIR] [-p|--project DIR] [-n|--name NAME]
[--caps | --list | --remove | --delete-image | --stop] [--keep]
[--readonly] [--no-network] [--no-sudo] [--unique]
[--podman-opt OPTION] [--debug] [--dryrun] [--refresh] [CMD]
Run a toolbox image in an isolated podman container
Available options:
-h,--help Show this help text
--version Show version
-v,--volume HOST:CONTAINER[:opts]
Bind mounts (default to selinux :z)
-e,--env KEY[=VALUE] Set or pass through an environment variable
-P,--path DIR Prepend a directory to PATH inside the container
-i,--init CMD A bash snippet run when creating the encapsule
container
--cap NAME Enable a capability from the config file
--home DIR Mount a directory as a writable home (created if
missing)
-p,--project DIR Mount a project directory and set as workdir
-n,--name NAME Container name (for creating or actions)
--caps List available capabilities from the config file
--list List encapsule images and containers
--remove Remove encapsule container
--delete-image Remove encapsule image
--stop Stop encapsule container
--keep Keep the encapsule container after exiting
--readonly Make the encapsule container filesystem read-only
--no-network Disable network access
--no-sudo Skip passwordless sudo setup
--unique Run a new encapsule container even if one is already
running
--podman-opt OPTION Pass an option directly to podman
--debug Show debug output
--dryrun Print the podman command instead of running it
--refresh Force re-commit of the toolbox image
Capabilities
Define reusable groups of volumes, environment variables, PATH entries,
and init commands in ~/.config/encapsule/config.toml:
[capabilities.ssh]
volumes = ["~/.ssh:~/.ssh:ro"]
[capabilities.git]
volumes = ["~/.gitconfig:ro"]
[capabilities.wayland]
env = ["WAYLAND_DISPLAY", "XDG_RUNTIME_DIR"]
volumes = ["$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"]
security_opts = ["label=disable"]
[capabilities.rust]
path = ["~/.cargo/bin"]
Each capability can define:
volumes — list of bind mount specs
env — list of environment variables to set or pass through
path — list of directories to prepend to $PATH
init — a bash snippet to run on encapsule container creation
security_opts — list of --security-opt values passed to podman
~ and envvars are expanded in volume and path specs.
If the host and container paths are the same, you can use the shorthand
PATH[:opts] instead of PATH:PATH[:opts].
How it works
- Commits the named toolbox container to an encapsule image using
buildah commit
(reuses the existing image unless --refresh is passed)
- Runs
podman run with --userns=keep-id so you are your own user, not root
- Tries to install runuser (util-linux) and sudo if they are missing with dnf or apt-get.
- Sets up passwordless
sudo inside the encapsule container (unless --no-sudo)
- Bind mounts get SELinux
:z (shared) labels automatically,
so multiple containers can safely access the same directories
- When
-p/--project DIR is used (and --name isn't), the container name
includes the project directory's name (e.g. encapsule-mytoolbox-myproject),
so you can run the same toolbox against different projects at the same time
in separate encapsule containers
Installation
A copr repo is available for Fedora and Epel 10:
https://copr.fedorainfracloud.org/coprs/petersen/encapsule/
Building from source
cabal install
or stack install.
Requirements
- podman and buildah
- An existing (toolbox) container (created with
toolbox create) or image.
- Alternatively some non-toolbox other container/images may also work.
I already mentioned toolbox-constrained from which the initial code was derived.
There is also similarly schupfn which uses QEMU to run a toolbox container image in a VM with a direct private ssh connection.
For stronger sandboxing and isolation, specially network, consider using OpenShell.
Contribute
encapsule is at https://github.com/juhp/encapsule and distributed
under the Apache-2.0 license.