DEV Community

Alain Airom
Alain Airom

Posted on

First Hands-On Experience with Apple Containers!

A very first test with Apple containers!

Introduction

In the world of software development, few concepts have been as transformative as containerization. For years, developers have battled the infamous “works on my machine” problem — a frustrating situation where code functions perfectly in one environment but fails to run in another. Containers emerged as the ultimate solution, providing a consistent, isolated, and portable environment that bundles an application and all its dependencies, ensuring it runs the same way everywhere.

Traditionally, developers on macOS have relied on virtualization technologies to run containers, primarily through tools like Docker Desktop. While effective, this layer of virtualization often introduced performance overhead and a slight disconnect from the native operating system. However, a new chapter is beginning. With the introduction of native container support on macOS, Apple is bringing containerization directly into the core of its operating system. This is poised to dramatically improve performance, streamline developer workflows, and usher in a new era of seamless, efficient development. This shift holds significant implications for how we build, test, and deploy applications on Apple’s platform.

By the way, since Docker Desktop is a commercial software, I use Podman / Podman desktop, open-source tool(s) which in many regards is way better than Docker Desktop.

First tests

If you want to try Apple “container”, go to the GitHub page (link provided below) and follow the steps.

Below is what we can read from the public Apple’s GitHub page;

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-compatible 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-compatible application.
container uses the Containerization Swift package for low level container, image, and process management.

The very first step to do is to download the container package and install it on a your Mac computer (silicon only). The releases are avaiable from this page: https://github.com/apple/container/releases

Once the package is installed, run the following command and follow the steps ⬇️

> container system start
Verifying apiserver is running...
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...

> container system start
Verifying apiserver is running...
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...
> container system start
Verifying apiserver is running...
Enter fullscreen mode Exit fullscreen mode

Then, refering to the documentation, you need to “Configure memory and CPUs for your containers”.

Since the containers created by container are lightweight virtual machines, consider the needs of your containerized application when you use container run. The --memory and --cpus options allow you to override the default memory and CPU limits for the virtual machine. The default values are 1 gigabyte of RAM and 4 CPUs. You can use abbreviations for memory units; for example, to run a container for image big with 8 CPUs and 32 gigabytes of memory, use:

container builder start --cpus 8 --memory 32g
Enter fullscreen mode Exit fullscreen mode

After this point, I followed the steps from this point on: “Build an image https://github.com/apple/container/blob/main/docs/tutorial.md#build-an-image”.

mkdir web-test
cd web-test
Enter fullscreen mode Exit fullscreen mode
FROM docker.io/python:alpine
WORKDIR /content
RUN apk add curl
RUN echo '<!DOCTYPE html><html><head><title>Hello</title></head><body><h1>Hello, world!</h1></body></html>' > index.html
CMD ["python3", "-m", "http.server", "80", "--bind", "0.0.0.0"]
Enter fullscreen mode Exit fullscreen mode
container build --tag web-test --file Dockerfile .
Enter fullscreen mode Exit fullscreen mode

But after failing 3 times (and not being able to resolve the problem);

> container build --tag web-test --file Dockerfile .
[+] Building 11.9s (5/8)                                                                                                                                                       
 => [resolver] fetching image...docker.io/library/python:alpine                                                                                                           0.0s
 => [internal] load .dockerignore                                                                                                                                         0.0s
 => => transferring context: 2B                                                                                                                                           0.0s
 => oci-layout://docker.io/library/python:alpine@sha256:9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef30ad48844                                                  0.0s
 => => resolve docker.io/library/python:alpine@sha256:9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef30ad48844                                                    0.0s
 => CACHED [linux/arm64/v8 1/6] WORKDIR /content                                                                                                                          0.0s
 => ERROR [linux/arm64 2/6] RUN apk update                                                                                                                               10.1s
------                                                                                                                                                                         
 > [linux/arm64 2/6] RUN apk update:                                                                                                                                           
0.056 fetch https://dl-cdn.alpinelinux.org/alpine/v3.22/main/aarch64/APKINDEX.tar.gz                                                                                           
5.071 WARNING: updating and opening https://dl-cdn.alpinelinux.org/alpine/v3.22/main: temporary error (try again later)                                                        
5.071 fetch https://dl-cdn.alpinelinux.org/alpine/v3.22/community/aarch64/APKINDEX.tar.gz
10.09 WARNING: updating and opening https://dl-cdn.alpinelinux.org/alpine/v3.22/community: temporary error (try again later)
10.09 4 unavailable, 0 stale; 29 distinct packages available
------
Error: unknown (2): failed to solve: process "/bin/sh -c apk update" did not complete successfully: exit code: 4

Enter fullscreen mode Exit fullscreen mode

I decided to bypass this and made a vey basic test as follows… ⬇️

  • The new Dockerfile;
FROM docker.io/python:alpine
WORKDIR /content
COPY index.html .
EXPOSE 80
CMD ["python3", "-m", "http.server", "80", "--bind", "0.0.0.0"]
Enter fullscreen mode Exit fullscreen mode
  • A simple HTML file;
<!DOCTYPE html>

<html>
<head>
<title>Hello</title>
</head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode
  • Build & Run ⬇️
container build --tag web-test --file Dockerfile .
[+] Building 1.2s (7/7) FINISHED                                                                                                                                               
 => [resolver] fetching image...docker.io/library/python:alpine                                                                                                           0.0s
 => [internal] load .dockerignore                                                                                                                                         0.0s
 => => transferring context: 2B                                                                                                                                           0.0s
 => oci-layout://docker.io/library/python:alpine@sha256:9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef30ad48844                                                  0.0s
 => => resolve docker.io/library/python:alpine@sha256:9ba6d8cbebf0fb6546ae71f2a1c14f6ffd2fdab83af7fa5669734ef30ad48844                                                    0.0s
 => [internal] load build context                                                                                                                                         0.0s
 => => transferring context: 140B                                                                                                                                         0.0s
 => CACHED [linux/arm64/v8 1/3] WORKDIR /content                                                                                                                          0.0s
 => [linux/arm64/v8 2/3] COPY index.html .                                                                                                                                0.0s
 => exporting to oci image format                                                                                                                                         0.1s
 => => exporting layers                                                                                                                                                   0.0s
 => => exporting manifest sha256:d8250bf6d460293ddd6c726a6c6d2fedf5572cc72016ecfef6b9391c7bbcd850                                                                         0.0s
 => => exporting config sha256:d3f2c260639da2faf5d3f965dc8683105c15142f10b9290977bd5d3e796b43d6                                                                           0.0s
 => => exporting manifest list sha256:7d964d2accb3140ccfb8ba01248c2aedc8a713f0e678a8bd7b82dd343462fc0b                                                                    0.0s
 => => sending tarball                                                                                                                                                    0.1s
Successfully built web-test:latest  
Enter fullscreen mode Exit fullscreen mode
container run -p 8080:80 --rm web-test
192.168.64.1 - - [08/Sep/2025 07:05:46] "GET / HTTP/1.1" 200 -
192.168.64.1 - - [08/Sep/2025 07:05:46] code 404, message File not found
192.168.64.1 - - [08/Sep/2025 07:05:46] "GET /favicon.ico HTTP/1.1" 404 -
Enter fullscreen mode Exit fullscreen mode

  • You can also test from the command line;
> curl http://localhost:8080
curl: (52) Empty reply from server

> container list
ID                                    IMAGE                                               OS     ARCH   STATE    ADDR
buildkit                              ghcr.io/apple/container-builder-shim/builder:0.6.0  linux  arm64  running  192.168.64.2
98e2f6ae-ae92-4ca9-8ffd-0dd7b61abba3  web-test:latest                                     linux  arm64  running  192.168.64.4
Enter fullscreen mode Exit fullscreen mode

Success ⛳

  • Stop the container.
> container stop web-test
Enter fullscreen mode Exit fullscreen mode
  • Delete the container.
> container image list
NAME      TAG     DIGEST
python    alpine  9ba6d8cbebf0fb6546ae71f2...
web-test  latest  7d964d2accb3140ccfb8ba01...


> container images delete web-test
web-test:latest
Reclaimed 124,7 MB in disk space
Enter fullscreen mode Exit fullscreen mode

Conclusion

We’ve seen how the introduction of native support has made using containers on macOS a seamless experience. This is a true game-changer, not just for performance, but also for paving the way for open-source container building and deployment tools. This integration lowers the barrier to entry, making it easier for developers to embrace powerful, community-driven solutions like Podman, which in turn fosters a more open and collaborative container ecosystem. This is a significant step forward, and it’s exciting to think about what the future holds.

Links

Top comments (0)