Running macOS inside Linux with Docker-OSX
Originally appeared on my blog.
It just happened to me that at my current workplace, Process Street, I had to fix a bug in our iOS application. But… I’d like to do this on a Linux box, and not on a MacBook. What to do in this case? Let’s run macOS inside a virtual machine!
Table Of Contents
Prerequisites
CPU virtualization
Your CPU should support virtualization like Intel VT or AMD-V. Enable it in your BIOS/UEFI before proceeding. (For example, on my Ryzen system, it was an “AMD SVM” setting that had to be enabled in BIOS.)
Then install Kernel Virtualization Manager (KVM) and QEMU. For Fedora Linux, see docs here. It’s as simple as:
# sudo dnf install @virtualization
Then start the libvirtd
systemd service and check if the kvm
kernel module is running.
With KVM, x86 virtualization offers near-native performance, which means that CPU calls from the Mac virtual machine are routed directly to your processor in a secure way without any kind of emulation penalty.
Although graphics and general UI responsiveness will be slow, but with KVM, software will run blazing fast provided that you have some strong CPU like a more recent Intel i7 or Ryzen 7.
Compare the efficiency of KVM with for example DOSBox, where full emulation is needed because of DOS programs using low-level BIOS interrupts and real CPU mode. That kind of emulation can be orders of magnitude slower, though on today’s machines this is not an issue when emulating DOOM. :)
RAM, disk space
If you want to run Xcode, have at least 16Gb of RAM installed so that you can allocate about 8Gb to the virtual machine.
You’ll need tens of gigabytes of disk space. QEMU “qcow” images will expand like crazy once you start installing software, until they hit a preset limit of 200 Gb. My image file grew to 170 Gb after a few days of use. So have a HDD/SSD ready with plenty of free space.
Docker
As we’ll be using the Docker-OSX project, you’ll need to pull, run and maybe create Docker images locally. You might have luck with podman, though it interacts with your system in a different way than Docker does. YMMV. For installing Docker, follow the installation guide.
Installing Docker-OSX
Get acquainted with the Docker-OSX download page. It has a nice, long README! Commands are subject to change, so please refer to the README for the latest version.
In short, Docker-OSX runs an Arch Linux container that executes QEMU and sets up preinstalled or vanilla macOS images for you. It’s insanely customizable: you can get started quickly via a single docker run
command, but depending on your needs, you can customize several aspects of how the virtual machine is run, like screen resolution, shared folders, USB passthrough, VNC connection and so on.
Get started!
Just run a basic image. Choose your OS version (Catalina, Big Sur, Monterey). I suggest choosing Big Sur which is still supported, but not as new as Monterey which may have some emulation issues.
Run the appropriate command:
docker run -it \
--device /dev/kvm \
-p 50922:10022 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e "DISPLAY=${DISPLAY:-:0.0}" \
sickcodes/docker-osx:big-sur
What does this do? It pulls a prebuilt Big Sur image, forwards your /dev/kvm
device and an X11 socket into the container. It exposes the 10022 port inside the container at 50922 port in your host machine for SSH access (optional). Also it sets up an environment variable which tells the container which X display to use.
For managing Docker containers, I suggest using the Docker extension for Visual Studio code if you don’t want to deal with the command line. It’s very convenient!
Basically, while the container is running, the QEMU virtual machine will keep on running. If you shut down the machine from inside macOS, the container would stop. docker run
starts a brand new container, but you can start the same one later via docker start
.
Install the OS
After booting up, you’ll be greeted with the recovery installer of macOS:
You have to follow the README’s “additional boot instructions” part to format the virtual disk image and install macOS on it (the image contains pre-mounted Big Sur installation media).
Formatting the virtual disk image
It’s really simple point-and click work and you’ll soon be greeted with your own macOS installation!
From here on it’s up to you how you want to customize your image. I’m going to show a few tricks here!
Customizing your installation
Extracting the disk image
The first thing I suggest doing is extracting the macOS disk image so that you’ll have a persistent installation with all your work and settings while you’re experimenting with VM settings. It’s just a single, large file inside /var/lib/docker
:
sudo find /var/lib/docker -size +10G | grep mac_hdd_ng.img
Copy the file to a convenient location where it has space to grow (2-300Gb!). From here on, you can create your own custom image using one of the “naked” containers where this file is simply mounted as a volume:
docker run -it \
--device /dev/kvm \
-v "${PWD}/mac_hdd_ng.img:/image" \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-e "DISPLAY=${DISPLAY:-:0.0}" \
sickcodes/docker-osx:naked
From here on, I suggest creating a text file where you store versions of the docker run
command for your convenience. Time to hack!
Adding RAM & CPU
默认情况下,虚拟机仅创建了 4 个核心和 4 GB 内存。为什么不使用更多呢?根据您的系统,添加参数-e RAM=8 -e CPU_STRING=16
可以使其运行速度更快!
从主机共享文件夹
这个功能非常有用,因为你可能想从主机共享一些文件。可惜的是,它并不那么简单。由于网络功能开箱即用,所以如果只是一些较小的文件,你最好通过 Dropbox 这样的云服务提供商来共享文件!
请参阅此处的说明。您基本上将文件夹名称作为docker run
参数传递,例如-v "$HOME/mac/shared:/mnt/hostshare"
,并添加一些额外的 QEMU 参数,将此文件夹定义为名为 的设备hostshare
。此外,在虚拟机内部,每次启动后,您都必须挂载此文件夹:sudo -S mount_9p hostshare
。
在 Finder 的菜单栏中,点击“前往 - 计算机”即可访问此共享文件夹。这种共享文件夹的速度不如原生的“qcow”磁盘映像快;对于包含数千个文件的文件夹(例如 Git 仓库),请勿使用它,否则访问体验会很慢。
写入共享文件夹
您可能会注意到无法写入共享文件夹。这是由于 Linux 权限系统的工作原理:每个用户都有一个与每个文件关联的 ID。在确定文件系统权限时,实际上是使用此 ID 而不是您的用户名。
macOS 也是符合 POSIX 标准的操作系统,它使用相同的访问模型,但您的 macOS 用户默认很可能具有不同的 ID,因此主机操作系统将拒绝权限。
让共享文件夹对任何人都可写或许可行,但从安全角度来看,这很糟糕。幸运的是,您可以使用几个命令更改您的 macOS 用户 ID。请参阅此处的指南。操作过程不算太复杂,但也不算简单。如果您打算这样做,我建议您在虚拟机中安装任何软件之前进行操作,因为每个文件都需要重置其用户 ID。
网络、访问端口
Docker 中的网络本身就很难,而且我们这个虚拟机是在 QEMU 中运行的。哎哟。除了浏览网页之外,你还可以使用其他用例,这些用例应该开箱即用。
将端口从虚拟机转发到主机(例如,在虚拟机中运行 nginx 或某些服务器后端)是一个有效的用例。对于每个要转发的端口,在设置容器时需要一些额外的参数,请参阅此处的README 部分。
虚拟机访问主机端口localhost
,也可以通过使用 Docker 参数将相应端口转发到容器来实现-p
。QEMU 会设置主机localhost
(位于 Docker 内部!)的10.0.2.2
端口,之后,
设置主机网络
如果您不想将端口逐个转发到 Docker 容器,可以选择使用“主机网络”驱动程序。在这种情况下,您可以通过访问 Linux 机器的所有端口10.0.2.2
。从安全角度来看,这也是一个缺点:只有在您知道自己在做什么的情况下才这样做。
使用 VNC 客户端
默认的 QEMU 窗口可以完成这项工作,但通过 VNC 客户端访问虚拟机更加方便。它具有以下优势:
- 关闭模拟器窗口时无需停止虚拟机
- 显示主机的鼠标光标以获得更流畅的体验
- 捕获键盘快捷键
CMD+C
等。 - 通过键入从主机剪贴板“插入”(即使没有直接剪贴板共享)
- 改变连接质量等。
我建议使用Remmina VNC 客户端,因为它相当先进,但您也可以使用自己的客户端。获取支持 VNC 的版本有多种方法,最简单的方法可能是在仓库中构建自定义 Dockerfile(如果您想要不同的分辨率,请编辑该文件):
$ git clone git@github.com:sickcodes/Docker-OSX.git
$ cd Docker-OSX/vnc-version
$ docker build -t docker-osx:nakedvnc -f Dockerfile.nakedvnc .
记下构建容器时打印的 VNC 密码!该密码在每次运行时都会永久生效,因此您可以将其保存到 VNC 客户端。您可以通过 连接到它。别忘了在 QEMU 菜单栏和VNC 客户端localhost:5999
中分别设置“抓取输入”和“隐藏菜单栏” 。
即使你终止 VNC 连接,你的 macOS 系统仍会继续运行。太棒了!
这是我的示例 Docker 命令供参考,运行具有共享文件夹、自定义图像和主机网络的支持 VNC 的容器(上面构建)。
docker run \
--device /dev/kvm \
--network host \
-v "$HOME/mac/mac_hdd_ng.img:/image" \
-v "$HOME/mac/shared:/mnt/hostshare" \
-e EXTRA="-virtfs local,path=/mnt/hostshare,mount_tag=hostshare,security_model=passthrough,id=hostshare" \
-e RAM=8 \
-e CPU_STRING=16 \
docker-osx:nakedvnc
结论
希望您喜欢这篇小指南。尝试一下这个实验,可以真正展现我们当前虚拟化技术的先进性,并让您能够将 macOS 用于合法用例,例如在安全的虚拟机中进行安全研究。
文章来源:https://dev.to/gombosg/running-macos-inside-linux-with-docker-osx-4e1i