1.目标任务至于图形界面,我们根本不需要。我们不期望图形界面比输入命令更快,也不期望图形界面成为主力军;所以本文的核心目标:在Mac上使用完整的dockercli命令,包括基本的-vmount支持以支持x86模拟,为x86构建或运行相关镜像,尽可能切换CPU架构,最好同时使用arm64和x862.工具选择首先我们最熟悉的是DockerDesktop,安装包特别大,UI卡顿,启动速度更不用说,时不时卡顿,所以DockerDesktop完全不用管;那么剩下的几种方案类型如下:VM虚拟机方案Colima方案Lima方案先说结论:LimaYES!在M1上,唯一可用或可用的虚拟机是ParallelsDesktop。至于其他的VBox和VMware,还不成熟;如果pureqemu有点太硬核了(如果你愿意自己打包脚本,我没说);以ParallelsDesktop为例,我们需要购买开发版的license,因为需要用到prlctl来实现一些自动化,一年几百……经过测试,这个方案也是可行的:1.首先创建一个Ubuntu等虚拟机通过PD2,在虚拟机中安装Docker3,通过cli程序启动虚拟机,挂载~rw到虚拟机。基于这个解决方案,我亲自尝试了一下。曾经写过一个PD的小工具,辅助完成挂载动作。但是这个工具有一些明显的缺点:目前不支持x86模拟,可以通过binfmt来缓解,但是不完善的虚拟机需要花钱,需要虚拟机cli支持才能改进。4、Colima解决方案Colima号称是专门为解决Mac平台Toolchain的容器化而设计的,但实际测试发现目前Colima并不稳定,有时可能会出现一些小问题;当然,Colima最大的问题是:定制化程度不高,底层是基于Lima。Colima的具体用法这里暂无详细说明,目前不稳定,不推荐使用。5.Lima解决方案Lima目前是基于QEMU的自动化VM方案,目前由于其优秀的设计,可以借助CloudInit帮助我们完成多阶段的hook;所以装个Docker或者k8s,或者弄个别的东西,都非常方便;而很多解决方案比如docker官方都有相关的sample,我们可以直接copy做一些定制。5.1.Lima安装Lima在Mac下安装比较简单,下面命令会安装master分支版本。brewinstalllima--HEADCopy一般情况下,Lima会随着InstallQEMU一起安装。如果本机已经安装QEMU,可能需要执行如下命令将QEMU升级到7.0:brewupgradeqemuCopy为了使用docker,还需要通过brew安装dockercli:brewinstalldockerCopy5.2,Lima使用lima默认安装完成后会生成一个lima的快捷命令,目前不推荐使用,因为看起来比较方便但是不能控制太多的参数,所以还是推荐使用标准的limactl命令进行操作。limactl的用法如下:Lima:Linux虚拟机用法:limactl[command]例子:启动默认实例:$limactlstart打开一个shell:$lima运行一个容器:$limanerdctlrun-d--namenginx-p8080:80nginx:alpine停止默认实例:$limactlstop另见YAML示例:/opt/homebrew/share/doc/lima/examplesAvailable命令:completion为指定的shellcopy生成自动完成脚本Copyhostandguestdelete之间的文件删除一个i利马的例子。edit编辑Lima的一个实例factory-reset出厂重置一个Lima的实例help关于任何命令的帮助信息显示诊断信息列表列出Lima的实例。prune修剪垃圾对象shell在Lima中执行shellshow-ssh显示ssh命令行start启动Lima的实例stop停止实例sudoers生成/etc/sudoers.d/lima文件以启用vmnet.framework支持validate验证YAML文件标志:--debugdebugmode-h,--helphelpforlimactl-v,--versionversionforlimactlUse"limactl[command]--help"获取命令的更多信息Copy5.3,Lima配置文件Lima决定如何创建一个虚拟机通过读取一个yaml配置描述文件,文件的基本结构如下:#定义各个平台架构需要使用的启动镜像images:-location:"https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img"架构:"x86_64"-位置:"https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img"arch:"aarch64"#定义虚拟机需要启动哪个架构(对应上图)arch:"x86_64"#CPU个数cpus:4#MemorySizememory:"16G"#Disksizedisk:"100G"#虚拟机和macOS主机挂载时使用的挂载技术#目前推荐9p,可以换成sshfs,但是sshfs会存在权限问题mountType:9p#Definition哪些目录可以在虚拟机和macOS主机之间共享?mounts:-location:"~"#定义虚拟机是否可以写入该目录writable:true9p:#对于可写的共享目录,推荐cachetypeismmap,notwrite好像默认的fscachecache:"mmap"-location:"/tmp/lima"writable:true9p:cache:"mmap"#containerd是Docker管理的,不是Lima管理的,所以这里的值设置为false.containerd:system:falseuser:false#cloud-inithookdefinitionprovision:#define在虚拟机中执行脚本的权限-mode:system#该脚本定义了hostResolver禁用时的host.docker.internal主机名。#lima0.8.2及更早版本也需要,不支持hostResolver.hosts。#使用hostResolver时,VM内/etc/hosts中定义的名称不会在容器内解析;使用hostResolver.hosts代替(需要lima0.8.3或更高版本)。脚本:|#!/bin/shsed-i's/host.lima.internal.*/host.lima.internalhost.docker.internal/'/etc/hosts-模式:系统脚本:|#!/bin/bashset-eux-opipefailifcommand-vdocker>/dev/null2>&1;然后dockerrun--platform=linux/amd64--privileged--rmtonistiigi/binfmt--installallexit0elseexportDEBIAN_FRONTEND=noninteractivecurl-fsSLhttps://get.docker.com|shdockerrun--platform=linux/amd64--privileged--rmtonistiigi/binfmt--installall#注意:如果你更喜欢使用rootfuldocker,而不是rootlesssystemctldisable--nowdockerapt,你可以删除下面的行-getinstall-yuidmapdbus-user-sessionfi-模式:用户脚本:|#!/bin/bashset-eux-opipefailsystemctl--userstartdbusdockerd-rootless-setuptool.shinstalldockercontext使用rootlessprobes:-脚本:|#!/bin/bashset-eux-opipefailif!超时30秒bash-c"直到命令-v泊坞窗>/dev/null2>&1;睡3;完成”;然后echo>&2“docker尚未安装”exit1fiif!timeout30sbash-c“untilpgreprootlesskit;睡3;done”;然后echo>&2“rootlesskit(由rootlessdocker使用)未运行”exit1fi提示:请参阅“/var/log/cloud-init-output.log”。在guesthostResolver中:#hostResolver.hosts需要lima0.8.3或更高版本。此处定义的名称还将#在容器内解析,而不仅仅是在VM本身内。hosts:host.docker.internal:host.lima.internalportForwards:-guestSocket:"/run/user/{{.UID}}/docker.sock"hostSocket:"{{.Dir}}/sock/docker.sock"#自定义启动后消息输出消息:|在主机上运行`docker`(假设docker-cli是安装),运行以下命令:------dockercontextcreateamd64--docker"host=unix://{{.Dir}}/sock/docker.sock"dockercontextuseamd64------Copy5.4,startVMlimactl命令提供了启动子命令来启动虚拟机,该子命令接受一个参数,该参数的不同形式会产生不同的结果行为:如果参数是文件路径,则假定该文件是一个lima虚拟机的yaml配置,如果参数是简单的字符串,则读取并启动,首先尝试从已有的虚拟机中寻找同名的,如果找到并立即启动如果参数是一个简单的字符串并且没有找到同名的现有虚拟机,则尝试通过内置模板创建一个新的虚拟机。以上面定义的docker配置文件为例,我们可以直接启动这个配置来创建一个docker虚拟机:limactlstart./docker-amd64.yamlCopy启动后会提示是否编辑,然后重新启动。这里是使用同一个配置启动多个vm,所以不用编辑直接启动:稍等一下最后虚拟机启动成功:启动完成后,执行最下面打印的两条命令就可以充分使用dockeron主机。它本质上是利用了dockercontext的功能,然后将虚拟机中的sock文件挂载到宿主机上,并配置dockercontext,实现docker命令的无缝使用。5.5.虚拟机调整在某些情况下,我们需要在VM中自定义一些配置。定制时,我们主要需要调整配置文件的provision部分;在本节中,如果mode定义为system,则相关命令将以root用户执行,否则命令将以普通用户执行。需要注意的是,我们定义的脚本需要是幂等的,因为脚本每次都会执行一次,所以一般情况下,对于可能导致数据擦除的命令都要写判断逻辑,避免重复执行。关于文件挂载,这里推荐使用9p类型,lima以后会彻底改用这种挂载方式;同时,经过测试,目前只有在9p挂载方式下,本地目录rw映射到虚拟机时不会出现权限问题。如果sshfs方式挂载,如果遇到chown等命令,会导致权限错误,可能导致容器无法启动(如mysql)。在测试虚拟机配置过程中,可以直接使用limactldelete-fxxxx强制删除目标虚拟机,然后重启;虚拟机名称默认与yaml文件名相同,可以使用limactlls命令查看。5.6、多平台兼容在我上面的docker配置例子中,每次虚拟机启动后都会自动安装binfmt:dockerrun--platform=linux/amd64--privileged--rmtonistiigi/binfmt--installallCopy可以保证无论Lima虚拟机原来的架构是什么,都可以运行其他平台的docker镜像;通常情况下,有些openjdk8镜像只有amd64版本,但是在lima虚拟机为aarch64时还是可以使用的。除了这种“更快”的跨架构运行方式,lima还支持直接在VM中定义架构,这样qemu启动时,会直接从VM系统层模拟目标架构;这种方式的好处是非常兼容目标架构,但是运行速度会慢一些。调整VM架构,只需要修改arch配置即可(注意必须配置目标架构的image):#定义各个平台架构images要使用的bootimageimages:-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"#定义本虚拟机需要启动哪个架构(对应使用上面目标架构的Image)arch:"aarch64"Copy6.总结目前DockerDesktop在Mac上基本难以使用,Colima还不成熟,适合轻度使用docker的用户;使用docker且有定制化需求的用户,还是推荐Lima虚拟机;同时,Lima还支持很多操作系统,并且有大量的官方示例模板(包括k8s、k3s、podman等),非常适合容器重度用户。
