feat(driver-oci): add OCI compute driver#2312
Conversation
7a55505 to
5fa410c
Compare
|
If we want to go full daemonless, containerd daemon dependency can eventually be removed, it just keeps the scope of this PR smaller for this iteration. |
Shouldn't it be named openshell-driver-containerd ?
Oh. That seems like it needs a really strong justification. This relates to #981 - I still would really like to move away from openshell driving lots of low level custom sandboxing itself towards one where it just reuses existing container framework tooling - especially where e.g. the proxy is a sidecar or other associated process etc. |
containerd-daemon dependency might eventually go away, it's undecided, it just keeps the implementation smaller for now, it only handles transport, runc or crun is orchestrated directly by OpenShell. This is sorta linked to that: oci-client crate in the Rust ecosystem I think, is not the right call. docker, podman, k8s remain separate drivers. |
|
But thanks @cgwalters I did rename: to the "containerd" part of the name does distract from the purpose here. It's OpenShell that kicks off the runc's or crun's. containerd has nothing to do with the isolation. |
Would you expand on this a bit? |
@krishicks see here, it's described in more detail: |
It's not really explained there either:
What's the problem that's being solved in #2313, and why is oci-client a mistake or not the right call? |
The OCI protocol is ossified... This new Rust crate is used in projects like oras, which is known to be unreliable compared to implementations based on containerd or containers/image |
|
It can be reliable on OCI registries like Docker Hub, but it's the internal ones where you get the bug reports, hand-rolled OCI clients reliably break on obscure auth schemes, manifest quirks, and layer edge cases |
|
I'm a bit skeptical of the oci-client crate being problematic as far as talking to registries, I think the larger picture thing is ecosystem stuff like finding and using pull secrets, which is outside the scope of that crate. And container storage. |
|
Thanks for putting this together. As discussed in our sync, the goal of an Using containerd for reliable registry access, content storage, unpacking, and That makes it especially important for the current implementation to make Conceptually, I would like to see something along these lines: Each provider may produce a backend-specific artifact—for example, OCI mounts I also think we should explicitly evaluate how much of the existing VM rootfs There are also parts of the VM driver that we should consider extracting instead
The VM-specific ext4, boot, libkrun, and VFIO code would remain in the VM While reviewing the implementation, I also found several issues that appear to
The unit tests cover the individual helpers well, but the real containerd/runtime tests are ignored and there is no native gateway end-to-end lane. I think an end-to-end test using the real supervisor is important before merging because it would catch the endpoint and lifecycle issues above. My preference would be to treat this PR as the start of an OCI sandbox Given the architectural questions and correctness issues above, I do not think |
"I do not, however, consider a required system containerd daemon to be a viable long-term design.". I agree here. I've been waiting for opinions and decisions on: before changing that here. I might not have communicated that great here. The three daemonless, out-of-the-box, single-node options, I can think of are:
I think 3. carries the most risk FWIW. And would likely end up in a multi-year effort.
The rest sounds ok, I think we can figure it out. |
5fa410c to
16ed6e6
Compare
|
@elezar pushed a round of fixes for the correctness issues you flagged (loopback endpoint, path traversal, runtime --root, subnet collisions, cleanup-on-error, token permissions), all with new unit tests. Left the RootfsProvider/SandboxProvisioner restructuring out of this push since it's a bigger design conversation. Want to spin that off as a follow-up issue/RFC before I touch the driver boundary? |
Is reusing / adapting the implementation the VM uses an option? While I understand that #2313 raises questions about the robustness of the implementation and the long-term maintenance costs, it may be useful to separate the discussion around what we use for rootfs construction (home-rolled vs containerd lib) from what we're using to provision the sandboxes (libkrun vs OCI). |
Yes I agree, that's an option and should be the end goal. Consolidate on whatever the transport is. |
16ed6e6 to
d873271
Compare
Extracts the VM driver's per-sandbox NAT + default-deny nftables ruleset generation into a new openshell-nft-ruleset crate so other compute drivers can share the same ruleset shape instead of reimplementing it. No behavior change to the VM driver. Related: NVIDIA#2255 Signed-off-by: Eric Curtin <eric.curtin@docker.com>
…vider Adds openshell-rootfs, the rootfs provider boundary for compute drivers: a provider resolves an OCI image reference into provider-neutral PreparedRootfs mounts keyed by a per-sandbox key, and owns image resolution, acquisition, unpacking, and the lifetime of the backend resources realizing the root filesystem. ContainerdRootfsProvider is the first implementation, backed by a system-provided containerd used only for image pull/unpack and snapshot management via its Transfer/Images/Content/Snapshots/Leases services. containerd concepts (snapshots, chain IDs, leases) are fully encapsulated: prepare() pulls, resolves the OCI chain ID, prepares a per-sandbox writable snapshot protected from containerd's GC by a lease, and cleans up after itself on failure; release() removes the snapshot and lease at teardown. Keeping the containerd daemon behind this boundary (rather than in a compute driver's own contract) leaves room to swap in a daemonless provider, or converge the VM driver's image acquisition pipeline onto the same types, without redesigning the sandbox provisioner on top. Related: NVIDIA#2255 Signed-off-by: Eric Curtin <eric.curtin@docker.com>
Adds openshell-driver-oci, an OCI/runc-based compute driver that builds sandboxes from Linux namespaces and cgroups v2. The driver is a sandbox provisioner: it generates the OCI runtime spec, assembles the bundle, manages per-sandbox network namespaces + veth + nftables, and drives the configured low-level OCI runtime (runc/crun) directly through its create/start/state/kill/delete CLI contract. containerd never creates a Container or Task for these sandboxes. All image handling goes through openshell-rootfs's ContainerdRootfsProvider from the previous commit: this crate has no containerd-client dependency and consumes only provider-neutral PreparedRootfs mounts, so the daemon-backed provider can later be swapped for a daemonless one without touching the driver. Also wires ComputeDriverKind::Oci through openshell-core and every openshell-server compute-driver selection path. Hardening from review: sandbox names are validated against path traversal, the runtime's --root is scoped under the driver's own state directory instead of the shared global default, the sandbox endpoint no longer defaults to an unreachable loopback address, per-sandbox subnet allocation detects and avoids collisions instead of a stateless hash, cleanup after a failed create no longer leaves a mounted rootfs and bundle directory behind, and sandbox token files are written with owner-only permissions. Verified end to end against a real containerd 2.x + runc/crun install (see tests/containerd_integration.rs, #[ignore]d in CI since CI has no containerd). Known gaps (rootless mode, image-based supervisor injection, full CDI GPU support, polling-based watch) are documented in the driver README and docs/reference/sandbox-compute-drivers.mdx. Related: NVIDIA#2255 Signed-off-by: Eric Curtin <eric.curtin@docker.com>
d873271 to
fe0f73f
Compare
Summary
Adds
openshell-driver-oci, an OCI/runc-based compute driver built from Linux namespaces and cgroups v2. The driver, not containerd, drives the configured low-level OCI runtime (runc/crun) directly, containerd never creates aContainerorTask.Per review, image handling is abstracted before the driver, so the PR is three commits:
refactor(driver-vm): extract the VM driver's nftables ruleset generator into a sharedopenshell-nft-rulesetcrate (no behavior change).feat(rootfs): newopenshell-rootfscrate, the rootfs provider boundary.ContainerdRootfsProvider(system containerd, used only for pull/unpack/snapshots) owns snapshots, GC leases, and chain IDs internally; consumers see only provider-neutralPreparedRootfsmounts. Mirrors the shape proposed in refactor(vm): separate rootfs materialization #2388.feat(driver-oci): the driver itself, OCI spec generation, bundle assembly, per-sandbox netns/veth/nftables, GPU device passthrough, direct runtime invocation, and gateway wiring (ComputeDriverKind::Oci). Nocontainerd-clientdependency: the daemon-backed provider can be swapped for a daemonless one without touching the driver.Related Issue
Related to #2255
Changes
crates/openshell-rootfs/(new): rootfs provider boundary + containerd-backed provider (prepare/release, self-cleaning on failure).crates/openshell-nft-ruleset/(new): shared NAT + default-deny ruleset generation (VM + OCI drivers).crates/openshell-driver-oci/(new): OCI spec (spec.rs), direct runtime invocation (runtime.rs), netns/veth/nftables (network.rs), GPU passthrough (gpu.rs), driver + gRPC service.ComputeDriverKind::Ociwiring, driver docs,architecture/compute-runtimes.md"Rootfs Provisioning Boundary" section.Includes the earlier hardening round from review (path traversal validation, scoped runtime
--root, reachable sandbox endpoint, collision-aware subnets, cleanup-on-error, token file permissions).Testing
mise run pre-commitequivalents pass (fmt, clippy-D warnings, license headers, markdownlint)cargo test --workspace --libpassesrunc/cruninstall (tests/containerd_integration.rs,#[ignore]d — CI has no containerd), including lease-protected snapshot GC behaviorKnown gaps (documented in the driver README and
docs/reference/sandbox-compute-drivers.mdx): rootless mode implemented but defaults off, host-path supervisor binary, kernel-device-node GPU passthrough only, pollingWatchSandboxes, no dedicated E2E lane yet. Converging the VM driver's image pipeline ontoopenshell-rootfsis follow-up alongside #2388.Checklist