diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 000000000..6921cb5f7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,76 @@ +name: Bug Report +description: File a bug report. +title: "[Bug]: " +labels: ["bug", "triage"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: checkboxes + id: prereqs + attributes: + label: + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/apple/container/blob/main/CONTRIBUTING.md). + options: + - label: I have searched the existing issues + required: true + - label: If possible, I've reproduced the issue using the 'main' branch of this project + required: false + - type: input + id: contact + attributes: + label: Contact Details + description: How can we get in touch with you if we need more info? ex. email@example.com + validations: + required: false + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + description: Explain how to reproduce the incorrect behavior. + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: Current behavior + description: A concise description of what you're experiencing. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: A concise description of what you expected to happen. + validations: + required: true + - type: textarea + attributes: + label: Environment + description: | + examples: + - **OS**: MacOS 26 Beta 1 + - **Swift**: Apple Swift version 6.2 + - **Xcode**: Xcode 26 Beta 17A5241e + value: | + - OS: + - Swift: + - Xcode: + render: markdown + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/apple/container/blob/main/CONTRIBUTING.md). + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..6f1492fa3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Security disclosure process + url: https://github.com/apple/container/security/advisories/new + about: Please report security vulnerabilities here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 000000000..cb8b3fccb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,32 @@ +name: Feature request +description: File a request for a feature +title: "[Request]: " +labels: ["feature", "triage"] +body: + - type: markdown + attributes: + value: | + Thanks for contributing to the container project! + - type: input + id: contact + attributes: + label: Contact Details + description: How can we get in touch with you if we need more info? + placeholder: ex. email@example.com + validations: + required: false + - type: textarea + id: request + attributes: + label: Feature request details + description: Describe your proposed feature. Code samples that show what's missing, or what new capabilities will be possible, are very helpful! Provide links to existing issues or external references/discussions, if appropriate. + validations: + required: true + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com). + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/.github/workflows/common.yml b/.github/workflows/common.yml index 0d5e27422..b439222b2 100644 --- a/.github/workflows/common.yml +++ b/.github/workflows/common.yml @@ -24,8 +24,6 @@ jobs: - name: Update containerization run: | /usr/bin/swift package update containerization - env: - CONTAINERIZATION_REPO: https://${{ secrets.REPO_READ }}@github.com/apple/containerization.git - name: Check formatting run: | ./scripts/install-hawkeye.sh @@ -33,14 +31,13 @@ jobs: if ! git diff --quiet -- . ':(exclude)Package.swift' ':(exclude)Package.resolved'; then echo "The following files require formatting or license header updates:\n$(git diff --name-only)" ; false ; fi - name: Check protobuf run: | - make BUILDER_SHIM_REPO=https://${{ secrets.REPO_READ }}@github.com/apple/container-builder-shim.git protos + make protos # TODO [launch]: TEMPORARILY we need to exclude these files since we had to modify them to add # the github token for pulling the private repos. if ! git diff --quiet -- . ':(exclude)Package.swift' ':(exclude)Package.resolved' ':(exclude)Protobuf.Makefile'; then echo "The following files require formatting or license header updates:\n$(git diff --name-only)" ; false ; fi env: CURRENT_SDK: y - CONTAINERIZATION_REPO: https://${{ secrets.REPO_READ }}@github.com/apple/containerization.git - name: Set build configuration run: | echo "BUILD_CONFIGURATION=debug" >> $GITHUB_ENV @@ -54,7 +51,6 @@ jobs: env: DEVELOPER_DIR: "/Applications/Xcode_16.3.app/Contents/Developer" CURRENT_SDK: y - CONTAINERIZATION_REPO: https://${{ secrets.REPO_READ }}@github.com/apple/containerization.git - name: Create package run: | mkdir -p outputs @@ -70,7 +66,6 @@ jobs: CONTAINER_REGISTRY_HOST: ghcr.io DEVELOPER_DIR: "/Applications/Xcode_16.3.app/Contents/Developer" CURRENT_SDK: y - CONTAINERIZATION_REPO: https://${{ secrets.REPO_READ }}@github.com/apple/containerization.git - name: Save documentation artifact uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/docs-release.yml b/.github/workflows/docs-release.yml index e27360426..8cfb0ec2a 100644 --- a/.github/workflows/docs-release.yml +++ b/.github/workflows/docs-release.yml @@ -7,7 +7,7 @@ on: jobs: checkBranch: runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags') || startsWith(github.ref, 'refs/heads/release') + if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags') || startsWith(github.ref, 'refs/heads/release') steps: - name: Branch validation run: echo "Branch ${{ github.ref_name }} is allowed" diff --git a/.gitignore b/.gitignore index 7e47ccfb8..024b97af5 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ test_results/ # API docs for local preview only. _site/ +_serve/ diff --git a/BUILDING.md b/BUILDING.md index 3432e5123..1d15e1298 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -13,7 +13,7 @@ Build `container` and the background services from source, and run basic and int make all test integration ``` -Copy the binaries to `/usr/local/bin` and `/usr/local/libexec` (requires entering the an administrator password): +Copy the binaries to `/usr/local/bin` and `/usr/local/libexec` (requires entering an administrator password): ```bash make install @@ -36,19 +36,19 @@ of the `container` repository. Ensure that you [follow containerization instruct to prepare your build environment. 2. In your development shell, go to the `container` project directory. - + ``` cd container ``` -3. If the `container` services are already running, stop them. +3. If the `container` services are already running, stop them. ``` bin/container system stop ``` 4. Configure the environment variable `CONTAINERIZATION_PATH` to refer to your Containerization project, and update your `Package.resolved` file. - + ``` export CONTAINERIZATION_PATH=../containerization swift package update containerization @@ -75,7 +75,7 @@ to prepare your build environment. To revert to using the Containerization dependency from your `Package.swift`: 1. Unset your `CONTAINERIZATION_PATH` environment variable, and update `Package.resolved`. - + ``` unset CONTAINERIZATION_PATH swift package update containerization diff --git a/Makefile b/Makefile index 769580d55..500c1f8c0 100644 --- a/Makefile +++ b/Makefile @@ -170,8 +170,11 @@ check-licenses: .PHONY: serve-docs serve-docs: - @echo 'to browse: open http://127.0.0.1:8000/documentation/' - @python3 -m http.server --bind 127.0.0.1 --directory ./_site + @echo 'to browse: open http://127.0.0.1:8000/container/documentation/' + @rm -rf _serve + @mkdir -p _serve + @cp -a _site _serve/container + @python3 -m http.server --bind 127.0.0.1 --directory ./_serve .PHONY: docs docs: _site @@ -179,7 +182,7 @@ docs: _site _site: @echo Updating API documentation... rm -rf $@ - @scripts/make-docs.sh $@ + @scripts/make-docs.sh $@ container .PHONY: cleancontent cleancontent: @@ -191,4 +194,5 @@ cleancontent: clean: @echo Cleaning the build files... @rm -rf bin/ libexec/ + @rm -rf _site _serve @$(SWIFT) package clean diff --git a/Package.swift b/Package.swift index edab1a1a4..b06883dd5 100644 --- a/Package.swift +++ b/Package.swift @@ -57,10 +57,10 @@ let package = Package( .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.26.0"), .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.29.0"), .package(url: "https://github.com/apple/swift-nio.git", from: "2.80.0"), - .package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.1.0"), + .package(url: "https://github.com/swiftlang/swift-docc-plugin.git", from: "1.1.0"), .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.20.1"), - .package(url: "https://github.com/orlandos-nl/DNSClient", from: "2.4.1"), - .package(url: "https://github.com/Bouke/DNS", from: "1.2.0"), + .package(url: "https://github.com/orlandos-nl/DNSClient.git", from: "2.4.1"), + .package(url: "https://github.com/Bouke/DNS.git", from: "1.2.0"), scDependency, ], targets: [ diff --git a/README.md b/README.md index 19e4ebf92..594a6cf59 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # `container` -`container` is a tool that you can use to create and run Linux containers as lightweight virtual machines on your Mac. It's written in Swift, and optimized for Apple silicon. +`container` is a tool that you can use to create and run Linux containers as lightweight virtual machines on your Mac. It's written in Swift, and optimized for Apple silicon. The tool consumes and produces OCI-compliant container images, so you can pull and run images from any standard container registry. You can push images that you build to those registries as well, and run the images in any other OCI-compliant application. @@ -50,7 +50,7 @@ uninstall-container.sh -k - Take [a guided tour of `container`](./docs/tutorial.md) by building, running, and publishing a simple web server image. - Learn how to [use various `container` features](./docs/how-to.md). - Read a brief description and [technical overview](./docs/technical-overview.md) of `container`. -- View the project [API documentation](https://pages.github.com/apple/container/). +- View the project [API documentation](https://apple.github.io/container/documentation/). ## Contributing diff --git a/Sources/CLI/Registry/Login.swift b/Sources/CLI/Registry/Login.swift index 018a131b3..617bc801e 100644 --- a/Sources/CLI/Registry/Login.swift +++ b/Sources/CLI/Registry/Login.swift @@ -36,9 +36,6 @@ extension Application { @Argument(help: "Registry server name") var server: String - @OptionGroup - var global: Flags.Global - @OptionGroup var registry: Flags.Registry diff --git a/Sources/CLI/System/SystemCommand.swift b/Sources/CLI/System/SystemCommand.swift index efeac1ff6..c884c8279 100644 --- a/Sources/CLI/System/SystemCommand.swift +++ b/Sources/CLI/System/SystemCommand.swift @@ -27,6 +27,7 @@ extension Application { SystemRestart.self, SystemStart.self, SystemStop.self, + SystemStatus.self, SystemKernel.self, ], aliases: ["s"] diff --git a/Sources/CLI/System/SystemStatus.swift b/Sources/CLI/System/SystemStatus.swift new file mode 100644 index 000000000..132607681 --- /dev/null +++ b/Sources/CLI/System/SystemStatus.swift @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// Copyright © 2025 Apple Inc. and the container project authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//===----------------------------------------------------------------------===// + +import ArgumentParser +import ContainerClient +import ContainerPlugin +import ContainerizationError +import Foundation +import Logging + +extension Application { + struct SystemStatus: AsyncParsableCommand { + static let configuration = CommandConfiguration( + commandName: "status", + abstract: "Show the status of `container` services" + ) + + @Option(name: .shortAndLong, help: "Launchd prefix for `container` services") + var prefix: String = "com.apple.container." + + func run() async throws { + let isRegistered = try ServiceManager.isRegistered(fullServiceLabel: "\(prefix)apiserver") + if !isRegistered { + print("apiserver is not running and not registered with launchd") + Application.exit(withError: ExitCode(1)) + } + + // Now ping our friendly daemon. Fail after 10 seconds with no response. + do { + print("Verifying apiserver is running...") + try await ClientHealthCheck.ping(timeout: .seconds(10)) + print("apiserver is running") + } catch { + print("apiserver is not running") + Application.exit(withError: ExitCode(1)) + } + } + } +} diff --git a/Sources/Services/ContainerImagesService/Server/SnapshotStore.swift b/Sources/Services/ContainerImagesService/Server/SnapshotStore.swift index a5f7e927e..40236d026 100644 --- a/Sources/Services/ContainerImagesService/Server/SnapshotStore.swift +++ b/Sources/Services/ContainerImagesService/Server/SnapshotStore.swift @@ -62,6 +62,9 @@ public actor SnapshotStore { guard let platform = desc.platform else { throw ContainerizationError(.internalError, message: "Missing platform for descriptor \(desc.digest)") } + guard Self.shouldUnpackPlatform(platform) else { + continue + } let currentSubTask = await taskManager.startTask() if let progressUpdate { let _taskUpdateProgress = ProgressTaskCoordinator.handler(for: currentSubTask, from: progressUpdate) @@ -183,6 +186,13 @@ public actor SnapshotStore { try self.fm.createDirectory(at: uniqueDirectoryURL, withIntermediateDirectories: true, attributes: nil) return uniqueDirectoryURL } + + private static func shouldUnpackPlatform(_ platform: Platform) -> Bool { + guard platform.os == "linux" else { + return false + } + return true + } } extension FileManager { diff --git a/docs/how-to.md b/docs/how-to.md index 06d48c3c5..8432fbe67 100644 --- a/docs/how-to.md +++ b/docs/how-to.md @@ -94,7 +94,7 @@ container images push registry.example.com/fido/web-test:latest Use the `inspect` command and send the result to the `jq` command to get pretty-printed JSON for the images or containers that you specify:
-% container images inspect web-test | jq
+% container images inspect web-test | jq
[
{
"name": "web-test:latest",
@@ -152,9 +152,9 @@ The `container logs` command displays the output from your containerized applica
% container run -d --dns-domain test --name my-web-server --rm registry.example.com/fido/web-test:latest
my-web-server
-% curl http://my-web-server.test
+% curl http://my-web-server.test
<!DOCTYPE html><html><head><title>Hello</title></head><body><h1>Hello, world!</h1></body></html>
-% container logs my-web-server
+% container logs my-web-server
192.168.64.1 - - [15/May/2025 03:00:03] "GET / HTTP/1.1" 200 -
%
diff --git a/docs/technical-overview.md b/docs/technical-overview.md
index 90346f6f2..55e2eda66 100644
--- a/docs/technical-overview.md
+++ b/docs/technical-overview.md
@@ -45,15 +45,15 @@ When `container-apiserver` starts, it launches an XPC helper `container-core-ima
## What limitations does `container` have today?
-With the initial release of `container`, you get basic facilities for building and running containers, but many common containerization features remain to be implemented. Consider [contributing](/CONTRIBUTING.md) new features and bug fixes to `container` and the Containerization projects!
+With the initial release of `container`, you get basic facilities for building and running containers, but many common containerization features remain to be implemented. Consider [contributing](../CONTRIBUTING.md) new features and bug fixes to `container` and the Containerization projects!
### Container to host networking
-In the initial release, there is no way to route traffic directly from a client in a container to an host-based application listening on the loopback interface at 127.0.0.1. If you were to configure the application in your container to connect to 127.0.0.1 or `localhost`, requests would simply go to the loopback interface in the container, rather than your host-based service.
+In the initial release, there is no way to route traffic directly from a client in a container to a host-based application listening on the loopback interface at 127.0.0.1. If you were to configure the application in your container to connect to 127.0.0.1 or `localhost`, requests would simply go to the loopback interface in the container, rather than your host-based service.
You can work around this limitation by configuring the host-based application to listen on the wildcard address 0.0.0.0, but this practice is insecure and not recommended because, without firewall rules, this exposes the application to external requests.
-A more secure approach uses `socat` to redirect traffic from the container network gateway to the host-based service. For example, to forward traffic for port 8000, configure your containerized application to connect to `192.68.64.1:8000` instead of `127.0.0.1:8000`, and then run the following command in a terminal on your Mac to forward the port traffic from the gateway to the host:
+A more secure approach uses `socat` to redirect traffic from the container network gateway to the host-based service. For example, to forward traffic for port 8000, configure your containerized application to connect to `192.168.64.1:8000` instead of `127.0.0.1:8000`, and then run the following command in a terminal on your Mac to forward the port traffic from the gateway to the host:
```bash
socat TCP-LISTEN:8000,fork,bind=192.168.64.1 TCP:127.0.0.1:8000
@@ -79,13 +79,13 @@ In macOS 15, limitations in the vmnet framework mean that the container network
Normally, vmnet creates the container network using the CIDR address 192.168.64.1/24, and on macOS 15, `container` defaults to using this CIDR address in the network helper. To diagnose and resolve issues stemming from a subnet address mismatch between vmnet and the network helper:
-- Before creating the first container, scan the output of the command `ifconfig` for all bridge interface named similarly to `bridge100`.
+- Before creating the first container, scan the output of the command `ifconfig` for a bridge interface named similarly to `bridge100`.
- After creating the first container, run `ifconfig` again, and locate the new bridge interface to determine container the subnet address.
- Run `container ls` to check the IP address given to the container by the network helper. If the address corresponds to a different network:
- Run `container system stop` to terminate the services for `container`.
- Using the macOS `defaults` command, update the default subnet value used by the network helper process. For example, if the bridge address shown by `ifconfig` is 192.168.66.1, run:
```bash
- defaults write com.apple.container.defaults default.subnet 192.168.66.1/24
+ defaults write com.apple.container.defaults network.subnet 192.168.66.1/24
```
- Run `container system start` to launch services again.
- Try running the container again and verify that its IP address matches the current bridge interface value.
diff --git a/docs/tutorial.md b/docs/tutorial.md
index 7e2bcfc44..f38612771 100644
--- a/docs/tutorial.md
+++ b/docs/tutorial.md
@@ -21,7 +21,7 @@ If you have not installed a Linux kernel yet, the command will prompt you to ins
Verifying apiserver is running...
Installing base container filesystem...
-No default kernel configured.
+No default kernel configured.
Install the recommended default kernel from [https://github.com/kata-containers/kata-containers/releases/download/3.17.0/kata-static-3.17.0-arm64.tar.xz]? [Y/n]: y
Installing kernel...
%
@@ -188,7 +188,7 @@ Open the website, using the container's IP address in the URL:
open http://192.168.64.3
```
-If you configured the local domain `test` earlier in the tutorial, you can also open the page the full hostname for the container:
+If you configured the local domain `test` earlier in the tutorial, you can also open the page with the full hostname for the container:
```bash
open http://my-web-server.test
@@ -244,7 +244,7 @@ container run -it --rm web-test curl http://my-web-server.test
## Run a published image
-Push your image to a container registry, publishing it so that you and others can use it.
+Push your image to a container registry, publishing it so that you and others can use it.
### Publish the web server image