banner

Running macOS in a Docker Container with Docker-OSX

Needing a spare macOS instance for testing, CI, or building an app is a common problem, and it usually means either buying more Apple hardware or wrestling with an unofficial VM setup. Docker-OSX takes a different approach: it packages a full macOS install as a Docker image, so you can spin one up, throw it away, and spin up another one with the same reproducibility you’d expect from any other container workload.

How It Actually Works

Docker-OSX isn’t running macOS natively inside a Linux container the way you’d run a normal Linux-based image – macOS isn’t Linux, and Docker’s isolation model is built around the host kernel. What it actually does is use KVM/QEMU hardware virtualisation, wrapped inside a Docker container, to boot a real macOS virtual machine. Docker here is mostly a distribution and orchestration mechanism: a convenient, versioned way to package the QEMU setup, the OpenCore bootloader configuration, and the installation media so the whole thing comes up with one command instead of a long manual VM build.

Because it needs hardware virtualisation, it only really works well on Linux hosts with KVM support and a CPU that supports the necessary virtualisation extensions (Intel VT-x or AMD-V). It is not a way to run macOS on non-Apple hardware in a way that sidesteps Apple’s normal licensing terms – Apple’s software licence agreement restricts running macOS to Apple-branded hardware, and Docker-OSX exists in a legal grey area that’s generally tolerated for personal testing and CI, not for production hosting of macOS workloads on commodity cloud servers.

Requirements

  • A Linux host (bare metal strongly recommended – nested virtualisation inside a cloud VM is possible but adds another layer of complexity and performance loss)
  • KVM support enabled (check with kvm-ok on Debian/Ubuntu, or verify /dev/kvm exists)
  • Docker installed and working
  • A reasonable chunk of RAM and disk – macOS itself isn’t light, so budget at least 8GB RAM and 60GB+ free disk for a comfortable instance

Getting a macOS Container Running

The project ships pre-built images for several recent macOS versions, which is the fastest path to a running instance:

docker run -it 
  --device /dev/kvm 
  -p 50922:10022 
  -v /tmp/.X11-unix:/tmp/.X11-unix 
  -e "DISPLAY=${DISPLAY:-:0.0}" 
  -e "GENERATE_UNIQUE=true" 
  -e "MASTER_PLIST_URL=" 
  sickcodes/docker-osx:latest

The container boots QEMU with a VNC or GUI display (depending on how you’ve mapped X11), walks through the usual macOS first-boot setup, and exposes SSH on the mapped port once it’s up – 50922 in the example above, forwarded to the guest’s SSH port. From there you can treat it like any other remote macOS box: SSH in, run Xcode builds, or drive it via automation.

For a from-scratch install rather than a pre-built image, the project also documents building your own image against an official macOS recovery image, which takes longer but avoids relying on a third party’s already-baked install.

What This Is Actually Good For

  • Disposable CI runners: spin up a fresh macOS instance per build, run your test suite or Xcode archive step, then throw it away – useful if your CI provider’s macOS runners are slow, expensive, or unavailable.
  • Testing across macOS versions: the project’s pre-built images cover several recent releases, so you can validate an installer script or app behaviour against more than one OS version without owning that many Macs.
  • Reproducible research and security testing: a clean, versioned macOS snapshot that resets to a known state every time is genuinely useful for malware analysis or testing installers, where you don’t want side effects persisting between runs.

Performance and Limitations

Set expectations accordingly: this is QEMU-emulated hardware, not a real Mac, so GPU-accelerated work and anything that depends on Apple Silicon specifically won’t behave the same way (Docker-OSX targets Intel-based macOS versions, since QEMU virtualising Apple Silicon is a different and far less mature problem). Boot times are slower than native, and heavy workloads will feel the virtualisation overhead. For quick CLI-driven builds and tests, it’s more than adequate; for GUI-heavy interactive development, a real Mac or a hosted Mac-in-the-cloud service is still the better choice.

If your goal is closer to “I need a Linux box I can throw disposable workloads at” rather than macOS specifically, it’s worth comparing against just running a lightweight VM or container on a Raspberry Pi instead – see our guide to running a k3s cluster on a Raspberry Pi 5 for that side of things.


Leave a Reply