image: resolve --image via the Docker daemon API instead of the CLI#74
Merged
Conversation
Sandlock used to shell out to the `docker` CLI on every --image invocation: `docker create` + `docker export` to dump the container's rootfs, `docker inspect` to read Entrypoint/Cmd, and `docker rm` to clean up. That made the `docker` executable a hard runtime dependency and meant parsing its textual output. Talk to the Docker daemon directly through its HTTP API (the bollard crate) instead. The --image flag still takes a local image reference (python:3.12-slim, a digest, an image id); only the mechanism changes. The `docker` binary no longer needs to be on PATH, though a running daemon with an accessible socket is still required. extract() and inspect_cmd() are now async (callers already run inside the tokio runtime). Both connect to the local daemon and ping it up front, so --image fails early with a clear message when the daemon is unreachable rather than partway through sandbox setup. Image lookup is local only: inspect_image never pulls, and a missing image surfaces the daemon's 404 as "image not found in local Docker storage". Rootfs materialization mirrors the old create+export path: a throwaway stopped container is created from the image, its flattened filesystem is streamed out with export_container into a temp tar (bounded memory, never held whole), then unpacked. The container is always removed afterward, even when the export fails. Because docker export yields an already merged filesystem, all the per-layer, gzip, and AUFS/OCI whiteout handling is gone; only the hard-link fixups remain, since the tar crate resolves link targets against the process cwd rather than the destination root. Extracted rootfs is cached at ~/.cache/sandlock/images/<image-id>/rootfs/, keyed by the image content id, with a .complete marker distinguishing a finished extraction from an interrupted one. Warm-cache invocations skip the daemon export entirely. Signed-off-by: Cong Wang <cwang@multikernel.io>
ff6f4d2 to
dfc9e6a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
--imagetakes a local Docker image reference again (python:3.12-slim, a digest, or an image id), not an archive path.bollardcrate) instead of shelling out to thedockerCLI. The old path randocker create+docker export+docker inspect+docker rmas subprocesses; those are gone, along with thetarsubprocess that piped the export. Thedockerbinary no longer needs to be onPATH.--imagepings the daemon up front and fails early with a clear message when it is unreachable, rather than partway through sandbox setup.inspect_imagenever pulls from a registry, and a missing image surfaces the daemon's 404 asimage not found in local Docker storage.docker exportworks: a throwaway stopped container is created, its flattened filesystem is streamed out withexport_containerinto a temp tar (bounded memory, never held whole), then unpacked. The container is always removed afterward, even when the export fails.docker exportyields an already merged filesystem, the per-layer, gzip, and AUFS/OCI whiteout handling is gone. Only the hard-link fixups remain (thetarcrate resolves link targets against the process cwd rather than the destination root).~/.cache/sandlock/images/<image-id>/rootfs/with a.completemarker distinguishing a finished extraction from an interrupted one. Warm-cache invocations skip the daemon export entirely.flate2andsha2; addbollardandfutures-util; enable tokio'sfsfeature.Also works with Podman: point
DOCKER_HOSTatpodman system service's socket, since bollard speaks the Docker API.Builds on #73.
Test plan
cargo test -p sandlock-core image::(5 image unit tests: hard-link forward references, regular files, default cmd, id sanitization) all greencargo test -p sandlock-cli(26 tests) greensandlock run --image python:3.11-slim -- python3 -c 'import sys; print(sys.version.split()[0])'returns 3.11.15sandlock run --image ubuntu:22.04 -- cat /etc/os-releasereturns Ubuntu 22.04.5 LTSDOCKER_HOSTpointed at a bogus socket) fails early before any sandbox setup