一、目标任务
首先要明确的是, 作为了一个每天在 Linux Server 上 rm -rf 的人来说, 如果想在 Mac 上使用 Docker, 最舒服的也是兼容所有 docker cli 命令行操作即可; 至于图形化的界面完全不需要, 我们并不指望图形化界面能比敲命令快到哪里去, 也不指望图形化界面变为主力; 所以本篇文章的核心目标:
二、工具选型
首先是我们最熟悉的 Docker Desktop, 安装包奇大无比, UI 卡成翔, 启动速度更不用提而且还时不时的卡死, 所以 Docker Desktop 是完全不考虑的; 那么剩下几种方案类型如下:
三、虚拟机方案
目前在 M1 上, 唯一可用或者说堪用的虚拟机当属 Parallels Desktop, 至于其他的 VBox、VMware 目前还不成熟; 如果纯 qemu 有点过于硬核(愿意自己封装脚本的当我没说); 对于 Parallels Desktop 来说, 我们需要购买开发版本的 License, 因为我们需要借助 prlctl 来实现一些自动化 , 一年好几百… 经过测试这种方案也有一定可行性:
五、Lima 方案
Lima 目前是基于 QEMU 的自动化 VM 方案, 当前由于其出色设计, 借助 Cloud Init 可以在很多阶段帮助我们完成 hook; 所以不论是装个 Docker 还是 k8s, 亦或是弄个其他的东西都很方便; 而且很多方案比如 docker 官方都有相关样例, 我们可以直接照抄外加做点自定义.
5.1、Lima 安装
Lima 在 Mac 下安装相对简单, 以下命令将安装 master 分支版本.
// 输入代码内容
brew install lima --HEAD
在正常情况下, 安装 Lima 会附带安装 QEMU, 如果本机已经安装 QEMU, 可能需要执行以下命令将 QEMU 升级到 7.0:
// 输入代码内容
brew upgrade qemu
为了使用 docker, 还需要通过 brew 安装一下 docker cli:
// 输入代码内容
brew install docker
5.2、Lima 使用
默认情况下 Lima 安装完成后会生成一个 lima 的快捷命令, 目前不太推荐使用, 原因是看起来方便一点但是没法控制太多参数, 所以仍然建议使用标准的 limactl 命令进行操作. limactl 使用方式如下:
// 输入代码内容
Lima: Linux virtual machines
Usage:
limactl [command]
Examples:
Start the default instance:
$ limactl start
Open a shell:
$ lima
Run a container:
$ lima nerdctl run -d --name nginx -p 8080:80 nginx:alpine
Stop the default instance:
$ limactl stop
See also example YAMLs: /opt/homebrew/share/doc/lima/examples
Available Commands:
completion Generate the autocompletion script for the specified shell
copy Copy files between host and guest
delete Delete an instance of Lima.
edit Edit an instance of Lima
factory-reset Factory reset an instance of Lima
help Help about any command
info Show diagnostic information
list List instances of Lima.
prune Prune garbage objects
shell Execute shell in Lima
show-ssh Show the ssh command line
start Start an instance of Lima
stop Stop an instance
sudoers Generate /etc/sudoers.d/lima file for enabling vmnet.framework support
validate Validate YAML files
Flags:
--debug debug mode
-h, --help help for limactl
-v, --version version for limactl
Use "limactl [command] --help" for more information about a command.Copy
5.3、Lima 配置文件
Lima 通过读取一个 yaml 配置描述文件来决定如何创建一个虚拟机, 该文件基本结构如下:
// 输入代码内容
# 定义每个平台架构需要使用的启动镜像
images:
- location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img"
arch: "x86_64"
- location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img"
arch: "aarch64"
# 定义虚拟机需要使用哪个架构启动(对应上面的镜像)
arch: "x86_64"
# CPU 数量
cpus: 4
# 内存大小
memory: "16G"
# 磁盘大小
disk: "100G"
# 虚拟机与 macOS 宿主机挂载时使用的挂载技术
# 目前推荐 9p, 可换成 sshfs, 但是 sshfs 会有权限问题
mountType: 9p
# 定义虚拟机和 macOS 宿主机有哪些目录可以共享
mounts:
- location: "~"
# 定义虚拟机对这个目录是否可写
writable: true
9p:
# 对于可写的共享目录, cache 推荐类型为 mmap, 不写好像默认 fscache
cache: "mmap"
- location: "/tmp/lima"
writable: true
9p:
cache: "mmap"
# containerd is managed by Docker, not by Lima, so the values are set to false here.
containerd:
system: false
user: false
# cloud-init hook 定义
provision:
# 定义以什么权限在虚拟机内执行脚本
- mode: system
# This script defines the host.docker.internal hostname when hostResolver is disabled.
# It is also needed for lima 0.8.2 and earlier, which does not support hostResolver.hosts.
# Names defined in /etc/hosts inside the VM are not resolved inside containers when
# using the hostResolver; use hostResolver.hosts instead (requires lima 0.8.3 or later).
script: |
#!/bin/sh
sed -i 's/host.lima.internal.*/host.lima.internal host.docker.internal/' /etc/hosts
- mode: system
script: |
#!/bin/bash
set -eux -o pipefail
if command -v docker >/dev/null 2>&1; then
docker run --platform=linux/amd64 --privileged --rm tonistiigi/binfmt --install all
exit
else
export DEBIAN_FRONTEND=noninteractive
curl -fsSL https://get.docker.com | sh
docker run --platform=linux/amd64 --privileged --rm tonistiigi/binfmt --install all
# NOTE: you may remove the lines below, if you prefer to use rootful docker, not rootless
systemctl disable --now docker
apt-get install -y uidmap dbus-user-session
fi
- mode: user
script: |
#!/bin/bash
set -eux -o pipefail
systemctl --user start dbus
dockerd-rootless-setuptool.sh install
docker context use rootless
probes:
- script: |
#!/bin/bash
set -eux -o pipefail
if ! timeout 30s bash -c "until command -v docker >/dev/null 2>&1; do sleep 3; done"; then
echo >&2 "docker is not installed yet"
exit 1
fi
if ! timeout 30s bash -c "until pgrep rootlesskit; do sleep 3; done"; then
echo >&2 "rootlesskit (used by rootless docker) is not running"
exit 1
fi
hint: See "/var/log/cloud-init-output.log". in the guest
hostResolver:
# hostResolver.hosts requires lima 0.8.3 or later. Names defined here will also
# resolve inside containers, and not just inside the VM itself.
hosts:
host.docker.internal: host.lima.internal
portForwards:
- guestSocket: "/run/user/{{.UID}}/docker.sock"
hostSocket: "{{.Dir}}/sock/docker.sock"
# 自己定义的启动后消息输出
message: |
To run `docker` on the host (assumes docker-cli is installed), run the following commands:
------
docker context create amd64 --docker "host=unix://{{.Dir}}/sock/docker.sock"
docker context use amd64
------
Copy
5.4、启动 VM
limactl 命令提供了一个 start 子命令用于启动一个虚拟机, 子命令接受一个参数, 这个参数形式不同会产生不同的行为:
// 输入代码内容
limactl start ./docker-amd64.yaml
启动后会提示是否编辑然后再启动, 这是为了使用同一个配置来启动多个 vm 使用的, 所以不编辑直接启动即可:
稍等片刻后虚拟机将启动成功:
启动完成后, 执行最下面打印出的两条命令, 即可在宿主机上完整的使用 docker. 其本质上利用 docker context 功能, 然后通过将虚拟机中的 sock 文件挂载到宿主机, 并配置 docker context 来实现无缝使用 docker 命令.
5.5、虚拟机调整
某些情况下, 我们需要定制一些 VM 里的配置, 在定制时主要需要调整配置文件的 provision 部分; 在该部分中, 如果 mode 被定义为 system 则会以 root 用户执行相关命令, 否则以普通用户来执行命令. 需要注意的是, 我们定义的脚本需要具有幂等性, 因为脚本在每次都会执行一次, 所以一般对于可能造成数据擦除动作的命令都要写好判断逻辑, 避免重复执行.
关于文件挂载, 这里推荐使用 9p 类型, 未来 lima 将完全切换到该挂载方式; 同时经过测试目前仅有 9p 挂载模式下, 本地目录 rw 映射到虚拟机时不会出现权限问题, sshfs 方式挂载如果遇到 chown 之类的命令会造成权限错误, 可能导致容器启动失败(例如 mysql).
在测试虚拟机配置过程中, 可以直接使用 limactl delete -f xxxx 来强制删除目标虚拟机, 然后重新启动即可; 虚拟机名称默认与 yaml 文件名相同, 可使用 limactl ls 命令查看.
5.6、多平台兼容
在上面我的 docker 配置样例中, 每次虚拟机启动完成后会自动安装 binfmt:
// 输入代码内容
docker run --platform=linux/amd64 --privileged --rm tonistiigi/binfmt --install all
这样能保证无论 Lima 虚拟机原始架构是什么, 都能运行其他平台的 docker 镜像; 典型的例如某些 openjdk8 镜像只有 amd64 的版本, 但是在 lima 虚拟机为 aarch64 的情况下仍然可以使用.
除了这种 “速度较快” 的跨架构运行方式, lima 还支持直接在 VM 中定义架构, 这样在 qemu 启动时则会直接从 VM 系统层模拟目标架构; 这种方式的好处是对目标架构兼容性很好, 但是运行速度会更慢. 调整 VM 架构只需要修改 arch 配置即可(注意, 目标架构的镜像一定要配置好):
// 输入代码内容
# 定义每个平台架构需要使用的启动镜像
images:
- location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img"
arch: "x86_64"
- location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img"
arch: "aarch64"
# 定义本虚拟机需要使用哪个架构启动(对应会使用上面目标架构的镜像)
arch: "aarch64"Copy
六、总结
目前整体来看, Docker Desktop 在 mac 上基本上是很难用的, Colima 现在还不太成熟, 适合轻度使用 docker 的用户; 而重度使用 docker 并且有定制化需求的用户还是推荐 Lima 虚拟机; 同时 Lima 也支持很多操作系统, 官方有大量的样例模版(包括 k8s、k3s、podman 等), 非常适合重度容器使用者.
源码附件已经打包好上传到百度云了,大家自行下载即可~
链接: https://pan.baidu.com/s/14G-bpVthImHD4eosZUNSFA?pwd=yu27
提取码: yu27
百度云链接不稳定,随时可能会失效,大家抓紧保存哈。
如果百度云链接失效了的话,请留言告诉我,我看到后会及时更新~
开源地址
码云地址:
http://github.crmeb.net/u/defu
Github 地址:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。