Containers
The docker and podman modules use VFS contexts to run Do
functions in the context of containers. Filesystem operations, external program
launching, and other supported APIs target the container, while the interpreter
remains on the host.
Running in a Container
Use docker.with or podman.with to run a block targeting a fresh container:
import podman systemd
let release = podman.with ubuntu:24.04 do
systemd.os_release()
echo $release["PRETTY_NAME"]
run, with, and build accept cd: and env:. Environment keys may be
strings or symbols; nil unsets a variable and :INHERIT: copies its current
strand value into the container.
run, with, and build also accept pull:, either :missing: (default;
pull only if the image isn't present locally) or :always:.
Starting a container waits for its VFS agent to come up with no built-in
timeout; wrap the call in time.timeout if a bound is needed.
Use with_host to temporarily return to the
host VFS context:
import podman
import fs:
- Path
podman.with ubuntu:24.04 do
let release = Path("/etc/os-release").read()
with_host do Path("release.txt").write $release
Building Images
Container builds use the VFS to keep build steps as executable Do blocks. A
run step can call programs, inspect structured data, loop, and use any
VFS-aware API:
import podman
let image = podman.build
from: ubuntu:24.04
mounts:
- type: cache
target: /var/cache/apt
run: do
run apt-get update
run apt-get install -y curl
add:
target: /etc/example.conf
content: |
enabled=false
chmod: 0o644
patch:
content: |
--- /etc/example.conf
+++ /etc/example.conf
@@ -1 +1 @@
-enabled=false
+enabled=true
tag: example:latest
Build steps are applied in order:
run:enters the build container's VFS and runs a block.add:copies a host path, URL, or inline content into the image.patch:applies a patch supplied by host path or inline content.tag:names the final image and may be repeated.
Top-level mounts: are available throughout the build. Cache mounts retain
downloaded data between builds; bind mounts expose an explicit host path.
Images and Containers
The Docker and Podman modules also provide a small management API:
imagesandcontainerslist and filter objects.imageandcontainerinspect an image reference or container name/ID.Images expose metadata and can be tagged, removed, saved, loaded, pulled, and pushed.Containers expose metadata and can be started, stopped, killed, restarted, or removed.
See the docker and
podman references for the complete interfaces.
Container objects inspect and change the lifecycle of existing containers.
Their with method copies dolang-vfs to a session-specific path under
/tmp, starts it through docker exec or podman exec, and runs a block with
that container as its VFS target. The copied helper uses the standard I/O
transport, so file and process handles use opaque RPC identities rather than
Unix SCM_RIGHTS handle passing.
docker.run and podman.run run a single direct command in a temporary
container, while docker.with and podman.with run a Do block with a
temporary container as a VFS target.
Image builds use a longer-lived temporary container VFS while applying their
ordered run, add, patch, and commit steps.
Manual Container VFS
The module helpers mount dolang-vfs into a temporary container and connect
through a jointly accessible Unix socket. For a long-lived or externally
managed container, the same setup can be performed manually:
- Make the
dolang-vfsbinary available inside the container. - Bind mount a shared private directory in the container.
- Start
dolang-vfsin the container with a socket path in that directory. - Instantiate
Vfswith the socket path on the host
import shell:
- Vfs
let agent = Vfs.unix_socket /run/container-vfs/socket
try
agent.with do run cat /etc/os-release
finally
agent.stop()
Be careful to suitably restrict access to the shared directory. dolang-vfs
will refuse to create a socket in a directory that is not exclusively
accessible by its owner (mode 0700). When connecting, the socket path is
resolved through the current VFS context, so a container can be reached via an
SSH context.
This gives the following common lifetimes:
| Form | Container and VFS lifetime |
|---|---|
docker.with / podman.with |
Temporary container and session for one block |
docker.build / podman.build |
Temporary container spanning the build steps |
Container.with |
Existing container and session for one block |
Other Container methods |
Management handle |
| Manual socket connection | Controlled by the caller and external container lifecycle |
To target Docker on another host, enter that host first and then use the ordinary Docker module: