Commit Graph
252 Commits
Author SHA1 Message Date
Dmitry Kovba a829fdcdfd Improve log and error messages (#352)
Improved log and error messages.
2025-10-27 09:21:54 -07:00
J Logan 3897e578c3 Use exact permissions for socket mount into guest. (#362)
- Closes #361.
2025-10-25 22:19:06 -07:00
Kathryn Baldauf 1165faabd8 Use correct flag size in Mount for glibc (#360)
The mount flags are defined as `Int`s for musl but as `Int32`s for
glibc, despite the mount methods expecting `Int32` for both. This was
leading to build errors when building with glibc like:

```
 |         "async": .init(true, MS_SYNCHRONOUS),
 |                              `- error: cannot convert value of type 'Int' to expected type 'Int32'
```

This PR allows for different Int sizes based on if we're building for
glibc or not to avoid this build error.

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
2025-10-24 17:32:35 -07:00
Kathryn Baldauf 41eda106e3 Only load epoll file if we can import musl (#359)
This class does not work for glibc due to missing flags and methods.
This PR removes the ability to load the `Epoll` class when using glibc
for now.

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
2025-10-24 16:48:25 -07:00
Kathryn Baldauf a27fefbb59 Add custom decoder inits for various oci types that use omitempty (#347)
Many fields on the various OCI types use "omitempty" for encoding and
decoding the json representation in golang. This PR adds custom json
decoder functions to allow for behavior similar to "omitempty".

---------

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
2025-10-24 15:05:40 -07:00
Danny Canter 0297605ef8 Bump ctr-example to 0.12.0 (#357)
It takes a pinned dependency on cz and was quite a bit behind.
2025-10-24 14:48:39 -07:00
Danny Canter f697215e54 LinuxContainer: Stop all relays on create failure (#358)
If create fails we don't cleanup the relays we may have setup.
2025-10-24 14:48:26 -07:00
Dmitry Kovba c7af5b8222 Rename process to command (#354)
Rename `process` to `command` (assuming we agree on the change).
2025-10-24 13:27:56 -07:00
J Logan 6f7601e475 Handle EOF on one side of a UnixSocketRelay. (#323)
- Current implementation shuts down everything as soon as EOF is
detected on DispatchSourceRead for the relay. This is problematic for,
say an HTTP request where the client makes a request, and calls
`shutdown(fd, SHUT_WR)` to close the send side, but it expects to be
able to keep calling `recv()` to get the response.
- Changed cancel handlers so that the one that sees that both sources
have been cancelled then closes both the UDS and vsock fds.
- Updated vminitd VsockProxy to also do `shutdown(fd, SHUT_WR)` for read
hangup or EOF, and only close the underlying fds and unwire pollers on
full hangup, broken pipe, error, or when both sides half-close.
2025-10-24 13:13:13 -07:00
Dmitry Kovba 57ad7ad629 Throw an error in StandardIO.resize() (#350)
Throw an error in `StandardIO.resize()`, which is unsupported.
2025-10-24 12:52:58 -07:00
Dmitry Kovba 2dbba786d2 Use a protocol type instead of the concrete type (#353)
Use a protocol type instead of the concrete type.
2025-10-24 12:49:03 -07:00
Dmitry Kovba 9f5aaf247a Remove an unnecessary function (#351)
Remove an unnecessary function to simplify the code.
2025-10-24 11:48:55 -07:00
Dmitry Kovba a405d88e6d Throw an error for an empty array (#349)
Throw an error for an empty array before accessing the first element.
2025-10-24 11:19:25 -07:00
Danny Canter ca657f5009 Always provide a serial console (#346) 2025-10-23 14:32:56 -07:00
Danny Canter dc4284a149 Introduce new experimental LinuxPod type (#343)
Closes #319

Introduces a new type capable of running > 1 container in the guest. The
API mostly follows LinuxContainer, and each individual container can be
addressed via any of the methods that require you to pass the
containerID as the first param. Today there's no support for namespace
sharing, but that shouldn't be terrible to support.
2025-10-23 13:59:58 -07:00
Dmitry Kovba 3d7bb7bb5c Fix log metadata when starting a process (#345) 2025-10-23 13:28:21 -07:00
Danny Canter 22f7b6ac13 LinuxContainer: Add bootlog as configuration field (#344)
Closes #227

Previously, the bootlog was supplied once in the constructor to
VZVirtualMachineManager which meant that if you used this same manager
for multiple ctrs that all logs would end up going to the same file,
which becomes quite cumbersome to follow..

This change moves bootlog to be a container configuration param and also
moves it to be a VMConfiguration param, so it can be threaded through
from LinuxContainer -> vmm.create() and be truly container unique now.
The largest driver for this was the integration tests which today every
single test spits out logs to a singular file, making guest
investigations tricky to actually look into.

Result after:
```
➜  containerization git:(bootlog-per-ctr) ✗ ls -alh bin/bootlogs
total 1520
drwxr-xr-x@ 24 dcantah  staff   768B Oct 22 17:34 .
drwxr-xr-x@  8 dcantah  staff   256B Oct 22 17:34 ..
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-cat-mount.log
-rw-------@  1 dcantah  staff    22K Oct 22 17:34 test-cgroup-limits.log
-rw-------@  1 dcantah  staff   249K Oct 22 17:34 test-concurrent-processes-output-stress.log
-rw-------@  1 dcantah  staff   167K Oct 22 17:34 test-concurrent-processes.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-container-devconsole.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-container-hostname.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-container-hosts-file.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-container-manager.log
-rw-------@  1 dcantah  staff    22K Oct 22 17:34 test-container-reuse.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-container-statistics.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-container-stdin.log
-rw-------@  1 dcantah  staff     0B Oct 22 17:34 test-nested-virt.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-pause-resume-io.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-pause-resume-wait.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-pause-resume.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-process-custom-home-envvar.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-process-echo-hi.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-process-false.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-process-home-envvar.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-process-true.log
-rw-------@  1 dcantah  staff    11K Oct 22 17:34 test-process-tty-envvar.log
-rw-------@  1 dcantah  staff    38K Oct 22 17:34 test-process-user.log
```
2025-10-23 03:27:24 -07:00
Danny Canter 1fa051bb69 VZVirtualMachineInstance: Move event loop shutdown slightly up (#342)
This and the work on it should likely be gone before vm shutdown.
2025-10-22 14:35:18 -04:00
Danny Canter 056a909081 VirtualMachineManager: Rework protocol (#341)
Today this protocols create method is just odd. Our only implementation
of it immediately casts to LinuxContainer, failing if it cannot do so. I
think what might make more sense is to pass in a configuration itself
with core parameters that we expect every vmm to be able to support, and
then in a specific implementation they can continue to cast this type to
a specific one to possibly extract some extra configuration values
(rosetta for VZ for example).

This rework will also make it simpler to support a Pod type, as the vm
setup is identical and simple.
2025-10-21 01:23:00 -07:00
Danny Canter 4f996d3509 LinuxContainer: Move Process type out of Configuration (#340)
As a first step to making a pod type, move the nested process
configuration out of LinuxContainer.Configuration.Process and into a
standalone LinuxProcessConfiguration type.
2025-10-20 10:52:48 -07:00
Melissa Kilby 26dcd68340 chore: restrict GitHub workflow permissions - future-proof (#339)
See https://github.com/swiftlang/github-workflows/issues/167 for
additional context

This approach aligns with security best practices, as detailed in the
following documentation:

-
https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions
-
https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#defining-access-for-the-github_token-scopes
-
https://openssf.org/blog/2024/08/12/mitigating-attack-vectors-in-github-workflows/


The default GITHUB_TOKEN permissions are defined at the repository
level. This PR modifies the workflow-level overrides to conform to
OpenSSF best practices -> defense in depth.

Allow me to quote OpenSSF:

https://github.com/ossf/scorecard/blob/main/docs/checks.md#token-permissions

> The highest score is awarded when the permissions definitions in each
workflow's yaml file are set as read-only at the top level and the
required write permissions are declared at the run-level.”

> Remediation steps
> - Set top-level permissions as read-all or contents: read as described
in GitHub's documentation.
> - Set any required write permissions at the job-level. Only set the
permissions required for that job; do not set permissions: write-all at
the job level.


Compare to the LLVM project:

Top-level: contents read, e.g.
https://github.com/swiftlang/llvm-project/blob/next/.github/workflows/build-ci-container-windows.yml#L3-L4
-> this makes it future-proof

Job-level: Allow write permissions as needed, e.g.
https://github.com/swiftlang/llvm-project/blob/next/.github/workflows/build-ci-container-windows.yml#L53-L58

Signed-off-by: Melissa Kilby <mkilby@apple.com>
2025-10-17 15:00:03 -07:00
Kathryn Baldauf 09da9205c6 Make vmm create protocol async (#338)
The `vmm.create` call is already made within an async function. This PR
updates the protocol to allow other vmm implementations more flexibility
in `create`.

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
2025-10-17 14:54:57 -07:00
Kathryn Baldauf a14fd26a24 Add fallback to use lstat to get file permissions in archive writer (#337)
Allow different path for getting file permissions in archive writer,
gated by OS check

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
2025-10-16 16:04:00 -07:00
Kathryn Baldauf fa3c348bfe Add close method to IO writer protocol (#336)
Add close method to IO writer protocol and update testing BufferWriter
to conform to the protocol

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
2025-10-16 14:23:39 -07:00
Kathryn Baldauf 61049408dc Make some image/mounting related functions public (#335)
Make some image/mounting related functions public for use outside of
this repo

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
2025-10-16 14:03:23 -07:00
Kathryn Baldauf a0f860822a Allow runtime options for generic mounts (#334)
Make generic mounts more flexible by passing in runtime options and
making the init function public

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
2025-10-16 11:52:45 -07:00
Danny Canter 21d0c799b8 Add runc process launch wrapper (#333)
Somewhat simple and missing events and some other bits I believe, but
it's a start. Maybe should use the async subprocess type as well instead
of our homegrown Command.
2025-10-16 14:24:25 -04:00
Danny Canter 8a34763e40 Socket: Add fd receiving (#330)
Via scm_rights. Useful for supporting spawning runc as an OCI runtime as
that's how the pty is passed to the client.
2025-10-14 15:59:56 -07:00
Danny Canter 91ef4009a3 Integration: Lower default concurrency (#331)
I only see a very small delta halving this (.6 seconds), and the default
will likely stress the CI machines a lot more. This change also swaps
the atomic increments to .relaxed, as there's no ordering required, just
need no torn writes.
2025-10-14 12:55:10 -07:00
Santosh Bhavani 87e8fd1673 Add configurable concurrent layer downloads (#311)
Adds `maxConcurrentDownloads` parameter to `ImageStore.pull()`.

Performance improvement: ~1.2-1.3x faster pulls for multi-layer images
with higher concurrency.

Signed-off-by: Santosh Bhavani <santosh.bhavani@live.com>
2025-10-13 22:29:12 -07:00
Kathryn Baldauf e283e023ab Use container's environment when starting the init process (#329)
Fixes an issue first described in
https://github.com/apple/container/issues/740.

Previously the initial process of the container was using vminitd's
environment variables to find the target executable. This PR updates the
code to use the container's configured environment for the initial
process instead. The behavior of an exec in a container should be the
same as before.

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
2025-10-13 21:33:18 -07:00
Danny Canter 6e96cdb3a0 Integration: Run tests concurrently (#326) 2025-10-10 11:02:58 -07:00
Danny Canter d0383eb5bf LinuxContainer: AsyncMutex-ify LinuxContainer (#325)
This change moves LinuxContainer to use the new AsyncMutex type. This allows us to keep using our old state machine model, but lock around the entirety of operations. This also allows us to axe quite a few states that were intermediary states only there to protect against multiple threads calling (even if it was unlikely..) the same method at the same time (.creating, .starting, .stopping etc.).

The rationale is: Mutex is somewhat tricky to use as you can't (for good reason) do any async work inside the closure. This makes some of our work difficult as every single interaction with the guest is via an rpc, which is all async. There really isn't a worry about contention, because most container methods will only ever be invoked once (create, start, stop) so a big heavy lock isn't much of a deterrent.
2025-10-09 15:09:53 -07:00
Danny Canter 40727e49ba Vminitd: Write cgroup limits (#322)
Fixes #320

Today we don't actually setup any cgroup limits, as because there's a
1-1 mapping from container<->vm we can just use the VMs resources as the
limit (can't use more than 1GB if that's all the guest sees :) ).
However, if we ever supported > 1 container in the guest it'd be
necessary to actually setup the cg limits. This change just sets a
memory limit and cpu toggles to match whatever was specific for the
container.
2025-10-09 16:03:40 -04:00
Danny Canter d18d1186a2 ContainerizationExtras: Add AsyncMutex (#324)
We already have `AsyncLock`, but in some cases it'd be nice to have the
type protect a piece of data that you access through the lock, much like
the Synchronization frameworks new `Mutex` type.

This change adds such a type.
2025-10-09 10:47:35 -04:00
J Logan 2443a245cb Fixes proxy logic in RegistryClient. (#314)
- Closes #255.
- Fixes ProxyUtils so that the environment variable to be used for proxy
selection is determined by the request scheme.
- RegistryClient uses ProxyUtils to get the proxy URL used by the
HTTPClient.
- Tweak hostname resolution error message to avoid misleading output if
the proxy hostname cannot be resolved.
2025-10-09 10:30:49 -04:00
Danny Canter 06d3a37f8d Add support for container statistics (#318)
Closes #138

This rounds up cgroup and network stats (via netlink) and exposes them
via an agent rpc and on LinuxContainer. While this is not an entirely
accurate view into the full resources being used by the container given
the virtualized nature (doesn't account for vcpu, device etc overhead)
it should give an accurate overview of the workload resource usage in
the guest.

This change besides the stated goal also removes the interfaceStatistics
rpc and just moves these network stats into the new containerStatistics
one. Related to that, it also renames the InterfaceStatistics struct to
NetworkStatistics and moves this into ContainerStatistics as a nested
struct.
2025-10-08 10:09:10 -04:00
Eric Ernst 85de8fc0c5 make: fix coverage target (#313)
Address capitalization error

Signed-off-by: Eric Ernst <eric_ernst@apple.com>
2025-10-06 11:16:14 -07:00
Danny Canter 996cdceae0 Update InterfaceStatistics.swift license header (#310)
Checked in before the all rights reserved was removed shortly after.
2025-10-05 15:02:48 -07:00
J Logan 995a231348 Removes "all rights reserved" from license header. (#309) 2025-10-03 13:27:59 -07:00
Danny Canter 80e2813bcf Netlink: Add stats support (#308)
Adds support for grabbing stats for an iface. This will be surfaced in a
coming change to get container level statistics from the guest, where
one field will be network stats.
2025-10-03 12:53:35 -07:00
Eric Ernst f9ae8f7801 make: add coverage target (#307)
Add coverage target for getting csv code-coverage output

Signed-off-by: Eric Ernst <eric_ernst@apple.com>
2025-10-03 01:43:11 -07:00
Danny Canter 183255ee0e Vminitd: Add cgroup stats support (#306)
This is not wired up to anything right now, but it will be used for
implementing stats gathering on the host via an rpc in the future. I've
left off the rpc portion as this is already a decent amount to review.
2025-10-01 11:26:45 -04:00
Dmitry Kovba b331d29959 Update an issue template (#304)
This PR adds the default value "N/A" to the logs section to prevent it
from being empty in most issues.
2025-10-01 11:24:31 -04:00
Danny Canter 28892cfa11 Kernel: Fix make (#301)
Fixes #296

Today the kernel subdirectory is somewhat useless. The dockerfile we had
tried to use an image that isn't actually on ghcr, so everything would
kind of just crap out. This change swaps things so that we build a local
image that has all the bits needed to compile the kernel, and then uses
that image to build the resulting kernel and plop it in the current
working directory. This change does add a reliance on `container` being
installed however, but for folks that need to build a custom kernel this
doesn't seem like too much of an issue to me.
2025-09-30 18:48:20 -07:00
J Logan 992ed9f5aa Adds public init for ExitStatus. (#305)
Client code may want to return ExitStatus from
functions that return a containerization process
return code, or -1 for caught exceptions.
2025-09-30 17:57:26 -07:00
Michael Crosby cb6b78f580 dns config should have options not opts (#303)
Signed-off-by: crosbymichael <michael_crosby@apple.com>
2025-09-29 16:35:58 -04:00
J Logan b61b932adf Adds --add-file to allow adding files to initfs. (#302)
- Motivation is to be able to add the `swift-backtrace-static` binary as
needed.
- Use singlular `--add-file` and `--label` options since both accept
multiple invocations with single values each.

Example usage:

```bash
./bin/cctl rootfs create \
                --vminitd vminitd/bin/vminitd \
                --vmexec vminitd/bin/vmexec \
                --add-file /Users/john/.swiftpm/swift-sdks/swift-6.2-RELEASE_static-linux-0.0.1.artifactbundle/swift-6.2-RELEASE_static-linux-0.0.1/swift-linux-musl/musl-1.2.5.sdk/aarch64/usr/libexec/swift/linux-static/swift-backtrace-static:sbin/swift-backtrace \
                --label org.opencontainers.image.source=https://github.com/apple/containerization \
                --image vminit:latest \
                bin/init.rootfs.tar.gz
```
2025-09-29 12:38:45 -07:00
Danny Canter 82f2d887dd LinuxContainer/LinuxProcess: Have wait return ExitStatus (#300)
Have wait return a struct containing the exit code and the time at which
the process actually exited. This is useful so higher level tools (like
container) don't need to craft a date themselves, and it will be more
accurate as it's taken in the guest directly after the process exits.
2025-09-29 14:09:37 -04:00
Euan Harris 511dd59e19 Remove accidental dependency on NIOFileSystem (#298)
swift-nio's public export of NIOFileSystem was removed in 2.86.1:
https://github.com/apple/swift-nio/pull/3370

NIOFileSystem was not yet supposed to be public, but _NIOFileSystem
depended on it as a public import. This made it possible for
`containerization` to see the `NIOFileSystem` package by accident.

Replacing the use of `NIOFileSystem` by `_NIOFileSystem`, as used
elsewhere, fixes the problem.

## Why does CI currently pass?

The change in `swift-nio` does not currently cause `containerization`'s
CI to fail because `Package.resolved` pins `swift-nio` to 2.83.0, before
the change was made. New versions of upstream dependencies will not be
tested until `Package.resolved` is explicitly updated.

When containerization is built as a dependency of a end-user project,
its `Package.resolved` file is ignored. Instead, the dependency
constraints from containerization's Package.swift file are combined with
those of the project and any other library dependencies, so SwiftPM or
Xcode can find a set of mutually compatible packages. This can lead to
new versions of containerization's upstream dependencies being used,
even though those versions have never been tested in CI.

The build failure can be demonstrated by creating a new package which
depends on `containerization` but does not constrain package versions:
```
    % swift package init --type executable
    Creating executable package: test
    Creating Package.swift
    Creating Sources
    Creating Sources/test/test.swift
    % cat > Package.swift <<EOF
    heredoc> // swift-tools-version: 6.2
    // The swift-tools-version declares the minimum version of Swift required to build this package.

    import PackageDescription

    let package = Package(
        name: "test",
        platforms: [
            .macOS(.v26),
        ],
        dependencies: [
            .package(url: "https://github.com/apple/containerization", from: "0.7.2"),

        ],
        targets: [
            // Targets are the basic building blocks of a package, defining a module or a test suite.
            // Targets can depend on other targets in this package and products from dependencies.
            .executableTarget(
                name: "test",
                dependencies: [
                    .product(name: "Containerization", package: "containerization"),
                ]
            ),
        ]
    )
    EOF
    % swift build
    ...
    /private/tmp/test/.build/checkouts/containerization/Sources/ContainerizationOCI/Client/RegistryClient+Fetch.swift:25:8: error: no such module 'NIOFileSystem'
     23 |
     24 | #if os(macOS)
     25 | import NIOFileSystem
        |        `- error: no such module 'NIOFileSystem'
     26 | #endif
     27 |
```
2025-09-23 09:52:29 -07:00