Apple Just Built WSL for the Mac (Container Machines)

BBetter Stack
Computing/SoftwareInternet Technology

Transcript

00:00:00Hidden behind all of the Apple intelligence stuff at WWDC this year,
00:00:03Apple quietly released their own version of Windows subsystem for Linux called Container
00:00:06Machines. These give you a lightweight persistent Linux environment on your Mac in a really easy
00:00:10to use way, and they're actually built on top of Apple's container project which they
00:00:14released last year, which is a Docker alternative, all of which of course is optimized for Apple
00:00:18Silicon. So let's take a look at what container machines are, how they work,
00:00:21and also do a quick recap of Apple containers for everyone who missed them.
00:00:29So I'm going to start by setting up a container machine, and then I'll talk through how all of
00:00:32this is working in a bit. But the one I want is going to be a Ubuntu Linux environment. So I simply
00:00:37have a Docker file here with the Ubuntu image, and then some things in here to install some common
00:00:41tools. This will work with any OCI compatible image, so pretty much all of the ones that you
00:00:46have working with Docker. The only thing it needs to include to be a VM is the system initialization
00:00:50program. Once we have the Docker file image that we want to use for our VM, all we need to do is
00:00:54build this using Apple's container tool. So you can see this is the command I'm using for mine,
00:00:58since I have the Docker file in this folder, and I'm simply going to tag this as local
00:01:01Ubuntu machine, and we can go ahead and hit enter on that and build. The container tool,
00:01:05by the way, works on macOS 26 and above, and you can install it from GitHub by simply going to the
00:01:09repo, going to releases, and downloading the latest package. It looks like the build of my image is
00:01:13done here, and you can see it's very similar to Docker. It's just building an OCI image.
00:01:17That's all we need for a container machine, so now we can simply run container machine create,
00:01:21say the image that we want for our container machine, give it a friendly name,
00:01:24and I'm also going to set this as default, so any command that I run is going to assume
00:01:27I'm on about this container machine, and I don't have to specify it by name. With this we can hit
00:01:31enter, and in literally seconds it is all set up. We can see a bit of information about the
00:01:35container machine that I just created by doing container machine list. Here you can see it has
00:01:38the Ubuntu one that I just created, the IP address, 7 CPUs, and 18 gigabytes of memory. CPU and memory
00:01:44are configurable by the way, but by default it will use half of the memory of your Mac. To actually get
00:01:48using your container machine though, all you need to do is container machine run,
00:01:51and you can leave this blank if you want to enter the interactive terminal, or you can actually just
00:01:54add a command after that if you want to run that on your Linux machine. In this case you can see I
00:01:58just hit enter, and now I'm on an interactive terminal on my Linux environment. We can confirm
00:02:02this by doing something like uname-a, and you see this is printing back that it's Linux Ubuntu,
00:02:06as opposed to when I run this on my Mac and we get back Darwin. Now one of the cool things about
00:02:10container machines is it's got automatic user sharing, so my user has already been copied from my Mac
00:02:14onto my Linux environment, and the same actually goes for your home directory. This will mount your
00:02:18entire home directory as read-write, so I have access in this Linux environment to all of the files that I
00:02:23have on my Mac. You can see where I actually ran container run, it's put me straight into that file
00:02:27in the Linux environment, and we already have those files in there. It does also have its own volume
00:02:31though, so if we navigate to the home directory of this Ubuntu machine, you can see there's currently
00:02:35nothing in there, even though there is on my Mac, and that is because this one is the Linux
00:02:39environment, and this is where you put your .files that are specific to Linux. The folder sharing
00:02:43makes it super easy to develop something on your Mac using all of your normal tools, and maybe even some
00:02:48that are only compatible with macOS, and then simply switch to Linux when you need to test something.
00:02:52For example, I have a very simple BUN application here, and I want to compile this into a single
00:02:56executable that will work on Linux, but I can't actually test Linux on my macOS, so running this,
00:03:01I don't know whether it's worked or not. If we switch over to the container machine though,
00:03:04you can see I can simply run the command straight away. I don't have to transfer files or anything,
00:03:08thanks to the fact that it shares the same file system. If I hit enter here, it works nicely.
00:03:12This application was just a very simple web server with this web page here, which prints what it's
00:03:16running on, so it's currently running on Ubuntu 24. You can also see there's a subscribe going
00:03:20around, something you should definitely do. Now I was just testing out running the BUN
00:03:23development server on the Linux environment, and it does all work, which we can see here,
00:03:27it's running on BUN dev, and it's not compiled. But if I modify one of the source files from my Mac
00:03:31here, maybe say hello instead of subscribe, I am noticing that the hot reloading doesn't seem to be
00:03:35picking up on that behaviour, and I have to restart the BUN development server to get the changes to
00:03:39apply. There we go, now it says hello. I think hot reloading will work the same way that breakpoints
00:03:43do, where they don't actually work if you're on your macOS code version, but what you can do is get
00:03:47your editor to connect to the container machine via SSH, and then edit the files that way, and that
00:03:52way breakpoints and hot reloading will probably work. They actually have a tutorial for how to do this
00:03:55in their documentation. That's basically all there is to show you when it comes to actually using a
00:03:59container machine. I mean, it's just a Ubuntu environment now, and honestly the whole experience
00:04:03is pretty seamless. It's also worth pointing out that you're not limited to just one machine. You could
00:04:08have an Alpine machine, a Ubuntu one, and a Debian one sitting side by side, so you have one distro
00:04:12per target, and honestly it's very nice if you're doing cross-target work. Plus, because these machines
00:04:17can actually run a real SystemD, you can test a proper service stack in there, like having Postgres
00:04:22running as an actual service with your app next to it, and the whole thing is going to behave like the
00:04:26Linux server that you're going to deploy to. The simplicity is one of the core design principles that
00:04:30Apple was pushing for when developing container machines. They wanted fast, lightweight VMs that
00:04:34integrate into your existing workflow and are super easy to spin up as needed, as well as be persistent
00:04:39over time so that you can set up a whole dev environment VM that has all of the tools that
00:04:42you normally need ready for when you need them. Again, it's pretty similar to what Windows subsystem
00:04:47for Linux was trying to achieve. As for how all of this is built and how it compares to Docker and
00:04:51OrbStack, we first need to understand the container tool that was released last year. This is written
00:04:55in Swift and it's meant to be a Docker alternative that can run containers, and it runs any standard
00:04:59OCI image, so anything that you can pull from Docker Hub is still going to work. The unique thing about
00:05:04Apple's approach though is that every container got its own lightweight virtual machine through their
00:05:08virtualization framework, rather than a bunch of containers sharing one big Linux VM, which is what
00:05:13Docker Desktop does. Some benefits of that approach can be security, since each container has the
00:05:17isolation properties of a full VM. Then there's also privacy, since you're only mounting the necessary
00:05:22data into each VM, whereas when you have a shared VM, you actually mount all of the data into that
00:05:27shared VM, so it can be mounted selectively into the individual containers. Finally, there can also be
00:05:31a performance benefit, since containers created using Apple Container actually require less memory than a
00:05:36full VM, and the boot times are pretty similar to Docker and other tools. If we actually look at some
00:05:41benchmarks that RepoFlow did here, comparing Apple Containers with OrbStack and Docker Desktop, we can see the
00:05:46results aren't actually too bad. It's hard to tell here, but Apple Containers actually does achieve the
00:05:50most single-threaded CPU events, but OrbStack was pretty close, there is fractions in it, and that
00:05:55same story continues when we go to multi-threaded as well, they all perform very well. Where Apple does
00:06:00seem to pull a bit of a lead though is in memory throughput, with OrbStack coming in second and Docker
00:06:04Desktop last, but when it comes to startup times for a tiny container, it seems that Apple does have some
00:06:09work left to do here, but it is still sub-second, it's just Docker Desktop and OrbStack do it in less
00:06:14than a quarter of a second. There's loads more benchmarks here, so I'll leave a link to this,
00:06:17but basically the rest of them show that OrbStack has exceptional file system and small file performance,
00:06:22but they also show that Apple Containers is pretty much level, if not better than Docker Desktop.
00:06:27There is a few catches though that you'll want to be aware of before you use container machines,
00:06:30and the first one is memory. As I mentioned earlier, the machine defaults to half of your system RAM,
00:06:35so it is worth knowing that it actually never gives this back. So if you have a memory-intensive
00:06:39workload in the container, maybe during a big build, that memory is actually held until you
00:06:43restart the machine. This is actually one of the unique benefits of OrbStack, where it has dynamic
00:06:47memory, which reduces the memory usage by releasing that unused memory back to macOS. As far as I know,
00:06:53nothing else does this. Second, there's also no GPU and USB pass-through. I have seen open issues
00:06:57for both of these on that GitHub though, so maybe it'll be supported in the future. Third, it also
00:07:02seems a little complex to get GUI apps running, like maybe if you wanted to run the Linux version of
00:07:06VS Code or other Linux-only apps. It's definitely not a seamless experience, I'd probably use something else for
00:07:11this. Finally, there's also a security trade-off because, as I mentioned earlier, that home directory
00:07:15mount that makes everything so convenient is read-write by default, which means that anything that you run
00:07:20inside of that Linux machine can touch your SSH keys, your cloud credentials, and everything on
00:07:25your Mac. It seems you can actually only set the mount to read-only or turn it off entirely. There
00:07:29doesn't seem to be an ability to only mount a specific folder. Overall, having tried out Apple
00:07:33container machines, I'm probably going to stick to OrbStack as it feels like the more polished option
00:07:37today with better resource management and more features, but I know some people don't like that
00:07:40OrbStack is paid for if you want business and commercial use, so without OrbStack, I probably
00:07:45would choose Apple Containers over Docker Desktop, and there's also Klima, which is another great
00:07:49alternative. What do you use? Is it OrbStack, Docker Desktop, or Lima? Let me know in the comments down
00:07:53below, while you're there to subscribe, and as always, see you in the next one.

Key Takeaway

Apple's Container Machines provide a native, virtualization-based Linux environment for macOS that prioritizes security and performance per container, though they currently lack the advanced resource management found in alternatives like OrbStack.

Highlights

  • Apple introduced Container Machines as a lightweight, persistent Linux environment optimized for Apple Silicon on macOS 26 and above.

  • Container Machines build upon Apple's container project, which utilizes the virtualization framework to assign a full virtual machine to every individual container.

  • Default memory allocation for a Container Machine is 50% of the host Mac's total RAM, which remains held by the VM until the machine is restarted.

  • The environment automatically mounts the macOS home directory as read-write, enabling seamless file access between the host and the Linux guest.

  • Benchmarking indicates Apple Containers achieve higher single-threaded CPU event performance than Docker Desktop, though they currently show slower startup times compared to OrbStack and Docker Desktop.

  • Security limitations include a lack of ability to mount specific subfolders, meaning the entire home directory is accessible to the Linux environment by default.

Timeline

Introduction to Container Machines

  • Apple released Container Machines as a Linux environment for macOS.
  • The project is built upon Apple's container tool, a Docker alternative optimized for Apple Silicon.

Container Machines offer a persistent Linux environment on macOS. These machines integrate with Apple's existing container project, which was designed to run OCI-compatible images on Apple Silicon.

Setup and Workflow

  • Setting up a machine requires an OCI-compatible image containing a system initialization program.
  • Users can define CPU and memory allocation, with the default setting using half of the total system memory.
  • The environment supports automatic mounting of the macOS home directory, simplifying file access for development tasks.
  • Running multiple machines side-by-side enables testing across different Linux distributions.

The setup process mimics Docker workflows, using OCI images built with Apple's tools. Upon creation, the VM provides an interactive terminal with direct access to host files. Development workflows benefit from the ability to run Linux-specific tools, though some features like hot reloading may require connecting an editor via SSH to function properly.

Technical Architecture and Performance

  • Every container runs within its own lightweight virtual machine to improve isolation.
  • Architecture prioritizes security and selective data mounting over the shared VM approach used by Docker Desktop.
  • Performance benchmarks show Apple Containers leading in memory throughput and single-threaded CPU events.

Unlike Docker Desktop, which shares one large Linux VM across all containers, Apple's approach assigns a specific virtual machine to each container via their virtualization framework. This isolation improves security and memory efficiency. Comparative tests reveal that while Apple Containers hold an edge in throughput, startup times are currently slower than established alternatives like OrbStack.

Limitations and Considerations

  • Memory allocated to the VM is not dynamically returned to the host OS until the machine is restarted.
  • Current limitations include the absence of GPU and USB pass-through support.
  • Read-write access to the entire home directory presents a security trade-off for users.
  • OrbStack remains a more polished alternative due to dynamic memory management and additional features.

While functional, Container Machines have drawbacks in resource flexibility and security configuration. The inability to release unused memory back to the macOS host and the default broad filesystem access require careful management. Users seeking more refined resource control often prefer alternatives like OrbStack, which supports dynamic memory.

Community Posts

View all posts