乐趣区

关于容器:为什么在-Apple-Silicon-上装-Docker-这么难

图为外部 Wiki,咱们尝试过各种不同的 Docker 开发环境

最近公司的很多共事都换上了搭载 M1 Pro 或 M1 Max 的新款 MacBook Pro,尽管日常应用的软件如 Chrome、Visual Studio Code 和 Slack 都曾经适配得很好了,但面对 Docker 却犯了难。

家喻户晓,Docker 用到了 Linux 的两项个性:namespaces 和 cgroups 来提供隔离与资源限度,因而无论如何在 macOS 上咱们都必须通过一个虚拟机来应用 Docker。

在 2021 年 4 月时,Docker for Mac(Docker Desktop)公布了 对 Apple Silicon 的实验性反对,它会应用 QEMU 运行一个 ARM 架构的 Linux 虚拟机,默认运行 ARM 架构的镜像,但也反对运行 x86 的镜像。

QEMU 是一个开源的虚拟机(Virtualizer)和仿真器(Emulator),所谓仿真器是说 QEMU 能够在没有来自硬件或操作系统的虚拟化反对的状况下,去模仿运行一台计算机,包含模仿与宿主机不同的 CPU 架构,例如在 Apple Silicon 上模仿 x86 架构的计算机。而在有硬件虚拟化反对的状况下,QEMU 也能够应用宿主机的 CPU 来间接运行,缩小模仿运行的性能开销,例如应用 macOS 提供的 Hypervisor.Framework

Docker for Mac 其实就是别离用到了 QEMU 的这两种能力来在 ARM 虚拟机上运行 x86 镜像,和在 Mac 上运行 ARM 虚拟机。

Docker for Mac 的确很好,除了解决新架构带来的问题之外它还对文件系统和网络进行了映射,容器能够像运行在本机上一样拜访文件系统或裸露网络端口到本机,简直感觉不到虚拟机的存在。但 LeanCloud 退出 TapTap 之后曾经不是小公司了,依照 Docker Desktop 在 2021 年 8 月推出的 新版价格计划,咱们每个人须要领取至多 $5 每月的订阅费用。倒不是咱们不违心付这个钱,只是我想要找一找开源的计划。

之前在 Intel Mac 上,咱们会用 Vagrant 或 minikube 来创立虚拟机,它们底层会应用 VirtualBox 或 HyperKit 来实现理论的虚拟化。但 VirtualBox 和 HyperKit 都没有反对 Apple Silicon 的打算。实际上目前开源的虚拟化计划中只有 QEMU 对 Apple Silicon 有比拟好的反对,QEMU 自身只提供命令行的接口,例如 Docker for Mac 调用 QEMU 时的命令行参数是这样:

/Applications/Docker.app/Contents/MacOS/qemu-system-aarch64 -accel hvf \
-cpu host -machine virt,highmem=off -m 2048 -smp 5 \
-kernel /Applications/Docker.app/Contents/Resources/linuxkit/kernel \
-append linuxkit.unified_cgroup_hierarchy=1 page_poison=1 vsyscall=emulate \
panic=1 nospec_store_bypass_disable noibrs noibpb no_stf_barrier mitigations=off \
vpnkit.connect=tcp+bootstrap+client://192.168.65.2:61473/f1c4db329a4a520d73a79eaa1360de7be7d09948a1ac348b04c8e01f6f6eb2c9 \
console=ttyAMA0 -initrd /Applications/Docker.app/Contents/Resources/linuxkit/initrd.img \
-serial pipe:/var/folders/12/_bbrd4692hv8r9bx_ggw5kp80000gn/T/qemu-console1367481183/fifo \
-drive if=none,file=/Users/ziting/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw,format=raw,id=hd0 \
-device virtio-blk-pci,drive=hd0,serial=dummyserial -netdev socket,id=net1,fd=3 -device virtio-net-device,netdev=net1,mac=02:50:00:00:00:01 \
-vga none -nographic -monitor none

为了理论应用 QEMU 进行开发,咱们须要一个应用上更敌对的封装,可能主动配置好 Docker 和 Kubernetes(或者至多不便编写像 Vagrantfile 一样的脚本),提供相似 Docker for Mac 的网络映射和文件映射,于是我找到了 Lima。

Lima 自称是 macOS 上的 Linux 子系统(macOS subsystem for Linux),它应用 QEMU 运行了一个 Linux 虚拟机,其中装置有 rootless 模式的 containerd,还通过 SSH 提供了文件映射和主动的端口转发。

但为什么是 containerd 而不是 Docker 呢?随着容器编排平台 Kubernetes 如日中天,社区心愿将运行容器这个关键环节进行标准化,让引入 Docker 之外的其余容器运行时更加容易,于是 推出了 Container Runtime Interface (CRI)。containerd 就是从 Docker 中拆分出的一个 CRI 的实现,相比于 Docker 本体更加精简,当初也交由社区保护。

因而如 Lima 这样新的的开源软件会更偏好抉择 containerd 来运行容器,因为组件更加精简会有更好的性能,也不容易受到 Docker 产品层面变动的影响。nerdctl 是与 containerd 配套的命令行客户端(nerdcontainerd 的开端 4 个字母),用法与 docker 或 docker-compose 类似(但并不齐全兼容)。

所谓 rootless 则是指通过替换一些组件,让容器运行时(containerd)和容器都运行在非 root 用户下,每个用户都有本人的 containerd,这样绝大部分操作都不须要切换到 root 来进行,也能够缩小安全漏洞的攻击面。

但咱们心愿能在本地运行残缺的 rootful 模式的 dockerd 和 Kubernetes 来尽可能地模仿实在的线上环境,好在 Lima 提供了丰盛的 自定义能力,我基于社区中的一些脚本(docker.yaml 和 minikube.yaml)实现了咱们的需要,而且这些自定义的逻辑都被以脚本的模式写到了 yaml 形容文件中,只需一条命令就能够创立出雷同的虚拟机。

~ ❯ limactl start docker.yaml
? Creating an instance "docker" Proceed with the default configuration
INFO[0005] Attempting to download the image from "https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-arm64.img"
INFO[0005] Using cache "/Users/ziting/Library/Caches/lima/download/by-url-sha256/ae20df823d41d1dd300f8866889804ab25fb8689c1a68da6b13dd60a8c5c9e35/data"
INFO[0006] [hostagent] Starting QEMU (hint: to watch the boot progress, see "/Users/ziting/.lima/docker/serial.log")
INFO[0006] SSH Local Port: 55942
INFO[0006] [hostagent] Waiting for the essential requirement 1 of 5: "ssh"
INFO[0039] [hostagent] Waiting for the essential requirement 2 of 5: "user session is ready for ssh"
INFO[0039] [hostagent] Waiting for the essential requirement 3 of 5: "sshfs binary to be installed"
INFO[0048] [hostagent] Waiting for the essential requirement 4 of 5: "/etc/fuse.conf to contain \"user_allow_other\""INFO[0051] [hostagent] Waiting for the essential requirement 5 of 5:"the guest agent to be running"INFO[0051] [hostagent] Mounting"/Users/ziting"INFO[0051] [hostagent] Mounting"/tmp/lima"INFO[0052] [hostagent] Forwarding"/run/lima-guestagent.sock"(guest) to"/Users/ziting/.lima/docker/ga.sock" (host)
INFO[0092] [hostagent] Waiting for the optional requirement 1 of 1: "user probe 1/1"
INFO[0154] [hostagent] Forwarding TCP from [::]:2376 to 127.0.0.1:2376
INFO[0304] [hostagent] Forwarding TCP from [::]:8443 to 127.0.0.1:8443
INFO[0332] [hostagent] Waiting for the final requirement 1 of 1: "boot scripts must have finished"
INFO[0351] READY. Run `limactl shell docker` to open the shell.
INFO[0351] To run `docker` on the host (assumes docker-cli is installed):
INFO[0351] $ export DOCKER_HOST=tcp://127.0.0.1:2376
INFO[0351] To run `kubectl` on the host (assumes kubernetes-cli is installed):
INFO[0351] $ mkdir -p .kube && limactl cp minikube:.kube/config .kube/config

我还发现了另外一个基于 Lima 的封装 —— Colima,默认提供 rootful 的 dockerd 和 Kubernetes,但 Colima 并没有对外裸露 Lima 弱小的自定义能力,因而咱们没有应用,但对于没那么多要求的开发者来说,也是一个更易用的抉择。

在默认的状况下,Lima 中的 Docker 在 Apple Silicon 上只能运行 ARM 架构的镜像,但就像后面提到的那样,咱们能够应用 QEMU 的模仿运行的能力来运行其余架构(如 x86)的容器。qemu-user-static 是一个过程级别的模拟器,能够像一个解释器一样运行其余架构的可执行文件,咱们能够利用 Linux 的一项 Binfmt_misc(中文版)的个性让 Linux 遇到特定架构的可执行文件时主动调用 qemu-user-static,这种能力同样实用于容器中的可执行文件。

社区中也有 qus 这样的我的项目,对这些能力进行了封装,只需执行一行 docker run --rm --privileged aptman/qus -s -- -p x86_64 就能够让你的 ARM 虚拟机魔法般地反对运行 x86 的镜像。

/usr/bin/containerd-shim-runc-v2
 \_ /qus/bin/qemu-x86_64-static /usr/sbin/nginx -g daemon off;
     \_ /qus/bin/qemu-x86_64-static /usr/sbin/nginx -g daemon off;
     \_ /qus/bin/qemu-x86_64-static /usr/sbin/nginx -g daemon off;
     \_ /qus/bin/qemu-x86_64-static /usr/sbin/nginx -g daemon off;
     \_ /qus/bin/qemu-x86_64-static /usr/sbin/nginx -g daemon off;

应用 qus 运行 x86 镜像的过程树如上,所有过程(包含创立出的子过程)都主动通过 QEMU 模仿运行。

回到题目中的问题,因为 Docker 依赖于 Linux 内核的个性,所以在 Mac 上必须通过虚拟机来运行;Apple Silicon 作为新的架构,虚拟机的抉择比拟受限,因为有些镜像并不提供 ARM 架构的镜像,所以有时还有模仿运行 x86 镜像的需要;Docker Desktop 作为商业产品,有足够的精力来去解决这些「脏活累活」,但它在这个工夫点抉择不再容许所有人收费应用;开源社区中新的我的项目都心愿去 Docker 化,用 containerd 取代 dockerd,但这又带来了应用习惯的变动并且可能与线上环境不统一。因为这些起因,目前在 Apple Silicon 上装置 Docker 还是须要花一些工夫去理解背景常识的,但好在仍然有这些优良的开源我的项目可供选择。

尽管 云引擎 也是基于 Docker 等容器技术构建的,但云引擎力求为用户提供开箱即用的应用体验而不用本人配置容器环境、编写构建脚本、收集日志和统计数据。如果想得到容器化带来的平滑部署、疾速回滚、主动扩容等益处但又不想花工夫配置,不如来试试云引擎。

其余参考资料:

  • https://www.tutorialworks.com…
退出移动版