Allow a container hotplugged into an already-running LinuxPod VM
(addContainer after create()) to have a virtiofs (directory-share)
rootfs, not just an ext4 virtio-blk image, on the cloud-hypervisor
backend.
Host side:
- Generalize CHHotplugProvider.hotplug to branch on the rootfs
runtimeOptions (.virtioblk / .virtiofs / unsupported), reusing the
per-tag virtiofsd/vm.add-fs machinery factored into a new
ensureVirtiofsDevice helper. Make registerMounts the sole writer of the
per-VM mount registry so the rootfs is always first and mounts are not
double-registered (also fixes a latent ordering bug on the block path).
Exclude the rootfs from the /run/virtiofs holding-dir loop in
addContainer.
Guest side (fixes a pre-existing, feature-independent bug):
- The addContainer-after-create (runtime hotplug) path had never been
exercised by any test. cloud-hypervisor adds hot-plugged
virtio-blk/virtio-fs devices to the guest PCI bus but the guest does not
auto-probe them, so a mount by /dev/vdX or virtio-fs tag fails (ENOENT /
tag-not-found) for ALL CH hotplug.
- vminitd's mount RPC now, on a mount failure for a hot-plug-candidate
source (virtiofs type or /dev/vd* source), forces /sys/bus/pci/rescan
and retries with a bounded wait. Scoped so boot-time and non-device
mounts are unaffected.
Tests / build:
- First coverage of LinuxPod.addContainer after create() (CH-only; VZ
has no runtime hotplug): pod hotplug virtiofs rootfs and pod hotplug
block rootfs, registered in a Linux-only test list, plus a
directory-rootfs unpack helper.
- make linux-integration gains an optional FILTER passthrough (make
linux-integration FILTER="pod hotplug").
Signed-off-by: michael_crosby <michael_crosby@apple.com>
- Closes#807.
- Ensure everything builds and passes with latest conforming package
versions.
- Use swift-collections 1.5.1 instead of 1.6.0 due to Swift 6.3
limitations.
- Closes#787.
- The `blockSizeInBytes` parameter on `EXT4Unpacker`
was misleading — it does not represent an ext4 filesystem
block size.
- This change renames `blockSizeInBytes` to
`capacityInBytes`, updates the doc comment to accurately
describe the parameter and updates the name in the call
sites.
- Fixes#776
- Release 2.9.0 of `grpc-swift-nio-transport` fixes
the HTTP/2 initialization race that required a
`HTTP2ConnectBufferingHandler` for the vminitd
API. This upgrades the dependency and eliminates
the workaround.
Changes the default Linux capability set for container processes from
`.allCapabilities` to `.defaultOCICapabilities`, making the library
secure-by-default. Callers that genuinely need elevated capabilities
must now opt in explicitly.
Signed-off-by: michael_crosby <michael_crosby@apple.com>
apple/containerization currently runs containers in per-container VMs on
macOS hosts via Virtualization.framework. This adds a second VMM backend
so the same Swift orchestration layer (LinuxContainer / LinuxPod /
Vminitd gRPC contract) runs on Linux hosts via cloud-hypervisor + KVM.
**CloudHypervisor Swift package** (`Sources/CloudHypervisor/`) — a thin
client for cloud-hypervisor's REST-over-UDS API, layered on
AsyncHTTPClient. Endpoints cover VMM / VM lifecycle / hotplug (disk, fs,
net, vsock, remove-device). Cross-platform (compiles on macOS for unit
tests; consumed at runtime only by the Linux side of Containerization).
**CH backend in Containerization** — one cloud-hypervisor subprocess per
VM, gated behind `#if os(Linux)`. CHVirtualMachineManager /
CHVirtualMachineInstance mirror the VZ shape behind the existing
VirtualMachineManager / VirtualMachineInstance protocol. CHProcess and
VirtiofsdProcess manage the binaries; CHHotplugProvider handles
virtio-blk and virtio-fs runtime hotplug (with one virtiofsd per unique
source-hash tag, refcounted across containers).
**Linux host networking** — BridgeManager brings up a Linux bridge with
an IPv4 subnet and (opt-in via `--enable-nat`) iptables MASQUERADE +
scoped FORWARD rules. LinuxBridgedNetwork enslaves a fresh TAP per
container to the bridge. State is recorded under `/run/containerization`
so `cctl bridge delete` reverses exactly what create did. Bridge
teardown verifies the link kind via sysfs to refuse deleting non-bridge
interfaces.
**cctl run / bridge** — end-to-end Linux container run path (image pull,
ext4 rootfs assembly, VM boot, container exec) plus `cctl bridge
create|delete` for the host network plumbing.
**Build & dist** — `make linux-build` / `make linux-integration` build
and exercise the host side inside an apple/container `--virtualization`
dev container. `make dist-x86_64` produces a deployment tarball (cctl +
cloud-hypervisor + virtiofsd + initfs + kernel) cross-compiled from the
aarch64 dev container; pipeline documented in `docs/x86_64-build.md`.
Static-musl C deps and the Zig cross compiler are pinned by SHA256.
The host orchestrator runs as root. Per-VM runtime state lives under
`/run/containerization/ch/<UUID>` with mode 0700; UDS sockets inside are
bound with mode 0600. Vminitd's gRPC channel inherits that trust
boundary — socket-file perms are the auth.
Sandbox flags are upstream-secure by default. Two per-component opt-outs
exist for the apple/container dev-container case (where the host seccomp
profile SIGSYS-kills CH and virtiofsd):
- `CONTAINERIZATION_NO_CH_SECCOMP=1` — `cloud-hypervisor --seccomp
false`.
- `CONTAINERIZATION_NO_VIRTIOFSD_SANDBOX=1` — `virtiofsd --sandbox
none`. Each emits a one-shot `logger.warning` at process start. Legacy
alias `CONTAINERIZATION_RELAXED_SANDBOX=1` flips both. cctl spawns both
binaries with `setsid` and a minimal env allowlist (PATH / HOME /
RUST_LOG / RUST_BACKTRACE) so the parent's secrets don't leak to
children.
`make linux-integration` runs the cross-platform integration suite
against a real cloud-hypervisor VM inside the dev container. Linux runs
the cross-platform subset (`process true`/`false`/`echo hi`, virtiofs
round-trip, hotplug); the macOS suite is unchanged.
Signed-off-by: michael_crosby <michael_crosby@apple.com>
The `PodVolume` type in `LinuxPod` only defined the `nbd` enum value -
however, disk based images are also supported and the pattern is
essentially the same
Signed-off-by: Aditya Ramani <a_ramani@apple.com>
- Closes#774.
- Adds a default journal configuration parameter to the EXT4Unpacker
init function, defaulting to nil (no journal) to preserve source
compatibility.
The `--log-level` option when running the agent sub-command for vminitd
was being silently ignored cause of the way the agent is being run. As a
workaround we need to read `/proc/self/cmdline` to get the right args
Extends the network plumbing to support per-interface IPv6 address
configuration.
The `Interface` protocol supports `ipv6Address` and `ipv6Gateway`.
The agent's networking RPCs carry per-family fields via new
`InterfaceAddress`, `LinkRoute`, and `DefaultRoute` types in
`ContainerizationExtras`.
`NetlinkSession` adds IPv6 methods for address and route operations.
---------
Co-authored-by: michael_crosby <michael_crosby@apple.com>
Co-authored-by: Michael Crosby <crosbymichael@gmail.com>
- Closes#712.
- Replace synchronous `write()` calls in
`BidirectionalRelay` with non-blocking I/O
and `DispatchSourceWrite` backpressure
handling. Under concurrent vsock proxy load,
a single blocked write on the shared serial
dispatch queue would freeze all relay
connections permanently, including unrelated
new connections.
- Set relay file descriptors to `O_NONBLOCK`
and handle `EAGAIN` by suspending reads and
installing a write source to drain pending data.
- Give each `BidirectionalRelay` its own serial queue
instead of sharing one from `UnixSocketRelayManager`,
eliminating cross-connection blocking.
- Resume suspended read sources before cancelling
in `stop()` — GCD does not deliver cancel handlers
on suspended dispatch sources, which caused file
descriptor and memory leaks on teardown under
backpressure.
- Guard-unwrap `buf.baseAddress` in
`drainPendingWrite`.
- Closes#749.
- ExportOperation hardcoded the pushed index descriptor's
mediaType to the OCI image index type. RegistryClient.push
uses that descriptor's mediaType as the HTTP Content-Type
header. When the source index was in
Docker manifest.list.v2+json format (the common case for
images pulled from Docker Hub and other public registries),
the body's embedded mediaType field disagreed with the
header, and OCI registries rejected the index PUT with
HTTP 400 MANIFEST_INVALID.
- Use the source index's mediaType for the pushed descriptor
so the header always matches the body. Per-architecture
child manifests are unaffected because they were already
pushed with their actual mediaType.
- Add a parameterized unit test for ExportOperation.export
covering both Docker manifest.list
This pull request enhances the handling of file and directory copy
operations in Linux containers, particularly by improving destination
path resolution and error handling for the `copyIn` operation with the
`Stat RPC`
This PR is needed for
[container#1190](https://github.com/apple/container/pull/1190)
Today we craft the proxied sockets we create at a path that contains the
container ID. This is normally completely fine, except if the ID is
enormous, as it can cause the UDS path to be longer than the allowed
length.
I think realistically we should have a limit on this. Technically today
the ID length restriction is whatever our grpc buffer length is..
I think 64 is long enough so that folks could use an entire hex based
sha256, any uuid, and also sethostname has a length restriction of 64
anyways.
Move the MiB rounding from LinuxContainer into
`VZVirtualMachineInstance`, so all callers are covered in one place and
the alignment constraint stays with the VMM layer that owns it.
This will also ensure LinuxPod can get memory alignment for free.
If someone wanted to use a custom guest agent/guest image in general the
overhead we chose is kind of a nuisance.. This allows the values to be
configurable, and raises the default to 128, and vminitds cgroup
monitoring to 80.
This change adds support for attaching network block device (NBD) to
both LinuxContainer and LinuxPod.
For LinuxContainer, whether to use the underlying
`VZNetworkBlockDeviceStorageDeviceAttachment` is determined by the URL
of the container Mount source.
For LinuxPod, adds additional API to support pod-level volumes that can
be mounted into multiple containers. The PodVolume type provides enum to
support multiple types of volume source. LinuxContainer can reference
the pod level volume using the `Mount.sharedMount()` constructor with
the name referencing the name of the pod volume. This will allow the NBD
to be attached to the pod at the VM level and then bind-mounted into the
container.
For integration tests, added a lightweight NBD server implementation in
swift that speaks the NBD protocol to ensure there is sufficient
coverage for the changes introduced.
Apple Virtualization NBD support documentation:
https://developer.apple.com/documentation/virtualization/vznetworkblockdevicestoragedeviceattachment
Replace the old platform-gated Signals helper in ContainerizationOS with
a Signal struct in Containerization. Signal provides named constants for
common signals (.kill, .term, etc.), platform-specific namespaces
(Signal.Linux for rtmin/stkflt/pwr, Signal.Darwin for emt/info), string
parsing, and ExpressibleByIntegerLiteral support.
LinuxContainer, LinuxProcess, and LinuxPod kill APIs now take Signal
instead of raw Int32.
Add `Stat` RPC to vminitd.
`Stat` RPC is used to stat file system objects in the VM. It accepts the
path to the object (resolved against VM root) and returns the stat
result.
Make the `HTTP2ConnectBufferingHandler` class public temporarily so that
consumers of the containerization package may reuse it for other grpc
clients.
Closes: #678
There's no reason to have an idle timeout per connection as users may
use this library in many different ways. The grpc lib defaults to a 30
min idle timeout which could be trivially reached if instead of waiting
on the init process, you were waiting on a bunch of execs. NIO under the
hood asserts on ebadfs (which is good, but bad for this scenario..), so
lets turn off the timeout altogether.
- Closes#51. Again.
- No real notable API changes. The largest change code-wise is in
Vminitd. The connection loop is set up immediately in the new API by
calling runConnections() on the client, and this blocks until either the
task it's running on is cancelled or beginGracefulShutdown is called.
Because of this, either we'd have to modify our API to have
VirtualMachineAgent implementations call some run() method, or we just
put runConnections in an internal task on Vminitd. This change uses the
latter approach as it's simpler.
- Updated dependencies to pick up latest protobuf and grpc-swift-2
fixes.
- ClientBootstrap.withConnectedSocket(fd).wait() registers the vsock fd
with epoll/kqueue immediately. vminitd sends its HTTP/2 SETTINGS frame
right away upon accepting the connection, so those bytes can arrive on
the fd — and be read by NIO — before the gRPC pipeline is installed.
With a bare pipeline, NIO has nowhere to send the bytes and discards
them.
- Buffer until ClientConnectionHandler is in the pipeline so it can
process the SETTINGS frame and fire .ready, then schedule delivery of
the buffered data with assumeIsolatedUnsafeUnchecked().execute.
- To help produce more accurate merged logs, defines a
`StderrLogHandler` in the vminitd Application.swift that writes
timestamps to the boot log with millisecond precision and format
identical to that of the log files created using the `--log-root` arg on
`container`.
- Updates hawkeye to latest version (v6.5.1).
- In vminitd, use the Server event loop group for the gRPC server.
Co-authored-by: Danny Canter <danny_canter@apple.com>
Related to https://github.com/apple/container/issues/1251
Change to sharing in the parent directory, and then bind mounting in the
file into the container. This has the unfortunate reality of being less
secure, but the current approach is burdended by a couple things,
namely:
1. You can't share in files that are on a different volume
2. There is a Virtualization bug that causes spurious errors when trying
to open the file.
I've added a doc to go over the approach we've taken, and some
workarounds if the approach is not satisfactory.