feat: add --init-image flag for specifying custom init filesystem images per VM - #937

Merged
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image
Feb 10, 2026
Merged

feat: add --init-image flag for specifying custom init filesystem images per VM#937
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image

Conversation

@manuschillerdev

@manuschillerdevmanuschillerdev commented Dec 7, 2025

Copy link
Copy Markdown
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

I've been tinkering with ways to extend container with a primitive for interacting with the VM layer. One approach: expose the internal init filesystem as a user-configurable option via --init-image.

What this enables:

  • Custom boot-time logic before the OCI container starts
  • Running additional processes and daemons (e.g., daemons to configure eBPF network filters, logging agents) inside the VM (not the container)
  • Debugging/instrumenting the init process

--init-image vs using the system property
we could also use container system property set image.init vminit:latest (documented via #1032), but this affects all VMs. I want to be able to override this only for a single VM.

In my current approach, the custom image wraps the default vminitd, so it's currently behaving like an entrypoint.
Curious if this direction aligns with the project's goals, or if there's a better abstraction for these use cases.
If there is interest, I would add proper docs and tests.

Example for a minimal entry point binary
Note: We use Go here for its straightforward cross-compilation to Linux ARM64.

// custom-init/wrapper.gopackage main
import (
"fmt""os""syscall"
)
funcmain() {
kmsg, err:=os.OpenFile("/dev/kmsg", os.O_WRONLY, 0)
iferr==nil {
kmsg.WriteString("<6>custom-init: === CUSTOM INIT IMAGE RUNNING ===\n")
kmsg.Close()
}
err=syscall.Exec("/sbin/vminitd.real", os.Args, os.Environ())
iferr!=nil {
fmt.Fprintf(os.Stderr, "Failed to exec vminitd.real: %v\n", err)
os.Exit(1)
}
}

Containerfile

# custom-init/Containerfile
FROM ghcr.io/apple/containerization/vminit:0.23.2 AS base
FROM ghcr.io/apple/containerization/vminit:0.23.2
COPY --from=base /sbin/vminitd /sbin/vminitd.real
COPY wrapper /sbin/vminitd
  • build the binary with cd custom-init && CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o wrapper wrapper.go
  • build the image with bin/container build -t local/custom-init:0.20.0 custom-init/
  • run the container with our custom init-image: bin/container run --name init-test --init-image local/custom-init:0.20.0 alpine:latest echo "hello"
  • check the logs with cat "/Users/$USER/Library/Application Support/com.apple.container/containers/init-test/vminitd.log" | head -50

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

@manuschillerdevmanuschillerdev changed the title feat: add init-image flag for specifying custom init filesystem images per VMfeat: add --init-image flag for specifying custom init filesystem images per VMDec 7, 2025
@jglogan

Copy link
Copy Markdown
Contributor

@dcantah see also #838

Comment threadSources/ContainerClient/Utility.swift
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@dcantah@jglogan would that be of interest for the project? Would be totally open to other suggestions on how one can interact with the startup process. Exposing --init-fs seemed like a viable option here

@manuschillerdev

manuschillerdev commented Jan 10, 2026

Copy link
Copy Markdown
ContributorAuthor

@jglogan@dcantah

I've rebased the PR, added tests and documentation, and updated the description to clarify why container system property set image.init doesn't fit my use case (it applies globally rather than per-VM).

Happy to elaborate on any open questions or explore alternative approaches that would better align with the project's architecture.
I'd appreciate any feedback on whether this direction makes sense to pursue or if there are concerns that would make it worth closing in favor of a different approach.

@jglogan

jglogan commented Jan 17, 2026

Copy link
Copy Markdown
Contributor

@manuschillerdev I haven't been able to review but it seems reasonable. Kernel and initfs config are birds of a feather, whatever config options exist for one, we should eventually provide for the other.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Could you run make fmt on this, and make sure build/test runs okay on your end, and then try pushing the changes? I made one change to resolve some merge conflicts on the Makefile

@jglogan

Copy link
Copy Markdown
Contributor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 5badfb6 to 6e1d1faCompareFebruary 1, 2026 10:15
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

thanks for having another look at this! I rebased the PR against main, resolved the conflicts, ran make fmt, and did a complete re-test locally with the steps from the PR description:

❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"| grep "==="
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
full output of vminitd.log after creating a custom init image, and starting a fresh container using the `--init-image` flag:
❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"
[ 0.069458] random: crng init done
[ 0.070722] brd: module loaded
[ 0.071338] loop: module loaded
[ 0.071436] virtio_blk virtio2: 1/0/0 default/read/poll queues
[ 0.071600] virtio_blk virtio2: [vda] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.071875] virtio_blk virtio3: 1/0/0 default/read/poll queues
[ 0.072020] virtio_blk virtio3: [vdb] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.072226] tun: Universal TUN/TAP device driver, 1.6
[ 0.072687] VFIO - User Level meta-driver version: 0.3
[ 0.072820] rtc-pl031 20050000.pl031: registered as rtc0
[ 0.072857] rtc-pl031 20050000.pl031: setting system clock to 2026-02-01T08:49:54 UTC (1769935794)
[ 0.073306] xt_time: kernel timezone is -0000
[ 0.073348] IPVS: Registered protocols (TCP, UDP, SCTP, AH, ESP)
[ 0.073434] IPVS: Connection hash table configured (size=4096, memory=32Kbytes)
[ 0.073579] IPVS: ipvs loaded.
[ 0.073615] IPVS: [rr] scheduler registered.
[ 0.073634] IPVS: [wrr] scheduler registered.
[ 0.073685] IPVS: [lc] scheduler registered.
[ 0.073718] IPVS: [wlc] scheduler registered.
[ 0.073767] IPVS: [fo] scheduler registered.
[ 0.073813] IPVS: [ovf] scheduler registered.
[ 0.073862] IPVS: [lblc] scheduler registered.
[ 0.073924] IPVS: [lblcr] scheduler registered.
[ 0.073942] IPVS: [dh] scheduler registered.
[ 0.073966] IPVS: [sh] scheduler registered.
[ 0.073991] IPVS: [sed] scheduler registered.
[ 0.074016] IPVS: [nq] scheduler registered.
[ 0.074043] IPVS: [sip] pe registered.
[ 0.074088] Initializing XFRM netlink socket
[ 0.074130] NET: Registered PF_INET6 protocol family
[ 0.074389] Segment Routing with IPv6
[ 0.074421] In-situ OAM (IOAM) with IPv6
[ 0.074462] NET: Registered PF_PACKET protocol family
[ 0.074505] 9pnet: Installing 9P2000 support
[ 0.074573] NET: Registered PF_VSOCK protocol family
[ 0.075578] registered taskstats version 1
[ 0.076957] alg: No testfor fips(ansi_cprng) (fips_ansi_cprng)
[ 0.077498] clk: Disabling unused clocks
[ 0.080034] EXT4-fs (vda): mounted filesystem 63cb0698-b5fe-4f00-ba03-179297b9693a ro without journal. Quota mode: disabled.
[ 0.080117] VFS: Mounted root (ext4 filesystem) readonly on device 254:0.
[ 0.080441] devtmpfs: mounted
[ 0.080801] Freeing unused kernel memory: 1856K
[ 0.080895] Run /sbin/vminitd as init process
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
2026-02-01T08:49:54+0000 info vminitd : [vminitd] Running init command
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /proc
2026-02-01T08:49:54+0000 info vminitd : [vminitd] vminitd booting
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /run
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys/fs/cgroup
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 debug vminitd : bytes=78643200 path=/sys/fs/cgroup/vminitd [Cgroup] setting memory.high
2026-02-01T08:49:54+0000 debug vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] adding new proc to cgroup
2026-02-01T08:49:54+0000 info vminitd : events_path=/sys/fs/cgroup/vminitd/memory.events threshold_bytes=78643200 [vminitd] Started memory monitoring
2026-02-01T08:49:54+0000 info vminitd : [vminitd] serving vminitd API
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] starting process supervisor
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] booting gRPC server on vsock
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] gRPC API serving on vsock
2026-02-01T08:49:54+0000 debug vminitd : interface=lo up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : key=PATH value=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [vminitd] setenv
2026-02-01T08:49:54+0000 debug vminitd : destination=/tmp source=tmpfs type=tmpfs [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/dev/pts source=devpts type=devpts [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/run/container/init-test/rootfs source=/dev/vdb type=ext4 [vminitd] mount
[ 0.268991] EXT4-fs (vdb): mounted filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab r/w without journal. Quota mode: disabled.
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Address=192.168.64.3/24 [vminitd] ipAddrAdd
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Gateway=192.168.64.1 [vminitd] ipRouteAddDefault
2026-02-01T08:49:54+0000 debug vminitd : domain= location=/run/container/init-test/rootfs nameservers=["192.168.64.1"] options=[] searchDomains=[] [vminitd] configureDns
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] writing to path /run/container/init-test/rootfs/etc/resolv.conf nameserver 192.168.64.1
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/resolv.conf [vminitd] wrote resolver configuration
2026-02-01T08:49:54+0000 debug vminitd : location=/run/container/init-test/rootfs [vminitd] configureHosts
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/hosts [vminitd] wrote /etc/hosts configuration
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test stderr=Port: 268435457 stdin=Port: 0 stdout=Port: 268435456 [vminitd] createProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] created bundle with spec Spec(version: "", hooks: nil, process: Optional(ContainerizationOCI.Process(cwd: "/", env: ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME=/root"], consoleSize: nil, selinuxLabel: "", noNewPrivileges: false, commandLine: "", oomScoreAdj: nil, capabilities: Optional(ContainerizationOCI.LinuxCapabilities(bounding: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), effective: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), inheritable: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), permitted: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), ambient: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]))), apparmorProfile: "", user: ContainerizationOCI.User(uid: 0, gid: 0, umask: nil, additionalGids: [0], username: ""), rlimits: [], args: ["echo", "hello"], terminal: false)), hostname: "init-test", domainname: "", mounts: [ContainerizationOCI.Mount(type: "proc", source: "proc", destination: "/proc", options: [], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "sysfs", source: "sysfs", destination: "/sys", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devtmpfs", source: "none", destination: "/dev", options: ["nosuid", "mode=755"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "mqueue", source: "mqueue", destination: "/dev/mqueue", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "tmpfs", source: "tmpfs", destination: "/dev/shm", options: ["nosuid", "noexec", "nodev", "mode=1777", "size=65536k"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "cgroup2", source: "none", destination: "/sys/fs/cgroup", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devpts", source: "devpts", destination: "/dev/pts", options: ["nosuid", "noexec", "newinstance", "gid=5", "mode=0620", "ptmxmode=0666"], uidMappings: nil, gidMappings: nil)], annotations: nil, root: Optional(ContainerizationOCI.Root(path: "/run/container/init-test/rootfs", readonly: false)), linux: Optional(ContainerizationOCI.Linux(uidMappings: [], gidMappings: [], sysctl: Optional([:]), resources: Optional(ContainerizationOCI.LinuxResources(devices: [], memory: Optional(ContainerizationOCI.LinuxMemory(limit: Optional(1073741824), reservation: nil, swap: nil, kernel: nil, kernelTCP: nil, swappiness: nil, disableOOMKiller: nil, useHierarchy: nil, checkBeforeUpdate: nil)), cpu: Optional(ContainerizationOCI.LinuxCPU(shares: nil, quota: Optional(400000), burst: nil, period: Optional(100000), realtimeRuntime: nil, realtimePeriod: nil, cpus: "", mems: "", idle: nil)), pids: nil, blockIO: nil, hugepageLimits: [], network: nil, rdma: nil, unified: Optional([:]))), cgroupsPath: "/container/init-test", namespaces: [ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.cgroup, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.ipc, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.mount, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.pid, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.uts, path: "")], devices: [], seccomp: nil, rootfsPropagation: "", maskedPaths: [], readonlyPaths: [], mountLabel: "", personality: nil)))
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting I/O
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stderr
2026-02-01T08:49:54+0000 info vminitd : [vminitd] created vmexec init process
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] startProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] in supervisor lock to start process
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting managed process
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78381056 high_events_total=1 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78442496 high_events_total=15 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78331904 high_events_total=18 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] got back pid data
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] sending pid acknowledgement
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[93: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] started managed process
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[94: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 debug vminitd : count=0 pid=94 status=0 [vminitd] managed process exited
2026-02-01T08:49:54+0000 info vminitd : id=init-test status=0 [vminitd] managed process exit
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stderr
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] 0 managed process waiters signaled
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : pid=-1 signal=9 [vminitd] kill
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : flags=0 path=/run/container/init-test/rootfs [vminitd] umount
[ 0.541866] EXT4-fs (vdb): unmounting filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab.
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] sync
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] deleteProcess
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] deleting cgroup manager

I also re-ran the tests:

❯ swift test --filter TestCLIRunInitImage 2>&1
Building for debugging...
[7/7] Write swift-version-1C31CF501CE571A8.txt
Build complete! (0.77s)
Test Suite 'Selected tests' started at 2026-02-01 11:10:47.076.
Test Suite 'containerPackageTests.xctest' started at 2026-02-01 11:10:47.077.
Test Suite 'containerPackageTests.xctest' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.1 (c9d57c83568b06d)
↳ Target Platform: arm64-apple-macosx
◇ Suite TestCLIRunInitImage started.
◇ Test testCreateWithNonExistentInitImage() started.
◇ Test testRunWithExplicitDefaultInitImage() started.
◇ Test testInitImageFlagInHelp() started.
◇ Test testRunWithNonExistentInitImage() started.
✔ Test testInitImageFlagInHelp() passed after 0.178 seconds.
✔ Test testRunWithNonExistentInitImage() passed after 10.584 seconds.
✔ Test testCreateWithNonExistentInitImage() passed after 20.668 seconds.
✔ Test testRunWithExplicitDefaultInitImage() passed after 25.314 seconds.
✔ Suite TestCLIRunInitImage passed after 25.314 seconds.
✔ Test run with 4 tests in 1 suite passed after 25.314 seconds.

@jglogan let me know if that works for you, or if I should rather still open a fresh PR. Don't worry, I'd aim for the cleanest solution for the maintainers and the repo. Re-organizing the PR is no effort at all. Thanks for your time again!

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev In CI I'm seeing this failure:

✔ Test testCreateWithNonExistentInitImage() passed after 43.897 seconds.
✘ Test testRunWithExplicitDefaultInitImage() recorded an issue at TestCLIRunInitImage.swift:93:6: Caught error: executionFailed("command failed: Warning! Running debug build. Performance may be degraded.\nError: internalError: \"failed to create container\" (cause: \"internalError: \"XPC timeout for request to com.apple.container.apiserver/containerCreate\"\")\n")
✘ Test testRunWithExplicitDefaultInitImage() failed after 87.555 seconds with 1 issue.
↳ /// Test that explicitly specifying the default init image works the same as
↳ /// not specifying any init image.
✔ Test testRunWithNonExistentInitImage() passed after 87.606 seconds.
✘ Suite TestCLIRunInitImage failed after 87.606 seconds with 1 issue.
✘ Test run with 4 tests in 1 suite failed after 87.606 seconds with 1 issue.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 7d9a37a to baae7c7CompareFebruary 3, 2026 22:05
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks! the tests did catch an error in the image selection logic - glad they did.
I pushed a separate fix, an re-ran make integrate locally without errors.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev OK, the updated tests worked fine. One last thing (thanks for your patience!)

ContainerClient got a big refactor your changes need to be updated to work with those.

@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan no worries. I rebased against main and verified that the changes still work.
make integration runs without errors, loading a custom init-image works and starting containers without a custom init image provided works as well

@jglogan
jglogan merged commit cf9b335 into apple:mainFeb 10, 2026
3 checks passed
@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Finally got it in there...thanks for the contribution!

simone-panico pushed a commit to simone-panico/container that referenced this pull request Feb 10, 2026
…ges per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks again for guiding me!

Mcrich23 added a commit to Mcrich23/container that referenced this pull request Feb 18, 2026
commit c791052
Author: Aditya Ramani <a_ramani@apple.com>
Date: Wed Feb 18 07:43:56 2026 +0530
Add init methods for all the members of the Flags type (apple#1203)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Authors of CLI plugins for container will be able to reuse the container
flags defined in the CLI package, instead of having to duplicate them in
their project
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit dfac83d
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 17 16:54:44 2026 -0800
ContainerService: Add minimum memory amount validation (apple#1208)
Closesapple#1202
Today it's possible to pass a memory amount that very easily will cause
the container's VM to not be able to boot. We should protect against
this to avoid weird hangs/error messages. I could be convinced that a
limit should be in Containerization as well, but I think having one in
the daemon is a decent idea regardless.
commit 5385a5c
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Tue Feb 17 15:08:32 2026 -0800
Support using multiple different network plugins (apple#1151)
## Type of Change
- [x] New feature
- [x] Breaking change
## Motivation and Context
We want to be able to support using multiple network plugins during
`container`'s lifetime. This additionally means needing to pick an
interface strategy to interpret a network attachment based on what
network plugin was used to create that attachment. This PR will
potentially replace apple#1081.
Followups:
- doc updates to include the ability to specify plugin in the network
creation cli
## Testing
- [x] Tested locally
- [x] Added/updated tests
commit 7476743
Author: AJ Emory <239216119+ajemory@users.noreply.github.com>
Date: Fri Feb 13 19:27:32 2026 -0800
feat: Moving bundle creation from ContainerService to SandboxService (apple#1076)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Closesapple#1046 -- Right now we're creating container bundles in
ContainersService. Move this to the SandboxService to make it easier to
support different container bundle types.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 4c800db
Author: J Logan <john_logan@apple.com>
Date: Fri Feb 13 10:51:27 2026 -0800
Fix persistent CI failures. (apple#1205)
## Type of Change
- [x] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
- CI build is failing because runners don't have an /etc/resolver
directory, causing the directory monitor to fail. This occurs while the
install-kernel make target is running, so it appears that kernel
download is failing when it's just that the API server is dying. Created
apple#1207 for the issue.
- Fixing the initial scan for the directory just moves the problem to
the filesystem watch loop, likely because we're not testing the result
of `open()` for errors.
- Right now the priority is getting CI running and PRs merged, so just
commenting out the realhost DNS server setup.
- Also seeing that under some conditions it can take quite a while for
launchd to start the helper for the default network (8 seconds or more).
With the 10 second health check timeout after API server registration,
this means that some CI runs can exhibit this failure mode. Added a
`--timeout` option to SystemStart and set a 60 second timeout for
install-kernel and integration Makefile targets.
- Fixed a bug where `--debug` was being placed in the wrong location in
the api server startup args.
- Disabled all network CLI tests due to container bootstrap errors when
trying to run the container immediately after creating the network. The
slow network helper launch could be the reason behind the failures that
drove us to serialize these tests. Filed apple#1206 for this issue.
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit f7d00aa
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 11 15:09:21 2026 -0800
APIServer: Add support for filtering to list rpc (apple#1175)
This is not intended to be used to support `--filter` or similar on the
CLIs list yet, it's solely to clean up our rather awkward use of
`ContainerClient.list()` today in the CLI. The list RPC simply returns
all of the containers we have created. Because of this, for a LOT of our
commands we filter to what we need client side, which feels like a
waste.. This change introduces a filter struct that we can provide an
array of container IDs, labels, and the status of the containers to
filter the `list()` output from.
This additionally, because it was killing (pun not intended) me and I
was already having to change this area for the `list()` additions,
changes container kill slightly to return an error if you try and kill a
container that doesn't exist.
commit c9f81ca
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Feb 11 04:26:33 2026 +0800
Feat: add container registry list (apple#1119)
- Requires apple/containerization#502
- Closesapple#1088
---------
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit cf9b335
Author: Manu Schiller <56154253+manuschillerdev@users.noreply.github.com>
Date: Tue Feb 10 03:11:27 2026 +0100
feat: add --init-image flag for specifying custom init filesystem images per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
commit 474906d
Author: Amir Alperin <me@remotecpp.dev>
Date: Fri Feb 6 23:38:19 2026 +0200
feat: Add runtime flag to container create and run commands (apple#1049) (apple#1109)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Fixesapple#1049
- Add --runtime option for Flags.Management
- Apply runtime handler in containerConfigFromFlags
- Update command-reference.md doc
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
Co-authored-by: J Logan <john_logan@apple.com>
commit 40de343
Author: Dmitry Kovba <dkovba@apple.com>
Date: Fri Feb 6 00:41:29 2026 -0800
Fix relative path mount tests (apple#1168)
`make test` occasionally fails with:
```
✘ Test testHostDNSReinitialize() recorded an issue at HostDNSResolverTest.swift:132:45: Expectation failed: (error →
Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory") as? (ContainerizationError → NSError)
✘ Suite HostDNSResolverTest failed after 0.119 seconds with 1 issue.
```
commit aa17d46
Author: Poetry Of Code <101225909+poetryofcode@users.noreply.github.com>
Date: Fri Feb 6 03:38:21 2026 -0500
Warn user when a named volume is auto-created (apple#1108)
- Implemented the TODO at
ContainerAPIService/Client/Utility.swift:358 — warn the
user when a named volume is auto-created.
- This only triggers for named volumes (not anonymous
ones), matching Docker's behavior of informing users
about implicit resource creation.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
commit adb3c44
Author: J Logan <john_logan@apple.com>
Date: Thu Feb 5 20:19:13 2026 -0800
Don't enable selinux LSM on boot. (apple#1166)
- Closesapple#1150.
- The problem seems to be that the selinux label attribute enforcement
doesn't play well with overlayfs.
- Solution is to set the `lsm` boot line argument. The new value
corresponds to what one would see in a Lima VM with Colima. The Kata
kernel we use doesn't provide any of those modules, so now if you run
`dmesg | grep -i lsm` in a container you will just see: `LSM:
initializing lsm=capability`
commit fdeb1b1
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 10:59:31 2026 -0800
Add builder tests (apple#1154)
- Adds test for apple#1094.
- Closesapple#933 (with apple/container-builder-shim#62).
- Closesapple#425 (with apple/container-builder-shim#63).
commit fabfc55
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 09:53:31 2026 -0800
Send tar hash in the first BuildTransfer packet (apple#1149)
Send the hash of entire tar file in the first BuildTransfer packet to
prevent container-builder-shim from using stale cached contents.
This PR resolvesapple#1143.
This PR relies on apple/container-builder-shim#64.
## Type of Change
- [X] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Current container-builder-shim uses only first few bytes of tar file as
checksum, which leads to the usage of stale cached contents if the
change of build context is not included in the first bytes of tar file.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit 6e9b8d7
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Feb 5 09:47:20 2026 -0800
CLI: Forego logging errors on multi-container operations (apple#1163)
Instead of logging errors, and then additionally throwing an error
stating what containers couldn't be stopped/killed/deleted, let's just
concatenate the errors and throw the single error.
commit d79bc0d
Author: Manoj Mahapatra <mahapatra.manoj@hotmail.com>
Date: Thu Feb 5 01:16:30 2026 -0800
chore: Replace force-unwrapped String(data:encoding:) with String(decoding:as:) (apple#1164)
Use the non-optional String(decoding:as:) initializer for converting
JSON-encoded Data to String. This is safe for UTF-8 and eliminates force
commit 21dabb7
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 03:13:36 2026 -0500
[build-command]: Add --pull option for fetching latest image (apple#844)
- Closesapple#733.
commit 6553f9c
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 01:16:08 2026 -0500
[deps]: bump containerization to 0.25.0 (apple#1161)
Co-authored-by: saehejkang <saehej.kang@gmail.com>
Co-authored-by: Anthony DePasquale <anthony@depasquale.org>
- Bump `containerization` to `0.25.0`
- Updates for parameter changes on containerization
registry access API.
- Updates for change to containerization
`cleanUpOrphanedBlobs` function.
commit 2d1dd6b
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 15:42:29 2026 -0800
Fix file path for the PR number in the PR labeler workflow (apple#1158)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR label applier GitHub workflow has been failing for a while. This
PR fixes that by correcting the file path we look for when trying to
read the PR number. See example failure here
https://github.com/apple/container/actions/runs/21691766538/job/62552959972#step:4:23
commit 6451e07
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 14:44:53 2026 -0800
Add debugging to the PR labeler CI flow (apple#1155)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR labeler workflow has been failing for a while but it's difficult
to know how to fix it since the PR labeler workflow is run from main
(aka NOT the current PR branch) for security reasons. Example at
https://github.com/apple/container/actions/runs/21690229300/workflow
commit 8fdfa29
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:52:09 2026 -0800
CLI: Rework ClientContainer (apple#1139)
ClientContainer was honestly extremely awkward. It could only be created
by passing either a ContainerConfiguration, or a Snapshot that had to be
obtained from calling a static method on the type itself. The type also
did not store a connection, so every single method got a new xpc
connection to the APIServer. This change aims to rework this type to be
just a generic client, that is *not* a client for one specific
container, but for any.
- Rename to ContainerClient
- Have list() return [ContainerSnapshot]
- Create a connection in the constructor
- Change all the callsites to use the new API
- Small, somewhat related, change to logs API in the APIServer. Now that
we don't need to call get() to grab a client anymore which was typically
what did "does this container exist" logic and gave a nice error
message, I added a small check in the APIServer to see if the container
exists and return mostly the same error message.
commit 23c0ece
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:19:50 2026 -0800
CI: Add signed commit check (apple#1152)
This requirement of ours often goes unnoticed because nothing yells at
you openly about it. Lets fail CI to make it more obvious.
commit ce1b629
Author: Manoj Mahapatra <mahaplipsa@gmail.com>
Date: Tue Feb 3 13:43:07 2026 -0800
[Docs] Fix typo in BUILDING.md: launchd -> launchctl (apple#1146)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [x] Documentation update
## Motivation and Context
The debug instructions in `BUILDING.md` incorrectly reference launchd
list instead of `launchctl` list. `launchd` is the daemon itself and
cannot be invoked directly.
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [x] Added/updated docs
commit 3e49dce
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 3 00:45:01 2026 -0800
Add in missing rlimits (apple#1140)
Containerization didn't have these defined until a recent tag.
commit c4c2e85
Author: J Logan <john_logan@apple.com>
Date: Tue Feb 3 00:27:09 2026 -0800
Upgrade kernel to Kata 3.26.0. (apple#1134)
- Upgrade to containerization 0.24.5 to pick up zstd decompression
enhancement.
- Closesapple#767.
- Closesapple#988.
- Closesapple#1132.
- Requires apple/containerization#508.
commit 5c86337
Author: William Laverty <developer@william-laverty.com>
Date: Mon Feb 2 13:57:59 2026 -0800
Add explanatory message before admin password prompt in uninstall script (apple#1118)
- Added message: "This script requires an administrator password to
remove the application files from system directories."
- Fixesapple#1111
commit 7da25e1
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:35:02 2026 -0800
Deps: Bump Containerization to 0.24.0 (apple#1127)
Brings in some rlimit bumps/adjustments
commit 7dfe27d
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:30:19 2026 -0800
CLI: Add support for rlimits (apple#1129)
Closesapple#1097.
commit b3b5c3e
Author: J Logan <john_logan@apple.com>
Date: Mon Feb 2 12:24:27 2026 -0800
Use labels instead of id to discriminate the builtin network. (apple#1123)
- Closesapple#1122.
- Adds placeholder ManagedResource and unit tests. Nothing is using
these yet.
- Adds system-defined resource labels for owning plugin and resource
role. The system discriminates the builtin network using role "builtin".
- Adds builtin role when creating builtin network at startup, and
ensures that a preexisting network with ID "default" gets updated with
the role label.
- Replace all network ID checks for "default" with the builtin role
check.
- Adds "builder" role to builder VM.
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Role and owner labels should make cross-cutting resource policy easier
to implement.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 1dae1cd
Author: w-ferg <43309695+w-ferg@users.noreply.github.com>
Date: Sun Feb 1 18:14:41 2026 -0500
Fix pfctl executable path in PacketFilter DNS reload (apple#1128)
## Summary
The `reload()` method in `PacketFilter.swift` references
`/sbin/reloadProcess` (the local variable name) instead of
`/sbin/pfctl`. This causes all DNS create and delete operations to fail:
```
Error: internalError: "pfctl reload exec failed: "Error Domain=NSCocoaErrorDomain Code=4 "The file "reloadProcess" doesn't exist.""
```
## Fix
One-line change: `/sbin/reloadProcess` → `/sbin/pfctl`
## Testing
Verified on macOS 26 (Tahoe) with Apple Silicon:
- `sudo container system dns create test.sdc.internal --localhost
203.0.113.1` succeeds without error
- Container can resolve and reach host services through the DNS redirect
commit 113a6ec
Author: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Date: Fri Jan 30 21:54:57 2026 -0600
Fix file descriptor leak in DirectoryWatcher (apple#1104)
- `DirectoryWatcher` opens file descriptors for monitoring
directories but never closes them, causing a file descriptor
leak.
- Adds `setCancelHandler` to properly close file descriptors
when the `DispatchSource` is cancelled.
Signed-off-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
commit 72f04b6
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Fri Jan 30 19:10:03 2026 -0800
[docs]: update steps on building with containerization project (apple#1116)
- Closesapple#1095
- Just added a few more details about how to build with the local
`containerization` dependency.
commit 3a0ad58
Author: Raj <rajaryan_singh@apple.com>
Date: Fri Jan 30 16:17:43 2026 -0800
Add resource.role label to builder container (apple#1120)
Add resource.role label to builder container
commit 1c01d0c
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 30 11:07:49 2026 -0800
Update to kata 3.20.0 kernel. (apple#1114)
- Closesapple#1113.
- This is the newest we can do until we address apple#767.
- Slight change to PacketFilter error handling so unit tests work more
reliably.
- Try making CLINetworkTests serialized to see if parallel execution is
causing flakes.
commit 3f2060e
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 18:25:48 2026 -0800
DirectoryWatcher: Small adjustments (apple#1112)
- Have the handler throw
- Log the failure at error level
commit 0a7fb07
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 14:21:12 2026 -0800
Set mtu to old Containerization default (apple#1110)
The old mtu default in containerization was 1280 to account for some
alpine/musl images that have issues with
1500. This changed in the last couple tags to be modifiable, but the new
default is the standard 1500. Ideally we eventually allow supplying the
mtu to be used when you create a network (or possibly a container
creation setting), but for now just default in here back to what CZ used
to use.
commit 0bceb23
Author: Aditya Ramani <a_ramani@apple.com>
Date: Thu Jan 29 12:08:42 2026 +0900
Bump to use containerization 0.23.2 (apple#1106)
Updating the package dependency on apple/containerization to pick up bug fixes
Signed-off-by: Aditya Ramani <a_ramani@apple.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit d762fe5
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 18:22:33 2026 -0800
Launch a service with waitForDebugger if specified (apple#1101)
This PR enables launching a service with `waitForDebugger` flag if the
service label matches a given env variable `CONTAINER_DEBUG`.
commit 4f93e3e
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed Jan 28 18:21:08 2026 -0800
ci: bump actions/checkout from 6.0.1 to 6.0.2 in the github-actions group (apple#1100)
- Updates `actions/checkout` from 6.0.1 to 6.0.2
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
commit 371db6d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 17:17:08 2026 -0800
Fix testExecOnExitingContainer (apple#1107)
Check the container remains only, not its status as the status might not
have been updated at the time checking.
commit d872270
Author: J Logan <john_logan@apple.com>
Date: Wed Jan 28 09:04:58 2026 -0800
Removes ArgumentParser import from NetworkMode. (apple#1102)
- ContainerResources shouldn't need to know anything about CLI stuff.
- Move ExpressibleByArgument protocol conformance to an extension in the
package where it's needed.
commit 3abf81f
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Tue Jan 27 20:00:43 2026 -0800
[image-list]: Add full size field to json output (apple#1098)
- Refer to apple#862
- Updated `SIZE` field to `FULL SIZE`, as it seemed more appropriate so
it does not get mixed up with the `descriptor size` field
- Closesapple#860
commit 24cbed5
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Jan 28 06:55:49 2026 +0800
Implement container prune (apple#904)
- Fixedapple#892.
- By contrast with `rm`, `prune` should display
the amount of reclaimed storage, so added code
to retrieve it.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit a57527e
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Tue Jan 27 11:15:22 2026 -0800
Refactor container lifecycle functions to perform scoped rollback on failure (apple#1080)
- Closesapple#977.
- Closesapple#1058.
- Prevents unexpected removal of containers on
bootstrapping and starting failures, by reorganizing
error handling for container `run`, `start`, and
`exec` so that error handling only unwinds that
which was done in the current scope.
- Relies on apple/containerization#495.
commit 6244129
Author: c <claudeaceae@icloud.com>
Date: Mon Jan 26 23:30:45 2026 -0500
Fix grammar in BUILDING.md (apple#984)
- Fixes a grammar error in the local Containerization development
instructions.
commit 9d4cded
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Mon Jan 26 19:35:41 2026 -0800
Isolated network (apple#1079)
- Closesapple#1037.
- Adds a `--mode` flag that has `nat` and `hostOnly` options.
The host-only option selects the vmnet host-only mode,
where containers attached to the network can reach each
other and the host, but not external systems.
commit 033c999
Author: J Logan <john_logan@apple.com>
Date: Mon Jan 26 14:07:00 2026 -0800
Make TerminalProgress a library. (apple#1093)
- Closesapple#1092.
- Allows 3rd party CLI plugins to use the progress indicator.
commit b371aee
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Tue Jan 27 05:07:05 2026 +0800
Feat: container image delete force option (apple#1096)
- Fixedapple#1087
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit ed1185d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Fri Jan 23 17:59:28 2026 -0800
Container-to-host networking. (apple#1078)
- Closesapple#346.
- This PR enables connecting host's localhost ports from
containers.
- It adds an option `--localhost <localhost>` to DNS
create command, after which the packets heading
ip address in container are redirected to localhost in
host machine. Packet filter rule is added and deleted
along with the creation and deletion of localhost domain.
commit 14c279f
Author: Patrick Linnane <patrick@linnane.io>
Date: Fri Jan 23 17:56:35 2026 -0800
Add option to stop services in all launchd domains (apple#1077)
- Services started from Terminal run in the `gui/$uid`
launchd domain. When `ensure-container-stopped.sh`
runs from a different context, `launchctl managername`
may return a different domain, causing the script to
check the wrong domain and miss running services.
I noticed this after upgrading `container` via Homebrew.
- Introduces a getopt option `-a` that allows booting out all
domains explicitly. Also adds `-h` for a usage message.
Signed-off-by: Patrick Linnane <patrick@linnane.io>
commit 751c1fc
Author: Stanislav Antonichev <cympak2@users.noreply.github.com>
Date: Fri Jan 23 23:01:26 2026 +0200
Add --dns support to build command for custom DNS resolution (apple#1067)
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
Changes:
- Added --dns option to BuildCommand to accept DNS nameserver IP
addresses
- Modified build logic to detect DNS configuration changes and recreate
the builder container when DNS settings differ
- Passed DNS configuration to BuilderStart.start() method
- Updated builder container creation to use specified DNS nameservers or
fall back to network gateway
## Type of Change
- [ ] Bug fix
- [X] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: J Logan <sgtbakerrahulnet@yahoo.com>
commit 55f2112
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 23 11:35:10 2026 -0800
Place image store data correctly for app-root path. (apple#1085)
- Closesapple#1084.
commit 5746ec3
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Sat Jan 24 03:32:59 2026 +0800
Fix: prevent delete default network (apple#1083)
- Fixedapple#1073
- Move the conditional check to the front; there's no need
to check for a default network after filtering.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@manuschillerdev@jglogan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: add --init-image flag for specifying custom init filesystem images per VM - #937

Merged
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image
Feb 10, 2026
Merged

feat: add --init-image flag for specifying custom init filesystem images per VM#937
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image

Conversation

@manuschillerdev

@manuschillerdevmanuschillerdev commented Dec 7, 2025

Copy link
Copy Markdown
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

I've been tinkering with ways to extend container with a primitive for interacting with the VM layer. One approach: expose the internal init filesystem as a user-configurable option via --init-image.

What this enables:

  • Custom boot-time logic before the OCI container starts
  • Running additional processes and daemons (e.g., daemons to configure eBPF network filters, logging agents) inside the VM (not the container)
  • Debugging/instrumenting the init process

--init-image vs using the system property
we could also use container system property set image.init vminit:latest (documented via #1032), but this affects all VMs. I want to be able to override this only for a single VM.

In my current approach, the custom image wraps the default vminitd, so it's currently behaving like an entrypoint.
Curious if this direction aligns with the project's goals, or if there's a better abstraction for these use cases.
If there is interest, I would add proper docs and tests.

Example for a minimal entry point binary
Note: We use Go here for its straightforward cross-compilation to Linux ARM64.

// custom-init/wrapper.gopackage main
import (
"fmt""os""syscall"
)
funcmain() {
kmsg, err:=os.OpenFile("/dev/kmsg", os.O_WRONLY, 0)
iferr==nil {
kmsg.WriteString("<6>custom-init: === CUSTOM INIT IMAGE RUNNING ===\n")
kmsg.Close()
}
err=syscall.Exec("/sbin/vminitd.real", os.Args, os.Environ())
iferr!=nil {
fmt.Fprintf(os.Stderr, "Failed to exec vminitd.real: %v\n", err)
os.Exit(1)
}
}

Containerfile

# custom-init/Containerfile
FROM ghcr.io/apple/containerization/vminit:0.23.2 AS base
FROM ghcr.io/apple/containerization/vminit:0.23.2
COPY --from=base /sbin/vminitd /sbin/vminitd.real
COPY wrapper /sbin/vminitd
  • build the binary with cd custom-init && CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o wrapper wrapper.go
  • build the image with bin/container build -t local/custom-init:0.20.0 custom-init/
  • run the container with our custom init-image: bin/container run --name init-test --init-image local/custom-init:0.20.0 alpine:latest echo "hello"
  • check the logs with cat "/Users/$USER/Library/Application Support/com.apple.container/containers/init-test/vminitd.log" | head -50

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

@manuschillerdevmanuschillerdev changed the title feat: add init-image flag for specifying custom init filesystem images per VMfeat: add --init-image flag for specifying custom init filesystem images per VMDec 7, 2025
@jglogan

Copy link
Copy Markdown
Contributor

@dcantah see also #838

Comment threadSources/ContainerClient/Utility.swift
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@dcantah@jglogan would that be of interest for the project? Would be totally open to other suggestions on how one can interact with the startup process. Exposing --init-fs seemed like a viable option here

@manuschillerdev

manuschillerdev commented Jan 10, 2026

Copy link
Copy Markdown
ContributorAuthor

@jglogan@dcantah

I've rebased the PR, added tests and documentation, and updated the description to clarify why container system property set image.init doesn't fit my use case (it applies globally rather than per-VM).

Happy to elaborate on any open questions or explore alternative approaches that would better align with the project's architecture.
I'd appreciate any feedback on whether this direction makes sense to pursue or if there are concerns that would make it worth closing in favor of a different approach.

@jglogan

jglogan commented Jan 17, 2026

Copy link
Copy Markdown
Contributor

@manuschillerdev I haven't been able to review but it seems reasonable. Kernel and initfs config are birds of a feather, whatever config options exist for one, we should eventually provide for the other.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Could you run make fmt on this, and make sure build/test runs okay on your end, and then try pushing the changes? I made one change to resolve some merge conflicts on the Makefile

@jglogan

Copy link
Copy Markdown
Contributor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 5badfb6 to 6e1d1faCompareFebruary 1, 2026 10:15
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

thanks for having another look at this! I rebased the PR against main, resolved the conflicts, ran make fmt, and did a complete re-test locally with the steps from the PR description:

❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"| grep "==="
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
full output of vminitd.log after creating a custom init image, and starting a fresh container using the `--init-image` flag:
❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"
[ 0.069458] random: crng init done
[ 0.070722] brd: module loaded
[ 0.071338] loop: module loaded
[ 0.071436] virtio_blk virtio2: 1/0/0 default/read/poll queues
[ 0.071600] virtio_blk virtio2: [vda] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.071875] virtio_blk virtio3: 1/0/0 default/read/poll queues
[ 0.072020] virtio_blk virtio3: [vdb] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.072226] tun: Universal TUN/TAP device driver, 1.6
[ 0.072687] VFIO - User Level meta-driver version: 0.3
[ 0.072820] rtc-pl031 20050000.pl031: registered as rtc0
[ 0.072857] rtc-pl031 20050000.pl031: setting system clock to 2026-02-01T08:49:54 UTC (1769935794)
[ 0.073306] xt_time: kernel timezone is -0000
[ 0.073348] IPVS: Registered protocols (TCP, UDP, SCTP, AH, ESP)
[ 0.073434] IPVS: Connection hash table configured (size=4096, memory=32Kbytes)
[ 0.073579] IPVS: ipvs loaded.
[ 0.073615] IPVS: [rr] scheduler registered.
[ 0.073634] IPVS: [wrr] scheduler registered.
[ 0.073685] IPVS: [lc] scheduler registered.
[ 0.073718] IPVS: [wlc] scheduler registered.
[ 0.073767] IPVS: [fo] scheduler registered.
[ 0.073813] IPVS: [ovf] scheduler registered.
[ 0.073862] IPVS: [lblc] scheduler registered.
[ 0.073924] IPVS: [lblcr] scheduler registered.
[ 0.073942] IPVS: [dh] scheduler registered.
[ 0.073966] IPVS: [sh] scheduler registered.
[ 0.073991] IPVS: [sed] scheduler registered.
[ 0.074016] IPVS: [nq] scheduler registered.
[ 0.074043] IPVS: [sip] pe registered.
[ 0.074088] Initializing XFRM netlink socket
[ 0.074130] NET: Registered PF_INET6 protocol family
[ 0.074389] Segment Routing with IPv6
[ 0.074421] In-situ OAM (IOAM) with IPv6
[ 0.074462] NET: Registered PF_PACKET protocol family
[ 0.074505] 9pnet: Installing 9P2000 support
[ 0.074573] NET: Registered PF_VSOCK protocol family
[ 0.075578] registered taskstats version 1
[ 0.076957] alg: No testfor fips(ansi_cprng) (fips_ansi_cprng)
[ 0.077498] clk: Disabling unused clocks
[ 0.080034] EXT4-fs (vda): mounted filesystem 63cb0698-b5fe-4f00-ba03-179297b9693a ro without journal. Quota mode: disabled.
[ 0.080117] VFS: Mounted root (ext4 filesystem) readonly on device 254:0.
[ 0.080441] devtmpfs: mounted
[ 0.080801] Freeing unused kernel memory: 1856K
[ 0.080895] Run /sbin/vminitd as init process
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
2026-02-01T08:49:54+0000 info vminitd : [vminitd] Running init command
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /proc
2026-02-01T08:49:54+0000 info vminitd : [vminitd] vminitd booting
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /run
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys/fs/cgroup
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 debug vminitd : bytes=78643200 path=/sys/fs/cgroup/vminitd [Cgroup] setting memory.high
2026-02-01T08:49:54+0000 debug vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] adding new proc to cgroup
2026-02-01T08:49:54+0000 info vminitd : events_path=/sys/fs/cgroup/vminitd/memory.events threshold_bytes=78643200 [vminitd] Started memory monitoring
2026-02-01T08:49:54+0000 info vminitd : [vminitd] serving vminitd API
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] starting process supervisor
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] booting gRPC server on vsock
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] gRPC API serving on vsock
2026-02-01T08:49:54+0000 debug vminitd : interface=lo up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : key=PATH value=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [vminitd] setenv
2026-02-01T08:49:54+0000 debug vminitd : destination=/tmp source=tmpfs type=tmpfs [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/dev/pts source=devpts type=devpts [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/run/container/init-test/rootfs source=/dev/vdb type=ext4 [vminitd] mount
[ 0.268991] EXT4-fs (vdb): mounted filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab r/w without journal. Quota mode: disabled.
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Address=192.168.64.3/24 [vminitd] ipAddrAdd
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Gateway=192.168.64.1 [vminitd] ipRouteAddDefault
2026-02-01T08:49:54+0000 debug vminitd : domain= location=/run/container/init-test/rootfs nameservers=["192.168.64.1"] options=[] searchDomains=[] [vminitd] configureDns
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] writing to path /run/container/init-test/rootfs/etc/resolv.conf nameserver 192.168.64.1
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/resolv.conf [vminitd] wrote resolver configuration
2026-02-01T08:49:54+0000 debug vminitd : location=/run/container/init-test/rootfs [vminitd] configureHosts
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/hosts [vminitd] wrote /etc/hosts configuration
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test stderr=Port: 268435457 stdin=Port: 0 stdout=Port: 268435456 [vminitd] createProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] created bundle with spec Spec(version: "", hooks: nil, process: Optional(ContainerizationOCI.Process(cwd: "/", env: ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME=/root"], consoleSize: nil, selinuxLabel: "", noNewPrivileges: false, commandLine: "", oomScoreAdj: nil, capabilities: Optional(ContainerizationOCI.LinuxCapabilities(bounding: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), effective: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), inheritable: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), permitted: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), ambient: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]))), apparmorProfile: "", user: ContainerizationOCI.User(uid: 0, gid: 0, umask: nil, additionalGids: [0], username: ""), rlimits: [], args: ["echo", "hello"], terminal: false)), hostname: "init-test", domainname: "", mounts: [ContainerizationOCI.Mount(type: "proc", source: "proc", destination: "/proc", options: [], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "sysfs", source: "sysfs", destination: "/sys", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devtmpfs", source: "none", destination: "/dev", options: ["nosuid", "mode=755"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "mqueue", source: "mqueue", destination: "/dev/mqueue", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "tmpfs", source: "tmpfs", destination: "/dev/shm", options: ["nosuid", "noexec", "nodev", "mode=1777", "size=65536k"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "cgroup2", source: "none", destination: "/sys/fs/cgroup", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devpts", source: "devpts", destination: "/dev/pts", options: ["nosuid", "noexec", "newinstance", "gid=5", "mode=0620", "ptmxmode=0666"], uidMappings: nil, gidMappings: nil)], annotations: nil, root: Optional(ContainerizationOCI.Root(path: "/run/container/init-test/rootfs", readonly: false)), linux: Optional(ContainerizationOCI.Linux(uidMappings: [], gidMappings: [], sysctl: Optional([:]), resources: Optional(ContainerizationOCI.LinuxResources(devices: [], memory: Optional(ContainerizationOCI.LinuxMemory(limit: Optional(1073741824), reservation: nil, swap: nil, kernel: nil, kernelTCP: nil, swappiness: nil, disableOOMKiller: nil, useHierarchy: nil, checkBeforeUpdate: nil)), cpu: Optional(ContainerizationOCI.LinuxCPU(shares: nil, quota: Optional(400000), burst: nil, period: Optional(100000), realtimeRuntime: nil, realtimePeriod: nil, cpus: "", mems: "", idle: nil)), pids: nil, blockIO: nil, hugepageLimits: [], network: nil, rdma: nil, unified: Optional([:]))), cgroupsPath: "/container/init-test", namespaces: [ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.cgroup, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.ipc, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.mount, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.pid, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.uts, path: "")], devices: [], seccomp: nil, rootfsPropagation: "", maskedPaths: [], readonlyPaths: [], mountLabel: "", personality: nil)))
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting I/O
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stderr
2026-02-01T08:49:54+0000 info vminitd : [vminitd] created vmexec init process
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] startProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] in supervisor lock to start process
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting managed process
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78381056 high_events_total=1 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78442496 high_events_total=15 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78331904 high_events_total=18 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] got back pid data
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] sending pid acknowledgement
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[93: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] started managed process
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[94: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 debug vminitd : count=0 pid=94 status=0 [vminitd] managed process exited
2026-02-01T08:49:54+0000 info vminitd : id=init-test status=0 [vminitd] managed process exit
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stderr
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] 0 managed process waiters signaled
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : pid=-1 signal=9 [vminitd] kill
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : flags=0 path=/run/container/init-test/rootfs [vminitd] umount
[ 0.541866] EXT4-fs (vdb): unmounting filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab.
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] sync
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] deleteProcess
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] deleting cgroup manager

I also re-ran the tests:

❯ swift test --filter TestCLIRunInitImage 2>&1
Building for debugging...
[7/7] Write swift-version-1C31CF501CE571A8.txt
Build complete! (0.77s)
Test Suite 'Selected tests' started at 2026-02-01 11:10:47.076.
Test Suite 'containerPackageTests.xctest' started at 2026-02-01 11:10:47.077.
Test Suite 'containerPackageTests.xctest' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.1 (c9d57c83568b06d)
↳ Target Platform: arm64-apple-macosx
◇ Suite TestCLIRunInitImage started.
◇ Test testCreateWithNonExistentInitImage() started.
◇ Test testRunWithExplicitDefaultInitImage() started.
◇ Test testInitImageFlagInHelp() started.
◇ Test testRunWithNonExistentInitImage() started.
✔ Test testInitImageFlagInHelp() passed after 0.178 seconds.
✔ Test testRunWithNonExistentInitImage() passed after 10.584 seconds.
✔ Test testCreateWithNonExistentInitImage() passed after 20.668 seconds.
✔ Test testRunWithExplicitDefaultInitImage() passed after 25.314 seconds.
✔ Suite TestCLIRunInitImage passed after 25.314 seconds.
✔ Test run with 4 tests in 1 suite passed after 25.314 seconds.

@jglogan let me know if that works for you, or if I should rather still open a fresh PR. Don't worry, I'd aim for the cleanest solution for the maintainers and the repo. Re-organizing the PR is no effort at all. Thanks for your time again!

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev In CI I'm seeing this failure:

✔ Test testCreateWithNonExistentInitImage() passed after 43.897 seconds.
✘ Test testRunWithExplicitDefaultInitImage() recorded an issue at TestCLIRunInitImage.swift:93:6: Caught error: executionFailed("command failed: Warning! Running debug build. Performance may be degraded.\nError: internalError: \"failed to create container\" (cause: \"internalError: \"XPC timeout for request to com.apple.container.apiserver/containerCreate\"\")\n")
✘ Test testRunWithExplicitDefaultInitImage() failed after 87.555 seconds with 1 issue.
↳ /// Test that explicitly specifying the default init image works the same as
↳ /// not specifying any init image.
✔ Test testRunWithNonExistentInitImage() passed after 87.606 seconds.
✘ Suite TestCLIRunInitImage failed after 87.606 seconds with 1 issue.
✘ Test run with 4 tests in 1 suite failed after 87.606 seconds with 1 issue.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 7d9a37a to baae7c7CompareFebruary 3, 2026 22:05
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks! the tests did catch an error in the image selection logic - glad they did.
I pushed a separate fix, an re-ran make integrate locally without errors.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev OK, the updated tests worked fine. One last thing (thanks for your patience!)

ContainerClient got a big refactor your changes need to be updated to work with those.

@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan no worries. I rebased against main and verified that the changes still work.
make integration runs without errors, loading a custom init-image works and starting containers without a custom init image provided works as well

@jglogan
jglogan merged commit cf9b335 into apple:mainFeb 10, 2026
3 checks passed
@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Finally got it in there...thanks for the contribution!

simone-panico pushed a commit to simone-panico/container that referenced this pull request Feb 10, 2026
…ges per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks again for guiding me!

Mcrich23 added a commit to Mcrich23/container that referenced this pull request Feb 18, 2026
commit c791052
Author: Aditya Ramani <a_ramani@apple.com>
Date: Wed Feb 18 07:43:56 2026 +0530
Add init methods for all the members of the Flags type (apple#1203)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Authors of CLI plugins for container will be able to reuse the container
flags defined in the CLI package, instead of having to duplicate them in
their project
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit dfac83d
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 17 16:54:44 2026 -0800
ContainerService: Add minimum memory amount validation (apple#1208)
Closesapple#1202
Today it's possible to pass a memory amount that very easily will cause
the container's VM to not be able to boot. We should protect against
this to avoid weird hangs/error messages. I could be convinced that a
limit should be in Containerization as well, but I think having one in
the daemon is a decent idea regardless.
commit 5385a5c
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Tue Feb 17 15:08:32 2026 -0800
Support using multiple different network plugins (apple#1151)
## Type of Change
- [x] New feature
- [x] Breaking change
## Motivation and Context
We want to be able to support using multiple network plugins during
`container`'s lifetime. This additionally means needing to pick an
interface strategy to interpret a network attachment based on what
network plugin was used to create that attachment. This PR will
potentially replace apple#1081.
Followups:
- doc updates to include the ability to specify plugin in the network
creation cli
## Testing
- [x] Tested locally
- [x] Added/updated tests
commit 7476743
Author: AJ Emory <239216119+ajemory@users.noreply.github.com>
Date: Fri Feb 13 19:27:32 2026 -0800
feat: Moving bundle creation from ContainerService to SandboxService (apple#1076)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Closesapple#1046 -- Right now we're creating container bundles in
ContainersService. Move this to the SandboxService to make it easier to
support different container bundle types.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 4c800db
Author: J Logan <john_logan@apple.com>
Date: Fri Feb 13 10:51:27 2026 -0800
Fix persistent CI failures. (apple#1205)
## Type of Change
- [x] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
- CI build is failing because runners don't have an /etc/resolver
directory, causing the directory monitor to fail. This occurs while the
install-kernel make target is running, so it appears that kernel
download is failing when it's just that the API server is dying. Created
apple#1207 for the issue.
- Fixing the initial scan for the directory just moves the problem to
the filesystem watch loop, likely because we're not testing the result
of `open()` for errors.
- Right now the priority is getting CI running and PRs merged, so just
commenting out the realhost DNS server setup.
- Also seeing that under some conditions it can take quite a while for
launchd to start the helper for the default network (8 seconds or more).
With the 10 second health check timeout after API server registration,
this means that some CI runs can exhibit this failure mode. Added a
`--timeout` option to SystemStart and set a 60 second timeout for
install-kernel and integration Makefile targets.
- Fixed a bug where `--debug` was being placed in the wrong location in
the api server startup args.
- Disabled all network CLI tests due to container bootstrap errors when
trying to run the container immediately after creating the network. The
slow network helper launch could be the reason behind the failures that
drove us to serialize these tests. Filed apple#1206 for this issue.
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit f7d00aa
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 11 15:09:21 2026 -0800
APIServer: Add support for filtering to list rpc (apple#1175)
This is not intended to be used to support `--filter` or similar on the
CLIs list yet, it's solely to clean up our rather awkward use of
`ContainerClient.list()` today in the CLI. The list RPC simply returns
all of the containers we have created. Because of this, for a LOT of our
commands we filter to what we need client side, which feels like a
waste.. This change introduces a filter struct that we can provide an
array of container IDs, labels, and the status of the containers to
filter the `list()` output from.
This additionally, because it was killing (pun not intended) me and I
was already having to change this area for the `list()` additions,
changes container kill slightly to return an error if you try and kill a
container that doesn't exist.
commit c9f81ca
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Feb 11 04:26:33 2026 +0800
Feat: add container registry list (apple#1119)
- Requires apple/containerization#502
- Closesapple#1088
---------
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit cf9b335
Author: Manu Schiller <56154253+manuschillerdev@users.noreply.github.com>
Date: Tue Feb 10 03:11:27 2026 +0100
feat: add --init-image flag for specifying custom init filesystem images per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
commit 474906d
Author: Amir Alperin <me@remotecpp.dev>
Date: Fri Feb 6 23:38:19 2026 +0200
feat: Add runtime flag to container create and run commands (apple#1049) (apple#1109)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Fixesapple#1049
- Add --runtime option for Flags.Management
- Apply runtime handler in containerConfigFromFlags
- Update command-reference.md doc
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
Co-authored-by: J Logan <john_logan@apple.com>
commit 40de343
Author: Dmitry Kovba <dkovba@apple.com>
Date: Fri Feb 6 00:41:29 2026 -0800
Fix relative path mount tests (apple#1168)
`make test` occasionally fails with:
```
✘ Test testHostDNSReinitialize() recorded an issue at HostDNSResolverTest.swift:132:45: Expectation failed: (error →
Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory") as? (ContainerizationError → NSError)
✘ Suite HostDNSResolverTest failed after 0.119 seconds with 1 issue.
```
commit aa17d46
Author: Poetry Of Code <101225909+poetryofcode@users.noreply.github.com>
Date: Fri Feb 6 03:38:21 2026 -0500
Warn user when a named volume is auto-created (apple#1108)
- Implemented the TODO at
ContainerAPIService/Client/Utility.swift:358 — warn the
user when a named volume is auto-created.
- This only triggers for named volumes (not anonymous
ones), matching Docker's behavior of informing users
about implicit resource creation.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
commit adb3c44
Author: J Logan <john_logan@apple.com>
Date: Thu Feb 5 20:19:13 2026 -0800
Don't enable selinux LSM on boot. (apple#1166)
- Closesapple#1150.
- The problem seems to be that the selinux label attribute enforcement
doesn't play well with overlayfs.
- Solution is to set the `lsm` boot line argument. The new value
corresponds to what one would see in a Lima VM with Colima. The Kata
kernel we use doesn't provide any of those modules, so now if you run
`dmesg | grep -i lsm` in a container you will just see: `LSM:
initializing lsm=capability`
commit fdeb1b1
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 10:59:31 2026 -0800
Add builder tests (apple#1154)
- Adds test for apple#1094.
- Closesapple#933 (with apple/container-builder-shim#62).
- Closesapple#425 (with apple/container-builder-shim#63).
commit fabfc55
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 09:53:31 2026 -0800
Send tar hash in the first BuildTransfer packet (apple#1149)
Send the hash of entire tar file in the first BuildTransfer packet to
prevent container-builder-shim from using stale cached contents.
This PR resolvesapple#1143.
This PR relies on apple/container-builder-shim#64.
## Type of Change
- [X] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Current container-builder-shim uses only first few bytes of tar file as
checksum, which leads to the usage of stale cached contents if the
change of build context is not included in the first bytes of tar file.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit 6e9b8d7
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Feb 5 09:47:20 2026 -0800
CLI: Forego logging errors on multi-container operations (apple#1163)
Instead of logging errors, and then additionally throwing an error
stating what containers couldn't be stopped/killed/deleted, let's just
concatenate the errors and throw the single error.
commit d79bc0d
Author: Manoj Mahapatra <mahapatra.manoj@hotmail.com>
Date: Thu Feb 5 01:16:30 2026 -0800
chore: Replace force-unwrapped String(data:encoding:) with String(decoding:as:) (apple#1164)
Use the non-optional String(decoding:as:) initializer for converting
JSON-encoded Data to String. This is safe for UTF-8 and eliminates force
commit 21dabb7
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 03:13:36 2026 -0500
[build-command]: Add --pull option for fetching latest image (apple#844)
- Closesapple#733.
commit 6553f9c
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 01:16:08 2026 -0500
[deps]: bump containerization to 0.25.0 (apple#1161)
Co-authored-by: saehejkang <saehej.kang@gmail.com>
Co-authored-by: Anthony DePasquale <anthony@depasquale.org>
- Bump `containerization` to `0.25.0`
- Updates for parameter changes on containerization
registry access API.
- Updates for change to containerization
`cleanUpOrphanedBlobs` function.
commit 2d1dd6b
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 15:42:29 2026 -0800
Fix file path for the PR number in the PR labeler workflow (apple#1158)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR label applier GitHub workflow has been failing for a while. This
PR fixes that by correcting the file path we look for when trying to
read the PR number. See example failure here
https://github.com/apple/container/actions/runs/21691766538/job/62552959972#step:4:23
commit 6451e07
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 14:44:53 2026 -0800
Add debugging to the PR labeler CI flow (apple#1155)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR labeler workflow has been failing for a while but it's difficult
to know how to fix it since the PR labeler workflow is run from main
(aka NOT the current PR branch) for security reasons. Example at
https://github.com/apple/container/actions/runs/21690229300/workflow
commit 8fdfa29
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:52:09 2026 -0800
CLI: Rework ClientContainer (apple#1139)
ClientContainer was honestly extremely awkward. It could only be created
by passing either a ContainerConfiguration, or a Snapshot that had to be
obtained from calling a static method on the type itself. The type also
did not store a connection, so every single method got a new xpc
connection to the APIServer. This change aims to rework this type to be
just a generic client, that is *not* a client for one specific
container, but for any.
- Rename to ContainerClient
- Have list() return [ContainerSnapshot]
- Create a connection in the constructor
- Change all the callsites to use the new API
- Small, somewhat related, change to logs API in the APIServer. Now that
we don't need to call get() to grab a client anymore which was typically
what did "does this container exist" logic and gave a nice error
message, I added a small check in the APIServer to see if the container
exists and return mostly the same error message.
commit 23c0ece
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:19:50 2026 -0800
CI: Add signed commit check (apple#1152)
This requirement of ours often goes unnoticed because nothing yells at
you openly about it. Lets fail CI to make it more obvious.
commit ce1b629
Author: Manoj Mahapatra <mahaplipsa@gmail.com>
Date: Tue Feb 3 13:43:07 2026 -0800
[Docs] Fix typo in BUILDING.md: launchd -> launchctl (apple#1146)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [x] Documentation update
## Motivation and Context
The debug instructions in `BUILDING.md` incorrectly reference launchd
list instead of `launchctl` list. `launchd` is the daemon itself and
cannot be invoked directly.
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [x] Added/updated docs
commit 3e49dce
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 3 00:45:01 2026 -0800
Add in missing rlimits (apple#1140)
Containerization didn't have these defined until a recent tag.
commit c4c2e85
Author: J Logan <john_logan@apple.com>
Date: Tue Feb 3 00:27:09 2026 -0800
Upgrade kernel to Kata 3.26.0. (apple#1134)
- Upgrade to containerization 0.24.5 to pick up zstd decompression
enhancement.
- Closesapple#767.
- Closesapple#988.
- Closesapple#1132.
- Requires apple/containerization#508.
commit 5c86337
Author: William Laverty <developer@william-laverty.com>
Date: Mon Feb 2 13:57:59 2026 -0800
Add explanatory message before admin password prompt in uninstall script (apple#1118)
- Added message: "This script requires an administrator password to
remove the application files from system directories."
- Fixesapple#1111
commit 7da25e1
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:35:02 2026 -0800
Deps: Bump Containerization to 0.24.0 (apple#1127)
Brings in some rlimit bumps/adjustments
commit 7dfe27d
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:30:19 2026 -0800
CLI: Add support for rlimits (apple#1129)
Closesapple#1097.
commit b3b5c3e
Author: J Logan <john_logan@apple.com>
Date: Mon Feb 2 12:24:27 2026 -0800
Use labels instead of id to discriminate the builtin network. (apple#1123)
- Closesapple#1122.
- Adds placeholder ManagedResource and unit tests. Nothing is using
these yet.
- Adds system-defined resource labels for owning plugin and resource
role. The system discriminates the builtin network using role "builtin".
- Adds builtin role when creating builtin network at startup, and
ensures that a preexisting network with ID "default" gets updated with
the role label.
- Replace all network ID checks for "default" with the builtin role
check.
- Adds "builder" role to builder VM.
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Role and owner labels should make cross-cutting resource policy easier
to implement.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 1dae1cd
Author: w-ferg <43309695+w-ferg@users.noreply.github.com>
Date: Sun Feb 1 18:14:41 2026 -0500
Fix pfctl executable path in PacketFilter DNS reload (apple#1128)
## Summary
The `reload()` method in `PacketFilter.swift` references
`/sbin/reloadProcess` (the local variable name) instead of
`/sbin/pfctl`. This causes all DNS create and delete operations to fail:
```
Error: internalError: "pfctl reload exec failed: "Error Domain=NSCocoaErrorDomain Code=4 "The file "reloadProcess" doesn't exist.""
```
## Fix
One-line change: `/sbin/reloadProcess` → `/sbin/pfctl`
## Testing
Verified on macOS 26 (Tahoe) with Apple Silicon:
- `sudo container system dns create test.sdc.internal --localhost
203.0.113.1` succeeds without error
- Container can resolve and reach host services through the DNS redirect
commit 113a6ec
Author: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Date: Fri Jan 30 21:54:57 2026 -0600
Fix file descriptor leak in DirectoryWatcher (apple#1104)
- `DirectoryWatcher` opens file descriptors for monitoring
directories but never closes them, causing a file descriptor
leak.
- Adds `setCancelHandler` to properly close file descriptors
when the `DispatchSource` is cancelled.
Signed-off-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
commit 72f04b6
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Fri Jan 30 19:10:03 2026 -0800
[docs]: update steps on building with containerization project (apple#1116)
- Closesapple#1095
- Just added a few more details about how to build with the local
`containerization` dependency.
commit 3a0ad58
Author: Raj <rajaryan_singh@apple.com>
Date: Fri Jan 30 16:17:43 2026 -0800
Add resource.role label to builder container (apple#1120)
Add resource.role label to builder container
commit 1c01d0c
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 30 11:07:49 2026 -0800
Update to kata 3.20.0 kernel. (apple#1114)
- Closesapple#1113.
- This is the newest we can do until we address apple#767.
- Slight change to PacketFilter error handling so unit tests work more
reliably.
- Try making CLINetworkTests serialized to see if parallel execution is
causing flakes.
commit 3f2060e
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 18:25:48 2026 -0800
DirectoryWatcher: Small adjustments (apple#1112)
- Have the handler throw
- Log the failure at error level
commit 0a7fb07
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 14:21:12 2026 -0800
Set mtu to old Containerization default (apple#1110)
The old mtu default in containerization was 1280 to account for some
alpine/musl images that have issues with
1500. This changed in the last couple tags to be modifiable, but the new
default is the standard 1500. Ideally we eventually allow supplying the
mtu to be used when you create a network (or possibly a container
creation setting), but for now just default in here back to what CZ used
to use.
commit 0bceb23
Author: Aditya Ramani <a_ramani@apple.com>
Date: Thu Jan 29 12:08:42 2026 +0900
Bump to use containerization 0.23.2 (apple#1106)
Updating the package dependency on apple/containerization to pick up bug fixes
Signed-off-by: Aditya Ramani <a_ramani@apple.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit d762fe5
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 18:22:33 2026 -0800
Launch a service with waitForDebugger if specified (apple#1101)
This PR enables launching a service with `waitForDebugger` flag if the
service label matches a given env variable `CONTAINER_DEBUG`.
commit 4f93e3e
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed Jan 28 18:21:08 2026 -0800
ci: bump actions/checkout from 6.0.1 to 6.0.2 in the github-actions group (apple#1100)
- Updates `actions/checkout` from 6.0.1 to 6.0.2
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
commit 371db6d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 17:17:08 2026 -0800
Fix testExecOnExitingContainer (apple#1107)
Check the container remains only, not its status as the status might not
have been updated at the time checking.
commit d872270
Author: J Logan <john_logan@apple.com>
Date: Wed Jan 28 09:04:58 2026 -0800
Removes ArgumentParser import from NetworkMode. (apple#1102)
- ContainerResources shouldn't need to know anything about CLI stuff.
- Move ExpressibleByArgument protocol conformance to an extension in the
package where it's needed.
commit 3abf81f
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Tue Jan 27 20:00:43 2026 -0800
[image-list]: Add full size field to json output (apple#1098)
- Refer to apple#862
- Updated `SIZE` field to `FULL SIZE`, as it seemed more appropriate so
it does not get mixed up with the `descriptor size` field
- Closesapple#860
commit 24cbed5
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Jan 28 06:55:49 2026 +0800
Implement container prune (apple#904)
- Fixedapple#892.
- By contrast with `rm`, `prune` should display
the amount of reclaimed storage, so added code
to retrieve it.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit a57527e
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Tue Jan 27 11:15:22 2026 -0800
Refactor container lifecycle functions to perform scoped rollback on failure (apple#1080)
- Closesapple#977.
- Closesapple#1058.
- Prevents unexpected removal of containers on
bootstrapping and starting failures, by reorganizing
error handling for container `run`, `start`, and
`exec` so that error handling only unwinds that
which was done in the current scope.
- Relies on apple/containerization#495.
commit 6244129
Author: c <claudeaceae@icloud.com>
Date: Mon Jan 26 23:30:45 2026 -0500
Fix grammar in BUILDING.md (apple#984)
- Fixes a grammar error in the local Containerization development
instructions.
commit 9d4cded
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Mon Jan 26 19:35:41 2026 -0800
Isolated network (apple#1079)
- Closesapple#1037.
- Adds a `--mode` flag that has `nat` and `hostOnly` options.
The host-only option selects the vmnet host-only mode,
where containers attached to the network can reach each
other and the host, but not external systems.
commit 033c999
Author: J Logan <john_logan@apple.com>
Date: Mon Jan 26 14:07:00 2026 -0800
Make TerminalProgress a library. (apple#1093)
- Closesapple#1092.
- Allows 3rd party CLI plugins to use the progress indicator.
commit b371aee
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Tue Jan 27 05:07:05 2026 +0800
Feat: container image delete force option (apple#1096)
- Fixedapple#1087
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit ed1185d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Fri Jan 23 17:59:28 2026 -0800
Container-to-host networking. (apple#1078)
- Closesapple#346.
- This PR enables connecting host's localhost ports from
containers.
- It adds an option `--localhost <localhost>` to DNS
create command, after which the packets heading
ip address in container are redirected to localhost in
host machine. Packet filter rule is added and deleted
along with the creation and deletion of localhost domain.
commit 14c279f
Author: Patrick Linnane <patrick@linnane.io>
Date: Fri Jan 23 17:56:35 2026 -0800
Add option to stop services in all launchd domains (apple#1077)
- Services started from Terminal run in the `gui/$uid`
launchd domain. When `ensure-container-stopped.sh`
runs from a different context, `launchctl managername`
may return a different domain, causing the script to
check the wrong domain and miss running services.
I noticed this after upgrading `container` via Homebrew.
- Introduces a getopt option `-a` that allows booting out all
domains explicitly. Also adds `-h` for a usage message.
Signed-off-by: Patrick Linnane <patrick@linnane.io>
commit 751c1fc
Author: Stanislav Antonichev <cympak2@users.noreply.github.com>
Date: Fri Jan 23 23:01:26 2026 +0200
Add --dns support to build command for custom DNS resolution (apple#1067)
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
Changes:
- Added --dns option to BuildCommand to accept DNS nameserver IP
addresses
- Modified build logic to detect DNS configuration changes and recreate
the builder container when DNS settings differ
- Passed DNS configuration to BuilderStart.start() method
- Updated builder container creation to use specified DNS nameservers or
fall back to network gateway
## Type of Change
- [ ] Bug fix
- [X] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: J Logan <sgtbakerrahulnet@yahoo.com>
commit 55f2112
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 23 11:35:10 2026 -0800
Place image store data correctly for app-root path. (apple#1085)
- Closesapple#1084.
commit 5746ec3
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Sat Jan 24 03:32:59 2026 +0800
Fix: prevent delete default network (apple#1083)
- Fixedapple#1073
- Move the conditional check to the front; there's no need
to check for a default network after filtering.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@manuschillerdev@jglogan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add --init-image flag for specifying custom init filesystem images per VM - #937

Merged
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image
Feb 10, 2026
Merged

feat: add --init-image flag for specifying custom init filesystem images per VM#937
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image

Conversation

@manuschillerdev

@manuschillerdevmanuschillerdev commented Dec 7, 2025

Copy link
Copy Markdown
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

I've been tinkering with ways to extend container with a primitive for interacting with the VM layer. One approach: expose the internal init filesystem as a user-configurable option via --init-image.

What this enables:

  • Custom boot-time logic before the OCI container starts
  • Running additional processes and daemons (e.g., daemons to configure eBPF network filters, logging agents) inside the VM (not the container)
  • Debugging/instrumenting the init process

--init-image vs using the system property
we could also use container system property set image.init vminit:latest (documented via #1032), but this affects all VMs. I want to be able to override this only for a single VM.

In my current approach, the custom image wraps the default vminitd, so it's currently behaving like an entrypoint.
Curious if this direction aligns with the project's goals, or if there's a better abstraction for these use cases.
If there is interest, I would add proper docs and tests.

Example for a minimal entry point binary
Note: We use Go here for its straightforward cross-compilation to Linux ARM64.

// custom-init/wrapper.gopackage main
import (
"fmt""os""syscall"
)
funcmain() {
kmsg, err:=os.OpenFile("/dev/kmsg", os.O_WRONLY, 0)
iferr==nil {
kmsg.WriteString("<6>custom-init: === CUSTOM INIT IMAGE RUNNING ===\n")
kmsg.Close()
}
err=syscall.Exec("/sbin/vminitd.real", os.Args, os.Environ())
iferr!=nil {
fmt.Fprintf(os.Stderr, "Failed to exec vminitd.real: %v\n", err)
os.Exit(1)
}
}

Containerfile

# custom-init/Containerfile
FROM ghcr.io/apple/containerization/vminit:0.23.2 AS base
FROM ghcr.io/apple/containerization/vminit:0.23.2
COPY --from=base /sbin/vminitd /sbin/vminitd.real
COPY wrapper /sbin/vminitd
  • build the binary with cd custom-init && CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o wrapper wrapper.go
  • build the image with bin/container build -t local/custom-init:0.20.0 custom-init/
  • run the container with our custom init-image: bin/container run --name init-test --init-image local/custom-init:0.20.0 alpine:latest echo "hello"
  • check the logs with cat "/Users/$USER/Library/Application Support/com.apple.container/containers/init-test/vminitd.log" | head -50

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

@manuschillerdevmanuschillerdev changed the title feat: add init-image flag for specifying custom init filesystem images per VMfeat: add --init-image flag for specifying custom init filesystem images per VMDec 7, 2025
@jglogan

Copy link
Copy Markdown
Contributor

@dcantah see also #838

Comment threadSources/ContainerClient/Utility.swift
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@dcantah@jglogan would that be of interest for the project? Would be totally open to other suggestions on how one can interact with the startup process. Exposing --init-fs seemed like a viable option here

@manuschillerdev

manuschillerdev commented Jan 10, 2026

Copy link
Copy Markdown
ContributorAuthor

@jglogan@dcantah

I've rebased the PR, added tests and documentation, and updated the description to clarify why container system property set image.init doesn't fit my use case (it applies globally rather than per-VM).

Happy to elaborate on any open questions or explore alternative approaches that would better align with the project's architecture.
I'd appreciate any feedback on whether this direction makes sense to pursue or if there are concerns that would make it worth closing in favor of a different approach.

@jglogan

jglogan commented Jan 17, 2026

Copy link
Copy Markdown
Contributor

@manuschillerdev I haven't been able to review but it seems reasonable. Kernel and initfs config are birds of a feather, whatever config options exist for one, we should eventually provide for the other.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Could you run make fmt on this, and make sure build/test runs okay on your end, and then try pushing the changes? I made one change to resolve some merge conflicts on the Makefile

@jglogan

Copy link
Copy Markdown
Contributor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 5badfb6 to 6e1d1faCompareFebruary 1, 2026 10:15
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

thanks for having another look at this! I rebased the PR against main, resolved the conflicts, ran make fmt, and did a complete re-test locally with the steps from the PR description:

❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"| grep "==="
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
full output of vminitd.log after creating a custom init image, and starting a fresh container using the `--init-image` flag:
❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"
[ 0.069458] random: crng init done
[ 0.070722] brd: module loaded
[ 0.071338] loop: module loaded
[ 0.071436] virtio_blk virtio2: 1/0/0 default/read/poll queues
[ 0.071600] virtio_blk virtio2: [vda] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.071875] virtio_blk virtio3: 1/0/0 default/read/poll queues
[ 0.072020] virtio_blk virtio3: [vdb] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.072226] tun: Universal TUN/TAP device driver, 1.6
[ 0.072687] VFIO - User Level meta-driver version: 0.3
[ 0.072820] rtc-pl031 20050000.pl031: registered as rtc0
[ 0.072857] rtc-pl031 20050000.pl031: setting system clock to 2026-02-01T08:49:54 UTC (1769935794)
[ 0.073306] xt_time: kernel timezone is -0000
[ 0.073348] IPVS: Registered protocols (TCP, UDP, SCTP, AH, ESP)
[ 0.073434] IPVS: Connection hash table configured (size=4096, memory=32Kbytes)
[ 0.073579] IPVS: ipvs loaded.
[ 0.073615] IPVS: [rr] scheduler registered.
[ 0.073634] IPVS: [wrr] scheduler registered.
[ 0.073685] IPVS: [lc] scheduler registered.
[ 0.073718] IPVS: [wlc] scheduler registered.
[ 0.073767] IPVS: [fo] scheduler registered.
[ 0.073813] IPVS: [ovf] scheduler registered.
[ 0.073862] IPVS: [lblc] scheduler registered.
[ 0.073924] IPVS: [lblcr] scheduler registered.
[ 0.073942] IPVS: [dh] scheduler registered.
[ 0.073966] IPVS: [sh] scheduler registered.
[ 0.073991] IPVS: [sed] scheduler registered.
[ 0.074016] IPVS: [nq] scheduler registered.
[ 0.074043] IPVS: [sip] pe registered.
[ 0.074088] Initializing XFRM netlink socket
[ 0.074130] NET: Registered PF_INET6 protocol family
[ 0.074389] Segment Routing with IPv6
[ 0.074421] In-situ OAM (IOAM) with IPv6
[ 0.074462] NET: Registered PF_PACKET protocol family
[ 0.074505] 9pnet: Installing 9P2000 support
[ 0.074573] NET: Registered PF_VSOCK protocol family
[ 0.075578] registered taskstats version 1
[ 0.076957] alg: No testfor fips(ansi_cprng) (fips_ansi_cprng)
[ 0.077498] clk: Disabling unused clocks
[ 0.080034] EXT4-fs (vda): mounted filesystem 63cb0698-b5fe-4f00-ba03-179297b9693a ro without journal. Quota mode: disabled.
[ 0.080117] VFS: Mounted root (ext4 filesystem) readonly on device 254:0.
[ 0.080441] devtmpfs: mounted
[ 0.080801] Freeing unused kernel memory: 1856K
[ 0.080895] Run /sbin/vminitd as init process
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
2026-02-01T08:49:54+0000 info vminitd : [vminitd] Running init command
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /proc
2026-02-01T08:49:54+0000 info vminitd : [vminitd] vminitd booting
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /run
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys/fs/cgroup
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 debug vminitd : bytes=78643200 path=/sys/fs/cgroup/vminitd [Cgroup] setting memory.high
2026-02-01T08:49:54+0000 debug vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] adding new proc to cgroup
2026-02-01T08:49:54+0000 info vminitd : events_path=/sys/fs/cgroup/vminitd/memory.events threshold_bytes=78643200 [vminitd] Started memory monitoring
2026-02-01T08:49:54+0000 info vminitd : [vminitd] serving vminitd API
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] starting process supervisor
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] booting gRPC server on vsock
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] gRPC API serving on vsock
2026-02-01T08:49:54+0000 debug vminitd : interface=lo up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : key=PATH value=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [vminitd] setenv
2026-02-01T08:49:54+0000 debug vminitd : destination=/tmp source=tmpfs type=tmpfs [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/dev/pts source=devpts type=devpts [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/run/container/init-test/rootfs source=/dev/vdb type=ext4 [vminitd] mount
[ 0.268991] EXT4-fs (vdb): mounted filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab r/w without journal. Quota mode: disabled.
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Address=192.168.64.3/24 [vminitd] ipAddrAdd
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Gateway=192.168.64.1 [vminitd] ipRouteAddDefault
2026-02-01T08:49:54+0000 debug vminitd : domain= location=/run/container/init-test/rootfs nameservers=["192.168.64.1"] options=[] searchDomains=[] [vminitd] configureDns
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] writing to path /run/container/init-test/rootfs/etc/resolv.conf nameserver 192.168.64.1
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/resolv.conf [vminitd] wrote resolver configuration
2026-02-01T08:49:54+0000 debug vminitd : location=/run/container/init-test/rootfs [vminitd] configureHosts
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/hosts [vminitd] wrote /etc/hosts configuration
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test stderr=Port: 268435457 stdin=Port: 0 stdout=Port: 268435456 [vminitd] createProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] created bundle with spec Spec(version: "", hooks: nil, process: Optional(ContainerizationOCI.Process(cwd: "/", env: ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME=/root"], consoleSize: nil, selinuxLabel: "", noNewPrivileges: false, commandLine: "", oomScoreAdj: nil, capabilities: Optional(ContainerizationOCI.LinuxCapabilities(bounding: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), effective: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), inheritable: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), permitted: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), ambient: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]))), apparmorProfile: "", user: ContainerizationOCI.User(uid: 0, gid: 0, umask: nil, additionalGids: [0], username: ""), rlimits: [], args: ["echo", "hello"], terminal: false)), hostname: "init-test", domainname: "", mounts: [ContainerizationOCI.Mount(type: "proc", source: "proc", destination: "/proc", options: [], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "sysfs", source: "sysfs", destination: "/sys", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devtmpfs", source: "none", destination: "/dev", options: ["nosuid", "mode=755"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "mqueue", source: "mqueue", destination: "/dev/mqueue", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "tmpfs", source: "tmpfs", destination: "/dev/shm", options: ["nosuid", "noexec", "nodev", "mode=1777", "size=65536k"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "cgroup2", source: "none", destination: "/sys/fs/cgroup", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devpts", source: "devpts", destination: "/dev/pts", options: ["nosuid", "noexec", "newinstance", "gid=5", "mode=0620", "ptmxmode=0666"], uidMappings: nil, gidMappings: nil)], annotations: nil, root: Optional(ContainerizationOCI.Root(path: "/run/container/init-test/rootfs", readonly: false)), linux: Optional(ContainerizationOCI.Linux(uidMappings: [], gidMappings: [], sysctl: Optional([:]), resources: Optional(ContainerizationOCI.LinuxResources(devices: [], memory: Optional(ContainerizationOCI.LinuxMemory(limit: Optional(1073741824), reservation: nil, swap: nil, kernel: nil, kernelTCP: nil, swappiness: nil, disableOOMKiller: nil, useHierarchy: nil, checkBeforeUpdate: nil)), cpu: Optional(ContainerizationOCI.LinuxCPU(shares: nil, quota: Optional(400000), burst: nil, period: Optional(100000), realtimeRuntime: nil, realtimePeriod: nil, cpus: "", mems: "", idle: nil)), pids: nil, blockIO: nil, hugepageLimits: [], network: nil, rdma: nil, unified: Optional([:]))), cgroupsPath: "/container/init-test", namespaces: [ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.cgroup, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.ipc, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.mount, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.pid, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.uts, path: "")], devices: [], seccomp: nil, rootfsPropagation: "", maskedPaths: [], readonlyPaths: [], mountLabel: "", personality: nil)))
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting I/O
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stderr
2026-02-01T08:49:54+0000 info vminitd : [vminitd] created vmexec init process
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] startProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] in supervisor lock to start process
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting managed process
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78381056 high_events_total=1 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78442496 high_events_total=15 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78331904 high_events_total=18 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] got back pid data
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] sending pid acknowledgement
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[93: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] started managed process
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[94: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 debug vminitd : count=0 pid=94 status=0 [vminitd] managed process exited
2026-02-01T08:49:54+0000 info vminitd : id=init-test status=0 [vminitd] managed process exit
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stderr
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] 0 managed process waiters signaled
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : pid=-1 signal=9 [vminitd] kill
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : flags=0 path=/run/container/init-test/rootfs [vminitd] umount
[ 0.541866] EXT4-fs (vdb): unmounting filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab.
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] sync
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] deleteProcess
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] deleting cgroup manager

I also re-ran the tests:

❯ swift test --filter TestCLIRunInitImage 2>&1
Building for debugging...
[7/7] Write swift-version-1C31CF501CE571A8.txt
Build complete! (0.77s)
Test Suite 'Selected tests' started at 2026-02-01 11:10:47.076.
Test Suite 'containerPackageTests.xctest' started at 2026-02-01 11:10:47.077.
Test Suite 'containerPackageTests.xctest' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.1 (c9d57c83568b06d)
↳ Target Platform: arm64-apple-macosx
◇ Suite TestCLIRunInitImage started.
◇ Test testCreateWithNonExistentInitImage() started.
◇ Test testRunWithExplicitDefaultInitImage() started.
◇ Test testInitImageFlagInHelp() started.
◇ Test testRunWithNonExistentInitImage() started.
✔ Test testInitImageFlagInHelp() passed after 0.178 seconds.
✔ Test testRunWithNonExistentInitImage() passed after 10.584 seconds.
✔ Test testCreateWithNonExistentInitImage() passed after 20.668 seconds.
✔ Test testRunWithExplicitDefaultInitImage() passed after 25.314 seconds.
✔ Suite TestCLIRunInitImage passed after 25.314 seconds.
✔ Test run with 4 tests in 1 suite passed after 25.314 seconds.

@jglogan let me know if that works for you, or if I should rather still open a fresh PR. Don't worry, I'd aim for the cleanest solution for the maintainers and the repo. Re-organizing the PR is no effort at all. Thanks for your time again!

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev In CI I'm seeing this failure:

✔ Test testCreateWithNonExistentInitImage() passed after 43.897 seconds.
✘ Test testRunWithExplicitDefaultInitImage() recorded an issue at TestCLIRunInitImage.swift:93:6: Caught error: executionFailed("command failed: Warning! Running debug build. Performance may be degraded.\nError: internalError: \"failed to create container\" (cause: \"internalError: \"XPC timeout for request to com.apple.container.apiserver/containerCreate\"\")\n")
✘ Test testRunWithExplicitDefaultInitImage() failed after 87.555 seconds with 1 issue.
↳ /// Test that explicitly specifying the default init image works the same as
↳ /// not specifying any init image.
✔ Test testRunWithNonExistentInitImage() passed after 87.606 seconds.
✘ Suite TestCLIRunInitImage failed after 87.606 seconds with 1 issue.
✘ Test run with 4 tests in 1 suite failed after 87.606 seconds with 1 issue.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 7d9a37a to baae7c7CompareFebruary 3, 2026 22:05
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks! the tests did catch an error in the image selection logic - glad they did.
I pushed a separate fix, an re-ran make integrate locally without errors.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev OK, the updated tests worked fine. One last thing (thanks for your patience!)

ContainerClient got a big refactor your changes need to be updated to work with those.

@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan no worries. I rebased against main and verified that the changes still work.
make integration runs without errors, loading a custom init-image works and starting containers without a custom init image provided works as well

@jglogan
jglogan merged commit cf9b335 into apple:mainFeb 10, 2026
3 checks passed
@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Finally got it in there...thanks for the contribution!

simone-panico pushed a commit to simone-panico/container that referenced this pull request Feb 10, 2026
…ges per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks again for guiding me!

Mcrich23 added a commit to Mcrich23/container that referenced this pull request Feb 18, 2026
commit c791052
Author: Aditya Ramani <a_ramani@apple.com>
Date: Wed Feb 18 07:43:56 2026 +0530
Add init methods for all the members of the Flags type (apple#1203)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Authors of CLI plugins for container will be able to reuse the container
flags defined in the CLI package, instead of having to duplicate them in
their project
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit dfac83d
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 17 16:54:44 2026 -0800
ContainerService: Add minimum memory amount validation (apple#1208)
Closesapple#1202
Today it's possible to pass a memory amount that very easily will cause
the container's VM to not be able to boot. We should protect against
this to avoid weird hangs/error messages. I could be convinced that a
limit should be in Containerization as well, but I think having one in
the daemon is a decent idea regardless.
commit 5385a5c
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Tue Feb 17 15:08:32 2026 -0800
Support using multiple different network plugins (apple#1151)
## Type of Change
- [x] New feature
- [x] Breaking change
## Motivation and Context
We want to be able to support using multiple network plugins during
`container`'s lifetime. This additionally means needing to pick an
interface strategy to interpret a network attachment based on what
network plugin was used to create that attachment. This PR will
potentially replace apple#1081.
Followups:
- doc updates to include the ability to specify plugin in the network
creation cli
## Testing
- [x] Tested locally
- [x] Added/updated tests
commit 7476743
Author: AJ Emory <239216119+ajemory@users.noreply.github.com>
Date: Fri Feb 13 19:27:32 2026 -0800
feat: Moving bundle creation from ContainerService to SandboxService (apple#1076)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Closesapple#1046 -- Right now we're creating container bundles in
ContainersService. Move this to the SandboxService to make it easier to
support different container bundle types.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 4c800db
Author: J Logan <john_logan@apple.com>
Date: Fri Feb 13 10:51:27 2026 -0800
Fix persistent CI failures. (apple#1205)
## Type of Change
- [x] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
- CI build is failing because runners don't have an /etc/resolver
directory, causing the directory monitor to fail. This occurs while the
install-kernel make target is running, so it appears that kernel
download is failing when it's just that the API server is dying. Created
apple#1207 for the issue.
- Fixing the initial scan for the directory just moves the problem to
the filesystem watch loop, likely because we're not testing the result
of `open()` for errors.
- Right now the priority is getting CI running and PRs merged, so just
commenting out the realhost DNS server setup.
- Also seeing that under some conditions it can take quite a while for
launchd to start the helper for the default network (8 seconds or more).
With the 10 second health check timeout after API server registration,
this means that some CI runs can exhibit this failure mode. Added a
`--timeout` option to SystemStart and set a 60 second timeout for
install-kernel and integration Makefile targets.
- Fixed a bug where `--debug` was being placed in the wrong location in
the api server startup args.
- Disabled all network CLI tests due to container bootstrap errors when
trying to run the container immediately after creating the network. The
slow network helper launch could be the reason behind the failures that
drove us to serialize these tests. Filed apple#1206 for this issue.
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit f7d00aa
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 11 15:09:21 2026 -0800
APIServer: Add support for filtering to list rpc (apple#1175)
This is not intended to be used to support `--filter` or similar on the
CLIs list yet, it's solely to clean up our rather awkward use of
`ContainerClient.list()` today in the CLI. The list RPC simply returns
all of the containers we have created. Because of this, for a LOT of our
commands we filter to what we need client side, which feels like a
waste.. This change introduces a filter struct that we can provide an
array of container IDs, labels, and the status of the containers to
filter the `list()` output from.
This additionally, because it was killing (pun not intended) me and I
was already having to change this area for the `list()` additions,
changes container kill slightly to return an error if you try and kill a
container that doesn't exist.
commit c9f81ca
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Feb 11 04:26:33 2026 +0800
Feat: add container registry list (apple#1119)
- Requires apple/containerization#502
- Closesapple#1088
---------
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit cf9b335
Author: Manu Schiller <56154253+manuschillerdev@users.noreply.github.com>
Date: Tue Feb 10 03:11:27 2026 +0100
feat: add --init-image flag for specifying custom init filesystem images per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
commit 474906d
Author: Amir Alperin <me@remotecpp.dev>
Date: Fri Feb 6 23:38:19 2026 +0200
feat: Add runtime flag to container create and run commands (apple#1049) (apple#1109)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Fixesapple#1049
- Add --runtime option for Flags.Management
- Apply runtime handler in containerConfigFromFlags
- Update command-reference.md doc
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
Co-authored-by: J Logan <john_logan@apple.com>
commit 40de343
Author: Dmitry Kovba <dkovba@apple.com>
Date: Fri Feb 6 00:41:29 2026 -0800
Fix relative path mount tests (apple#1168)
`make test` occasionally fails with:
```
✘ Test testHostDNSReinitialize() recorded an issue at HostDNSResolverTest.swift:132:45: Expectation failed: (error →
Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory") as? (ContainerizationError → NSError)
✘ Suite HostDNSResolverTest failed after 0.119 seconds with 1 issue.
```
commit aa17d46
Author: Poetry Of Code <101225909+poetryofcode@users.noreply.github.com>
Date: Fri Feb 6 03:38:21 2026 -0500
Warn user when a named volume is auto-created (apple#1108)
- Implemented the TODO at
ContainerAPIService/Client/Utility.swift:358 — warn the
user when a named volume is auto-created.
- This only triggers for named volumes (not anonymous
ones), matching Docker's behavior of informing users
about implicit resource creation.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
commit adb3c44
Author: J Logan <john_logan@apple.com>
Date: Thu Feb 5 20:19:13 2026 -0800
Don't enable selinux LSM on boot. (apple#1166)
- Closesapple#1150.
- The problem seems to be that the selinux label attribute enforcement
doesn't play well with overlayfs.
- Solution is to set the `lsm` boot line argument. The new value
corresponds to what one would see in a Lima VM with Colima. The Kata
kernel we use doesn't provide any of those modules, so now if you run
`dmesg | grep -i lsm` in a container you will just see: `LSM:
initializing lsm=capability`
commit fdeb1b1
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 10:59:31 2026 -0800
Add builder tests (apple#1154)
- Adds test for apple#1094.
- Closesapple#933 (with apple/container-builder-shim#62).
- Closesapple#425 (with apple/container-builder-shim#63).
commit fabfc55
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 09:53:31 2026 -0800
Send tar hash in the first BuildTransfer packet (apple#1149)
Send the hash of entire tar file in the first BuildTransfer packet to
prevent container-builder-shim from using stale cached contents.
This PR resolvesapple#1143.
This PR relies on apple/container-builder-shim#64.
## Type of Change
- [X] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Current container-builder-shim uses only first few bytes of tar file as
checksum, which leads to the usage of stale cached contents if the
change of build context is not included in the first bytes of tar file.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit 6e9b8d7
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Feb 5 09:47:20 2026 -0800
CLI: Forego logging errors on multi-container operations (apple#1163)
Instead of logging errors, and then additionally throwing an error
stating what containers couldn't be stopped/killed/deleted, let's just
concatenate the errors and throw the single error.
commit d79bc0d
Author: Manoj Mahapatra <mahapatra.manoj@hotmail.com>
Date: Thu Feb 5 01:16:30 2026 -0800
chore: Replace force-unwrapped String(data:encoding:) with String(decoding:as:) (apple#1164)
Use the non-optional String(decoding:as:) initializer for converting
JSON-encoded Data to String. This is safe for UTF-8 and eliminates force
commit 21dabb7
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 03:13:36 2026 -0500
[build-command]: Add --pull option for fetching latest image (apple#844)
- Closesapple#733.
commit 6553f9c
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 01:16:08 2026 -0500
[deps]: bump containerization to 0.25.0 (apple#1161)
Co-authored-by: saehejkang <saehej.kang@gmail.com>
Co-authored-by: Anthony DePasquale <anthony@depasquale.org>
- Bump `containerization` to `0.25.0`
- Updates for parameter changes on containerization
registry access API.
- Updates for change to containerization
`cleanUpOrphanedBlobs` function.
commit 2d1dd6b
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 15:42:29 2026 -0800
Fix file path for the PR number in the PR labeler workflow (apple#1158)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR label applier GitHub workflow has been failing for a while. This
PR fixes that by correcting the file path we look for when trying to
read the PR number. See example failure here
https://github.com/apple/container/actions/runs/21691766538/job/62552959972#step:4:23
commit 6451e07
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 14:44:53 2026 -0800
Add debugging to the PR labeler CI flow (apple#1155)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR labeler workflow has been failing for a while but it's difficult
to know how to fix it since the PR labeler workflow is run from main
(aka NOT the current PR branch) for security reasons. Example at
https://github.com/apple/container/actions/runs/21690229300/workflow
commit 8fdfa29
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:52:09 2026 -0800
CLI: Rework ClientContainer (apple#1139)
ClientContainer was honestly extremely awkward. It could only be created
by passing either a ContainerConfiguration, or a Snapshot that had to be
obtained from calling a static method on the type itself. The type also
did not store a connection, so every single method got a new xpc
connection to the APIServer. This change aims to rework this type to be
just a generic client, that is *not* a client for one specific
container, but for any.
- Rename to ContainerClient
- Have list() return [ContainerSnapshot]
- Create a connection in the constructor
- Change all the callsites to use the new API
- Small, somewhat related, change to logs API in the APIServer. Now that
we don't need to call get() to grab a client anymore which was typically
what did "does this container exist" logic and gave a nice error
message, I added a small check in the APIServer to see if the container
exists and return mostly the same error message.
commit 23c0ece
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:19:50 2026 -0800
CI: Add signed commit check (apple#1152)
This requirement of ours often goes unnoticed because nothing yells at
you openly about it. Lets fail CI to make it more obvious.
commit ce1b629
Author: Manoj Mahapatra <mahaplipsa@gmail.com>
Date: Tue Feb 3 13:43:07 2026 -0800
[Docs] Fix typo in BUILDING.md: launchd -> launchctl (apple#1146)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [x] Documentation update
## Motivation and Context
The debug instructions in `BUILDING.md` incorrectly reference launchd
list instead of `launchctl` list. `launchd` is the daemon itself and
cannot be invoked directly.
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [x] Added/updated docs
commit 3e49dce
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 3 00:45:01 2026 -0800
Add in missing rlimits (apple#1140)
Containerization didn't have these defined until a recent tag.
commit c4c2e85
Author: J Logan <john_logan@apple.com>
Date: Tue Feb 3 00:27:09 2026 -0800
Upgrade kernel to Kata 3.26.0. (apple#1134)
- Upgrade to containerization 0.24.5 to pick up zstd decompression
enhancement.
- Closesapple#767.
- Closesapple#988.
- Closesapple#1132.
- Requires apple/containerization#508.
commit 5c86337
Author: William Laverty <developer@william-laverty.com>
Date: Mon Feb 2 13:57:59 2026 -0800
Add explanatory message before admin password prompt in uninstall script (apple#1118)
- Added message: "This script requires an administrator password to
remove the application files from system directories."
- Fixesapple#1111
commit 7da25e1
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:35:02 2026 -0800
Deps: Bump Containerization to 0.24.0 (apple#1127)
Brings in some rlimit bumps/adjustments
commit 7dfe27d
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:30:19 2026 -0800
CLI: Add support for rlimits (apple#1129)
Closesapple#1097.
commit b3b5c3e
Author: J Logan <john_logan@apple.com>
Date: Mon Feb 2 12:24:27 2026 -0800
Use labels instead of id to discriminate the builtin network. (apple#1123)
- Closesapple#1122.
- Adds placeholder ManagedResource and unit tests. Nothing is using
these yet.
- Adds system-defined resource labels for owning plugin and resource
role. The system discriminates the builtin network using role "builtin".
- Adds builtin role when creating builtin network at startup, and
ensures that a preexisting network with ID "default" gets updated with
the role label.
- Replace all network ID checks for "default" with the builtin role
check.
- Adds "builder" role to builder VM.
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Role and owner labels should make cross-cutting resource policy easier
to implement.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 1dae1cd
Author: w-ferg <43309695+w-ferg@users.noreply.github.com>
Date: Sun Feb 1 18:14:41 2026 -0500
Fix pfctl executable path in PacketFilter DNS reload (apple#1128)
## Summary
The `reload()` method in `PacketFilter.swift` references
`/sbin/reloadProcess` (the local variable name) instead of
`/sbin/pfctl`. This causes all DNS create and delete operations to fail:
```
Error: internalError: "pfctl reload exec failed: "Error Domain=NSCocoaErrorDomain Code=4 "The file "reloadProcess" doesn't exist.""
```
## Fix
One-line change: `/sbin/reloadProcess` → `/sbin/pfctl`
## Testing
Verified on macOS 26 (Tahoe) with Apple Silicon:
- `sudo container system dns create test.sdc.internal --localhost
203.0.113.1` succeeds without error
- Container can resolve and reach host services through the DNS redirect
commit 113a6ec
Author: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Date: Fri Jan 30 21:54:57 2026 -0600
Fix file descriptor leak in DirectoryWatcher (apple#1104)
- `DirectoryWatcher` opens file descriptors for monitoring
directories but never closes them, causing a file descriptor
leak.
- Adds `setCancelHandler` to properly close file descriptors
when the `DispatchSource` is cancelled.
Signed-off-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
commit 72f04b6
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Fri Jan 30 19:10:03 2026 -0800
[docs]: update steps on building with containerization project (apple#1116)
- Closesapple#1095
- Just added a few more details about how to build with the local
`containerization` dependency.
commit 3a0ad58
Author: Raj <rajaryan_singh@apple.com>
Date: Fri Jan 30 16:17:43 2026 -0800
Add resource.role label to builder container (apple#1120)
Add resource.role label to builder container
commit 1c01d0c
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 30 11:07:49 2026 -0800
Update to kata 3.20.0 kernel. (apple#1114)
- Closesapple#1113.
- This is the newest we can do until we address apple#767.
- Slight change to PacketFilter error handling so unit tests work more
reliably.
- Try making CLINetworkTests serialized to see if parallel execution is
causing flakes.
commit 3f2060e
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 18:25:48 2026 -0800
DirectoryWatcher: Small adjustments (apple#1112)
- Have the handler throw
- Log the failure at error level
commit 0a7fb07
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 14:21:12 2026 -0800
Set mtu to old Containerization default (apple#1110)
The old mtu default in containerization was 1280 to account for some
alpine/musl images that have issues with
1500. This changed in the last couple tags to be modifiable, but the new
default is the standard 1500. Ideally we eventually allow supplying the
mtu to be used when you create a network (or possibly a container
creation setting), but for now just default in here back to what CZ used
to use.
commit 0bceb23
Author: Aditya Ramani <a_ramani@apple.com>
Date: Thu Jan 29 12:08:42 2026 +0900
Bump to use containerization 0.23.2 (apple#1106)
Updating the package dependency on apple/containerization to pick up bug fixes
Signed-off-by: Aditya Ramani <a_ramani@apple.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit d762fe5
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 18:22:33 2026 -0800
Launch a service with waitForDebugger if specified (apple#1101)
This PR enables launching a service with `waitForDebugger` flag if the
service label matches a given env variable `CONTAINER_DEBUG`.
commit 4f93e3e
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed Jan 28 18:21:08 2026 -0800
ci: bump actions/checkout from 6.0.1 to 6.0.2 in the github-actions group (apple#1100)
- Updates `actions/checkout` from 6.0.1 to 6.0.2
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
commit 371db6d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 17:17:08 2026 -0800
Fix testExecOnExitingContainer (apple#1107)
Check the container remains only, not its status as the status might not
have been updated at the time checking.
commit d872270
Author: J Logan <john_logan@apple.com>
Date: Wed Jan 28 09:04:58 2026 -0800
Removes ArgumentParser import from NetworkMode. (apple#1102)
- ContainerResources shouldn't need to know anything about CLI stuff.
- Move ExpressibleByArgument protocol conformance to an extension in the
package where it's needed.
commit 3abf81f
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Tue Jan 27 20:00:43 2026 -0800
[image-list]: Add full size field to json output (apple#1098)
- Refer to apple#862
- Updated `SIZE` field to `FULL SIZE`, as it seemed more appropriate so
it does not get mixed up with the `descriptor size` field
- Closesapple#860
commit 24cbed5
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Jan 28 06:55:49 2026 +0800
Implement container prune (apple#904)
- Fixedapple#892.
- By contrast with `rm`, `prune` should display
the amount of reclaimed storage, so added code
to retrieve it.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit a57527e
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Tue Jan 27 11:15:22 2026 -0800
Refactor container lifecycle functions to perform scoped rollback on failure (apple#1080)
- Closesapple#977.
- Closesapple#1058.
- Prevents unexpected removal of containers on
bootstrapping and starting failures, by reorganizing
error handling for container `run`, `start`, and
`exec` so that error handling only unwinds that
which was done in the current scope.
- Relies on apple/containerization#495.
commit 6244129
Author: c <claudeaceae@icloud.com>
Date: Mon Jan 26 23:30:45 2026 -0500
Fix grammar in BUILDING.md (apple#984)
- Fixes a grammar error in the local Containerization development
instructions.
commit 9d4cded
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Mon Jan 26 19:35:41 2026 -0800
Isolated network (apple#1079)
- Closesapple#1037.
- Adds a `--mode` flag that has `nat` and `hostOnly` options.
The host-only option selects the vmnet host-only mode,
where containers attached to the network can reach each
other and the host, but not external systems.
commit 033c999
Author: J Logan <john_logan@apple.com>
Date: Mon Jan 26 14:07:00 2026 -0800
Make TerminalProgress a library. (apple#1093)
- Closesapple#1092.
- Allows 3rd party CLI plugins to use the progress indicator.
commit b371aee
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Tue Jan 27 05:07:05 2026 +0800
Feat: container image delete force option (apple#1096)
- Fixedapple#1087
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit ed1185d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Fri Jan 23 17:59:28 2026 -0800
Container-to-host networking. (apple#1078)
- Closesapple#346.
- This PR enables connecting host's localhost ports from
containers.
- It adds an option `--localhost <localhost>` to DNS
create command, after which the packets heading
ip address in container are redirected to localhost in
host machine. Packet filter rule is added and deleted
along with the creation and deletion of localhost domain.
commit 14c279f
Author: Patrick Linnane <patrick@linnane.io>
Date: Fri Jan 23 17:56:35 2026 -0800
Add option to stop services in all launchd domains (apple#1077)
- Services started from Terminal run in the `gui/$uid`
launchd domain. When `ensure-container-stopped.sh`
runs from a different context, `launchctl managername`
may return a different domain, causing the script to
check the wrong domain and miss running services.
I noticed this after upgrading `container` via Homebrew.
- Introduces a getopt option `-a` that allows booting out all
domains explicitly. Also adds `-h` for a usage message.
Signed-off-by: Patrick Linnane <patrick@linnane.io>
commit 751c1fc
Author: Stanislav Antonichev <cympak2@users.noreply.github.com>
Date: Fri Jan 23 23:01:26 2026 +0200
Add --dns support to build command for custom DNS resolution (apple#1067)
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
Changes:
- Added --dns option to BuildCommand to accept DNS nameserver IP
addresses
- Modified build logic to detect DNS configuration changes and recreate
the builder container when DNS settings differ
- Passed DNS configuration to BuilderStart.start() method
- Updated builder container creation to use specified DNS nameservers or
fall back to network gateway
## Type of Change
- [ ] Bug fix
- [X] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: J Logan <sgtbakerrahulnet@yahoo.com>
commit 55f2112
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 23 11:35:10 2026 -0800
Place image store data correctly for app-root path. (apple#1085)
- Closesapple#1084.
commit 5746ec3
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Sat Jan 24 03:32:59 2026 +0800
Fix: prevent delete default network (apple#1083)
- Fixedapple#1073
- Move the conditional check to the front; there's no need
to check for a default network after filtering.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@manuschillerdev@jglogan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add --init-image flag for specifying custom init filesystem images per VM - #937

Merged
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image
Feb 10, 2026
Merged

feat: add --init-image flag for specifying custom init filesystem images per VM#937
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image

Conversation

@manuschillerdev

@manuschillerdevmanuschillerdev commented Dec 7, 2025

Copy link
Copy Markdown
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

I've been tinkering with ways to extend container with a primitive for interacting with the VM layer. One approach: expose the internal init filesystem as a user-configurable option via --init-image.

What this enables:

  • Custom boot-time logic before the OCI container starts
  • Running additional processes and daemons (e.g., daemons to configure eBPF network filters, logging agents) inside the VM (not the container)
  • Debugging/instrumenting the init process

--init-image vs using the system property
we could also use container system property set image.init vminit:latest (documented via #1032), but this affects all VMs. I want to be able to override this only for a single VM.

In my current approach, the custom image wraps the default vminitd, so it's currently behaving like an entrypoint.
Curious if this direction aligns with the project's goals, or if there's a better abstraction for these use cases.
If there is interest, I would add proper docs and tests.

Example for a minimal entry point binary
Note: We use Go here for its straightforward cross-compilation to Linux ARM64.

// custom-init/wrapper.gopackage main
import (
"fmt""os""syscall"
)
funcmain() {
kmsg, err:=os.OpenFile("/dev/kmsg", os.O_WRONLY, 0)
iferr==nil {
kmsg.WriteString("<6>custom-init: === CUSTOM INIT IMAGE RUNNING ===\n")
kmsg.Close()
}
err=syscall.Exec("/sbin/vminitd.real", os.Args, os.Environ())
iferr!=nil {
fmt.Fprintf(os.Stderr, "Failed to exec vminitd.real: %v\n", err)
os.Exit(1)
}
}

Containerfile

# custom-init/Containerfile
FROM ghcr.io/apple/containerization/vminit:0.23.2 AS base
FROM ghcr.io/apple/containerization/vminit:0.23.2
COPY --from=base /sbin/vminitd /sbin/vminitd.real
COPY wrapper /sbin/vminitd
  • build the binary with cd custom-init && CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o wrapper wrapper.go
  • build the image with bin/container build -t local/custom-init:0.20.0 custom-init/
  • run the container with our custom init-image: bin/container run --name init-test --init-image local/custom-init:0.20.0 alpine:latest echo "hello"
  • check the logs with cat "/Users/$USER/Library/Application Support/com.apple.container/containers/init-test/vminitd.log" | head -50

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

@manuschillerdevmanuschillerdev changed the title feat: add init-image flag for specifying custom init filesystem images per VMfeat: add --init-image flag for specifying custom init filesystem images per VMDec 7, 2025
@jglogan

Copy link
Copy Markdown
Contributor

@dcantah see also #838

Comment threadSources/ContainerClient/Utility.swift
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@dcantah@jglogan would that be of interest for the project? Would be totally open to other suggestions on how one can interact with the startup process. Exposing --init-fs seemed like a viable option here

@manuschillerdev

manuschillerdev commented Jan 10, 2026

Copy link
Copy Markdown
ContributorAuthor

@jglogan@dcantah

I've rebased the PR, added tests and documentation, and updated the description to clarify why container system property set image.init doesn't fit my use case (it applies globally rather than per-VM).

Happy to elaborate on any open questions or explore alternative approaches that would better align with the project's architecture.
I'd appreciate any feedback on whether this direction makes sense to pursue or if there are concerns that would make it worth closing in favor of a different approach.

@jglogan

jglogan commented Jan 17, 2026

Copy link
Copy Markdown
Contributor

@manuschillerdev I haven't been able to review but it seems reasonable. Kernel and initfs config are birds of a feather, whatever config options exist for one, we should eventually provide for the other.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Could you run make fmt on this, and make sure build/test runs okay on your end, and then try pushing the changes? I made one change to resolve some merge conflicts on the Makefile

@jglogan

Copy link
Copy Markdown
Contributor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 5badfb6 to 6e1d1faCompareFebruary 1, 2026 10:15
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

thanks for having another look at this! I rebased the PR against main, resolved the conflicts, ran make fmt, and did a complete re-test locally with the steps from the PR description:

❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"| grep "==="
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
full output of vminitd.log after creating a custom init image, and starting a fresh container using the `--init-image` flag:
❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"
[ 0.069458] random: crng init done
[ 0.070722] brd: module loaded
[ 0.071338] loop: module loaded
[ 0.071436] virtio_blk virtio2: 1/0/0 default/read/poll queues
[ 0.071600] virtio_blk virtio2: [vda] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.071875] virtio_blk virtio3: 1/0/0 default/read/poll queues
[ 0.072020] virtio_blk virtio3: [vdb] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.072226] tun: Universal TUN/TAP device driver, 1.6
[ 0.072687] VFIO - User Level meta-driver version: 0.3
[ 0.072820] rtc-pl031 20050000.pl031: registered as rtc0
[ 0.072857] rtc-pl031 20050000.pl031: setting system clock to 2026-02-01T08:49:54 UTC (1769935794)
[ 0.073306] xt_time: kernel timezone is -0000
[ 0.073348] IPVS: Registered protocols (TCP, UDP, SCTP, AH, ESP)
[ 0.073434] IPVS: Connection hash table configured (size=4096, memory=32Kbytes)
[ 0.073579] IPVS: ipvs loaded.
[ 0.073615] IPVS: [rr] scheduler registered.
[ 0.073634] IPVS: [wrr] scheduler registered.
[ 0.073685] IPVS: [lc] scheduler registered.
[ 0.073718] IPVS: [wlc] scheduler registered.
[ 0.073767] IPVS: [fo] scheduler registered.
[ 0.073813] IPVS: [ovf] scheduler registered.
[ 0.073862] IPVS: [lblc] scheduler registered.
[ 0.073924] IPVS: [lblcr] scheduler registered.
[ 0.073942] IPVS: [dh] scheduler registered.
[ 0.073966] IPVS: [sh] scheduler registered.
[ 0.073991] IPVS: [sed] scheduler registered.
[ 0.074016] IPVS: [nq] scheduler registered.
[ 0.074043] IPVS: [sip] pe registered.
[ 0.074088] Initializing XFRM netlink socket
[ 0.074130] NET: Registered PF_INET6 protocol family
[ 0.074389] Segment Routing with IPv6
[ 0.074421] In-situ OAM (IOAM) with IPv6
[ 0.074462] NET: Registered PF_PACKET protocol family
[ 0.074505] 9pnet: Installing 9P2000 support
[ 0.074573] NET: Registered PF_VSOCK protocol family
[ 0.075578] registered taskstats version 1
[ 0.076957] alg: No testfor fips(ansi_cprng) (fips_ansi_cprng)
[ 0.077498] clk: Disabling unused clocks
[ 0.080034] EXT4-fs (vda): mounted filesystem 63cb0698-b5fe-4f00-ba03-179297b9693a ro without journal. Quota mode: disabled.
[ 0.080117] VFS: Mounted root (ext4 filesystem) readonly on device 254:0.
[ 0.080441] devtmpfs: mounted
[ 0.080801] Freeing unused kernel memory: 1856K
[ 0.080895] Run /sbin/vminitd as init process
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
2026-02-01T08:49:54+0000 info vminitd : [vminitd] Running init command
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /proc
2026-02-01T08:49:54+0000 info vminitd : [vminitd] vminitd booting
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /run
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys/fs/cgroup
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 debug vminitd : bytes=78643200 path=/sys/fs/cgroup/vminitd [Cgroup] setting memory.high
2026-02-01T08:49:54+0000 debug vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] adding new proc to cgroup
2026-02-01T08:49:54+0000 info vminitd : events_path=/sys/fs/cgroup/vminitd/memory.events threshold_bytes=78643200 [vminitd] Started memory monitoring
2026-02-01T08:49:54+0000 info vminitd : [vminitd] serving vminitd API
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] starting process supervisor
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] booting gRPC server on vsock
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] gRPC API serving on vsock
2026-02-01T08:49:54+0000 debug vminitd : interface=lo up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : key=PATH value=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [vminitd] setenv
2026-02-01T08:49:54+0000 debug vminitd : destination=/tmp source=tmpfs type=tmpfs [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/dev/pts source=devpts type=devpts [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/run/container/init-test/rootfs source=/dev/vdb type=ext4 [vminitd] mount
[ 0.268991] EXT4-fs (vdb): mounted filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab r/w without journal. Quota mode: disabled.
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Address=192.168.64.3/24 [vminitd] ipAddrAdd
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Gateway=192.168.64.1 [vminitd] ipRouteAddDefault
2026-02-01T08:49:54+0000 debug vminitd : domain= location=/run/container/init-test/rootfs nameservers=["192.168.64.1"] options=[] searchDomains=[] [vminitd] configureDns
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] writing to path /run/container/init-test/rootfs/etc/resolv.conf nameserver 192.168.64.1
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/resolv.conf [vminitd] wrote resolver configuration
2026-02-01T08:49:54+0000 debug vminitd : location=/run/container/init-test/rootfs [vminitd] configureHosts
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/hosts [vminitd] wrote /etc/hosts configuration
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test stderr=Port: 268435457 stdin=Port: 0 stdout=Port: 268435456 [vminitd] createProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] created bundle with spec Spec(version: "", hooks: nil, process: Optional(ContainerizationOCI.Process(cwd: "/", env: ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME=/root"], consoleSize: nil, selinuxLabel: "", noNewPrivileges: false, commandLine: "", oomScoreAdj: nil, capabilities: Optional(ContainerizationOCI.LinuxCapabilities(bounding: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), effective: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), inheritable: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), permitted: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), ambient: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]))), apparmorProfile: "", user: ContainerizationOCI.User(uid: 0, gid: 0, umask: nil, additionalGids: [0], username: ""), rlimits: [], args: ["echo", "hello"], terminal: false)), hostname: "init-test", domainname: "", mounts: [ContainerizationOCI.Mount(type: "proc", source: "proc", destination: "/proc", options: [], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "sysfs", source: "sysfs", destination: "/sys", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devtmpfs", source: "none", destination: "/dev", options: ["nosuid", "mode=755"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "mqueue", source: "mqueue", destination: "/dev/mqueue", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "tmpfs", source: "tmpfs", destination: "/dev/shm", options: ["nosuid", "noexec", "nodev", "mode=1777", "size=65536k"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "cgroup2", source: "none", destination: "/sys/fs/cgroup", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devpts", source: "devpts", destination: "/dev/pts", options: ["nosuid", "noexec", "newinstance", "gid=5", "mode=0620", "ptmxmode=0666"], uidMappings: nil, gidMappings: nil)], annotations: nil, root: Optional(ContainerizationOCI.Root(path: "/run/container/init-test/rootfs", readonly: false)), linux: Optional(ContainerizationOCI.Linux(uidMappings: [], gidMappings: [], sysctl: Optional([:]), resources: Optional(ContainerizationOCI.LinuxResources(devices: [], memory: Optional(ContainerizationOCI.LinuxMemory(limit: Optional(1073741824), reservation: nil, swap: nil, kernel: nil, kernelTCP: nil, swappiness: nil, disableOOMKiller: nil, useHierarchy: nil, checkBeforeUpdate: nil)), cpu: Optional(ContainerizationOCI.LinuxCPU(shares: nil, quota: Optional(400000), burst: nil, period: Optional(100000), realtimeRuntime: nil, realtimePeriod: nil, cpus: "", mems: "", idle: nil)), pids: nil, blockIO: nil, hugepageLimits: [], network: nil, rdma: nil, unified: Optional([:]))), cgroupsPath: "/container/init-test", namespaces: [ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.cgroup, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.ipc, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.mount, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.pid, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.uts, path: "")], devices: [], seccomp: nil, rootfsPropagation: "", maskedPaths: [], readonlyPaths: [], mountLabel: "", personality: nil)))
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting I/O
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stderr
2026-02-01T08:49:54+0000 info vminitd : [vminitd] created vmexec init process
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] startProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] in supervisor lock to start process
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting managed process
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78381056 high_events_total=1 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78442496 high_events_total=15 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78331904 high_events_total=18 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] got back pid data
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] sending pid acknowledgement
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[93: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] started managed process
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[94: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 debug vminitd : count=0 pid=94 status=0 [vminitd] managed process exited
2026-02-01T08:49:54+0000 info vminitd : id=init-test status=0 [vminitd] managed process exit
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stderr
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] 0 managed process waiters signaled
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : pid=-1 signal=9 [vminitd] kill
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : flags=0 path=/run/container/init-test/rootfs [vminitd] umount
[ 0.541866] EXT4-fs (vdb): unmounting filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab.
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] sync
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] deleteProcess
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] deleting cgroup manager

I also re-ran the tests:

❯ swift test --filter TestCLIRunInitImage 2>&1
Building for debugging...
[7/7] Write swift-version-1C31CF501CE571A8.txt
Build complete! (0.77s)
Test Suite 'Selected tests' started at 2026-02-01 11:10:47.076.
Test Suite 'containerPackageTests.xctest' started at 2026-02-01 11:10:47.077.
Test Suite 'containerPackageTests.xctest' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.1 (c9d57c83568b06d)
↳ Target Platform: arm64-apple-macosx
◇ Suite TestCLIRunInitImage started.
◇ Test testCreateWithNonExistentInitImage() started.
◇ Test testRunWithExplicitDefaultInitImage() started.
◇ Test testInitImageFlagInHelp() started.
◇ Test testRunWithNonExistentInitImage() started.
✔ Test testInitImageFlagInHelp() passed after 0.178 seconds.
✔ Test testRunWithNonExistentInitImage() passed after 10.584 seconds.
✔ Test testCreateWithNonExistentInitImage() passed after 20.668 seconds.
✔ Test testRunWithExplicitDefaultInitImage() passed after 25.314 seconds.
✔ Suite TestCLIRunInitImage passed after 25.314 seconds.
✔ Test run with 4 tests in 1 suite passed after 25.314 seconds.

@jglogan let me know if that works for you, or if I should rather still open a fresh PR. Don't worry, I'd aim for the cleanest solution for the maintainers and the repo. Re-organizing the PR is no effort at all. Thanks for your time again!

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev In CI I'm seeing this failure:

✔ Test testCreateWithNonExistentInitImage() passed after 43.897 seconds.
✘ Test testRunWithExplicitDefaultInitImage() recorded an issue at TestCLIRunInitImage.swift:93:6: Caught error: executionFailed("command failed: Warning! Running debug build. Performance may be degraded.\nError: internalError: \"failed to create container\" (cause: \"internalError: \"XPC timeout for request to com.apple.container.apiserver/containerCreate\"\")\n")
✘ Test testRunWithExplicitDefaultInitImage() failed after 87.555 seconds with 1 issue.
↳ /// Test that explicitly specifying the default init image works the same as
↳ /// not specifying any init image.
✔ Test testRunWithNonExistentInitImage() passed after 87.606 seconds.
✘ Suite TestCLIRunInitImage failed after 87.606 seconds with 1 issue.
✘ Test run with 4 tests in 1 suite failed after 87.606 seconds with 1 issue.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 7d9a37a to baae7c7CompareFebruary 3, 2026 22:05
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks! the tests did catch an error in the image selection logic - glad they did.
I pushed a separate fix, an re-ran make integrate locally without errors.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev OK, the updated tests worked fine. One last thing (thanks for your patience!)

ContainerClient got a big refactor your changes need to be updated to work with those.

@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan no worries. I rebased against main and verified that the changes still work.
make integration runs without errors, loading a custom init-image works and starting containers without a custom init image provided works as well

@jglogan
jglogan merged commit cf9b335 into apple:mainFeb 10, 2026
3 checks passed
@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Finally got it in there...thanks for the contribution!

simone-panico pushed a commit to simone-panico/container that referenced this pull request Feb 10, 2026
…ges per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks again for guiding me!

Mcrich23 added a commit to Mcrich23/container that referenced this pull request Feb 18, 2026
commit c791052
Author: Aditya Ramani <a_ramani@apple.com>
Date: Wed Feb 18 07:43:56 2026 +0530
Add init methods for all the members of the Flags type (apple#1203)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Authors of CLI plugins for container will be able to reuse the container
flags defined in the CLI package, instead of having to duplicate them in
their project
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit dfac83d
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 17 16:54:44 2026 -0800
ContainerService: Add minimum memory amount validation (apple#1208)
Closesapple#1202
Today it's possible to pass a memory amount that very easily will cause
the container's VM to not be able to boot. We should protect against
this to avoid weird hangs/error messages. I could be convinced that a
limit should be in Containerization as well, but I think having one in
the daemon is a decent idea regardless.
commit 5385a5c
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Tue Feb 17 15:08:32 2026 -0800
Support using multiple different network plugins (apple#1151)
## Type of Change
- [x] New feature
- [x] Breaking change
## Motivation and Context
We want to be able to support using multiple network plugins during
`container`'s lifetime. This additionally means needing to pick an
interface strategy to interpret a network attachment based on what
network plugin was used to create that attachment. This PR will
potentially replace apple#1081.
Followups:
- doc updates to include the ability to specify plugin in the network
creation cli
## Testing
- [x] Tested locally
- [x] Added/updated tests
commit 7476743
Author: AJ Emory <239216119+ajemory@users.noreply.github.com>
Date: Fri Feb 13 19:27:32 2026 -0800
feat: Moving bundle creation from ContainerService to SandboxService (apple#1076)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Closesapple#1046 -- Right now we're creating container bundles in
ContainersService. Move this to the SandboxService to make it easier to
support different container bundle types.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 4c800db
Author: J Logan <john_logan@apple.com>
Date: Fri Feb 13 10:51:27 2026 -0800
Fix persistent CI failures. (apple#1205)
## Type of Change
- [x] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
- CI build is failing because runners don't have an /etc/resolver
directory, causing the directory monitor to fail. This occurs while the
install-kernel make target is running, so it appears that kernel
download is failing when it's just that the API server is dying. Created
apple#1207 for the issue.
- Fixing the initial scan for the directory just moves the problem to
the filesystem watch loop, likely because we're not testing the result
of `open()` for errors.
- Right now the priority is getting CI running and PRs merged, so just
commenting out the realhost DNS server setup.
- Also seeing that under some conditions it can take quite a while for
launchd to start the helper for the default network (8 seconds or more).
With the 10 second health check timeout after API server registration,
this means that some CI runs can exhibit this failure mode. Added a
`--timeout` option to SystemStart and set a 60 second timeout for
install-kernel and integration Makefile targets.
- Fixed a bug where `--debug` was being placed in the wrong location in
the api server startup args.
- Disabled all network CLI tests due to container bootstrap errors when
trying to run the container immediately after creating the network. The
slow network helper launch could be the reason behind the failures that
drove us to serialize these tests. Filed apple#1206 for this issue.
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit f7d00aa
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 11 15:09:21 2026 -0800
APIServer: Add support for filtering to list rpc (apple#1175)
This is not intended to be used to support `--filter` or similar on the
CLIs list yet, it's solely to clean up our rather awkward use of
`ContainerClient.list()` today in the CLI. The list RPC simply returns
all of the containers we have created. Because of this, for a LOT of our
commands we filter to what we need client side, which feels like a
waste.. This change introduces a filter struct that we can provide an
array of container IDs, labels, and the status of the containers to
filter the `list()` output from.
This additionally, because it was killing (pun not intended) me and I
was already having to change this area for the `list()` additions,
changes container kill slightly to return an error if you try and kill a
container that doesn't exist.
commit c9f81ca
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Feb 11 04:26:33 2026 +0800
Feat: add container registry list (apple#1119)
- Requires apple/containerization#502
- Closesapple#1088
---------
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit cf9b335
Author: Manu Schiller <56154253+manuschillerdev@users.noreply.github.com>
Date: Tue Feb 10 03:11:27 2026 +0100
feat: add --init-image flag for specifying custom init filesystem images per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
commit 474906d
Author: Amir Alperin <me@remotecpp.dev>
Date: Fri Feb 6 23:38:19 2026 +0200
feat: Add runtime flag to container create and run commands (apple#1049) (apple#1109)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Fixesapple#1049
- Add --runtime option for Flags.Management
- Apply runtime handler in containerConfigFromFlags
- Update command-reference.md doc
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
Co-authored-by: J Logan <john_logan@apple.com>
commit 40de343
Author: Dmitry Kovba <dkovba@apple.com>
Date: Fri Feb 6 00:41:29 2026 -0800
Fix relative path mount tests (apple#1168)
`make test` occasionally fails with:
```
✘ Test testHostDNSReinitialize() recorded an issue at HostDNSResolverTest.swift:132:45: Expectation failed: (error →
Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory") as? (ContainerizationError → NSError)
✘ Suite HostDNSResolverTest failed after 0.119 seconds with 1 issue.
```
commit aa17d46
Author: Poetry Of Code <101225909+poetryofcode@users.noreply.github.com>
Date: Fri Feb 6 03:38:21 2026 -0500
Warn user when a named volume is auto-created (apple#1108)
- Implemented the TODO at
ContainerAPIService/Client/Utility.swift:358 — warn the
user when a named volume is auto-created.
- This only triggers for named volumes (not anonymous
ones), matching Docker's behavior of informing users
about implicit resource creation.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
commit adb3c44
Author: J Logan <john_logan@apple.com>
Date: Thu Feb 5 20:19:13 2026 -0800
Don't enable selinux LSM on boot. (apple#1166)
- Closesapple#1150.
- The problem seems to be that the selinux label attribute enforcement
doesn't play well with overlayfs.
- Solution is to set the `lsm` boot line argument. The new value
corresponds to what one would see in a Lima VM with Colima. The Kata
kernel we use doesn't provide any of those modules, so now if you run
`dmesg | grep -i lsm` in a container you will just see: `LSM:
initializing lsm=capability`
commit fdeb1b1
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 10:59:31 2026 -0800
Add builder tests (apple#1154)
- Adds test for apple#1094.
- Closesapple#933 (with apple/container-builder-shim#62).
- Closesapple#425 (with apple/container-builder-shim#63).
commit fabfc55
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 09:53:31 2026 -0800
Send tar hash in the first BuildTransfer packet (apple#1149)
Send the hash of entire tar file in the first BuildTransfer packet to
prevent container-builder-shim from using stale cached contents.
This PR resolvesapple#1143.
This PR relies on apple/container-builder-shim#64.
## Type of Change
- [X] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Current container-builder-shim uses only first few bytes of tar file as
checksum, which leads to the usage of stale cached contents if the
change of build context is not included in the first bytes of tar file.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit 6e9b8d7
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Feb 5 09:47:20 2026 -0800
CLI: Forego logging errors on multi-container operations (apple#1163)
Instead of logging errors, and then additionally throwing an error
stating what containers couldn't be stopped/killed/deleted, let's just
concatenate the errors and throw the single error.
commit d79bc0d
Author: Manoj Mahapatra <mahapatra.manoj@hotmail.com>
Date: Thu Feb 5 01:16:30 2026 -0800
chore: Replace force-unwrapped String(data:encoding:) with String(decoding:as:) (apple#1164)
Use the non-optional String(decoding:as:) initializer for converting
JSON-encoded Data to String. This is safe for UTF-8 and eliminates force
commit 21dabb7
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 03:13:36 2026 -0500
[build-command]: Add --pull option for fetching latest image (apple#844)
- Closesapple#733.
commit 6553f9c
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 01:16:08 2026 -0500
[deps]: bump containerization to 0.25.0 (apple#1161)
Co-authored-by: saehejkang <saehej.kang@gmail.com>
Co-authored-by: Anthony DePasquale <anthony@depasquale.org>
- Bump `containerization` to `0.25.0`
- Updates for parameter changes on containerization
registry access API.
- Updates for change to containerization
`cleanUpOrphanedBlobs` function.
commit 2d1dd6b
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 15:42:29 2026 -0800
Fix file path for the PR number in the PR labeler workflow (apple#1158)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR label applier GitHub workflow has been failing for a while. This
PR fixes that by correcting the file path we look for when trying to
read the PR number. See example failure here
https://github.com/apple/container/actions/runs/21691766538/job/62552959972#step:4:23
commit 6451e07
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 14:44:53 2026 -0800
Add debugging to the PR labeler CI flow (apple#1155)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR labeler workflow has been failing for a while but it's difficult
to know how to fix it since the PR labeler workflow is run from main
(aka NOT the current PR branch) for security reasons. Example at
https://github.com/apple/container/actions/runs/21690229300/workflow
commit 8fdfa29
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:52:09 2026 -0800
CLI: Rework ClientContainer (apple#1139)
ClientContainer was honestly extremely awkward. It could only be created
by passing either a ContainerConfiguration, or a Snapshot that had to be
obtained from calling a static method on the type itself. The type also
did not store a connection, so every single method got a new xpc
connection to the APIServer. This change aims to rework this type to be
just a generic client, that is *not* a client for one specific
container, but for any.
- Rename to ContainerClient
- Have list() return [ContainerSnapshot]
- Create a connection in the constructor
- Change all the callsites to use the new API
- Small, somewhat related, change to logs API in the APIServer. Now that
we don't need to call get() to grab a client anymore which was typically
what did "does this container exist" logic and gave a nice error
message, I added a small check in the APIServer to see if the container
exists and return mostly the same error message.
commit 23c0ece
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:19:50 2026 -0800
CI: Add signed commit check (apple#1152)
This requirement of ours often goes unnoticed because nothing yells at
you openly about it. Lets fail CI to make it more obvious.
commit ce1b629
Author: Manoj Mahapatra <mahaplipsa@gmail.com>
Date: Tue Feb 3 13:43:07 2026 -0800
[Docs] Fix typo in BUILDING.md: launchd -> launchctl (apple#1146)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [x] Documentation update
## Motivation and Context
The debug instructions in `BUILDING.md` incorrectly reference launchd
list instead of `launchctl` list. `launchd` is the daemon itself and
cannot be invoked directly.
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [x] Added/updated docs
commit 3e49dce
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 3 00:45:01 2026 -0800
Add in missing rlimits (apple#1140)
Containerization didn't have these defined until a recent tag.
commit c4c2e85
Author: J Logan <john_logan@apple.com>
Date: Tue Feb 3 00:27:09 2026 -0800
Upgrade kernel to Kata 3.26.0. (apple#1134)
- Upgrade to containerization 0.24.5 to pick up zstd decompression
enhancement.
- Closesapple#767.
- Closesapple#988.
- Closesapple#1132.
- Requires apple/containerization#508.
commit 5c86337
Author: William Laverty <developer@william-laverty.com>
Date: Mon Feb 2 13:57:59 2026 -0800
Add explanatory message before admin password prompt in uninstall script (apple#1118)
- Added message: "This script requires an administrator password to
remove the application files from system directories."
- Fixesapple#1111
commit 7da25e1
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:35:02 2026 -0800
Deps: Bump Containerization to 0.24.0 (apple#1127)
Brings in some rlimit bumps/adjustments
commit 7dfe27d
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:30:19 2026 -0800
CLI: Add support for rlimits (apple#1129)
Closesapple#1097.
commit b3b5c3e
Author: J Logan <john_logan@apple.com>
Date: Mon Feb 2 12:24:27 2026 -0800
Use labels instead of id to discriminate the builtin network. (apple#1123)
- Closesapple#1122.
- Adds placeholder ManagedResource and unit tests. Nothing is using
these yet.
- Adds system-defined resource labels for owning plugin and resource
role. The system discriminates the builtin network using role "builtin".
- Adds builtin role when creating builtin network at startup, and
ensures that a preexisting network with ID "default" gets updated with
the role label.
- Replace all network ID checks for "default" with the builtin role
check.
- Adds "builder" role to builder VM.
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Role and owner labels should make cross-cutting resource policy easier
to implement.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 1dae1cd
Author: w-ferg <43309695+w-ferg@users.noreply.github.com>
Date: Sun Feb 1 18:14:41 2026 -0500
Fix pfctl executable path in PacketFilter DNS reload (apple#1128)
## Summary
The `reload()` method in `PacketFilter.swift` references
`/sbin/reloadProcess` (the local variable name) instead of
`/sbin/pfctl`. This causes all DNS create and delete operations to fail:
```
Error: internalError: "pfctl reload exec failed: "Error Domain=NSCocoaErrorDomain Code=4 "The file "reloadProcess" doesn't exist.""
```
## Fix
One-line change: `/sbin/reloadProcess` → `/sbin/pfctl`
## Testing
Verified on macOS 26 (Tahoe) with Apple Silicon:
- `sudo container system dns create test.sdc.internal --localhost
203.0.113.1` succeeds without error
- Container can resolve and reach host services through the DNS redirect
commit 113a6ec
Author: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Date: Fri Jan 30 21:54:57 2026 -0600
Fix file descriptor leak in DirectoryWatcher (apple#1104)
- `DirectoryWatcher` opens file descriptors for monitoring
directories but never closes them, causing a file descriptor
leak.
- Adds `setCancelHandler` to properly close file descriptors
when the `DispatchSource` is cancelled.
Signed-off-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
commit 72f04b6
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Fri Jan 30 19:10:03 2026 -0800
[docs]: update steps on building with containerization project (apple#1116)
- Closesapple#1095
- Just added a few more details about how to build with the local
`containerization` dependency.
commit 3a0ad58
Author: Raj <rajaryan_singh@apple.com>
Date: Fri Jan 30 16:17:43 2026 -0800
Add resource.role label to builder container (apple#1120)
Add resource.role label to builder container
commit 1c01d0c
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 30 11:07:49 2026 -0800
Update to kata 3.20.0 kernel. (apple#1114)
- Closesapple#1113.
- This is the newest we can do until we address apple#767.
- Slight change to PacketFilter error handling so unit tests work more
reliably.
- Try making CLINetworkTests serialized to see if parallel execution is
causing flakes.
commit 3f2060e
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 18:25:48 2026 -0800
DirectoryWatcher: Small adjustments (apple#1112)
- Have the handler throw
- Log the failure at error level
commit 0a7fb07
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 14:21:12 2026 -0800
Set mtu to old Containerization default (apple#1110)
The old mtu default in containerization was 1280 to account for some
alpine/musl images that have issues with
1500. This changed in the last couple tags to be modifiable, but the new
default is the standard 1500. Ideally we eventually allow supplying the
mtu to be used when you create a network (or possibly a container
creation setting), but for now just default in here back to what CZ used
to use.
commit 0bceb23
Author: Aditya Ramani <a_ramani@apple.com>
Date: Thu Jan 29 12:08:42 2026 +0900
Bump to use containerization 0.23.2 (apple#1106)
Updating the package dependency on apple/containerization to pick up bug fixes
Signed-off-by: Aditya Ramani <a_ramani@apple.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit d762fe5
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 18:22:33 2026 -0800
Launch a service with waitForDebugger if specified (apple#1101)
This PR enables launching a service with `waitForDebugger` flag if the
service label matches a given env variable `CONTAINER_DEBUG`.
commit 4f93e3e
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed Jan 28 18:21:08 2026 -0800
ci: bump actions/checkout from 6.0.1 to 6.0.2 in the github-actions group (apple#1100)
- Updates `actions/checkout` from 6.0.1 to 6.0.2
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
commit 371db6d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 17:17:08 2026 -0800
Fix testExecOnExitingContainer (apple#1107)
Check the container remains only, not its status as the status might not
have been updated at the time checking.
commit d872270
Author: J Logan <john_logan@apple.com>
Date: Wed Jan 28 09:04:58 2026 -0800
Removes ArgumentParser import from NetworkMode. (apple#1102)
- ContainerResources shouldn't need to know anything about CLI stuff.
- Move ExpressibleByArgument protocol conformance to an extension in the
package where it's needed.
commit 3abf81f
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Tue Jan 27 20:00:43 2026 -0800
[image-list]: Add full size field to json output (apple#1098)
- Refer to apple#862
- Updated `SIZE` field to `FULL SIZE`, as it seemed more appropriate so
it does not get mixed up with the `descriptor size` field
- Closesapple#860
commit 24cbed5
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Jan 28 06:55:49 2026 +0800
Implement container prune (apple#904)
- Fixedapple#892.
- By contrast with `rm`, `prune` should display
the amount of reclaimed storage, so added code
to retrieve it.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit a57527e
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Tue Jan 27 11:15:22 2026 -0800
Refactor container lifecycle functions to perform scoped rollback on failure (apple#1080)
- Closesapple#977.
- Closesapple#1058.
- Prevents unexpected removal of containers on
bootstrapping and starting failures, by reorganizing
error handling for container `run`, `start`, and
`exec` so that error handling only unwinds that
which was done in the current scope.
- Relies on apple/containerization#495.
commit 6244129
Author: c <claudeaceae@icloud.com>
Date: Mon Jan 26 23:30:45 2026 -0500
Fix grammar in BUILDING.md (apple#984)
- Fixes a grammar error in the local Containerization development
instructions.
commit 9d4cded
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Mon Jan 26 19:35:41 2026 -0800
Isolated network (apple#1079)
- Closesapple#1037.
- Adds a `--mode` flag that has `nat` and `hostOnly` options.
The host-only option selects the vmnet host-only mode,
where containers attached to the network can reach each
other and the host, but not external systems.
commit 033c999
Author: J Logan <john_logan@apple.com>
Date: Mon Jan 26 14:07:00 2026 -0800
Make TerminalProgress a library. (apple#1093)
- Closesapple#1092.
- Allows 3rd party CLI plugins to use the progress indicator.
commit b371aee
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Tue Jan 27 05:07:05 2026 +0800
Feat: container image delete force option (apple#1096)
- Fixedapple#1087
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit ed1185d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Fri Jan 23 17:59:28 2026 -0800
Container-to-host networking. (apple#1078)
- Closesapple#346.
- This PR enables connecting host's localhost ports from
containers.
- It adds an option `--localhost <localhost>` to DNS
create command, after which the packets heading
ip address in container are redirected to localhost in
host machine. Packet filter rule is added and deleted
along with the creation and deletion of localhost domain.
commit 14c279f
Author: Patrick Linnane <patrick@linnane.io>
Date: Fri Jan 23 17:56:35 2026 -0800
Add option to stop services in all launchd domains (apple#1077)
- Services started from Terminal run in the `gui/$uid`
launchd domain. When `ensure-container-stopped.sh`
runs from a different context, `launchctl managername`
may return a different domain, causing the script to
check the wrong domain and miss running services.
I noticed this after upgrading `container` via Homebrew.
- Introduces a getopt option `-a` that allows booting out all
domains explicitly. Also adds `-h` for a usage message.
Signed-off-by: Patrick Linnane <patrick@linnane.io>
commit 751c1fc
Author: Stanislav Antonichev <cympak2@users.noreply.github.com>
Date: Fri Jan 23 23:01:26 2026 +0200
Add --dns support to build command for custom DNS resolution (apple#1067)
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
Changes:
- Added --dns option to BuildCommand to accept DNS nameserver IP
addresses
- Modified build logic to detect DNS configuration changes and recreate
the builder container when DNS settings differ
- Passed DNS configuration to BuilderStart.start() method
- Updated builder container creation to use specified DNS nameservers or
fall back to network gateway
## Type of Change
- [ ] Bug fix
- [X] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: J Logan <sgtbakerrahulnet@yahoo.com>
commit 55f2112
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 23 11:35:10 2026 -0800
Place image store data correctly for app-root path. (apple#1085)
- Closesapple#1084.
commit 5746ec3
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Sat Jan 24 03:32:59 2026 +0800
Fix: prevent delete default network (apple#1083)
- Fixedapple#1073
- Move the conditional check to the front; there's no need
to check for a default network after filtering.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@manuschillerdev@jglogan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: add --init-image flag for specifying custom init filesystem images per VM - #937

Merged
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image
Feb 10, 2026
Merged

feat: add --init-image flag for specifying custom init filesystem images per VM#937
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image

Conversation

@manuschillerdev

@manuschillerdevmanuschillerdev commented Dec 7, 2025

Copy link
Copy Markdown
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

I've been tinkering with ways to extend container with a primitive for interacting with the VM layer. One approach: expose the internal init filesystem as a user-configurable option via --init-image.

What this enables:

  • Custom boot-time logic before the OCI container starts
  • Running additional processes and daemons (e.g., daemons to configure eBPF network filters, logging agents) inside the VM (not the container)
  • Debugging/instrumenting the init process

--init-image vs using the system property
we could also use container system property set image.init vminit:latest (documented via #1032), but this affects all VMs. I want to be able to override this only for a single VM.

In my current approach, the custom image wraps the default vminitd, so it's currently behaving like an entrypoint.
Curious if this direction aligns with the project's goals, or if there's a better abstraction for these use cases.
If there is interest, I would add proper docs and tests.

Example for a minimal entry point binary
Note: We use Go here for its straightforward cross-compilation to Linux ARM64.

// custom-init/wrapper.gopackage main
import (
"fmt""os""syscall"
)
funcmain() {
kmsg, err:=os.OpenFile("/dev/kmsg", os.O_WRONLY, 0)
iferr==nil {
kmsg.WriteString("<6>custom-init: === CUSTOM INIT IMAGE RUNNING ===\n")
kmsg.Close()
}
err=syscall.Exec("/sbin/vminitd.real", os.Args, os.Environ())
iferr!=nil {
fmt.Fprintf(os.Stderr, "Failed to exec vminitd.real: %v\n", err)
os.Exit(1)
}
}

Containerfile

# custom-init/Containerfile
FROM ghcr.io/apple/containerization/vminit:0.23.2 AS base
FROM ghcr.io/apple/containerization/vminit:0.23.2
COPY --from=base /sbin/vminitd /sbin/vminitd.real
COPY wrapper /sbin/vminitd
  • build the binary with cd custom-init && CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o wrapper wrapper.go
  • build the image with bin/container build -t local/custom-init:0.20.0 custom-init/
  • run the container with our custom init-image: bin/container run --name init-test --init-image local/custom-init:0.20.0 alpine:latest echo "hello"
  • check the logs with cat "/Users/$USER/Library/Application Support/com.apple.container/containers/init-test/vminitd.log" | head -50

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

@manuschillerdevmanuschillerdev changed the title feat: add init-image flag for specifying custom init filesystem images per VMfeat: add --init-image flag for specifying custom init filesystem images per VMDec 7, 2025
@jglogan

Copy link
Copy Markdown
Contributor

@dcantah see also #838

Comment threadSources/ContainerClient/Utility.swift
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@dcantah@jglogan would that be of interest for the project? Would be totally open to other suggestions on how one can interact with the startup process. Exposing --init-fs seemed like a viable option here

@manuschillerdev

manuschillerdev commented Jan 10, 2026

Copy link
Copy Markdown
ContributorAuthor

@jglogan@dcantah

I've rebased the PR, added tests and documentation, and updated the description to clarify why container system property set image.init doesn't fit my use case (it applies globally rather than per-VM).

Happy to elaborate on any open questions or explore alternative approaches that would better align with the project's architecture.
I'd appreciate any feedback on whether this direction makes sense to pursue or if there are concerns that would make it worth closing in favor of a different approach.

@jglogan

jglogan commented Jan 17, 2026

Copy link
Copy Markdown
Contributor

@manuschillerdev I haven't been able to review but it seems reasonable. Kernel and initfs config are birds of a feather, whatever config options exist for one, we should eventually provide for the other.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Could you run make fmt on this, and make sure build/test runs okay on your end, and then try pushing the changes? I made one change to resolve some merge conflicts on the Makefile

@jglogan

Copy link
Copy Markdown
Contributor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 5badfb6 to 6e1d1faCompareFebruary 1, 2026 10:15
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

thanks for having another look at this! I rebased the PR against main, resolved the conflicts, ran make fmt, and did a complete re-test locally with the steps from the PR description:

❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"| grep "==="
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
full output of vminitd.log after creating a custom init image, and starting a fresh container using the `--init-image` flag:
❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"
[ 0.069458] random: crng init done
[ 0.070722] brd: module loaded
[ 0.071338] loop: module loaded
[ 0.071436] virtio_blk virtio2: 1/0/0 default/read/poll queues
[ 0.071600] virtio_blk virtio2: [vda] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.071875] virtio_blk virtio3: 1/0/0 default/read/poll queues
[ 0.072020] virtio_blk virtio3: [vdb] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.072226] tun: Universal TUN/TAP device driver, 1.6
[ 0.072687] VFIO - User Level meta-driver version: 0.3
[ 0.072820] rtc-pl031 20050000.pl031: registered as rtc0
[ 0.072857] rtc-pl031 20050000.pl031: setting system clock to 2026-02-01T08:49:54 UTC (1769935794)
[ 0.073306] xt_time: kernel timezone is -0000
[ 0.073348] IPVS: Registered protocols (TCP, UDP, SCTP, AH, ESP)
[ 0.073434] IPVS: Connection hash table configured (size=4096, memory=32Kbytes)
[ 0.073579] IPVS: ipvs loaded.
[ 0.073615] IPVS: [rr] scheduler registered.
[ 0.073634] IPVS: [wrr] scheduler registered.
[ 0.073685] IPVS: [lc] scheduler registered.
[ 0.073718] IPVS: [wlc] scheduler registered.
[ 0.073767] IPVS: [fo] scheduler registered.
[ 0.073813] IPVS: [ovf] scheduler registered.
[ 0.073862] IPVS: [lblc] scheduler registered.
[ 0.073924] IPVS: [lblcr] scheduler registered.
[ 0.073942] IPVS: [dh] scheduler registered.
[ 0.073966] IPVS: [sh] scheduler registered.
[ 0.073991] IPVS: [sed] scheduler registered.
[ 0.074016] IPVS: [nq] scheduler registered.
[ 0.074043] IPVS: [sip] pe registered.
[ 0.074088] Initializing XFRM netlink socket
[ 0.074130] NET: Registered PF_INET6 protocol family
[ 0.074389] Segment Routing with IPv6
[ 0.074421] In-situ OAM (IOAM) with IPv6
[ 0.074462] NET: Registered PF_PACKET protocol family
[ 0.074505] 9pnet: Installing 9P2000 support
[ 0.074573] NET: Registered PF_VSOCK protocol family
[ 0.075578] registered taskstats version 1
[ 0.076957] alg: No testfor fips(ansi_cprng) (fips_ansi_cprng)
[ 0.077498] clk: Disabling unused clocks
[ 0.080034] EXT4-fs (vda): mounted filesystem 63cb0698-b5fe-4f00-ba03-179297b9693a ro without journal. Quota mode: disabled.
[ 0.080117] VFS: Mounted root (ext4 filesystem) readonly on device 254:0.
[ 0.080441] devtmpfs: mounted
[ 0.080801] Freeing unused kernel memory: 1856K
[ 0.080895] Run /sbin/vminitd as init process
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
2026-02-01T08:49:54+0000 info vminitd : [vminitd] Running init command
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /proc
2026-02-01T08:49:54+0000 info vminitd : [vminitd] vminitd booting
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /run
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys/fs/cgroup
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 debug vminitd : bytes=78643200 path=/sys/fs/cgroup/vminitd [Cgroup] setting memory.high
2026-02-01T08:49:54+0000 debug vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] adding new proc to cgroup
2026-02-01T08:49:54+0000 info vminitd : events_path=/sys/fs/cgroup/vminitd/memory.events threshold_bytes=78643200 [vminitd] Started memory monitoring
2026-02-01T08:49:54+0000 info vminitd : [vminitd] serving vminitd API
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] starting process supervisor
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] booting gRPC server on vsock
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] gRPC API serving on vsock
2026-02-01T08:49:54+0000 debug vminitd : interface=lo up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : key=PATH value=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [vminitd] setenv
2026-02-01T08:49:54+0000 debug vminitd : destination=/tmp source=tmpfs type=tmpfs [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/dev/pts source=devpts type=devpts [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/run/container/init-test/rootfs source=/dev/vdb type=ext4 [vminitd] mount
[ 0.268991] EXT4-fs (vdb): mounted filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab r/w without journal. Quota mode: disabled.
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Address=192.168.64.3/24 [vminitd] ipAddrAdd
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Gateway=192.168.64.1 [vminitd] ipRouteAddDefault
2026-02-01T08:49:54+0000 debug vminitd : domain= location=/run/container/init-test/rootfs nameservers=["192.168.64.1"] options=[] searchDomains=[] [vminitd] configureDns
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] writing to path /run/container/init-test/rootfs/etc/resolv.conf nameserver 192.168.64.1
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/resolv.conf [vminitd] wrote resolver configuration
2026-02-01T08:49:54+0000 debug vminitd : location=/run/container/init-test/rootfs [vminitd] configureHosts
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/hosts [vminitd] wrote /etc/hosts configuration
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test stderr=Port: 268435457 stdin=Port: 0 stdout=Port: 268435456 [vminitd] createProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] created bundle with spec Spec(version: "", hooks: nil, process: Optional(ContainerizationOCI.Process(cwd: "/", env: ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME=/root"], consoleSize: nil, selinuxLabel: "", noNewPrivileges: false, commandLine: "", oomScoreAdj: nil, capabilities: Optional(ContainerizationOCI.LinuxCapabilities(bounding: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), effective: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), inheritable: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), permitted: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), ambient: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]))), apparmorProfile: "", user: ContainerizationOCI.User(uid: 0, gid: 0, umask: nil, additionalGids: [0], username: ""), rlimits: [], args: ["echo", "hello"], terminal: false)), hostname: "init-test", domainname: "", mounts: [ContainerizationOCI.Mount(type: "proc", source: "proc", destination: "/proc", options: [], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "sysfs", source: "sysfs", destination: "/sys", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devtmpfs", source: "none", destination: "/dev", options: ["nosuid", "mode=755"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "mqueue", source: "mqueue", destination: "/dev/mqueue", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "tmpfs", source: "tmpfs", destination: "/dev/shm", options: ["nosuid", "noexec", "nodev", "mode=1777", "size=65536k"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "cgroup2", source: "none", destination: "/sys/fs/cgroup", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devpts", source: "devpts", destination: "/dev/pts", options: ["nosuid", "noexec", "newinstance", "gid=5", "mode=0620", "ptmxmode=0666"], uidMappings: nil, gidMappings: nil)], annotations: nil, root: Optional(ContainerizationOCI.Root(path: "/run/container/init-test/rootfs", readonly: false)), linux: Optional(ContainerizationOCI.Linux(uidMappings: [], gidMappings: [], sysctl: Optional([:]), resources: Optional(ContainerizationOCI.LinuxResources(devices: [], memory: Optional(ContainerizationOCI.LinuxMemory(limit: Optional(1073741824), reservation: nil, swap: nil, kernel: nil, kernelTCP: nil, swappiness: nil, disableOOMKiller: nil, useHierarchy: nil, checkBeforeUpdate: nil)), cpu: Optional(ContainerizationOCI.LinuxCPU(shares: nil, quota: Optional(400000), burst: nil, period: Optional(100000), realtimeRuntime: nil, realtimePeriod: nil, cpus: "", mems: "", idle: nil)), pids: nil, blockIO: nil, hugepageLimits: [], network: nil, rdma: nil, unified: Optional([:]))), cgroupsPath: "/container/init-test", namespaces: [ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.cgroup, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.ipc, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.mount, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.pid, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.uts, path: "")], devices: [], seccomp: nil, rootfsPropagation: "", maskedPaths: [], readonlyPaths: [], mountLabel: "", personality: nil)))
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting I/O
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stderr
2026-02-01T08:49:54+0000 info vminitd : [vminitd] created vmexec init process
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] startProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] in supervisor lock to start process
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting managed process
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78381056 high_events_total=1 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78442496 high_events_total=15 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78331904 high_events_total=18 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] got back pid data
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] sending pid acknowledgement
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[93: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] started managed process
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[94: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 debug vminitd : count=0 pid=94 status=0 [vminitd] managed process exited
2026-02-01T08:49:54+0000 info vminitd : id=init-test status=0 [vminitd] managed process exit
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stderr
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] 0 managed process waiters signaled
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : pid=-1 signal=9 [vminitd] kill
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : flags=0 path=/run/container/init-test/rootfs [vminitd] umount
[ 0.541866] EXT4-fs (vdb): unmounting filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab.
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] sync
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] deleteProcess
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] deleting cgroup manager

I also re-ran the tests:

❯ swift test --filter TestCLIRunInitImage 2>&1
Building for debugging...
[7/7] Write swift-version-1C31CF501CE571A8.txt
Build complete! (0.77s)
Test Suite 'Selected tests' started at 2026-02-01 11:10:47.076.
Test Suite 'containerPackageTests.xctest' started at 2026-02-01 11:10:47.077.
Test Suite 'containerPackageTests.xctest' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.1 (c9d57c83568b06d)
↳ Target Platform: arm64-apple-macosx
◇ Suite TestCLIRunInitImage started.
◇ Test testCreateWithNonExistentInitImage() started.
◇ Test testRunWithExplicitDefaultInitImage() started.
◇ Test testInitImageFlagInHelp() started.
◇ Test testRunWithNonExistentInitImage() started.
✔ Test testInitImageFlagInHelp() passed after 0.178 seconds.
✔ Test testRunWithNonExistentInitImage() passed after 10.584 seconds.
✔ Test testCreateWithNonExistentInitImage() passed after 20.668 seconds.
✔ Test testRunWithExplicitDefaultInitImage() passed after 25.314 seconds.
✔ Suite TestCLIRunInitImage passed after 25.314 seconds.
✔ Test run with 4 tests in 1 suite passed after 25.314 seconds.

@jglogan let me know if that works for you, or if I should rather still open a fresh PR. Don't worry, I'd aim for the cleanest solution for the maintainers and the repo. Re-organizing the PR is no effort at all. Thanks for your time again!

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev In CI I'm seeing this failure:

✔ Test testCreateWithNonExistentInitImage() passed after 43.897 seconds.
✘ Test testRunWithExplicitDefaultInitImage() recorded an issue at TestCLIRunInitImage.swift:93:6: Caught error: executionFailed("command failed: Warning! Running debug build. Performance may be degraded.\nError: internalError: \"failed to create container\" (cause: \"internalError: \"XPC timeout for request to com.apple.container.apiserver/containerCreate\"\")\n")
✘ Test testRunWithExplicitDefaultInitImage() failed after 87.555 seconds with 1 issue.
↳ /// Test that explicitly specifying the default init image works the same as
↳ /// not specifying any init image.
✔ Test testRunWithNonExistentInitImage() passed after 87.606 seconds.
✘ Suite TestCLIRunInitImage failed after 87.606 seconds with 1 issue.
✘ Test run with 4 tests in 1 suite failed after 87.606 seconds with 1 issue.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 7d9a37a to baae7c7CompareFebruary 3, 2026 22:05
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks! the tests did catch an error in the image selection logic - glad they did.
I pushed a separate fix, an re-ran make integrate locally without errors.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev OK, the updated tests worked fine. One last thing (thanks for your patience!)

ContainerClient got a big refactor your changes need to be updated to work with those.

@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan no worries. I rebased against main and verified that the changes still work.
make integration runs without errors, loading a custom init-image works and starting containers without a custom init image provided works as well

@jglogan
jglogan merged commit cf9b335 into apple:mainFeb 10, 2026
3 checks passed
@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Finally got it in there...thanks for the contribution!

simone-panico pushed a commit to simone-panico/container that referenced this pull request Feb 10, 2026
…ges per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks again for guiding me!

Mcrich23 added a commit to Mcrich23/container that referenced this pull request Feb 18, 2026
commit c791052
Author: Aditya Ramani <a_ramani@apple.com>
Date: Wed Feb 18 07:43:56 2026 +0530
Add init methods for all the members of the Flags type (apple#1203)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Authors of CLI plugins for container will be able to reuse the container
flags defined in the CLI package, instead of having to duplicate them in
their project
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit dfac83d
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 17 16:54:44 2026 -0800
ContainerService: Add minimum memory amount validation (apple#1208)
Closesapple#1202
Today it's possible to pass a memory amount that very easily will cause
the container's VM to not be able to boot. We should protect against
this to avoid weird hangs/error messages. I could be convinced that a
limit should be in Containerization as well, but I think having one in
the daemon is a decent idea regardless.
commit 5385a5c
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Tue Feb 17 15:08:32 2026 -0800
Support using multiple different network plugins (apple#1151)
## Type of Change
- [x] New feature
- [x] Breaking change
## Motivation and Context
We want to be able to support using multiple network plugins during
`container`'s lifetime. This additionally means needing to pick an
interface strategy to interpret a network attachment based on what
network plugin was used to create that attachment. This PR will
potentially replace apple#1081.
Followups:
- doc updates to include the ability to specify plugin in the network
creation cli
## Testing
- [x] Tested locally
- [x] Added/updated tests
commit 7476743
Author: AJ Emory <239216119+ajemory@users.noreply.github.com>
Date: Fri Feb 13 19:27:32 2026 -0800
feat: Moving bundle creation from ContainerService to SandboxService (apple#1076)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Closesapple#1046 -- Right now we're creating container bundles in
ContainersService. Move this to the SandboxService to make it easier to
support different container bundle types.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 4c800db
Author: J Logan <john_logan@apple.com>
Date: Fri Feb 13 10:51:27 2026 -0800
Fix persistent CI failures. (apple#1205)
## Type of Change
- [x] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
- CI build is failing because runners don't have an /etc/resolver
directory, causing the directory monitor to fail. This occurs while the
install-kernel make target is running, so it appears that kernel
download is failing when it's just that the API server is dying. Created
apple#1207 for the issue.
- Fixing the initial scan for the directory just moves the problem to
the filesystem watch loop, likely because we're not testing the result
of `open()` for errors.
- Right now the priority is getting CI running and PRs merged, so just
commenting out the realhost DNS server setup.
- Also seeing that under some conditions it can take quite a while for
launchd to start the helper for the default network (8 seconds or more).
With the 10 second health check timeout after API server registration,
this means that some CI runs can exhibit this failure mode. Added a
`--timeout` option to SystemStart and set a 60 second timeout for
install-kernel and integration Makefile targets.
- Fixed a bug where `--debug` was being placed in the wrong location in
the api server startup args.
- Disabled all network CLI tests due to container bootstrap errors when
trying to run the container immediately after creating the network. The
slow network helper launch could be the reason behind the failures that
drove us to serialize these tests. Filed apple#1206 for this issue.
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit f7d00aa
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 11 15:09:21 2026 -0800
APIServer: Add support for filtering to list rpc (apple#1175)
This is not intended to be used to support `--filter` or similar on the
CLIs list yet, it's solely to clean up our rather awkward use of
`ContainerClient.list()` today in the CLI. The list RPC simply returns
all of the containers we have created. Because of this, for a LOT of our
commands we filter to what we need client side, which feels like a
waste.. This change introduces a filter struct that we can provide an
array of container IDs, labels, and the status of the containers to
filter the `list()` output from.
This additionally, because it was killing (pun not intended) me and I
was already having to change this area for the `list()` additions,
changes container kill slightly to return an error if you try and kill a
container that doesn't exist.
commit c9f81ca
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Feb 11 04:26:33 2026 +0800
Feat: add container registry list (apple#1119)
- Requires apple/containerization#502
- Closesapple#1088
---------
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit cf9b335
Author: Manu Schiller <56154253+manuschillerdev@users.noreply.github.com>
Date: Tue Feb 10 03:11:27 2026 +0100
feat: add --init-image flag for specifying custom init filesystem images per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
commit 474906d
Author: Amir Alperin <me@remotecpp.dev>
Date: Fri Feb 6 23:38:19 2026 +0200
feat: Add runtime flag to container create and run commands (apple#1049) (apple#1109)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Fixesapple#1049
- Add --runtime option for Flags.Management
- Apply runtime handler in containerConfigFromFlags
- Update command-reference.md doc
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
Co-authored-by: J Logan <john_logan@apple.com>
commit 40de343
Author: Dmitry Kovba <dkovba@apple.com>
Date: Fri Feb 6 00:41:29 2026 -0800
Fix relative path mount tests (apple#1168)
`make test` occasionally fails with:
```
✘ Test testHostDNSReinitialize() recorded an issue at HostDNSResolverTest.swift:132:45: Expectation failed: (error →
Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory") as? (ContainerizationError → NSError)
✘ Suite HostDNSResolverTest failed after 0.119 seconds with 1 issue.
```
commit aa17d46
Author: Poetry Of Code <101225909+poetryofcode@users.noreply.github.com>
Date: Fri Feb 6 03:38:21 2026 -0500
Warn user when a named volume is auto-created (apple#1108)
- Implemented the TODO at
ContainerAPIService/Client/Utility.swift:358 — warn the
user when a named volume is auto-created.
- This only triggers for named volumes (not anonymous
ones), matching Docker's behavior of informing users
about implicit resource creation.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
commit adb3c44
Author: J Logan <john_logan@apple.com>
Date: Thu Feb 5 20:19:13 2026 -0800
Don't enable selinux LSM on boot. (apple#1166)
- Closesapple#1150.
- The problem seems to be that the selinux label attribute enforcement
doesn't play well with overlayfs.
- Solution is to set the `lsm` boot line argument. The new value
corresponds to what one would see in a Lima VM with Colima. The Kata
kernel we use doesn't provide any of those modules, so now if you run
`dmesg | grep -i lsm` in a container you will just see: `LSM:
initializing lsm=capability`
commit fdeb1b1
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 10:59:31 2026 -0800
Add builder tests (apple#1154)
- Adds test for apple#1094.
- Closesapple#933 (with apple/container-builder-shim#62).
- Closesapple#425 (with apple/container-builder-shim#63).
commit fabfc55
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 09:53:31 2026 -0800
Send tar hash in the first BuildTransfer packet (apple#1149)
Send the hash of entire tar file in the first BuildTransfer packet to
prevent container-builder-shim from using stale cached contents.
This PR resolvesapple#1143.
This PR relies on apple/container-builder-shim#64.
## Type of Change
- [X] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Current container-builder-shim uses only first few bytes of tar file as
checksum, which leads to the usage of stale cached contents if the
change of build context is not included in the first bytes of tar file.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit 6e9b8d7
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Feb 5 09:47:20 2026 -0800
CLI: Forego logging errors on multi-container operations (apple#1163)
Instead of logging errors, and then additionally throwing an error
stating what containers couldn't be stopped/killed/deleted, let's just
concatenate the errors and throw the single error.
commit d79bc0d
Author: Manoj Mahapatra <mahapatra.manoj@hotmail.com>
Date: Thu Feb 5 01:16:30 2026 -0800
chore: Replace force-unwrapped String(data:encoding:) with String(decoding:as:) (apple#1164)
Use the non-optional String(decoding:as:) initializer for converting
JSON-encoded Data to String. This is safe for UTF-8 and eliminates force
commit 21dabb7
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 03:13:36 2026 -0500
[build-command]: Add --pull option for fetching latest image (apple#844)
- Closesapple#733.
commit 6553f9c
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 01:16:08 2026 -0500
[deps]: bump containerization to 0.25.0 (apple#1161)
Co-authored-by: saehejkang <saehej.kang@gmail.com>
Co-authored-by: Anthony DePasquale <anthony@depasquale.org>
- Bump `containerization` to `0.25.0`
- Updates for parameter changes on containerization
registry access API.
- Updates for change to containerization
`cleanUpOrphanedBlobs` function.
commit 2d1dd6b
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 15:42:29 2026 -0800
Fix file path for the PR number in the PR labeler workflow (apple#1158)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR label applier GitHub workflow has been failing for a while. This
PR fixes that by correcting the file path we look for when trying to
read the PR number. See example failure here
https://github.com/apple/container/actions/runs/21691766538/job/62552959972#step:4:23
commit 6451e07
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 14:44:53 2026 -0800
Add debugging to the PR labeler CI flow (apple#1155)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR labeler workflow has been failing for a while but it's difficult
to know how to fix it since the PR labeler workflow is run from main
(aka NOT the current PR branch) for security reasons. Example at
https://github.com/apple/container/actions/runs/21690229300/workflow
commit 8fdfa29
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:52:09 2026 -0800
CLI: Rework ClientContainer (apple#1139)
ClientContainer was honestly extremely awkward. It could only be created
by passing either a ContainerConfiguration, or a Snapshot that had to be
obtained from calling a static method on the type itself. The type also
did not store a connection, so every single method got a new xpc
connection to the APIServer. This change aims to rework this type to be
just a generic client, that is *not* a client for one specific
container, but for any.
- Rename to ContainerClient
- Have list() return [ContainerSnapshot]
- Create a connection in the constructor
- Change all the callsites to use the new API
- Small, somewhat related, change to logs API in the APIServer. Now that
we don't need to call get() to grab a client anymore which was typically
what did "does this container exist" logic and gave a nice error
message, I added a small check in the APIServer to see if the container
exists and return mostly the same error message.
commit 23c0ece
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:19:50 2026 -0800
CI: Add signed commit check (apple#1152)
This requirement of ours often goes unnoticed because nothing yells at
you openly about it. Lets fail CI to make it more obvious.
commit ce1b629
Author: Manoj Mahapatra <mahaplipsa@gmail.com>
Date: Tue Feb 3 13:43:07 2026 -0800
[Docs] Fix typo in BUILDING.md: launchd -> launchctl (apple#1146)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [x] Documentation update
## Motivation and Context
The debug instructions in `BUILDING.md` incorrectly reference launchd
list instead of `launchctl` list. `launchd` is the daemon itself and
cannot be invoked directly.
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [x] Added/updated docs
commit 3e49dce
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 3 00:45:01 2026 -0800
Add in missing rlimits (apple#1140)
Containerization didn't have these defined until a recent tag.
commit c4c2e85
Author: J Logan <john_logan@apple.com>
Date: Tue Feb 3 00:27:09 2026 -0800
Upgrade kernel to Kata 3.26.0. (apple#1134)
- Upgrade to containerization 0.24.5 to pick up zstd decompression
enhancement.
- Closesapple#767.
- Closesapple#988.
- Closesapple#1132.
- Requires apple/containerization#508.
commit 5c86337
Author: William Laverty <developer@william-laverty.com>
Date: Mon Feb 2 13:57:59 2026 -0800
Add explanatory message before admin password prompt in uninstall script (apple#1118)
- Added message: "This script requires an administrator password to
remove the application files from system directories."
- Fixesapple#1111
commit 7da25e1
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:35:02 2026 -0800
Deps: Bump Containerization to 0.24.0 (apple#1127)
Brings in some rlimit bumps/adjustments
commit 7dfe27d
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:30:19 2026 -0800
CLI: Add support for rlimits (apple#1129)
Closesapple#1097.
commit b3b5c3e
Author: J Logan <john_logan@apple.com>
Date: Mon Feb 2 12:24:27 2026 -0800
Use labels instead of id to discriminate the builtin network. (apple#1123)
- Closesapple#1122.
- Adds placeholder ManagedResource and unit tests. Nothing is using
these yet.
- Adds system-defined resource labels for owning plugin and resource
role. The system discriminates the builtin network using role "builtin".
- Adds builtin role when creating builtin network at startup, and
ensures that a preexisting network with ID "default" gets updated with
the role label.
- Replace all network ID checks for "default" with the builtin role
check.
- Adds "builder" role to builder VM.
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Role and owner labels should make cross-cutting resource policy easier
to implement.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 1dae1cd
Author: w-ferg <43309695+w-ferg@users.noreply.github.com>
Date: Sun Feb 1 18:14:41 2026 -0500
Fix pfctl executable path in PacketFilter DNS reload (apple#1128)
## Summary
The `reload()` method in `PacketFilter.swift` references
`/sbin/reloadProcess` (the local variable name) instead of
`/sbin/pfctl`. This causes all DNS create and delete operations to fail:
```
Error: internalError: "pfctl reload exec failed: "Error Domain=NSCocoaErrorDomain Code=4 "The file "reloadProcess" doesn't exist.""
```
## Fix
One-line change: `/sbin/reloadProcess` → `/sbin/pfctl`
## Testing
Verified on macOS 26 (Tahoe) with Apple Silicon:
- `sudo container system dns create test.sdc.internal --localhost
203.0.113.1` succeeds without error
- Container can resolve and reach host services through the DNS redirect
commit 113a6ec
Author: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Date: Fri Jan 30 21:54:57 2026 -0600
Fix file descriptor leak in DirectoryWatcher (apple#1104)
- `DirectoryWatcher` opens file descriptors for monitoring
directories but never closes them, causing a file descriptor
leak.
- Adds `setCancelHandler` to properly close file descriptors
when the `DispatchSource` is cancelled.
Signed-off-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
commit 72f04b6
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Fri Jan 30 19:10:03 2026 -0800
[docs]: update steps on building with containerization project (apple#1116)
- Closesapple#1095
- Just added a few more details about how to build with the local
`containerization` dependency.
commit 3a0ad58
Author: Raj <rajaryan_singh@apple.com>
Date: Fri Jan 30 16:17:43 2026 -0800
Add resource.role label to builder container (apple#1120)
Add resource.role label to builder container
commit 1c01d0c
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 30 11:07:49 2026 -0800
Update to kata 3.20.0 kernel. (apple#1114)
- Closesapple#1113.
- This is the newest we can do until we address apple#767.
- Slight change to PacketFilter error handling so unit tests work more
reliably.
- Try making CLINetworkTests serialized to see if parallel execution is
causing flakes.
commit 3f2060e
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 18:25:48 2026 -0800
DirectoryWatcher: Small adjustments (apple#1112)
- Have the handler throw
- Log the failure at error level
commit 0a7fb07
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 14:21:12 2026 -0800
Set mtu to old Containerization default (apple#1110)
The old mtu default in containerization was 1280 to account for some
alpine/musl images that have issues with
1500. This changed in the last couple tags to be modifiable, but the new
default is the standard 1500. Ideally we eventually allow supplying the
mtu to be used when you create a network (or possibly a container
creation setting), but for now just default in here back to what CZ used
to use.
commit 0bceb23
Author: Aditya Ramani <a_ramani@apple.com>
Date: Thu Jan 29 12:08:42 2026 +0900
Bump to use containerization 0.23.2 (apple#1106)
Updating the package dependency on apple/containerization to pick up bug fixes
Signed-off-by: Aditya Ramani <a_ramani@apple.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit d762fe5
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 18:22:33 2026 -0800
Launch a service with waitForDebugger if specified (apple#1101)
This PR enables launching a service with `waitForDebugger` flag if the
service label matches a given env variable `CONTAINER_DEBUG`.
commit 4f93e3e
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed Jan 28 18:21:08 2026 -0800
ci: bump actions/checkout from 6.0.1 to 6.0.2 in the github-actions group (apple#1100)
- Updates `actions/checkout` from 6.0.1 to 6.0.2
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
commit 371db6d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 17:17:08 2026 -0800
Fix testExecOnExitingContainer (apple#1107)
Check the container remains only, not its status as the status might not
have been updated at the time checking.
commit d872270
Author: J Logan <john_logan@apple.com>
Date: Wed Jan 28 09:04:58 2026 -0800
Removes ArgumentParser import from NetworkMode. (apple#1102)
- ContainerResources shouldn't need to know anything about CLI stuff.
- Move ExpressibleByArgument protocol conformance to an extension in the
package where it's needed.
commit 3abf81f
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Tue Jan 27 20:00:43 2026 -0800
[image-list]: Add full size field to json output (apple#1098)
- Refer to apple#862
- Updated `SIZE` field to `FULL SIZE`, as it seemed more appropriate so
it does not get mixed up with the `descriptor size` field
- Closesapple#860
commit 24cbed5
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Jan 28 06:55:49 2026 +0800
Implement container prune (apple#904)
- Fixedapple#892.
- By contrast with `rm`, `prune` should display
the amount of reclaimed storage, so added code
to retrieve it.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit a57527e
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Tue Jan 27 11:15:22 2026 -0800
Refactor container lifecycle functions to perform scoped rollback on failure (apple#1080)
- Closesapple#977.
- Closesapple#1058.
- Prevents unexpected removal of containers on
bootstrapping and starting failures, by reorganizing
error handling for container `run`, `start`, and
`exec` so that error handling only unwinds that
which was done in the current scope.
- Relies on apple/containerization#495.
commit 6244129
Author: c <claudeaceae@icloud.com>
Date: Mon Jan 26 23:30:45 2026 -0500
Fix grammar in BUILDING.md (apple#984)
- Fixes a grammar error in the local Containerization development
instructions.
commit 9d4cded
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Mon Jan 26 19:35:41 2026 -0800
Isolated network (apple#1079)
- Closesapple#1037.
- Adds a `--mode` flag that has `nat` and `hostOnly` options.
The host-only option selects the vmnet host-only mode,
where containers attached to the network can reach each
other and the host, but not external systems.
commit 033c999
Author: J Logan <john_logan@apple.com>
Date: Mon Jan 26 14:07:00 2026 -0800
Make TerminalProgress a library. (apple#1093)
- Closesapple#1092.
- Allows 3rd party CLI plugins to use the progress indicator.
commit b371aee
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Tue Jan 27 05:07:05 2026 +0800
Feat: container image delete force option (apple#1096)
- Fixedapple#1087
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit ed1185d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Fri Jan 23 17:59:28 2026 -0800
Container-to-host networking. (apple#1078)
- Closesapple#346.
- This PR enables connecting host's localhost ports from
containers.
- It adds an option `--localhost <localhost>` to DNS
create command, after which the packets heading
ip address in container are redirected to localhost in
host machine. Packet filter rule is added and deleted
along with the creation and deletion of localhost domain.
commit 14c279f
Author: Patrick Linnane <patrick@linnane.io>
Date: Fri Jan 23 17:56:35 2026 -0800
Add option to stop services in all launchd domains (apple#1077)
- Services started from Terminal run in the `gui/$uid`
launchd domain. When `ensure-container-stopped.sh`
runs from a different context, `launchctl managername`
may return a different domain, causing the script to
check the wrong domain and miss running services.
I noticed this after upgrading `container` via Homebrew.
- Introduces a getopt option `-a` that allows booting out all
domains explicitly. Also adds `-h` for a usage message.
Signed-off-by: Patrick Linnane <patrick@linnane.io>
commit 751c1fc
Author: Stanislav Antonichev <cympak2@users.noreply.github.com>
Date: Fri Jan 23 23:01:26 2026 +0200
Add --dns support to build command for custom DNS resolution (apple#1067)
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
Changes:
- Added --dns option to BuildCommand to accept DNS nameserver IP
addresses
- Modified build logic to detect DNS configuration changes and recreate
the builder container when DNS settings differ
- Passed DNS configuration to BuilderStart.start() method
- Updated builder container creation to use specified DNS nameservers or
fall back to network gateway
## Type of Change
- [ ] Bug fix
- [X] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: J Logan <sgtbakerrahulnet@yahoo.com>
commit 55f2112
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 23 11:35:10 2026 -0800
Place image store data correctly for app-root path. (apple#1085)
- Closesapple#1084.
commit 5746ec3
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Sat Jan 24 03:32:59 2026 +0800
Fix: prevent delete default network (apple#1083)
- Fixedapple#1073
- Move the conditional check to the front; there's no need
to check for a default network after filtering.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@manuschillerdev@jglogan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add --init-image flag for specifying custom init filesystem images per VM - #937

Merged
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image
Feb 10, 2026
Merged

feat: add --init-image flag for specifying custom init filesystem images per VM#937
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image

Conversation

@manuschillerdev

@manuschillerdevmanuschillerdev commented Dec 7, 2025

Copy link
Copy Markdown
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

I've been tinkering with ways to extend container with a primitive for interacting with the VM layer. One approach: expose the internal init filesystem as a user-configurable option via --init-image.

What this enables:

  • Custom boot-time logic before the OCI container starts
  • Running additional processes and daemons (e.g., daemons to configure eBPF network filters, logging agents) inside the VM (not the container)
  • Debugging/instrumenting the init process

--init-image vs using the system property
we could also use container system property set image.init vminit:latest (documented via #1032), but this affects all VMs. I want to be able to override this only for a single VM.

In my current approach, the custom image wraps the default vminitd, so it's currently behaving like an entrypoint.
Curious if this direction aligns with the project's goals, or if there's a better abstraction for these use cases.
If there is interest, I would add proper docs and tests.

Example for a minimal entry point binary
Note: We use Go here for its straightforward cross-compilation to Linux ARM64.

// custom-init/wrapper.gopackage main
import (
"fmt""os""syscall"
)
funcmain() {
kmsg, err:=os.OpenFile("/dev/kmsg", os.O_WRONLY, 0)
iferr==nil {
kmsg.WriteString("<6>custom-init: === CUSTOM INIT IMAGE RUNNING ===\n")
kmsg.Close()
}
err=syscall.Exec("/sbin/vminitd.real", os.Args, os.Environ())
iferr!=nil {
fmt.Fprintf(os.Stderr, "Failed to exec vminitd.real: %v\n", err)
os.Exit(1)
}
}

Containerfile

# custom-init/Containerfile
FROM ghcr.io/apple/containerization/vminit:0.23.2 AS base
FROM ghcr.io/apple/containerization/vminit:0.23.2
COPY --from=base /sbin/vminitd /sbin/vminitd.real
COPY wrapper /sbin/vminitd
  • build the binary with cd custom-init && CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o wrapper wrapper.go
  • build the image with bin/container build -t local/custom-init:0.20.0 custom-init/
  • run the container with our custom init-image: bin/container run --name init-test --init-image local/custom-init:0.20.0 alpine:latest echo "hello"
  • check the logs with cat "/Users/$USER/Library/Application Support/com.apple.container/containers/init-test/vminitd.log" | head -50

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

@manuschillerdevmanuschillerdev changed the title feat: add init-image flag for specifying custom init filesystem images per VMfeat: add --init-image flag for specifying custom init filesystem images per VMDec 7, 2025
@jglogan

Copy link
Copy Markdown
Contributor

@dcantah see also #838

Comment threadSources/ContainerClient/Utility.swift
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@dcantah@jglogan would that be of interest for the project? Would be totally open to other suggestions on how one can interact with the startup process. Exposing --init-fs seemed like a viable option here

@manuschillerdev

manuschillerdev commented Jan 10, 2026

Copy link
Copy Markdown
ContributorAuthor

@jglogan@dcantah

I've rebased the PR, added tests and documentation, and updated the description to clarify why container system property set image.init doesn't fit my use case (it applies globally rather than per-VM).

Happy to elaborate on any open questions or explore alternative approaches that would better align with the project's architecture.
I'd appreciate any feedback on whether this direction makes sense to pursue or if there are concerns that would make it worth closing in favor of a different approach.

@jglogan

jglogan commented Jan 17, 2026

Copy link
Copy Markdown
Contributor

@manuschillerdev I haven't been able to review but it seems reasonable. Kernel and initfs config are birds of a feather, whatever config options exist for one, we should eventually provide for the other.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Could you run make fmt on this, and make sure build/test runs okay on your end, and then try pushing the changes? I made one change to resolve some merge conflicts on the Makefile

@jglogan

Copy link
Copy Markdown
Contributor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 5badfb6 to 6e1d1faCompareFebruary 1, 2026 10:15
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

thanks for having another look at this! I rebased the PR against main, resolved the conflicts, ran make fmt, and did a complete re-test locally with the steps from the PR description:

❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"| grep "==="
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
full output of vminitd.log after creating a custom init image, and starting a fresh container using the `--init-image` flag:
❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"
[ 0.069458] random: crng init done
[ 0.070722] brd: module loaded
[ 0.071338] loop: module loaded
[ 0.071436] virtio_blk virtio2: 1/0/0 default/read/poll queues
[ 0.071600] virtio_blk virtio2: [vda] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.071875] virtio_blk virtio3: 1/0/0 default/read/poll queues
[ 0.072020] virtio_blk virtio3: [vdb] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.072226] tun: Universal TUN/TAP device driver, 1.6
[ 0.072687] VFIO - User Level meta-driver version: 0.3
[ 0.072820] rtc-pl031 20050000.pl031: registered as rtc0
[ 0.072857] rtc-pl031 20050000.pl031: setting system clock to 2026-02-01T08:49:54 UTC (1769935794)
[ 0.073306] xt_time: kernel timezone is -0000
[ 0.073348] IPVS: Registered protocols (TCP, UDP, SCTP, AH, ESP)
[ 0.073434] IPVS: Connection hash table configured (size=4096, memory=32Kbytes)
[ 0.073579] IPVS: ipvs loaded.
[ 0.073615] IPVS: [rr] scheduler registered.
[ 0.073634] IPVS: [wrr] scheduler registered.
[ 0.073685] IPVS: [lc] scheduler registered.
[ 0.073718] IPVS: [wlc] scheduler registered.
[ 0.073767] IPVS: [fo] scheduler registered.
[ 0.073813] IPVS: [ovf] scheduler registered.
[ 0.073862] IPVS: [lblc] scheduler registered.
[ 0.073924] IPVS: [lblcr] scheduler registered.
[ 0.073942] IPVS: [dh] scheduler registered.
[ 0.073966] IPVS: [sh] scheduler registered.
[ 0.073991] IPVS: [sed] scheduler registered.
[ 0.074016] IPVS: [nq] scheduler registered.
[ 0.074043] IPVS: [sip] pe registered.
[ 0.074088] Initializing XFRM netlink socket
[ 0.074130] NET: Registered PF_INET6 protocol family
[ 0.074389] Segment Routing with IPv6
[ 0.074421] In-situ OAM (IOAM) with IPv6
[ 0.074462] NET: Registered PF_PACKET protocol family
[ 0.074505] 9pnet: Installing 9P2000 support
[ 0.074573] NET: Registered PF_VSOCK protocol family
[ 0.075578] registered taskstats version 1
[ 0.076957] alg: No testfor fips(ansi_cprng) (fips_ansi_cprng)
[ 0.077498] clk: Disabling unused clocks
[ 0.080034] EXT4-fs (vda): mounted filesystem 63cb0698-b5fe-4f00-ba03-179297b9693a ro without journal. Quota mode: disabled.
[ 0.080117] VFS: Mounted root (ext4 filesystem) readonly on device 254:0.
[ 0.080441] devtmpfs: mounted
[ 0.080801] Freeing unused kernel memory: 1856K
[ 0.080895] Run /sbin/vminitd as init process
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
2026-02-01T08:49:54+0000 info vminitd : [vminitd] Running init command
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /proc
2026-02-01T08:49:54+0000 info vminitd : [vminitd] vminitd booting
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /run
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys/fs/cgroup
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 debug vminitd : bytes=78643200 path=/sys/fs/cgroup/vminitd [Cgroup] setting memory.high
2026-02-01T08:49:54+0000 debug vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] adding new proc to cgroup
2026-02-01T08:49:54+0000 info vminitd : events_path=/sys/fs/cgroup/vminitd/memory.events threshold_bytes=78643200 [vminitd] Started memory monitoring
2026-02-01T08:49:54+0000 info vminitd : [vminitd] serving vminitd API
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] starting process supervisor
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] booting gRPC server on vsock
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] gRPC API serving on vsock
2026-02-01T08:49:54+0000 debug vminitd : interface=lo up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : key=PATH value=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [vminitd] setenv
2026-02-01T08:49:54+0000 debug vminitd : destination=/tmp source=tmpfs type=tmpfs [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/dev/pts source=devpts type=devpts [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/run/container/init-test/rootfs source=/dev/vdb type=ext4 [vminitd] mount
[ 0.268991] EXT4-fs (vdb): mounted filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab r/w without journal. Quota mode: disabled.
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Address=192.168.64.3/24 [vminitd] ipAddrAdd
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Gateway=192.168.64.1 [vminitd] ipRouteAddDefault
2026-02-01T08:49:54+0000 debug vminitd : domain= location=/run/container/init-test/rootfs nameservers=["192.168.64.1"] options=[] searchDomains=[] [vminitd] configureDns
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] writing to path /run/container/init-test/rootfs/etc/resolv.conf nameserver 192.168.64.1
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/resolv.conf [vminitd] wrote resolver configuration
2026-02-01T08:49:54+0000 debug vminitd : location=/run/container/init-test/rootfs [vminitd] configureHosts
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/hosts [vminitd] wrote /etc/hosts configuration
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test stderr=Port: 268435457 stdin=Port: 0 stdout=Port: 268435456 [vminitd] createProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] created bundle with spec Spec(version: "", hooks: nil, process: Optional(ContainerizationOCI.Process(cwd: "/", env: ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME=/root"], consoleSize: nil, selinuxLabel: "", noNewPrivileges: false, commandLine: "", oomScoreAdj: nil, capabilities: Optional(ContainerizationOCI.LinuxCapabilities(bounding: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), effective: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), inheritable: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), permitted: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), ambient: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]))), apparmorProfile: "", user: ContainerizationOCI.User(uid: 0, gid: 0, umask: nil, additionalGids: [0], username: ""), rlimits: [], args: ["echo", "hello"], terminal: false)), hostname: "init-test", domainname: "", mounts: [ContainerizationOCI.Mount(type: "proc", source: "proc", destination: "/proc", options: [], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "sysfs", source: "sysfs", destination: "/sys", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devtmpfs", source: "none", destination: "/dev", options: ["nosuid", "mode=755"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "mqueue", source: "mqueue", destination: "/dev/mqueue", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "tmpfs", source: "tmpfs", destination: "/dev/shm", options: ["nosuid", "noexec", "nodev", "mode=1777", "size=65536k"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "cgroup2", source: "none", destination: "/sys/fs/cgroup", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devpts", source: "devpts", destination: "/dev/pts", options: ["nosuid", "noexec", "newinstance", "gid=5", "mode=0620", "ptmxmode=0666"], uidMappings: nil, gidMappings: nil)], annotations: nil, root: Optional(ContainerizationOCI.Root(path: "/run/container/init-test/rootfs", readonly: false)), linux: Optional(ContainerizationOCI.Linux(uidMappings: [], gidMappings: [], sysctl: Optional([:]), resources: Optional(ContainerizationOCI.LinuxResources(devices: [], memory: Optional(ContainerizationOCI.LinuxMemory(limit: Optional(1073741824), reservation: nil, swap: nil, kernel: nil, kernelTCP: nil, swappiness: nil, disableOOMKiller: nil, useHierarchy: nil, checkBeforeUpdate: nil)), cpu: Optional(ContainerizationOCI.LinuxCPU(shares: nil, quota: Optional(400000), burst: nil, period: Optional(100000), realtimeRuntime: nil, realtimePeriod: nil, cpus: "", mems: "", idle: nil)), pids: nil, blockIO: nil, hugepageLimits: [], network: nil, rdma: nil, unified: Optional([:]))), cgroupsPath: "/container/init-test", namespaces: [ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.cgroup, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.ipc, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.mount, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.pid, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.uts, path: "")], devices: [], seccomp: nil, rootfsPropagation: "", maskedPaths: [], readonlyPaths: [], mountLabel: "", personality: nil)))
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting I/O
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stderr
2026-02-01T08:49:54+0000 info vminitd : [vminitd] created vmexec init process
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] startProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] in supervisor lock to start process
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting managed process
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78381056 high_events_total=1 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78442496 high_events_total=15 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78331904 high_events_total=18 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] got back pid data
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] sending pid acknowledgement
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[93: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] started managed process
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[94: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 debug vminitd : count=0 pid=94 status=0 [vminitd] managed process exited
2026-02-01T08:49:54+0000 info vminitd : id=init-test status=0 [vminitd] managed process exit
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stderr
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] 0 managed process waiters signaled
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : pid=-1 signal=9 [vminitd] kill
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : flags=0 path=/run/container/init-test/rootfs [vminitd] umount
[ 0.541866] EXT4-fs (vdb): unmounting filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab.
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] sync
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] deleteProcess
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] deleting cgroup manager

I also re-ran the tests:

❯ swift test --filter TestCLIRunInitImage 2>&1
Building for debugging...
[7/7] Write swift-version-1C31CF501CE571A8.txt
Build complete! (0.77s)
Test Suite 'Selected tests' started at 2026-02-01 11:10:47.076.
Test Suite 'containerPackageTests.xctest' started at 2026-02-01 11:10:47.077.
Test Suite 'containerPackageTests.xctest' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.1 (c9d57c83568b06d)
↳ Target Platform: arm64-apple-macosx
◇ Suite TestCLIRunInitImage started.
◇ Test testCreateWithNonExistentInitImage() started.
◇ Test testRunWithExplicitDefaultInitImage() started.
◇ Test testInitImageFlagInHelp() started.
◇ Test testRunWithNonExistentInitImage() started.
✔ Test testInitImageFlagInHelp() passed after 0.178 seconds.
✔ Test testRunWithNonExistentInitImage() passed after 10.584 seconds.
✔ Test testCreateWithNonExistentInitImage() passed after 20.668 seconds.
✔ Test testRunWithExplicitDefaultInitImage() passed after 25.314 seconds.
✔ Suite TestCLIRunInitImage passed after 25.314 seconds.
✔ Test run with 4 tests in 1 suite passed after 25.314 seconds.

@jglogan let me know if that works for you, or if I should rather still open a fresh PR. Don't worry, I'd aim for the cleanest solution for the maintainers and the repo. Re-organizing the PR is no effort at all. Thanks for your time again!

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev In CI I'm seeing this failure:

✔ Test testCreateWithNonExistentInitImage() passed after 43.897 seconds.
✘ Test testRunWithExplicitDefaultInitImage() recorded an issue at TestCLIRunInitImage.swift:93:6: Caught error: executionFailed("command failed: Warning! Running debug build. Performance may be degraded.\nError: internalError: \"failed to create container\" (cause: \"internalError: \"XPC timeout for request to com.apple.container.apiserver/containerCreate\"\")\n")
✘ Test testRunWithExplicitDefaultInitImage() failed after 87.555 seconds with 1 issue.
↳ /// Test that explicitly specifying the default init image works the same as
↳ /// not specifying any init image.
✔ Test testRunWithNonExistentInitImage() passed after 87.606 seconds.
✘ Suite TestCLIRunInitImage failed after 87.606 seconds with 1 issue.
✘ Test run with 4 tests in 1 suite failed after 87.606 seconds with 1 issue.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 7d9a37a to baae7c7CompareFebruary 3, 2026 22:05
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks! the tests did catch an error in the image selection logic - glad they did.
I pushed a separate fix, an re-ran make integrate locally without errors.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev OK, the updated tests worked fine. One last thing (thanks for your patience!)

ContainerClient got a big refactor your changes need to be updated to work with those.

@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan no worries. I rebased against main and verified that the changes still work.
make integration runs without errors, loading a custom init-image works and starting containers without a custom init image provided works as well

@jglogan
jglogan merged commit cf9b335 into apple:mainFeb 10, 2026
3 checks passed
@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Finally got it in there...thanks for the contribution!

simone-panico pushed a commit to simone-panico/container that referenced this pull request Feb 10, 2026
…ges per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks again for guiding me!

Mcrich23 added a commit to Mcrich23/container that referenced this pull request Feb 18, 2026
commit c791052
Author: Aditya Ramani <a_ramani@apple.com>
Date: Wed Feb 18 07:43:56 2026 +0530
Add init methods for all the members of the Flags type (apple#1203)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Authors of CLI plugins for container will be able to reuse the container
flags defined in the CLI package, instead of having to duplicate them in
their project
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit dfac83d
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 17 16:54:44 2026 -0800
ContainerService: Add minimum memory amount validation (apple#1208)
Closesapple#1202
Today it's possible to pass a memory amount that very easily will cause
the container's VM to not be able to boot. We should protect against
this to avoid weird hangs/error messages. I could be convinced that a
limit should be in Containerization as well, but I think having one in
the daemon is a decent idea regardless.
commit 5385a5c
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Tue Feb 17 15:08:32 2026 -0800
Support using multiple different network plugins (apple#1151)
## Type of Change
- [x] New feature
- [x] Breaking change
## Motivation and Context
We want to be able to support using multiple network plugins during
`container`'s lifetime. This additionally means needing to pick an
interface strategy to interpret a network attachment based on what
network plugin was used to create that attachment. This PR will
potentially replace apple#1081.
Followups:
- doc updates to include the ability to specify plugin in the network
creation cli
## Testing
- [x] Tested locally
- [x] Added/updated tests
commit 7476743
Author: AJ Emory <239216119+ajemory@users.noreply.github.com>
Date: Fri Feb 13 19:27:32 2026 -0800
feat: Moving bundle creation from ContainerService to SandboxService (apple#1076)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Closesapple#1046 -- Right now we're creating container bundles in
ContainersService. Move this to the SandboxService to make it easier to
support different container bundle types.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 4c800db
Author: J Logan <john_logan@apple.com>
Date: Fri Feb 13 10:51:27 2026 -0800
Fix persistent CI failures. (apple#1205)
## Type of Change
- [x] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
- CI build is failing because runners don't have an /etc/resolver
directory, causing the directory monitor to fail. This occurs while the
install-kernel make target is running, so it appears that kernel
download is failing when it's just that the API server is dying. Created
apple#1207 for the issue.
- Fixing the initial scan for the directory just moves the problem to
the filesystem watch loop, likely because we're not testing the result
of `open()` for errors.
- Right now the priority is getting CI running and PRs merged, so just
commenting out the realhost DNS server setup.
- Also seeing that under some conditions it can take quite a while for
launchd to start the helper for the default network (8 seconds or more).
With the 10 second health check timeout after API server registration,
this means that some CI runs can exhibit this failure mode. Added a
`--timeout` option to SystemStart and set a 60 second timeout for
install-kernel and integration Makefile targets.
- Fixed a bug where `--debug` was being placed in the wrong location in
the api server startup args.
- Disabled all network CLI tests due to container bootstrap errors when
trying to run the container immediately after creating the network. The
slow network helper launch could be the reason behind the failures that
drove us to serialize these tests. Filed apple#1206 for this issue.
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit f7d00aa
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 11 15:09:21 2026 -0800
APIServer: Add support for filtering to list rpc (apple#1175)
This is not intended to be used to support `--filter` or similar on the
CLIs list yet, it's solely to clean up our rather awkward use of
`ContainerClient.list()` today in the CLI. The list RPC simply returns
all of the containers we have created. Because of this, for a LOT of our
commands we filter to what we need client side, which feels like a
waste.. This change introduces a filter struct that we can provide an
array of container IDs, labels, and the status of the containers to
filter the `list()` output from.
This additionally, because it was killing (pun not intended) me and I
was already having to change this area for the `list()` additions,
changes container kill slightly to return an error if you try and kill a
container that doesn't exist.
commit c9f81ca
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Feb 11 04:26:33 2026 +0800
Feat: add container registry list (apple#1119)
- Requires apple/containerization#502
- Closesapple#1088
---------
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit cf9b335
Author: Manu Schiller <56154253+manuschillerdev@users.noreply.github.com>
Date: Tue Feb 10 03:11:27 2026 +0100
feat: add --init-image flag for specifying custom init filesystem images per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
commit 474906d
Author: Amir Alperin <me@remotecpp.dev>
Date: Fri Feb 6 23:38:19 2026 +0200
feat: Add runtime flag to container create and run commands (apple#1049) (apple#1109)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Fixesapple#1049
- Add --runtime option for Flags.Management
- Apply runtime handler in containerConfigFromFlags
- Update command-reference.md doc
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
Co-authored-by: J Logan <john_logan@apple.com>
commit 40de343
Author: Dmitry Kovba <dkovba@apple.com>
Date: Fri Feb 6 00:41:29 2026 -0800
Fix relative path mount tests (apple#1168)
`make test` occasionally fails with:
```
✘ Test testHostDNSReinitialize() recorded an issue at HostDNSResolverTest.swift:132:45: Expectation failed: (error →
Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory") as? (ContainerizationError → NSError)
✘ Suite HostDNSResolverTest failed after 0.119 seconds with 1 issue.
```
commit aa17d46
Author: Poetry Of Code <101225909+poetryofcode@users.noreply.github.com>
Date: Fri Feb 6 03:38:21 2026 -0500
Warn user when a named volume is auto-created (apple#1108)
- Implemented the TODO at
ContainerAPIService/Client/Utility.swift:358 — warn the
user when a named volume is auto-created.
- This only triggers for named volumes (not anonymous
ones), matching Docker's behavior of informing users
about implicit resource creation.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
commit adb3c44
Author: J Logan <john_logan@apple.com>
Date: Thu Feb 5 20:19:13 2026 -0800
Don't enable selinux LSM on boot. (apple#1166)
- Closesapple#1150.
- The problem seems to be that the selinux label attribute enforcement
doesn't play well with overlayfs.
- Solution is to set the `lsm` boot line argument. The new value
corresponds to what one would see in a Lima VM with Colima. The Kata
kernel we use doesn't provide any of those modules, so now if you run
`dmesg | grep -i lsm` in a container you will just see: `LSM:
initializing lsm=capability`
commit fdeb1b1
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 10:59:31 2026 -0800
Add builder tests (apple#1154)
- Adds test for apple#1094.
- Closesapple#933 (with apple/container-builder-shim#62).
- Closesapple#425 (with apple/container-builder-shim#63).
commit fabfc55
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 09:53:31 2026 -0800
Send tar hash in the first BuildTransfer packet (apple#1149)
Send the hash of entire tar file in the first BuildTransfer packet to
prevent container-builder-shim from using stale cached contents.
This PR resolvesapple#1143.
This PR relies on apple/container-builder-shim#64.
## Type of Change
- [X] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Current container-builder-shim uses only first few bytes of tar file as
checksum, which leads to the usage of stale cached contents if the
change of build context is not included in the first bytes of tar file.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit 6e9b8d7
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Feb 5 09:47:20 2026 -0800
CLI: Forego logging errors on multi-container operations (apple#1163)
Instead of logging errors, and then additionally throwing an error
stating what containers couldn't be stopped/killed/deleted, let's just
concatenate the errors and throw the single error.
commit d79bc0d
Author: Manoj Mahapatra <mahapatra.manoj@hotmail.com>
Date: Thu Feb 5 01:16:30 2026 -0800
chore: Replace force-unwrapped String(data:encoding:) with String(decoding:as:) (apple#1164)
Use the non-optional String(decoding:as:) initializer for converting
JSON-encoded Data to String. This is safe for UTF-8 and eliminates force
commit 21dabb7
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 03:13:36 2026 -0500
[build-command]: Add --pull option for fetching latest image (apple#844)
- Closesapple#733.
commit 6553f9c
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 01:16:08 2026 -0500
[deps]: bump containerization to 0.25.0 (apple#1161)
Co-authored-by: saehejkang <saehej.kang@gmail.com>
Co-authored-by: Anthony DePasquale <anthony@depasquale.org>
- Bump `containerization` to `0.25.0`
- Updates for parameter changes on containerization
registry access API.
- Updates for change to containerization
`cleanUpOrphanedBlobs` function.
commit 2d1dd6b
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 15:42:29 2026 -0800
Fix file path for the PR number in the PR labeler workflow (apple#1158)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR label applier GitHub workflow has been failing for a while. This
PR fixes that by correcting the file path we look for when trying to
read the PR number. See example failure here
https://github.com/apple/container/actions/runs/21691766538/job/62552959972#step:4:23
commit 6451e07
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 14:44:53 2026 -0800
Add debugging to the PR labeler CI flow (apple#1155)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR labeler workflow has been failing for a while but it's difficult
to know how to fix it since the PR labeler workflow is run from main
(aka NOT the current PR branch) for security reasons. Example at
https://github.com/apple/container/actions/runs/21690229300/workflow
commit 8fdfa29
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:52:09 2026 -0800
CLI: Rework ClientContainer (apple#1139)
ClientContainer was honestly extremely awkward. It could only be created
by passing either a ContainerConfiguration, or a Snapshot that had to be
obtained from calling a static method on the type itself. The type also
did not store a connection, so every single method got a new xpc
connection to the APIServer. This change aims to rework this type to be
just a generic client, that is *not* a client for one specific
container, but for any.
- Rename to ContainerClient
- Have list() return [ContainerSnapshot]
- Create a connection in the constructor
- Change all the callsites to use the new API
- Small, somewhat related, change to logs API in the APIServer. Now that
we don't need to call get() to grab a client anymore which was typically
what did "does this container exist" logic and gave a nice error
message, I added a small check in the APIServer to see if the container
exists and return mostly the same error message.
commit 23c0ece
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:19:50 2026 -0800
CI: Add signed commit check (apple#1152)
This requirement of ours often goes unnoticed because nothing yells at
you openly about it. Lets fail CI to make it more obvious.
commit ce1b629
Author: Manoj Mahapatra <mahaplipsa@gmail.com>
Date: Tue Feb 3 13:43:07 2026 -0800
[Docs] Fix typo in BUILDING.md: launchd -> launchctl (apple#1146)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [x] Documentation update
## Motivation and Context
The debug instructions in `BUILDING.md` incorrectly reference launchd
list instead of `launchctl` list. `launchd` is the daemon itself and
cannot be invoked directly.
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [x] Added/updated docs
commit 3e49dce
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 3 00:45:01 2026 -0800
Add in missing rlimits (apple#1140)
Containerization didn't have these defined until a recent tag.
commit c4c2e85
Author: J Logan <john_logan@apple.com>
Date: Tue Feb 3 00:27:09 2026 -0800
Upgrade kernel to Kata 3.26.0. (apple#1134)
- Upgrade to containerization 0.24.5 to pick up zstd decompression
enhancement.
- Closesapple#767.
- Closesapple#988.
- Closesapple#1132.
- Requires apple/containerization#508.
commit 5c86337
Author: William Laverty <developer@william-laverty.com>
Date: Mon Feb 2 13:57:59 2026 -0800
Add explanatory message before admin password prompt in uninstall script (apple#1118)
- Added message: "This script requires an administrator password to
remove the application files from system directories."
- Fixesapple#1111
commit 7da25e1
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:35:02 2026 -0800
Deps: Bump Containerization to 0.24.0 (apple#1127)
Brings in some rlimit bumps/adjustments
commit 7dfe27d
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:30:19 2026 -0800
CLI: Add support for rlimits (apple#1129)
Closesapple#1097.
commit b3b5c3e
Author: J Logan <john_logan@apple.com>
Date: Mon Feb 2 12:24:27 2026 -0800
Use labels instead of id to discriminate the builtin network. (apple#1123)
- Closesapple#1122.
- Adds placeholder ManagedResource and unit tests. Nothing is using
these yet.
- Adds system-defined resource labels for owning plugin and resource
role. The system discriminates the builtin network using role "builtin".
- Adds builtin role when creating builtin network at startup, and
ensures that a preexisting network with ID "default" gets updated with
the role label.
- Replace all network ID checks for "default" with the builtin role
check.
- Adds "builder" role to builder VM.
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Role and owner labels should make cross-cutting resource policy easier
to implement.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 1dae1cd
Author: w-ferg <43309695+w-ferg@users.noreply.github.com>
Date: Sun Feb 1 18:14:41 2026 -0500
Fix pfctl executable path in PacketFilter DNS reload (apple#1128)
## Summary
The `reload()` method in `PacketFilter.swift` references
`/sbin/reloadProcess` (the local variable name) instead of
`/sbin/pfctl`. This causes all DNS create and delete operations to fail:
```
Error: internalError: "pfctl reload exec failed: "Error Domain=NSCocoaErrorDomain Code=4 "The file "reloadProcess" doesn't exist.""
```
## Fix
One-line change: `/sbin/reloadProcess` → `/sbin/pfctl`
## Testing
Verified on macOS 26 (Tahoe) with Apple Silicon:
- `sudo container system dns create test.sdc.internal --localhost
203.0.113.1` succeeds without error
- Container can resolve and reach host services through the DNS redirect
commit 113a6ec
Author: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Date: Fri Jan 30 21:54:57 2026 -0600
Fix file descriptor leak in DirectoryWatcher (apple#1104)
- `DirectoryWatcher` opens file descriptors for monitoring
directories but never closes them, causing a file descriptor
leak.
- Adds `setCancelHandler` to properly close file descriptors
when the `DispatchSource` is cancelled.
Signed-off-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
commit 72f04b6
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Fri Jan 30 19:10:03 2026 -0800
[docs]: update steps on building with containerization project (apple#1116)
- Closesapple#1095
- Just added a few more details about how to build with the local
`containerization` dependency.
commit 3a0ad58
Author: Raj <rajaryan_singh@apple.com>
Date: Fri Jan 30 16:17:43 2026 -0800
Add resource.role label to builder container (apple#1120)
Add resource.role label to builder container
commit 1c01d0c
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 30 11:07:49 2026 -0800
Update to kata 3.20.0 kernel. (apple#1114)
- Closesapple#1113.
- This is the newest we can do until we address apple#767.
- Slight change to PacketFilter error handling so unit tests work more
reliably.
- Try making CLINetworkTests serialized to see if parallel execution is
causing flakes.
commit 3f2060e
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 18:25:48 2026 -0800
DirectoryWatcher: Small adjustments (apple#1112)
- Have the handler throw
- Log the failure at error level
commit 0a7fb07
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 14:21:12 2026 -0800
Set mtu to old Containerization default (apple#1110)
The old mtu default in containerization was 1280 to account for some
alpine/musl images that have issues with
1500. This changed in the last couple tags to be modifiable, but the new
default is the standard 1500. Ideally we eventually allow supplying the
mtu to be used when you create a network (or possibly a container
creation setting), but for now just default in here back to what CZ used
to use.
commit 0bceb23
Author: Aditya Ramani <a_ramani@apple.com>
Date: Thu Jan 29 12:08:42 2026 +0900
Bump to use containerization 0.23.2 (apple#1106)
Updating the package dependency on apple/containerization to pick up bug fixes
Signed-off-by: Aditya Ramani <a_ramani@apple.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit d762fe5
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 18:22:33 2026 -0800
Launch a service with waitForDebugger if specified (apple#1101)
This PR enables launching a service with `waitForDebugger` flag if the
service label matches a given env variable `CONTAINER_DEBUG`.
commit 4f93e3e
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed Jan 28 18:21:08 2026 -0800
ci: bump actions/checkout from 6.0.1 to 6.0.2 in the github-actions group (apple#1100)
- Updates `actions/checkout` from 6.0.1 to 6.0.2
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
commit 371db6d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 17:17:08 2026 -0800
Fix testExecOnExitingContainer (apple#1107)
Check the container remains only, not its status as the status might not
have been updated at the time checking.
commit d872270
Author: J Logan <john_logan@apple.com>
Date: Wed Jan 28 09:04:58 2026 -0800
Removes ArgumentParser import from NetworkMode. (apple#1102)
- ContainerResources shouldn't need to know anything about CLI stuff.
- Move ExpressibleByArgument protocol conformance to an extension in the
package where it's needed.
commit 3abf81f
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Tue Jan 27 20:00:43 2026 -0800
[image-list]: Add full size field to json output (apple#1098)
- Refer to apple#862
- Updated `SIZE` field to `FULL SIZE`, as it seemed more appropriate so
it does not get mixed up with the `descriptor size` field
- Closesapple#860
commit 24cbed5
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Jan 28 06:55:49 2026 +0800
Implement container prune (apple#904)
- Fixedapple#892.
- By contrast with `rm`, `prune` should display
the amount of reclaimed storage, so added code
to retrieve it.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit a57527e
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Tue Jan 27 11:15:22 2026 -0800
Refactor container lifecycle functions to perform scoped rollback on failure (apple#1080)
- Closesapple#977.
- Closesapple#1058.
- Prevents unexpected removal of containers on
bootstrapping and starting failures, by reorganizing
error handling for container `run`, `start`, and
`exec` so that error handling only unwinds that
which was done in the current scope.
- Relies on apple/containerization#495.
commit 6244129
Author: c <claudeaceae@icloud.com>
Date: Mon Jan 26 23:30:45 2026 -0500
Fix grammar in BUILDING.md (apple#984)
- Fixes a grammar error in the local Containerization development
instructions.
commit 9d4cded
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Mon Jan 26 19:35:41 2026 -0800
Isolated network (apple#1079)
- Closesapple#1037.
- Adds a `--mode` flag that has `nat` and `hostOnly` options.
The host-only option selects the vmnet host-only mode,
where containers attached to the network can reach each
other and the host, but not external systems.
commit 033c999
Author: J Logan <john_logan@apple.com>
Date: Mon Jan 26 14:07:00 2026 -0800
Make TerminalProgress a library. (apple#1093)
- Closesapple#1092.
- Allows 3rd party CLI plugins to use the progress indicator.
commit b371aee
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Tue Jan 27 05:07:05 2026 +0800
Feat: container image delete force option (apple#1096)
- Fixedapple#1087
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit ed1185d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Fri Jan 23 17:59:28 2026 -0800
Container-to-host networking. (apple#1078)
- Closesapple#346.
- This PR enables connecting host's localhost ports from
containers.
- It adds an option `--localhost <localhost>` to DNS
create command, after which the packets heading
ip address in container are redirected to localhost in
host machine. Packet filter rule is added and deleted
along with the creation and deletion of localhost domain.
commit 14c279f
Author: Patrick Linnane <patrick@linnane.io>
Date: Fri Jan 23 17:56:35 2026 -0800
Add option to stop services in all launchd domains (apple#1077)
- Services started from Terminal run in the `gui/$uid`
launchd domain. When `ensure-container-stopped.sh`
runs from a different context, `launchctl managername`
may return a different domain, causing the script to
check the wrong domain and miss running services.
I noticed this after upgrading `container` via Homebrew.
- Introduces a getopt option `-a` that allows booting out all
domains explicitly. Also adds `-h` for a usage message.
Signed-off-by: Patrick Linnane <patrick@linnane.io>
commit 751c1fc
Author: Stanislav Antonichev <cympak2@users.noreply.github.com>
Date: Fri Jan 23 23:01:26 2026 +0200
Add --dns support to build command for custom DNS resolution (apple#1067)
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
Changes:
- Added --dns option to BuildCommand to accept DNS nameserver IP
addresses
- Modified build logic to detect DNS configuration changes and recreate
the builder container when DNS settings differ
- Passed DNS configuration to BuilderStart.start() method
- Updated builder container creation to use specified DNS nameservers or
fall back to network gateway
## Type of Change
- [ ] Bug fix
- [X] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: J Logan <sgtbakerrahulnet@yahoo.com>
commit 55f2112
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 23 11:35:10 2026 -0800
Place image store data correctly for app-root path. (apple#1085)
- Closesapple#1084.
commit 5746ec3
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Sat Jan 24 03:32:59 2026 +0800
Fix: prevent delete default network (apple#1083)
- Fixedapple#1073
- Move the conditional check to the front; there's no need
to check for a default network after filtering.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@manuschillerdev@jglogan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add --init-image flag for specifying custom init filesystem images per VM - #937

Merged
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image
Feb 10, 2026
Merged

feat: add --init-image flag for specifying custom init filesystem images per VM#937
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image

Conversation

@manuschillerdev

@manuschillerdevmanuschillerdev commented Dec 7, 2025

Copy link
Copy Markdown
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

I've been tinkering with ways to extend container with a primitive for interacting with the VM layer. One approach: expose the internal init filesystem as a user-configurable option via --init-image.

What this enables:

  • Custom boot-time logic before the OCI container starts
  • Running additional processes and daemons (e.g., daemons to configure eBPF network filters, logging agents) inside the VM (not the container)
  • Debugging/instrumenting the init process

--init-image vs using the system property
we could also use container system property set image.init vminit:latest (documented via #1032), but this affects all VMs. I want to be able to override this only for a single VM.

In my current approach, the custom image wraps the default vminitd, so it's currently behaving like an entrypoint.
Curious if this direction aligns with the project's goals, or if there's a better abstraction for these use cases.
If there is interest, I would add proper docs and tests.

Example for a minimal entry point binary
Note: We use Go here for its straightforward cross-compilation to Linux ARM64.

// custom-init/wrapper.gopackage main
import (
"fmt""os""syscall"
)
funcmain() {
kmsg, err:=os.OpenFile("/dev/kmsg", os.O_WRONLY, 0)
iferr==nil {
kmsg.WriteString("<6>custom-init: === CUSTOM INIT IMAGE RUNNING ===\n")
kmsg.Close()
}
err=syscall.Exec("/sbin/vminitd.real", os.Args, os.Environ())
iferr!=nil {
fmt.Fprintf(os.Stderr, "Failed to exec vminitd.real: %v\n", err)
os.Exit(1)
}
}

Containerfile

# custom-init/Containerfile
FROM ghcr.io/apple/containerization/vminit:0.23.2 AS base
FROM ghcr.io/apple/containerization/vminit:0.23.2
COPY --from=base /sbin/vminitd /sbin/vminitd.real
COPY wrapper /sbin/vminitd
  • build the binary with cd custom-init && CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o wrapper wrapper.go
  • build the image with bin/container build -t local/custom-init:0.20.0 custom-init/
  • run the container with our custom init-image: bin/container run --name init-test --init-image local/custom-init:0.20.0 alpine:latest echo "hello"
  • check the logs with cat "/Users/$USER/Library/Application Support/com.apple.container/containers/init-test/vminitd.log" | head -50

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

@manuschillerdevmanuschillerdev changed the title feat: add init-image flag for specifying custom init filesystem images per VMfeat: add --init-image flag for specifying custom init filesystem images per VMDec 7, 2025
@jglogan

Copy link
Copy Markdown
Contributor

@dcantah see also #838

Comment threadSources/ContainerClient/Utility.swift
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@dcantah@jglogan would that be of interest for the project? Would be totally open to other suggestions on how one can interact with the startup process. Exposing --init-fs seemed like a viable option here

@manuschillerdev

manuschillerdev commented Jan 10, 2026

Copy link
Copy Markdown
ContributorAuthor

@jglogan@dcantah

I've rebased the PR, added tests and documentation, and updated the description to clarify why container system property set image.init doesn't fit my use case (it applies globally rather than per-VM).

Happy to elaborate on any open questions or explore alternative approaches that would better align with the project's architecture.
I'd appreciate any feedback on whether this direction makes sense to pursue or if there are concerns that would make it worth closing in favor of a different approach.

@jglogan

jglogan commented Jan 17, 2026

Copy link
Copy Markdown
Contributor

@manuschillerdev I haven't been able to review but it seems reasonable. Kernel and initfs config are birds of a feather, whatever config options exist for one, we should eventually provide for the other.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Could you run make fmt on this, and make sure build/test runs okay on your end, and then try pushing the changes? I made one change to resolve some merge conflicts on the Makefile

@jglogan

Copy link
Copy Markdown
Contributor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 5badfb6 to 6e1d1faCompareFebruary 1, 2026 10:15
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

thanks for having another look at this! I rebased the PR against main, resolved the conflicts, ran make fmt, and did a complete re-test locally with the steps from the PR description:

❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"| grep "==="
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
full output of vminitd.log after creating a custom init image, and starting a fresh container using the `--init-image` flag:
❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"
[ 0.069458] random: crng init done
[ 0.070722] brd: module loaded
[ 0.071338] loop: module loaded
[ 0.071436] virtio_blk virtio2: 1/0/0 default/read/poll queues
[ 0.071600] virtio_blk virtio2: [vda] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.071875] virtio_blk virtio3: 1/0/0 default/read/poll queues
[ 0.072020] virtio_blk virtio3: [vdb] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.072226] tun: Universal TUN/TAP device driver, 1.6
[ 0.072687] VFIO - User Level meta-driver version: 0.3
[ 0.072820] rtc-pl031 20050000.pl031: registered as rtc0
[ 0.072857] rtc-pl031 20050000.pl031: setting system clock to 2026-02-01T08:49:54 UTC (1769935794)
[ 0.073306] xt_time: kernel timezone is -0000
[ 0.073348] IPVS: Registered protocols (TCP, UDP, SCTP, AH, ESP)
[ 0.073434] IPVS: Connection hash table configured (size=4096, memory=32Kbytes)
[ 0.073579] IPVS: ipvs loaded.
[ 0.073615] IPVS: [rr] scheduler registered.
[ 0.073634] IPVS: [wrr] scheduler registered.
[ 0.073685] IPVS: [lc] scheduler registered.
[ 0.073718] IPVS: [wlc] scheduler registered.
[ 0.073767] IPVS: [fo] scheduler registered.
[ 0.073813] IPVS: [ovf] scheduler registered.
[ 0.073862] IPVS: [lblc] scheduler registered.
[ 0.073924] IPVS: [lblcr] scheduler registered.
[ 0.073942] IPVS: [dh] scheduler registered.
[ 0.073966] IPVS: [sh] scheduler registered.
[ 0.073991] IPVS: [sed] scheduler registered.
[ 0.074016] IPVS: [nq] scheduler registered.
[ 0.074043] IPVS: [sip] pe registered.
[ 0.074088] Initializing XFRM netlink socket
[ 0.074130] NET: Registered PF_INET6 protocol family
[ 0.074389] Segment Routing with IPv6
[ 0.074421] In-situ OAM (IOAM) with IPv6
[ 0.074462] NET: Registered PF_PACKET protocol family
[ 0.074505] 9pnet: Installing 9P2000 support
[ 0.074573] NET: Registered PF_VSOCK protocol family
[ 0.075578] registered taskstats version 1
[ 0.076957] alg: No testfor fips(ansi_cprng) (fips_ansi_cprng)
[ 0.077498] clk: Disabling unused clocks
[ 0.080034] EXT4-fs (vda): mounted filesystem 63cb0698-b5fe-4f00-ba03-179297b9693a ro without journal. Quota mode: disabled.
[ 0.080117] VFS: Mounted root (ext4 filesystem) readonly on device 254:0.
[ 0.080441] devtmpfs: mounted
[ 0.080801] Freeing unused kernel memory: 1856K
[ 0.080895] Run /sbin/vminitd as init process
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
2026-02-01T08:49:54+0000 info vminitd : [vminitd] Running init command
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /proc
2026-02-01T08:49:54+0000 info vminitd : [vminitd] vminitd booting
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /run
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys/fs/cgroup
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 debug vminitd : bytes=78643200 path=/sys/fs/cgroup/vminitd [Cgroup] setting memory.high
2026-02-01T08:49:54+0000 debug vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] adding new proc to cgroup
2026-02-01T08:49:54+0000 info vminitd : events_path=/sys/fs/cgroup/vminitd/memory.events threshold_bytes=78643200 [vminitd] Started memory monitoring
2026-02-01T08:49:54+0000 info vminitd : [vminitd] serving vminitd API
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] starting process supervisor
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] booting gRPC server on vsock
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] gRPC API serving on vsock
2026-02-01T08:49:54+0000 debug vminitd : interface=lo up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : key=PATH value=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [vminitd] setenv
2026-02-01T08:49:54+0000 debug vminitd : destination=/tmp source=tmpfs type=tmpfs [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/dev/pts source=devpts type=devpts [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/run/container/init-test/rootfs source=/dev/vdb type=ext4 [vminitd] mount
[ 0.268991] EXT4-fs (vdb): mounted filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab r/w without journal. Quota mode: disabled.
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Address=192.168.64.3/24 [vminitd] ipAddrAdd
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Gateway=192.168.64.1 [vminitd] ipRouteAddDefault
2026-02-01T08:49:54+0000 debug vminitd : domain= location=/run/container/init-test/rootfs nameservers=["192.168.64.1"] options=[] searchDomains=[] [vminitd] configureDns
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] writing to path /run/container/init-test/rootfs/etc/resolv.conf nameserver 192.168.64.1
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/resolv.conf [vminitd] wrote resolver configuration
2026-02-01T08:49:54+0000 debug vminitd : location=/run/container/init-test/rootfs [vminitd] configureHosts
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/hosts [vminitd] wrote /etc/hosts configuration
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test stderr=Port: 268435457 stdin=Port: 0 stdout=Port: 268435456 [vminitd] createProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] created bundle with spec Spec(version: "", hooks: nil, process: Optional(ContainerizationOCI.Process(cwd: "/", env: ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME=/root"], consoleSize: nil, selinuxLabel: "", noNewPrivileges: false, commandLine: "", oomScoreAdj: nil, capabilities: Optional(ContainerizationOCI.LinuxCapabilities(bounding: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), effective: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), inheritable: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), permitted: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), ambient: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]))), apparmorProfile: "", user: ContainerizationOCI.User(uid: 0, gid: 0, umask: nil, additionalGids: [0], username: ""), rlimits: [], args: ["echo", "hello"], terminal: false)), hostname: "init-test", domainname: "", mounts: [ContainerizationOCI.Mount(type: "proc", source: "proc", destination: "/proc", options: [], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "sysfs", source: "sysfs", destination: "/sys", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devtmpfs", source: "none", destination: "/dev", options: ["nosuid", "mode=755"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "mqueue", source: "mqueue", destination: "/dev/mqueue", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "tmpfs", source: "tmpfs", destination: "/dev/shm", options: ["nosuid", "noexec", "nodev", "mode=1777", "size=65536k"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "cgroup2", source: "none", destination: "/sys/fs/cgroup", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devpts", source: "devpts", destination: "/dev/pts", options: ["nosuid", "noexec", "newinstance", "gid=5", "mode=0620", "ptmxmode=0666"], uidMappings: nil, gidMappings: nil)], annotations: nil, root: Optional(ContainerizationOCI.Root(path: "/run/container/init-test/rootfs", readonly: false)), linux: Optional(ContainerizationOCI.Linux(uidMappings: [], gidMappings: [], sysctl: Optional([:]), resources: Optional(ContainerizationOCI.LinuxResources(devices: [], memory: Optional(ContainerizationOCI.LinuxMemory(limit: Optional(1073741824), reservation: nil, swap: nil, kernel: nil, kernelTCP: nil, swappiness: nil, disableOOMKiller: nil, useHierarchy: nil, checkBeforeUpdate: nil)), cpu: Optional(ContainerizationOCI.LinuxCPU(shares: nil, quota: Optional(400000), burst: nil, period: Optional(100000), realtimeRuntime: nil, realtimePeriod: nil, cpus: "", mems: "", idle: nil)), pids: nil, blockIO: nil, hugepageLimits: [], network: nil, rdma: nil, unified: Optional([:]))), cgroupsPath: "/container/init-test", namespaces: [ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.cgroup, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.ipc, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.mount, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.pid, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.uts, path: "")], devices: [], seccomp: nil, rootfsPropagation: "", maskedPaths: [], readonlyPaths: [], mountLabel: "", personality: nil)))
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting I/O
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stderr
2026-02-01T08:49:54+0000 info vminitd : [vminitd] created vmexec init process
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] startProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] in supervisor lock to start process
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting managed process
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78381056 high_events_total=1 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78442496 high_events_total=15 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78331904 high_events_total=18 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] got back pid data
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] sending pid acknowledgement
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[93: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] started managed process
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[94: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 debug vminitd : count=0 pid=94 status=0 [vminitd] managed process exited
2026-02-01T08:49:54+0000 info vminitd : id=init-test status=0 [vminitd] managed process exit
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stderr
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] 0 managed process waiters signaled
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : pid=-1 signal=9 [vminitd] kill
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : flags=0 path=/run/container/init-test/rootfs [vminitd] umount
[ 0.541866] EXT4-fs (vdb): unmounting filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab.
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] sync
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] deleteProcess
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] deleting cgroup manager

I also re-ran the tests:

❯ swift test --filter TestCLIRunInitImage 2>&1
Building for debugging...
[7/7] Write swift-version-1C31CF501CE571A8.txt
Build complete! (0.77s)
Test Suite 'Selected tests' started at 2026-02-01 11:10:47.076.
Test Suite 'containerPackageTests.xctest' started at 2026-02-01 11:10:47.077.
Test Suite 'containerPackageTests.xctest' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.1 (c9d57c83568b06d)
↳ Target Platform: arm64-apple-macosx
◇ Suite TestCLIRunInitImage started.
◇ Test testCreateWithNonExistentInitImage() started.
◇ Test testRunWithExplicitDefaultInitImage() started.
◇ Test testInitImageFlagInHelp() started.
◇ Test testRunWithNonExistentInitImage() started.
✔ Test testInitImageFlagInHelp() passed after 0.178 seconds.
✔ Test testRunWithNonExistentInitImage() passed after 10.584 seconds.
✔ Test testCreateWithNonExistentInitImage() passed after 20.668 seconds.
✔ Test testRunWithExplicitDefaultInitImage() passed after 25.314 seconds.
✔ Suite TestCLIRunInitImage passed after 25.314 seconds.
✔ Test run with 4 tests in 1 suite passed after 25.314 seconds.

@jglogan let me know if that works for you, or if I should rather still open a fresh PR. Don't worry, I'd aim for the cleanest solution for the maintainers and the repo. Re-organizing the PR is no effort at all. Thanks for your time again!

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev In CI I'm seeing this failure:

✔ Test testCreateWithNonExistentInitImage() passed after 43.897 seconds.
✘ Test testRunWithExplicitDefaultInitImage() recorded an issue at TestCLIRunInitImage.swift:93:6: Caught error: executionFailed("command failed: Warning! Running debug build. Performance may be degraded.\nError: internalError: \"failed to create container\" (cause: \"internalError: \"XPC timeout for request to com.apple.container.apiserver/containerCreate\"\")\n")
✘ Test testRunWithExplicitDefaultInitImage() failed after 87.555 seconds with 1 issue.
↳ /// Test that explicitly specifying the default init image works the same as
↳ /// not specifying any init image.
✔ Test testRunWithNonExistentInitImage() passed after 87.606 seconds.
✘ Suite TestCLIRunInitImage failed after 87.606 seconds with 1 issue.
✘ Test run with 4 tests in 1 suite failed after 87.606 seconds with 1 issue.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 7d9a37a to baae7c7CompareFebruary 3, 2026 22:05
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks! the tests did catch an error in the image selection logic - glad they did.
I pushed a separate fix, an re-ran make integrate locally without errors.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev OK, the updated tests worked fine. One last thing (thanks for your patience!)

ContainerClient got a big refactor your changes need to be updated to work with those.

@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan no worries. I rebased against main and verified that the changes still work.
make integration runs without errors, loading a custom init-image works and starting containers without a custom init image provided works as well

@jglogan
jglogan merged commit cf9b335 into apple:mainFeb 10, 2026
3 checks passed
@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Finally got it in there...thanks for the contribution!

simone-panico pushed a commit to simone-panico/container that referenced this pull request Feb 10, 2026
…ges per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks again for guiding me!

Mcrich23 added a commit to Mcrich23/container that referenced this pull request Feb 18, 2026
commit c791052
Author: Aditya Ramani <a_ramani@apple.com>
Date: Wed Feb 18 07:43:56 2026 +0530
Add init methods for all the members of the Flags type (apple#1203)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Authors of CLI plugins for container will be able to reuse the container
flags defined in the CLI package, instead of having to duplicate them in
their project
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit dfac83d
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 17 16:54:44 2026 -0800
ContainerService: Add minimum memory amount validation (apple#1208)
Closesapple#1202
Today it's possible to pass a memory amount that very easily will cause
the container's VM to not be able to boot. We should protect against
this to avoid weird hangs/error messages. I could be convinced that a
limit should be in Containerization as well, but I think having one in
the daemon is a decent idea regardless.
commit 5385a5c
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Tue Feb 17 15:08:32 2026 -0800
Support using multiple different network plugins (apple#1151)
## Type of Change
- [x] New feature
- [x] Breaking change
## Motivation and Context
We want to be able to support using multiple network plugins during
`container`'s lifetime. This additionally means needing to pick an
interface strategy to interpret a network attachment based on what
network plugin was used to create that attachment. This PR will
potentially replace apple#1081.
Followups:
- doc updates to include the ability to specify plugin in the network
creation cli
## Testing
- [x] Tested locally
- [x] Added/updated tests
commit 7476743
Author: AJ Emory <239216119+ajemory@users.noreply.github.com>
Date: Fri Feb 13 19:27:32 2026 -0800
feat: Moving bundle creation from ContainerService to SandboxService (apple#1076)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Closesapple#1046 -- Right now we're creating container bundles in
ContainersService. Move this to the SandboxService to make it easier to
support different container bundle types.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 4c800db
Author: J Logan <john_logan@apple.com>
Date: Fri Feb 13 10:51:27 2026 -0800
Fix persistent CI failures. (apple#1205)
## Type of Change
- [x] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
- CI build is failing because runners don't have an /etc/resolver
directory, causing the directory monitor to fail. This occurs while the
install-kernel make target is running, so it appears that kernel
download is failing when it's just that the API server is dying. Created
apple#1207 for the issue.
- Fixing the initial scan for the directory just moves the problem to
the filesystem watch loop, likely because we're not testing the result
of `open()` for errors.
- Right now the priority is getting CI running and PRs merged, so just
commenting out the realhost DNS server setup.
- Also seeing that under some conditions it can take quite a while for
launchd to start the helper for the default network (8 seconds or more).
With the 10 second health check timeout after API server registration,
this means that some CI runs can exhibit this failure mode. Added a
`--timeout` option to SystemStart and set a 60 second timeout for
install-kernel and integration Makefile targets.
- Fixed a bug where `--debug` was being placed in the wrong location in
the api server startup args.
- Disabled all network CLI tests due to container bootstrap errors when
trying to run the container immediately after creating the network. The
slow network helper launch could be the reason behind the failures that
drove us to serialize these tests. Filed apple#1206 for this issue.
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit f7d00aa
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 11 15:09:21 2026 -0800
APIServer: Add support for filtering to list rpc (apple#1175)
This is not intended to be used to support `--filter` or similar on the
CLIs list yet, it's solely to clean up our rather awkward use of
`ContainerClient.list()` today in the CLI. The list RPC simply returns
all of the containers we have created. Because of this, for a LOT of our
commands we filter to what we need client side, which feels like a
waste.. This change introduces a filter struct that we can provide an
array of container IDs, labels, and the status of the containers to
filter the `list()` output from.
This additionally, because it was killing (pun not intended) me and I
was already having to change this area for the `list()` additions,
changes container kill slightly to return an error if you try and kill a
container that doesn't exist.
commit c9f81ca
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Feb 11 04:26:33 2026 +0800
Feat: add container registry list (apple#1119)
- Requires apple/containerization#502
- Closesapple#1088
---------
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit cf9b335
Author: Manu Schiller <56154253+manuschillerdev@users.noreply.github.com>
Date: Tue Feb 10 03:11:27 2026 +0100
feat: add --init-image flag for specifying custom init filesystem images per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
commit 474906d
Author: Amir Alperin <me@remotecpp.dev>
Date: Fri Feb 6 23:38:19 2026 +0200
feat: Add runtime flag to container create and run commands (apple#1049) (apple#1109)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Fixesapple#1049
- Add --runtime option for Flags.Management
- Apply runtime handler in containerConfigFromFlags
- Update command-reference.md doc
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
Co-authored-by: J Logan <john_logan@apple.com>
commit 40de343
Author: Dmitry Kovba <dkovba@apple.com>
Date: Fri Feb 6 00:41:29 2026 -0800
Fix relative path mount tests (apple#1168)
`make test` occasionally fails with:
```
✘ Test testHostDNSReinitialize() recorded an issue at HostDNSResolverTest.swift:132:45: Expectation failed: (error →
Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory") as? (ContainerizationError → NSError)
✘ Suite HostDNSResolverTest failed after 0.119 seconds with 1 issue.
```
commit aa17d46
Author: Poetry Of Code <101225909+poetryofcode@users.noreply.github.com>
Date: Fri Feb 6 03:38:21 2026 -0500
Warn user when a named volume is auto-created (apple#1108)
- Implemented the TODO at
ContainerAPIService/Client/Utility.swift:358 — warn the
user when a named volume is auto-created.
- This only triggers for named volumes (not anonymous
ones), matching Docker's behavior of informing users
about implicit resource creation.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
commit adb3c44
Author: J Logan <john_logan@apple.com>
Date: Thu Feb 5 20:19:13 2026 -0800
Don't enable selinux LSM on boot. (apple#1166)
- Closesapple#1150.
- The problem seems to be that the selinux label attribute enforcement
doesn't play well with overlayfs.
- Solution is to set the `lsm` boot line argument. The new value
corresponds to what one would see in a Lima VM with Colima. The Kata
kernel we use doesn't provide any of those modules, so now if you run
`dmesg | grep -i lsm` in a container you will just see: `LSM:
initializing lsm=capability`
commit fdeb1b1
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 10:59:31 2026 -0800
Add builder tests (apple#1154)
- Adds test for apple#1094.
- Closesapple#933 (with apple/container-builder-shim#62).
- Closesapple#425 (with apple/container-builder-shim#63).
commit fabfc55
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 09:53:31 2026 -0800
Send tar hash in the first BuildTransfer packet (apple#1149)
Send the hash of entire tar file in the first BuildTransfer packet to
prevent container-builder-shim from using stale cached contents.
This PR resolvesapple#1143.
This PR relies on apple/container-builder-shim#64.
## Type of Change
- [X] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Current container-builder-shim uses only first few bytes of tar file as
checksum, which leads to the usage of stale cached contents if the
change of build context is not included in the first bytes of tar file.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit 6e9b8d7
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Feb 5 09:47:20 2026 -0800
CLI: Forego logging errors on multi-container operations (apple#1163)
Instead of logging errors, and then additionally throwing an error
stating what containers couldn't be stopped/killed/deleted, let's just
concatenate the errors and throw the single error.
commit d79bc0d
Author: Manoj Mahapatra <mahapatra.manoj@hotmail.com>
Date: Thu Feb 5 01:16:30 2026 -0800
chore: Replace force-unwrapped String(data:encoding:) with String(decoding:as:) (apple#1164)
Use the non-optional String(decoding:as:) initializer for converting
JSON-encoded Data to String. This is safe for UTF-8 and eliminates force
commit 21dabb7
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 03:13:36 2026 -0500
[build-command]: Add --pull option for fetching latest image (apple#844)
- Closesapple#733.
commit 6553f9c
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 01:16:08 2026 -0500
[deps]: bump containerization to 0.25.0 (apple#1161)
Co-authored-by: saehejkang <saehej.kang@gmail.com>
Co-authored-by: Anthony DePasquale <anthony@depasquale.org>
- Bump `containerization` to `0.25.0`
- Updates for parameter changes on containerization
registry access API.
- Updates for change to containerization
`cleanUpOrphanedBlobs` function.
commit 2d1dd6b
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 15:42:29 2026 -0800
Fix file path for the PR number in the PR labeler workflow (apple#1158)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR label applier GitHub workflow has been failing for a while. This
PR fixes that by correcting the file path we look for when trying to
read the PR number. See example failure here
https://github.com/apple/container/actions/runs/21691766538/job/62552959972#step:4:23
commit 6451e07
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 14:44:53 2026 -0800
Add debugging to the PR labeler CI flow (apple#1155)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR labeler workflow has been failing for a while but it's difficult
to know how to fix it since the PR labeler workflow is run from main
(aka NOT the current PR branch) for security reasons. Example at
https://github.com/apple/container/actions/runs/21690229300/workflow
commit 8fdfa29
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:52:09 2026 -0800
CLI: Rework ClientContainer (apple#1139)
ClientContainer was honestly extremely awkward. It could only be created
by passing either a ContainerConfiguration, or a Snapshot that had to be
obtained from calling a static method on the type itself. The type also
did not store a connection, so every single method got a new xpc
connection to the APIServer. This change aims to rework this type to be
just a generic client, that is *not* a client for one specific
container, but for any.
- Rename to ContainerClient
- Have list() return [ContainerSnapshot]
- Create a connection in the constructor
- Change all the callsites to use the new API
- Small, somewhat related, change to logs API in the APIServer. Now that
we don't need to call get() to grab a client anymore which was typically
what did "does this container exist" logic and gave a nice error
message, I added a small check in the APIServer to see if the container
exists and return mostly the same error message.
commit 23c0ece
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:19:50 2026 -0800
CI: Add signed commit check (apple#1152)
This requirement of ours often goes unnoticed because nothing yells at
you openly about it. Lets fail CI to make it more obvious.
commit ce1b629
Author: Manoj Mahapatra <mahaplipsa@gmail.com>
Date: Tue Feb 3 13:43:07 2026 -0800
[Docs] Fix typo in BUILDING.md: launchd -> launchctl (apple#1146)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [x] Documentation update
## Motivation and Context
The debug instructions in `BUILDING.md` incorrectly reference launchd
list instead of `launchctl` list. `launchd` is the daemon itself and
cannot be invoked directly.
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [x] Added/updated docs
commit 3e49dce
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 3 00:45:01 2026 -0800
Add in missing rlimits (apple#1140)
Containerization didn't have these defined until a recent tag.
commit c4c2e85
Author: J Logan <john_logan@apple.com>
Date: Tue Feb 3 00:27:09 2026 -0800
Upgrade kernel to Kata 3.26.0. (apple#1134)
- Upgrade to containerization 0.24.5 to pick up zstd decompression
enhancement.
- Closesapple#767.
- Closesapple#988.
- Closesapple#1132.
- Requires apple/containerization#508.
commit 5c86337
Author: William Laverty <developer@william-laverty.com>
Date: Mon Feb 2 13:57:59 2026 -0800
Add explanatory message before admin password prompt in uninstall script (apple#1118)
- Added message: "This script requires an administrator password to
remove the application files from system directories."
- Fixesapple#1111
commit 7da25e1
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:35:02 2026 -0800
Deps: Bump Containerization to 0.24.0 (apple#1127)
Brings in some rlimit bumps/adjustments
commit 7dfe27d
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:30:19 2026 -0800
CLI: Add support for rlimits (apple#1129)
Closesapple#1097.
commit b3b5c3e
Author: J Logan <john_logan@apple.com>
Date: Mon Feb 2 12:24:27 2026 -0800
Use labels instead of id to discriminate the builtin network. (apple#1123)
- Closesapple#1122.
- Adds placeholder ManagedResource and unit tests. Nothing is using
these yet.
- Adds system-defined resource labels for owning plugin and resource
role. The system discriminates the builtin network using role "builtin".
- Adds builtin role when creating builtin network at startup, and
ensures that a preexisting network with ID "default" gets updated with
the role label.
- Replace all network ID checks for "default" with the builtin role
check.
- Adds "builder" role to builder VM.
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Role and owner labels should make cross-cutting resource policy easier
to implement.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 1dae1cd
Author: w-ferg <43309695+w-ferg@users.noreply.github.com>
Date: Sun Feb 1 18:14:41 2026 -0500
Fix pfctl executable path in PacketFilter DNS reload (apple#1128)
## Summary
The `reload()` method in `PacketFilter.swift` references
`/sbin/reloadProcess` (the local variable name) instead of
`/sbin/pfctl`. This causes all DNS create and delete operations to fail:
```
Error: internalError: "pfctl reload exec failed: "Error Domain=NSCocoaErrorDomain Code=4 "The file "reloadProcess" doesn't exist.""
```
## Fix
One-line change: `/sbin/reloadProcess` → `/sbin/pfctl`
## Testing
Verified on macOS 26 (Tahoe) with Apple Silicon:
- `sudo container system dns create test.sdc.internal --localhost
203.0.113.1` succeeds without error
- Container can resolve and reach host services through the DNS redirect
commit 113a6ec
Author: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Date: Fri Jan 30 21:54:57 2026 -0600
Fix file descriptor leak in DirectoryWatcher (apple#1104)
- `DirectoryWatcher` opens file descriptors for monitoring
directories but never closes them, causing a file descriptor
leak.
- Adds `setCancelHandler` to properly close file descriptors
when the `DispatchSource` is cancelled.
Signed-off-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
commit 72f04b6
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Fri Jan 30 19:10:03 2026 -0800
[docs]: update steps on building with containerization project (apple#1116)
- Closesapple#1095
- Just added a few more details about how to build with the local
`containerization` dependency.
commit 3a0ad58
Author: Raj <rajaryan_singh@apple.com>
Date: Fri Jan 30 16:17:43 2026 -0800
Add resource.role label to builder container (apple#1120)
Add resource.role label to builder container
commit 1c01d0c
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 30 11:07:49 2026 -0800
Update to kata 3.20.0 kernel. (apple#1114)
- Closesapple#1113.
- This is the newest we can do until we address apple#767.
- Slight change to PacketFilter error handling so unit tests work more
reliably.
- Try making CLINetworkTests serialized to see if parallel execution is
causing flakes.
commit 3f2060e
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 18:25:48 2026 -0800
DirectoryWatcher: Small adjustments (apple#1112)
- Have the handler throw
- Log the failure at error level
commit 0a7fb07
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 14:21:12 2026 -0800
Set mtu to old Containerization default (apple#1110)
The old mtu default in containerization was 1280 to account for some
alpine/musl images that have issues with
1500. This changed in the last couple tags to be modifiable, but the new
default is the standard 1500. Ideally we eventually allow supplying the
mtu to be used when you create a network (or possibly a container
creation setting), but for now just default in here back to what CZ used
to use.
commit 0bceb23
Author: Aditya Ramani <a_ramani@apple.com>
Date: Thu Jan 29 12:08:42 2026 +0900
Bump to use containerization 0.23.2 (apple#1106)
Updating the package dependency on apple/containerization to pick up bug fixes
Signed-off-by: Aditya Ramani <a_ramani@apple.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit d762fe5
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 18:22:33 2026 -0800
Launch a service with waitForDebugger if specified (apple#1101)
This PR enables launching a service with `waitForDebugger` flag if the
service label matches a given env variable `CONTAINER_DEBUG`.
commit 4f93e3e
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed Jan 28 18:21:08 2026 -0800
ci: bump actions/checkout from 6.0.1 to 6.0.2 in the github-actions group (apple#1100)
- Updates `actions/checkout` from 6.0.1 to 6.0.2
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
commit 371db6d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 17:17:08 2026 -0800
Fix testExecOnExitingContainer (apple#1107)
Check the container remains only, not its status as the status might not
have been updated at the time checking.
commit d872270
Author: J Logan <john_logan@apple.com>
Date: Wed Jan 28 09:04:58 2026 -0800
Removes ArgumentParser import from NetworkMode. (apple#1102)
- ContainerResources shouldn't need to know anything about CLI stuff.
- Move ExpressibleByArgument protocol conformance to an extension in the
package where it's needed.
commit 3abf81f
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Tue Jan 27 20:00:43 2026 -0800
[image-list]: Add full size field to json output (apple#1098)
- Refer to apple#862
- Updated `SIZE` field to `FULL SIZE`, as it seemed more appropriate so
it does not get mixed up with the `descriptor size` field
- Closesapple#860
commit 24cbed5
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Jan 28 06:55:49 2026 +0800
Implement container prune (apple#904)
- Fixedapple#892.
- By contrast with `rm`, `prune` should display
the amount of reclaimed storage, so added code
to retrieve it.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit a57527e
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Tue Jan 27 11:15:22 2026 -0800
Refactor container lifecycle functions to perform scoped rollback on failure (apple#1080)
- Closesapple#977.
- Closesapple#1058.
- Prevents unexpected removal of containers on
bootstrapping and starting failures, by reorganizing
error handling for container `run`, `start`, and
`exec` so that error handling only unwinds that
which was done in the current scope.
- Relies on apple/containerization#495.
commit 6244129
Author: c <claudeaceae@icloud.com>
Date: Mon Jan 26 23:30:45 2026 -0500
Fix grammar in BUILDING.md (apple#984)
- Fixes a grammar error in the local Containerization development
instructions.
commit 9d4cded
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Mon Jan 26 19:35:41 2026 -0800
Isolated network (apple#1079)
- Closesapple#1037.
- Adds a `--mode` flag that has `nat` and `hostOnly` options.
The host-only option selects the vmnet host-only mode,
where containers attached to the network can reach each
other and the host, but not external systems.
commit 033c999
Author: J Logan <john_logan@apple.com>
Date: Mon Jan 26 14:07:00 2026 -0800
Make TerminalProgress a library. (apple#1093)
- Closesapple#1092.
- Allows 3rd party CLI plugins to use the progress indicator.
commit b371aee
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Tue Jan 27 05:07:05 2026 +0800
Feat: container image delete force option (apple#1096)
- Fixedapple#1087
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit ed1185d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Fri Jan 23 17:59:28 2026 -0800
Container-to-host networking. (apple#1078)
- Closesapple#346.
- This PR enables connecting host's localhost ports from
containers.
- It adds an option `--localhost <localhost>` to DNS
create command, after which the packets heading
ip address in container are redirected to localhost in
host machine. Packet filter rule is added and deleted
along with the creation and deletion of localhost domain.
commit 14c279f
Author: Patrick Linnane <patrick@linnane.io>
Date: Fri Jan 23 17:56:35 2026 -0800
Add option to stop services in all launchd domains (apple#1077)
- Services started from Terminal run in the `gui/$uid`
launchd domain. When `ensure-container-stopped.sh`
runs from a different context, `launchctl managername`
may return a different domain, causing the script to
check the wrong domain and miss running services.
I noticed this after upgrading `container` via Homebrew.
- Introduces a getopt option `-a` that allows booting out all
domains explicitly. Also adds `-h` for a usage message.
Signed-off-by: Patrick Linnane <patrick@linnane.io>
commit 751c1fc
Author: Stanislav Antonichev <cympak2@users.noreply.github.com>
Date: Fri Jan 23 23:01:26 2026 +0200
Add --dns support to build command for custom DNS resolution (apple#1067)
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
Changes:
- Added --dns option to BuildCommand to accept DNS nameserver IP
addresses
- Modified build logic to detect DNS configuration changes and recreate
the builder container when DNS settings differ
- Passed DNS configuration to BuilderStart.start() method
- Updated builder container creation to use specified DNS nameservers or
fall back to network gateway
## Type of Change
- [ ] Bug fix
- [X] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: J Logan <sgtbakerrahulnet@yahoo.com>
commit 55f2112
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 23 11:35:10 2026 -0800
Place image store data correctly for app-root path. (apple#1085)
- Closesapple#1084.
commit 5746ec3
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Sat Jan 24 03:32:59 2026 +0800
Fix: prevent delete default network (apple#1083)
- Fixedapple#1073
- Move the conditional check to the front; there's no need
to check for a default network after filtering.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@manuschillerdev@jglogan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: add --init-image flag for specifying custom init filesystem images per VM - #937

Merged
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image
Feb 10, 2026
Merged

feat: add --init-image flag for specifying custom init filesystem images per VM#937
jglogan merged 2 commits into
apple:mainfrom
manuschillerdev:feat/init-image

Conversation

@manuschillerdev

@manuschillerdevmanuschillerdev commented Dec 7, 2025

Copy link
Copy Markdown
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

I've been tinkering with ways to extend container with a primitive for interacting with the VM layer. One approach: expose the internal init filesystem as a user-configurable option via --init-image.

What this enables:

  • Custom boot-time logic before the OCI container starts
  • Running additional processes and daemons (e.g., daemons to configure eBPF network filters, logging agents) inside the VM (not the container)
  • Debugging/instrumenting the init process

--init-image vs using the system property
we could also use container system property set image.init vminit:latest (documented via #1032), but this affects all VMs. I want to be able to override this only for a single VM.

In my current approach, the custom image wraps the default vminitd, so it's currently behaving like an entrypoint.
Curious if this direction aligns with the project's goals, or if there's a better abstraction for these use cases.
If there is interest, I would add proper docs and tests.

Example for a minimal entry point binary
Note: We use Go here for its straightforward cross-compilation to Linux ARM64.

// custom-init/wrapper.gopackage main
import (
"fmt""os""syscall"
)
funcmain() {
kmsg, err:=os.OpenFile("/dev/kmsg", os.O_WRONLY, 0)
iferr==nil {
kmsg.WriteString("<6>custom-init: === CUSTOM INIT IMAGE RUNNING ===\n")
kmsg.Close()
}
err=syscall.Exec("/sbin/vminitd.real", os.Args, os.Environ())
iferr!=nil {
fmt.Fprintf(os.Stderr, "Failed to exec vminitd.real: %v\n", err)
os.Exit(1)
}
}

Containerfile

# custom-init/Containerfile
FROM ghcr.io/apple/containerization/vminit:0.23.2 AS base
FROM ghcr.io/apple/containerization/vminit:0.23.2
COPY --from=base /sbin/vminitd /sbin/vminitd.real
COPY wrapper /sbin/vminitd
  • build the binary with cd custom-init && CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o wrapper wrapper.go
  • build the image with bin/container build -t local/custom-init:0.20.0 custom-init/
  • run the container with our custom init-image: bin/container run --name init-test --init-image local/custom-init:0.20.0 alpine:latest echo "hello"
  • check the logs with cat "/Users/$USER/Library/Application Support/com.apple.container/containers/init-test/vminitd.log" | head -50

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

@manuschillerdevmanuschillerdev changed the title feat: add init-image flag for specifying custom init filesystem images per VMfeat: add --init-image flag for specifying custom init filesystem images per VMDec 7, 2025
@jglogan

Copy link
Copy Markdown
Contributor

@dcantah see also #838

Comment threadSources/ContainerClient/Utility.swift
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@dcantah@jglogan would that be of interest for the project? Would be totally open to other suggestions on how one can interact with the startup process. Exposing --init-fs seemed like a viable option here

@manuschillerdev

manuschillerdev commented Jan 10, 2026

Copy link
Copy Markdown
ContributorAuthor

@jglogan@dcantah

I've rebased the PR, added tests and documentation, and updated the description to clarify why container system property set image.init doesn't fit my use case (it applies globally rather than per-VM).

Happy to elaborate on any open questions or explore alternative approaches that would better align with the project's architecture.
I'd appreciate any feedback on whether this direction makes sense to pursue or if there are concerns that would make it worth closing in favor of a different approach.

@jglogan

jglogan commented Jan 17, 2026

Copy link
Copy Markdown
Contributor

@manuschillerdev I haven't been able to review but it seems reasonable. Kernel and initfs config are birds of a feather, whatever config options exist for one, we should eventually provide for the other.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Could you run make fmt on this, and make sure build/test runs okay on your end, and then try pushing the changes? I made one change to resolve some merge conflicts on the Makefile

@jglogan

Copy link
Copy Markdown
Contributor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 5badfb6 to 6e1d1faCompareFebruary 1, 2026 10:15
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

Actually it might be easier to close this PR and open a new one on main.

Everything looks fine, but there's a problem with the format checks such that short term it's easier to get a build done with a new PR. Sorry for the bother.

thanks for having another look at this! I rebased the PR against main, resolved the conflicts, ran make fmt, and did a complete re-test locally with the steps from the PR description:

❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"| grep "==="
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
full output of vminitd.log after creating a custom init image, and starting a fresh container using the `--init-image` flag:
❯ cat "$HOME/Library/Application Support/com.apple.container/containers/init-test/vminitd.log"
[ 0.069458] random: crng init done
[ 0.070722] brd: module loaded
[ 0.071338] loop: module loaded
[ 0.071436] virtio_blk virtio2: 1/0/0 default/read/poll queues
[ 0.071600] virtio_blk virtio2: [vda] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.071875] virtio_blk virtio3: 1/0/0 default/read/poll queues
[ 0.072020] virtio_blk virtio3: [vdb] 1073741824 512-byte logical blocks (550 GB/512 GiB)
[ 0.072226] tun: Universal TUN/TAP device driver, 1.6
[ 0.072687] VFIO - User Level meta-driver version: 0.3
[ 0.072820] rtc-pl031 20050000.pl031: registered as rtc0
[ 0.072857] rtc-pl031 20050000.pl031: setting system clock to 2026-02-01T08:49:54 UTC (1769935794)
[ 0.073306] xt_time: kernel timezone is -0000
[ 0.073348] IPVS: Registered protocols (TCP, UDP, SCTP, AH, ESP)
[ 0.073434] IPVS: Connection hash table configured (size=4096, memory=32Kbytes)
[ 0.073579] IPVS: ipvs loaded.
[ 0.073615] IPVS: [rr] scheduler registered.
[ 0.073634] IPVS: [wrr] scheduler registered.
[ 0.073685] IPVS: [lc] scheduler registered.
[ 0.073718] IPVS: [wlc] scheduler registered.
[ 0.073767] IPVS: [fo] scheduler registered.
[ 0.073813] IPVS: [ovf] scheduler registered.
[ 0.073862] IPVS: [lblc] scheduler registered.
[ 0.073924] IPVS: [lblcr] scheduler registered.
[ 0.073942] IPVS: [dh] scheduler registered.
[ 0.073966] IPVS: [sh] scheduler registered.
[ 0.073991] IPVS: [sed] scheduler registered.
[ 0.074016] IPVS: [nq] scheduler registered.
[ 0.074043] IPVS: [sip] pe registered.
[ 0.074088] Initializing XFRM netlink socket
[ 0.074130] NET: Registered PF_INET6 protocol family
[ 0.074389] Segment Routing with IPv6
[ 0.074421] In-situ OAM (IOAM) with IPv6
[ 0.074462] NET: Registered PF_PACKET protocol family
[ 0.074505] 9pnet: Installing 9P2000 support
[ 0.074573] NET: Registered PF_VSOCK protocol family
[ 0.075578] registered taskstats version 1
[ 0.076957] alg: No testfor fips(ansi_cprng) (fips_ansi_cprng)
[ 0.077498] clk: Disabling unused clocks
[ 0.080034] EXT4-fs (vda): mounted filesystem 63cb0698-b5fe-4f00-ba03-179297b9693a ro without journal. Quota mode: disabled.
[ 0.080117] VFS: Mounted root (ext4 filesystem) readonly on device 254:0.
[ 0.080441] devtmpfs: mounted
[ 0.080801] Freeing unused kernel memory: 1856K
[ 0.080895] Run /sbin/vminitd as init process
[ 0.086171] custom-init: === CUSTOM INIT IMAGE RUNNING ===
2026-02-01T08:49:54+0000 info vminitd : [vminitd] Running init command
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /proc
2026-02-01T08:49:54+0000 info vminitd : [vminitd] vminitd booting
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /run
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys
2026-02-01T08:49:54+0000 info vminitd : [vminitd] mounting /sys/fs/cgroup
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 debug vminitd : bytes=78643200 path=/sys/fs/cgroup/vminitd [Cgroup] setting memory.high
2026-02-01T08:49:54+0000 debug vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/vminitd [Cgroup] adding new proc to cgroup
2026-02-01T08:49:54+0000 info vminitd : events_path=/sys/fs/cgroup/vminitd/memory.events threshold_bytes=78643200 [vminitd] Started memory monitoring
2026-02-01T08:49:54+0000 info vminitd : [vminitd] serving vminitd API
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] starting process supervisor
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] booting gRPC server on vsock
2026-02-01T08:49:54+0000 info vminitd : port=1024 [vminitd] gRPC API serving on vsock
2026-02-01T08:49:54+0000 debug vminitd : interface=lo up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : key=PATH value=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin [vminitd] setenv
2026-02-01T08:49:54+0000 debug vminitd : destination=/tmp source=tmpfs type=tmpfs [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/dev/pts source=devpts type=devpts [vminitd] mount
2026-02-01T08:49:54+0000 debug vminitd : destination=/run/container/init-test/rootfs source=/dev/vdb type=ext4 [vminitd] mount
[ 0.268991] EXT4-fs (vdb): mounted filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab r/w without journal. Quota mode: disabled.
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Address=192.168.64.3/24 [vminitd] ipAddrAdd
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 up=true [vminitd] ipLinkSet
2026-02-01T08:49:54+0000 debug vminitd : interface=eth0 ipv4Gateway=192.168.64.1 [vminitd] ipRouteAddDefault
2026-02-01T08:49:54+0000 debug vminitd : domain= location=/run/container/init-test/rootfs nameservers=["192.168.64.1"] options=[] searchDomains=[] [vminitd] configureDns
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] writing to path /run/container/init-test/rootfs/etc/resolv.conf nameserver 192.168.64.1
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/resolv.conf [vminitd] wrote resolver configuration
2026-02-01T08:49:54+0000 debug vminitd : location=/run/container/init-test/rootfs [vminitd] configureHosts
2026-02-01T08:49:54+0000 debug vminitd : path=/run/container/init-test/rootfs/etc/hosts [vminitd] wrote /etc/hosts configuration
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test stderr=Port: 268435457 stdin=Port: 0 stdout=Port: 268435456 [vminitd] createProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] created bundle with spec Spec(version: "", hooks: nil, process: Optional(ContainerizationOCI.Process(cwd: "/", env: ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOME=/root"], consoleSize: nil, selinuxLabel: "", noNewPrivileges: false, commandLine: "", oomScoreAdj: nil, capabilities: Optional(ContainerizationOCI.LinuxCapabilities(bounding: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), effective: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), inheritable: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), permitted: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]), ambient: Optional(["CAP_CHOWN", "CAP_DAC_OVERRIDE", "CAP_DAC_READ_SEARCH", "CAP_FOWNER", "CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_SETPCAP", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE", "CAP_NET_BROADCAST", "CAP_NET_ADMIN", "CAP_NET_RAW", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_BOOT", "CAP_SYS_NICE", "CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_LEASE", "CAP_AUDIT_WRITE", "CAP_AUDIT_CONTROL", "CAP_SETFCAP", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_SYSLOG", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND", "CAP_AUDIT_READ", "CAP_PERFMON", "CAP_BPF", "CAP_CHECKPOINT_RESTORE"]))), apparmorProfile: "", user: ContainerizationOCI.User(uid: 0, gid: 0, umask: nil, additionalGids: [0], username: ""), rlimits: [], args: ["echo", "hello"], terminal: false)), hostname: "init-test", domainname: "", mounts: [ContainerizationOCI.Mount(type: "proc", source: "proc", destination: "/proc", options: [], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "sysfs", source: "sysfs", destination: "/sys", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devtmpfs", source: "none", destination: "/dev", options: ["nosuid", "mode=755"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "mqueue", source: "mqueue", destination: "/dev/mqueue", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "tmpfs", source: "tmpfs", destination: "/dev/shm", options: ["nosuid", "noexec", "nodev", "mode=1777", "size=65536k"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "cgroup2", source: "none", destination: "/sys/fs/cgroup", options: ["nosuid", "noexec", "nodev"], uidMappings: nil, gidMappings: nil), ContainerizationOCI.Mount(type: "devpts", source: "devpts", destination: "/dev/pts", options: ["nosuid", "noexec", "newinstance", "gid=5", "mode=0620", "ptmxmode=0666"], uidMappings: nil, gidMappings: nil)], annotations: nil, root: Optional(ContainerizationOCI.Root(path: "/run/container/init-test/rootfs", readonly: false)), linux: Optional(ContainerizationOCI.Linux(uidMappings: [], gidMappings: [], sysctl: Optional([:]), resources: Optional(ContainerizationOCI.LinuxResources(devices: [], memory: Optional(ContainerizationOCI.LinuxMemory(limit: Optional(1073741824), reservation: nil, swap: nil, kernel: nil, kernelTCP: nil, swappiness: nil, disableOOMKiller: nil, useHierarchy: nil, checkBeforeUpdate: nil)), cpu: Optional(ContainerizationOCI.LinuxCPU(shares: nil, quota: Optional(400000), burst: nil, period: Optional(100000), realtimeRuntime: nil, realtimePeriod: nil, cpus: "", mems: "", idle: nil)), pids: nil, blockIO: nil, hugepageLimits: [], network: nil, rdma: nil, unified: Optional([:]))), cgroupsPath: "/container/init-test", namespaces: [ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.cgroup, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.ipc, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.mount, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.pid, path: ""), ContainerizationOCI.LinuxNamespace(type: ContainerizationOCI.LinuxNamespaceType.uts, path: "")], devices: [], seccomp: nil, rootfsPropagation: "", maskedPaths: [], readonlyPaths: [], mountLabel: "", personality: nil)))
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] creating cgroup manager
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting I/O
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] setting up relay for StandardIO stderr
2026-02-01T08:49:54+0000 info vminitd : [vminitd] created vmexec init process
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] startProcess
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] in supervisor lock to start process
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] starting managed process
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78381056 high_events_total=1 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78442496 high_events_total=15 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 warning vminitd : current_bytes=78331904 high_events_total=18 threshold_bytes=78643200 [vminitd] vminitd memory threshold exceeded
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] got back pid data
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] sending pid acknowledgement
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[93: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 info vminitd : id=init-test pid=94 [vminitd] started managed process
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] received SIGCHLD, reaping processes
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] received EPOLLHUP with no EPOLLIN
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] finished wait4 of 1 processes
2026-02-01T08:49:54+0000 debug vminitd : exits=[94: 0] processes=1 [vminitd] checking forexit of managed process
2026-02-01T08:49:54+0000 debug vminitd : count=0 pid=94 status=0 [vminitd] managed process exited
2026-02-01T08:49:54+0000 info vminitd : id=init-test status=0 [vminitd] managed process exit
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stdout
2026-02-01T08:49:54+0000 info vminitd : id=init-test [vminitd] closing relay for StandardIO stderr
2026-02-01T08:49:54+0000 debug vminitd : id=init-test [vminitd] 0 managed process waiters signaled
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : pid=-1 signal=9 [vminitd] kill
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] waitProcess
2026-02-01T08:49:54+0000 debug vminitd : flags=0 path=/run/container/init-test/rootfs [vminitd] umount
[ 0.541866] EXT4-fs (vdb): unmounting filesystem 7b9883bc-6f26-4570-8176-4daf1326a3ab.
2026-02-01T08:49:54+0000 debug vminitd : [vminitd] sync
2026-02-01T08:49:54+0000 debug vminitd : containerID=init-test id=init-test [vminitd] deleteProcess
2026-02-01T08:49:54+0000 info vminitd : mountpoint=/sys/fs/cgroup path=/sys/fs/cgroup/container/init-test [Cgroup] deleting cgroup manager

I also re-ran the tests:

❯ swift test --filter TestCLIRunInitImage 2>&1
Building for debugging...
[7/7] Write swift-version-1C31CF501CE571A8.txt
Build complete! (0.77s)
Test Suite 'Selected tests' started at 2026-02-01 11:10:47.076.
Test Suite 'containerPackageTests.xctest' started at 2026-02-01 11:10:47.077.
Test Suite 'containerPackageTests.xctest' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds
Test Suite 'Selected tests' passed at 2026-02-01 11:10:47.077.
Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.1 (c9d57c83568b06d)
↳ Target Platform: arm64-apple-macosx
◇ Suite TestCLIRunInitImage started.
◇ Test testCreateWithNonExistentInitImage() started.
◇ Test testRunWithExplicitDefaultInitImage() started.
◇ Test testInitImageFlagInHelp() started.
◇ Test testRunWithNonExistentInitImage() started.
✔ Test testInitImageFlagInHelp() passed after 0.178 seconds.
✔ Test testRunWithNonExistentInitImage() passed after 10.584 seconds.
✔ Test testCreateWithNonExistentInitImage() passed after 20.668 seconds.
✔ Test testRunWithExplicitDefaultInitImage() passed after 25.314 seconds.
✔ Suite TestCLIRunInitImage passed after 25.314 seconds.
✔ Test run with 4 tests in 1 suite passed after 25.314 seconds.

@jglogan let me know if that works for you, or if I should rather still open a fresh PR. Don't worry, I'd aim for the cleanest solution for the maintainers and the repo. Re-organizing the PR is no effort at all. Thanks for your time again!

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev In CI I'm seeing this failure:

✔ Test testCreateWithNonExistentInitImage() passed after 43.897 seconds.
✘ Test testRunWithExplicitDefaultInitImage() recorded an issue at TestCLIRunInitImage.swift:93:6: Caught error: executionFailed("command failed: Warning! Running debug build. Performance may be degraded.\nError: internalError: \"failed to create container\" (cause: \"internalError: \"XPC timeout for request to com.apple.container.apiserver/containerCreate\"\")\n")
✘ Test testRunWithExplicitDefaultInitImage() failed after 87.555 seconds with 1 issue.
↳ /// Test that explicitly specifying the default init image works the same as
↳ /// not specifying any init image.
✔ Test testRunWithNonExistentInitImage() passed after 87.606 seconds.
✘ Suite TestCLIRunInitImage failed after 87.606 seconds with 1 issue.
✘ Test run with 4 tests in 1 suite failed after 87.606 seconds with 1 issue.

@manuschillerdev
manuschillerdevforce-pushed the feat/init-image branch 2 times, most recently from 7d9a37a to baae7c7CompareFebruary 3, 2026 22:05
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks! the tests did catch an error in the image selection logic - glad they did.
I pushed a separate fix, an re-ran make integrate locally without errors.

@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev OK, the updated tests worked fine. One last thing (thanks for your patience!)

ContainerClient got a big refactor your changes need to be updated to work with those.

@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan no worries. I rebased against main and verified that the changes still work.
make integration runs without errors, loading a custom init-image works and starting containers without a custom init image provided works as well

@jglogan
jglogan merged commit cf9b335 into apple:mainFeb 10, 2026
3 checks passed
@jglogan

Copy link
Copy Markdown
Contributor

@manuschillerdev Finally got it in there...thanks for the contribution!

simone-panico pushed a commit to simone-panico/container that referenced this pull request Feb 10, 2026
…ges per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
@manuschillerdev

Copy link
Copy Markdown
ContributorAuthor

@jglogan thanks again for guiding me!

Mcrich23 added a commit to Mcrich23/container that referenced this pull request Feb 18, 2026
commit c791052
Author: Aditya Ramani <a_ramani@apple.com>
Date: Wed Feb 18 07:43:56 2026 +0530
Add init methods for all the members of the Flags type (apple#1203)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Authors of CLI plugins for container will be able to reuse the container
flags defined in the CLI package, instead of having to duplicate them in
their project
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit dfac83d
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 17 16:54:44 2026 -0800
ContainerService: Add minimum memory amount validation (apple#1208)
Closesapple#1202
Today it's possible to pass a memory amount that very easily will cause
the container's VM to not be able to boot. We should protect against
this to avoid weird hangs/error messages. I could be convinced that a
limit should be in Containerization as well, but I think having one in
the daemon is a decent idea regardless.
commit 5385a5c
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Tue Feb 17 15:08:32 2026 -0800
Support using multiple different network plugins (apple#1151)
## Type of Change
- [x] New feature
- [x] Breaking change
## Motivation and Context
We want to be able to support using multiple network plugins during
`container`'s lifetime. This additionally means needing to pick an
interface strategy to interpret a network attachment based on what
network plugin was used to create that attachment. This PR will
potentially replace apple#1081.
Followups:
- doc updates to include the ability to specify plugin in the network
creation cli
## Testing
- [x] Tested locally
- [x] Added/updated tests
commit 7476743
Author: AJ Emory <239216119+ajemory@users.noreply.github.com>
Date: Fri Feb 13 19:27:32 2026 -0800
feat: Moving bundle creation from ContainerService to SandboxService (apple#1076)
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Closesapple#1046 -- Right now we're creating container bundles in
ContainersService. Move this to the SandboxService to make it easier to
support different container bundle types.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 4c800db
Author: J Logan <john_logan@apple.com>
Date: Fri Feb 13 10:51:27 2026 -0800
Fix persistent CI failures. (apple#1205)
## Type of Change
- [x] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
- CI build is failing because runners don't have an /etc/resolver
directory, causing the directory monitor to fail. This occurs while the
install-kernel make target is running, so it appears that kernel
download is failing when it's just that the API server is dying. Created
apple#1207 for the issue.
- Fixing the initial scan for the directory just moves the problem to
the filesystem watch loop, likely because we're not testing the result
of `open()` for errors.
- Right now the priority is getting CI running and PRs merged, so just
commenting out the realhost DNS server setup.
- Also seeing that under some conditions it can take quite a while for
launchd to start the helper for the default network (8 seconds or more).
With the 10 second health check timeout after API server registration,
this means that some CI runs can exhibit this failure mode. Added a
`--timeout` option to SystemStart and set a 60 second timeout for
install-kernel and integration Makefile targets.
- Fixed a bug where `--debug` was being placed in the wrong location in
the api server startup args.
- Disabled all network CLI tests due to container bootstrap errors when
trying to run the container immediately after creating the network. The
slow network helper launch could be the reason behind the failures that
drove us to serialize these tests. Filed apple#1206 for this issue.
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
commit f7d00aa
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 11 15:09:21 2026 -0800
APIServer: Add support for filtering to list rpc (apple#1175)
This is not intended to be used to support `--filter` or similar on the
CLIs list yet, it's solely to clean up our rather awkward use of
`ContainerClient.list()` today in the CLI. The list RPC simply returns
all of the containers we have created. Because of this, for a LOT of our
commands we filter to what we need client side, which feels like a
waste.. This change introduces a filter struct that we can provide an
array of container IDs, labels, and the status of the containers to
filter the `list()` output from.
This additionally, because it was killing (pun not intended) me and I
was already having to change this area for the `list()` additions,
changes container kill slightly to return an error if you try and kill a
container that doesn't exist.
commit c9f81ca
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Feb 11 04:26:33 2026 +0800
Feat: add container registry list (apple#1119)
- Requires apple/containerization#502
- Closesapple#1088
---------
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit cf9b335
Author: Manu Schiller <56154253+manuschillerdev@users.noreply.github.com>
Date: Tue Feb 10 03:11:27 2026 +0100
feat: add --init-image flag for specifying custom init filesystem images per VM (apple#937)
- Users can now specify an alternate image to use
with the `container run ---init-image` flag.
commit 474906d
Author: Amir Alperin <me@remotecpp.dev>
Date: Fri Feb 6 23:38:19 2026 +0200
feat: Add runtime flag to container create and run commands (apple#1049) (apple#1109)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Fixesapple#1049
- Add --runtime option for Flags.Management
- Apply runtime handler in containerConfigFromFlags
- Update command-reference.md doc
## Testing
- [x] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
Co-authored-by: J Logan <john_logan@apple.com>
commit 40de343
Author: Dmitry Kovba <dkovba@apple.com>
Date: Fri Feb 6 00:41:29 2026 -0800
Fix relative path mount tests (apple#1168)
`make test` occasionally fails with:
```
✘ Test testHostDNSReinitialize() recorded an issue at HostDNSResolverTest.swift:132:45: Expectation failed: (error →
Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory") as? (ContainerizationError → NSError)
✘ Suite HostDNSResolverTest failed after 0.119 seconds with 1 issue.
```
commit aa17d46
Author: Poetry Of Code <101225909+poetryofcode@users.noreply.github.com>
Date: Fri Feb 6 03:38:21 2026 -0500
Warn user when a named volume is auto-created (apple#1108)
- Implemented the TODO at
ContainerAPIService/Client/Utility.swift:358 — warn the
user when a named volume is auto-created.
- This only triggers for named volumes (not anonymous
ones), matching Docker's behavior of informing users
about implicit resource creation.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
commit adb3c44
Author: J Logan <john_logan@apple.com>
Date: Thu Feb 5 20:19:13 2026 -0800
Don't enable selinux LSM on boot. (apple#1166)
- Closesapple#1150.
- The problem seems to be that the selinux label attribute enforcement
doesn't play well with overlayfs.
- Solution is to set the `lsm` boot line argument. The new value
corresponds to what one would see in a Lima VM with Colima. The Kata
kernel we use doesn't provide any of those modules, so now if you run
`dmesg | grep -i lsm` in a container you will just see: `LSM:
initializing lsm=capability`
commit fdeb1b1
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 10:59:31 2026 -0800
Add builder tests (apple#1154)
- Adds test for apple#1094.
- Closesapple#933 (with apple/container-builder-shim#62).
- Closesapple#425 (with apple/container-builder-shim#63).
commit fabfc55
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Thu Feb 5 09:53:31 2026 -0800
Send tar hash in the first BuildTransfer packet (apple#1149)
Send the hash of entire tar file in the first BuildTransfer packet to
prevent container-builder-shim from using stale cached contents.
This PR resolvesapple#1143.
This PR relies on apple/container-builder-shim#64.
## Type of Change
- [X] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Current container-builder-shim uses only first few bytes of tar file as
checksum, which leads to the usage of stale cached contents if the
change of build context is not included in the first bytes of tar file.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit 6e9b8d7
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Feb 5 09:47:20 2026 -0800
CLI: Forego logging errors on multi-container operations (apple#1163)
Instead of logging errors, and then additionally throwing an error
stating what containers couldn't be stopped/killed/deleted, let's just
concatenate the errors and throw the single error.
commit d79bc0d
Author: Manoj Mahapatra <mahapatra.manoj@hotmail.com>
Date: Thu Feb 5 01:16:30 2026 -0800
chore: Replace force-unwrapped String(data:encoding:) with String(decoding:as:) (apple#1164)
Use the non-optional String(decoding:as:) initializer for converting
JSON-encoded Data to String. This is safe for UTF-8 and eliminates force
commit 21dabb7
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 03:13:36 2026 -0500
[build-command]: Add --pull option for fetching latest image (apple#844)
- Closesapple#733.
commit 6553f9c
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Thu Feb 5 01:16:08 2026 -0500
[deps]: bump containerization to 0.25.0 (apple#1161)
Co-authored-by: saehejkang <saehej.kang@gmail.com>
Co-authored-by: Anthony DePasquale <anthony@depasquale.org>
- Bump `containerization` to `0.25.0`
- Updates for parameter changes on containerization
registry access API.
- Updates for change to containerization
`cleanUpOrphanedBlobs` function.
commit 2d1dd6b
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 15:42:29 2026 -0800
Fix file path for the PR number in the PR labeler workflow (apple#1158)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR label applier GitHub workflow has been failing for a while. This
PR fixes that by correcting the file path we look for when trying to
read the PR number. See example failure here
https://github.com/apple/container/actions/runs/21691766538/job/62552959972#step:4:23
commit 6451e07
Author: Kathryn Baldauf <k_baldauf@apple.com>
Date: Wed Feb 4 14:44:53 2026 -0800
Add debugging to the PR labeler CI flow (apple#1155)
## Type of Change
- [x] Bug fix
## Motivation and Context
The PR labeler workflow has been failing for a while but it's difficult
to know how to fix it since the PR labeler workflow is run from main
(aka NOT the current PR branch) for security reasons. Example at
https://github.com/apple/container/actions/runs/21690229300/workflow
commit 8fdfa29
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:52:09 2026 -0800
CLI: Rework ClientContainer (apple#1139)
ClientContainer was honestly extremely awkward. It could only be created
by passing either a ContainerConfiguration, or a Snapshot that had to be
obtained from calling a static method on the type itself. The type also
did not store a connection, so every single method got a new xpc
connection to the APIServer. This change aims to rework this type to be
just a generic client, that is *not* a client for one specific
container, but for any.
- Rename to ContainerClient
- Have list() return [ContainerSnapshot]
- Create a connection in the constructor
- Change all the callsites to use the new API
- Small, somewhat related, change to logs API in the APIServer. Now that
we don't need to call get() to grab a client anymore which was typically
what did "does this container exist" logic and gave a nice error
message, I added a small check in the APIServer to see if the container
exists and return mostly the same error message.
commit 23c0ece
Author: Danny Canter <danny_canter@apple.com>
Date: Wed Feb 4 09:19:50 2026 -0800
CI: Add signed commit check (apple#1152)
This requirement of ours often goes unnoticed because nothing yells at
you openly about it. Lets fail CI to make it more obvious.
commit ce1b629
Author: Manoj Mahapatra <mahaplipsa@gmail.com>
Date: Tue Feb 3 13:43:07 2026 -0800
[Docs] Fix typo in BUILDING.md: launchd -> launchctl (apple#1146)
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [x] Documentation update
## Motivation and Context
The debug instructions in `BUILDING.md` incorrectly reference launchd
list instead of `launchctl` list. `launchd` is the daemon itself and
cannot be invoked directly.
## Testing
- [ ] Tested locally
- [ ] Added/updated tests
- [x] Added/updated docs
commit 3e49dce
Author: Danny Canter <danny_canter@apple.com>
Date: Tue Feb 3 00:45:01 2026 -0800
Add in missing rlimits (apple#1140)
Containerization didn't have these defined until a recent tag.
commit c4c2e85
Author: J Logan <john_logan@apple.com>
Date: Tue Feb 3 00:27:09 2026 -0800
Upgrade kernel to Kata 3.26.0. (apple#1134)
- Upgrade to containerization 0.24.5 to pick up zstd decompression
enhancement.
- Closesapple#767.
- Closesapple#988.
- Closesapple#1132.
- Requires apple/containerization#508.
commit 5c86337
Author: William Laverty <developer@william-laverty.com>
Date: Mon Feb 2 13:57:59 2026 -0800
Add explanatory message before admin password prompt in uninstall script (apple#1118)
- Added message: "This script requires an administrator password to
remove the application files from system directories."
- Fixesapple#1111
commit 7da25e1
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:35:02 2026 -0800
Deps: Bump Containerization to 0.24.0 (apple#1127)
Brings in some rlimit bumps/adjustments
commit 7dfe27d
Author: Danny Canter <danny_canter@apple.com>
Date: Mon Feb 2 13:30:19 2026 -0800
CLI: Add support for rlimits (apple#1129)
Closesapple#1097.
commit b3b5c3e
Author: J Logan <john_logan@apple.com>
Date: Mon Feb 2 12:24:27 2026 -0800
Use labels instead of id to discriminate the builtin network. (apple#1123)
- Closesapple#1122.
- Adds placeholder ManagedResource and unit tests. Nothing is using
these yet.
- Adds system-defined resource labels for owning plugin and resource
role. The system discriminates the builtin network using role "builtin".
- Adds builtin role when creating builtin network at startup, and
ensures that a preexisting network with ID "default" gets updated with
the role label.
- Replace all network ID checks for "default" with the builtin role
check.
- Adds "builder" role to builder VM.
## Type of Change
- [ ] Bug fix
- [x] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
Role and owner labels should make cross-cutting resource policy easier
to implement.
## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
commit 1dae1cd
Author: w-ferg <43309695+w-ferg@users.noreply.github.com>
Date: Sun Feb 1 18:14:41 2026 -0500
Fix pfctl executable path in PacketFilter DNS reload (apple#1128)
## Summary
The `reload()` method in `PacketFilter.swift` references
`/sbin/reloadProcess` (the local variable name) instead of
`/sbin/pfctl`. This causes all DNS create and delete operations to fail:
```
Error: internalError: "pfctl reload exec failed: "Error Domain=NSCocoaErrorDomain Code=4 "The file "reloadProcess" doesn't exist.""
```
## Fix
One-line change: `/sbin/reloadProcess` → `/sbin/pfctl`
## Testing
Verified on macOS 26 (Tahoe) with Apple Silicon:
- `sudo container system dns create test.sdc.internal --localhost
203.0.113.1` succeeds without error
- Container can resolve and reach host services through the DNS redirect
commit 113a6ec
Author: Ronit Sabhaya <ronitsabhaya75@gmail.com>
Date: Fri Jan 30 21:54:57 2026 -0600
Fix file descriptor leak in DirectoryWatcher (apple#1104)
- `DirectoryWatcher` opens file descriptors for monitoring
directories but never closes them, causing a file descriptor
leak.
- Adds `setCancelHandler` to properly close file descriptors
when the `DispatchSource` is cancelled.
Signed-off-by: Ronit Sabhaya <ronitsabhaya75@gmail.com>
commit 72f04b6
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Fri Jan 30 19:10:03 2026 -0800
[docs]: update steps on building with containerization project (apple#1116)
- Closesapple#1095
- Just added a few more details about how to build with the local
`containerization` dependency.
commit 3a0ad58
Author: Raj <rajaryan_singh@apple.com>
Date: Fri Jan 30 16:17:43 2026 -0800
Add resource.role label to builder container (apple#1120)
Add resource.role label to builder container
commit 1c01d0c
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 30 11:07:49 2026 -0800
Update to kata 3.20.0 kernel. (apple#1114)
- Closesapple#1113.
- This is the newest we can do until we address apple#767.
- Slight change to PacketFilter error handling so unit tests work more
reliably.
- Try making CLINetworkTests serialized to see if parallel execution is
causing flakes.
commit 3f2060e
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 18:25:48 2026 -0800
DirectoryWatcher: Small adjustments (apple#1112)
- Have the handler throw
- Log the failure at error level
commit 0a7fb07
Author: Danny Canter <danny_canter@apple.com>
Date: Thu Jan 29 14:21:12 2026 -0800
Set mtu to old Containerization default (apple#1110)
The old mtu default in containerization was 1280 to account for some
alpine/musl images that have issues with
1500. This changed in the last couple tags to be modifiable, but the new
default is the standard 1500. Ideally we eventually allow supplying the
mtu to be used when you create a network (or possibly a container
creation setting), but for now just default in here back to what CZ used
to use.
commit 0bceb23
Author: Aditya Ramani <a_ramani@apple.com>
Date: Thu Jan 29 12:08:42 2026 +0900
Bump to use containerization 0.23.2 (apple#1106)
Updating the package dependency on apple/containerization to pick up bug fixes
Signed-off-by: Aditya Ramani <a_ramani@apple.com>
Co-authored-by: J Logan <john_logan@apple.com>
commit d762fe5
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 18:22:33 2026 -0800
Launch a service with waitForDebugger if specified (apple#1101)
This PR enables launching a service with `waitForDebugger` flag if the
service label matches a given env variable `CONTAINER_DEBUG`.
commit 4f93e3e
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed Jan 28 18:21:08 2026 -0800
ci: bump actions/checkout from 6.0.1 to 6.0.2 in the github-actions group (apple#1100)
- Updates `actions/checkout` from 6.0.1 to 6.0.2
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
commit 371db6d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Wed Jan 28 17:17:08 2026 -0800
Fix testExecOnExitingContainer (apple#1107)
Check the container remains only, not its status as the status might not
have been updated at the time checking.
commit d872270
Author: J Logan <john_logan@apple.com>
Date: Wed Jan 28 09:04:58 2026 -0800
Removes ArgumentParser import from NetworkMode. (apple#1102)
- ContainerResources shouldn't need to know anything about CLI stuff.
- Move ExpressibleByArgument protocol conformance to an extension in the
package where it's needed.
commit 3abf81f
Author: Saehej Kang <saehej.kang@gmail.com>
Date: Tue Jan 27 20:00:43 2026 -0800
[image-list]: Add full size field to json output (apple#1098)
- Refer to apple#862
- Updated `SIZE` field to `FULL SIZE`, as it seemed more appropriate so
it does not get mixed up with the `descriptor size` field
- Closesapple#860
commit 24cbed5
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Wed Jan 28 06:55:49 2026 +0800
Implement container prune (apple#904)
- Fixedapple#892.
- By contrast with `rm`, `prune` should display
the amount of reclaimed storage, so added code
to retrieve it.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit a57527e
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Tue Jan 27 11:15:22 2026 -0800
Refactor container lifecycle functions to perform scoped rollback on failure (apple#1080)
- Closesapple#977.
- Closesapple#1058.
- Prevents unexpected removal of containers on
bootstrapping and starting failures, by reorganizing
error handling for container `run`, `start`, and
`exec` so that error handling only unwinds that
which was done in the current scope.
- Relies on apple/containerization#495.
commit 6244129
Author: c <claudeaceae@icloud.com>
Date: Mon Jan 26 23:30:45 2026 -0500
Fix grammar in BUILDING.md (apple#984)
- Fixes a grammar error in the local Containerization development
instructions.
commit 9d4cded
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Mon Jan 26 19:35:41 2026 -0800
Isolated network (apple#1079)
- Closesapple#1037.
- Adds a `--mode` flag that has `nat` and `hostOnly` options.
The host-only option selects the vmnet host-only mode,
where containers attached to the network can reach each
other and the host, but not external systems.
commit 033c999
Author: J Logan <john_logan@apple.com>
Date: Mon Jan 26 14:07:00 2026 -0800
Make TerminalProgress a library. (apple#1093)
- Closesapple#1092.
- Allows 3rd party CLI plugins to use the progress indicator.
commit b371aee
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Tue Jan 27 05:07:05 2026 +0800
Feat: container image delete force option (apple#1096)
- Fixedapple#1087
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
commit ed1185d
Author: jwhur <57657645+JaewonHur@users.noreply.github.com>
Date: Fri Jan 23 17:59:28 2026 -0800
Container-to-host networking. (apple#1078)
- Closesapple#346.
- This PR enables connecting host's localhost ports from
containers.
- It adds an option `--localhost <localhost>` to DNS
create command, after which the packets heading
ip address in container are redirected to localhost in
host machine. Packet filter rule is added and deleted
along with the creation and deletion of localhost domain.
commit 14c279f
Author: Patrick Linnane <patrick@linnane.io>
Date: Fri Jan 23 17:56:35 2026 -0800
Add option to stop services in all launchd domains (apple#1077)
- Services started from Terminal run in the `gui/$uid`
launchd domain. When `ensure-container-stopped.sh`
runs from a different context, `launchctl managername`
may return a different domain, causing the script to
check the wrong domain and miss running services.
I noticed this after upgrading `container` via Homebrew.
- Introduces a getopt option `-a` that allows booting out all
domains explicitly. Also adds `-h` for a usage message.
Signed-off-by: Patrick Linnane <patrick@linnane.io>
commit 751c1fc
Author: Stanislav Antonichev <cympak2@users.noreply.github.com>
Date: Fri Jan 23 23:01:26 2026 +0200
Add --dns support to build command for custom DNS resolution (apple#1067)
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
Changes:
- Added --dns option to BuildCommand to accept DNS nameserver IP
addresses
- Modified build logic to detect DNS configuration changes and recreate
the builder container when DNS settings differ
- Passed DNS configuration to BuilderStart.start() method
- Updated builder container creation to use specified DNS nameservers or
fall back to network gateway
## Type of Change
- [ ] Bug fix
- [X] New feature
- [ ] Breaking change
- [ ] Documentation update
## Motivation and Context
This change adds --dns parameter support to the build command, matching
the existing functionality in the run command. This allows users to
specify custom DNS nameservers (like Google DNS 8.8.8.8) when building
container images, which is essential when the host machine uses a local
DNS resolver (e.g., 127.0.0.2) that doesn't work inside containers.
## Testing
- [X] Tested locally
- [ ] Added/updated tests
- [ ] Added/updated docs
---------
Co-authored-by: J Logan <sgtbakerrahulnet@yahoo.com>
commit 55f2112
Author: J Logan <john_logan@apple.com>
Date: Fri Jan 23 11:35:10 2026 -0800
Place image store data correctly for app-root path. (apple#1085)
- Closesapple#1084.
commit 5746ec3
Author: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Date: Sat Jan 24 03:32:59 2026 +0800
Fix: prevent delete default network (apple#1083)
- Fixedapple#1073
- Move the conditional check to the front; there's no need
to check for a default network after filtering.
Signed-off-by: ChengHao Yang <17496418+tico88612@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@manuschillerdev@jglogan