前言
之前我给大家介绍过如何?在 macOS 上使用 multipass 创建轻量级虚拟机来使用 Podman,众小伙伴纷纷齐说真香。今天我要给大家介绍一个全新的黑科技,利用 macOS Big Sur
引入的全新虚拟化框架 Virtualization Kit[1] 来创建更加轻量级的虚拟机。准确地说,这个最新的虚拟化框架并不能直接使用,它只是提供了 API,为许多设备类型定义了标准接口,包括网络、存储等设备,且支持 Virtio 标准。要想使用该框架来创建管理虚拟机,需要对其进行封装,构建出一个易于使用的工具,目前最优秀的就是 vftool[2]。
下面就来看看如何使用 vftool
来创建 Ubuntu
虚拟机。
vftool[3] 使用的是 Swift
语言,要想成功编译出可执行文件,需要安装 Xcode 命令行工具,你可以通过下面的命令直接安装:
$ xcode-select --install
或者到官方网站下载安装:https://developer.apple.com/download/more/[4]
或者你也可以直接安装 Xcode
。
安装好 Xcode 命令行工具后,就可以拉取 vftool 仓库进行编译了:
$ git clone https://github.com/evansm7/vftool.git
$ clang -framework Foundation -framework Virtualization vftool/vftool/main.m -o /usr/local/bin/vftool
后面创建虚拟机的时候,你可能会遇到以下的报错:
Configuration vaildation failure! Error Domain=VZErrorDomain Code=2 “Virtualization requires the “com.apple.security.virtualization” entitlement” UserInfo={NSDebugDescription=Virtualization requires the “com.apple.security.virtualization” entitlement}
这是因为编译完成后需要对二进制文件进行签名,而签名是需要授权的,所以需要创建一个自签名证书。打开钥匙串访问,依次选择 证书助理 --> 创建证书:
选择证书类型为 代码签名,名字随便写,然后点击创建:
然后利用新建的自签名证书对二进制文件进行签名:
$ codesign --entitlements vftool/vftool/vftool.entitlements -s "<NAME ON CERTIFICATE>" /usr/local/bin/vftool
除了上面的方法之外,还有一种编译方法,直接运行以下命令:
$ xcodebuild
$ cp build/Release/vftool /usr/local/bin/vftool
现在就可以使用这个二进制文件来创建虚拟机了。
需要准备三个文件:
下载相关文件:
$ mkdir -p ~/bin/vm
$ cd ~/bin/vm
$ wget https://cloud-images.ubuntu.com/releases/focal/release/unpacked/ubuntu-20.04-server-cloudimg-amd64-vmlinuz-generic
$ wget https://cloud-images.ubuntu.com/releases/focal/release/unpacked/ubuntu-20.04-server-cloudimg-amd64-initrd-generic
$ wget https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64.tar.gz
$ mv ubuntu-20.04-server-cloudimg-amd64-vmlinuz-generic vmlinux
$ mv ubuntu-20.04-server-cloudimg-amd64-initrd-generic initrd
$ tar xvfz ubuntu-20.04-server-cloudimg-amd64.tar.gz
创建数据盘:
$ dd if=/dev/zero of=data.img bs=1m count=51200
如果你想自定义虚拟机的网段,可以直接修改文件 /Library/Preferences/SystemConfiguration/com.apple.vmnet.plist
。例如修改为:
<key>Shared_Net_Address</key>
<string>192.168.64.1</string>
<key>Shared_Net_Mask</key>
<string>255.255.255.0</string>
直接通过 vftool 创建虚拟机:
$ vftool \
-k vmlinux \
-i initrd \
-c focal-server-cloudimg-amd64.img \
-d data.img \
-m 2048 \
-a "console=hvc0"
2021-01-14 13:27:08.223 vftool[66147:839169] vftool (v0.3 10/12/2020) starting
2021-01-14 13:27:08.223 vftool[66147:839169] +++ kernel at vmlinux, initrd at initrd, cmdline 'console=hvc0', 1 cpus, 2048MB memory
2021-01-14 13:27:08.224 vftool[66147:839169] +++ fd 3 connected to /dev/ttys000
2021-01-14 13:27:08.224 vftool[66147:839169] +++ Waiting for connection to: /dev/ttys000
从日志信息可以看到该虚拟机连接的 TTY
,我这里是 /dev/ttys000
。打开一个新的终端窗口,连接该 TTY,然后执行一系列命令来进行初始化操作:
$ screen /dev/ttys000
<LOTS OF OUTPUT>
(initramfs) dd if=/dev/vda of=/dev/vdb bs=1024k &
(initramfs) mkdir /mnt
(initramfs) mount /dev/vdb /mnt
(initramfs) chroot /mnt
root@(none):/# touch /etc/cloud/cloud-init.disabled
root@(none):/# echo 'root:root' | chpasswd
root@(none):/# echo "podman" >/etc/hostname
root@(none):/# ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa
root@(none):/# ssh-keygen -f /etc/ssh/ssh_host_dsa_key -N '' -t dsa
root@(none):/# ssh-keygen -f /etc/ssh/ssh_host_ed25519_key -N '' -t ed25519
root@(none):/# cat <<EOF > /etc/netplan/01-dhcp.yaml
network:
renderer: networkd
ethernets:
enp0s1:
dhcp4: no
addresses: [192.168.64.2/24]
gateway4: 192.168.64.1
nameservers:
addresses: [114.114.114.114]
version: 2
EOF
root@(none):/# echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
root@(none):/# sed -i "/^PasswordAuthentication/ c PasswordAuthentication yes" /etc/ssh/sshd_config
root@(none):/# exit
(initramfs) umount /dev/vda
上面的步骤总共干了这么几件事:
然后在运行 vftool 命令的窗口中按 CTRL-C
来关闭虚拟机。
接着使用新的硬盘来启动虚拟机:
$ vftool \
-k vmlinux \
-i initrd \
-d data.img \
-m 2048 \
-a "console=hvc0 root=/dev/vda" \
-t 0
打开一个新的终端窗口,通过 ssh 连接虚拟机,调整硬盘容量,移除不必要的组件:
$ ssh root@192.168.64.2
# login as root
root@podman:~# systemctl disable --now snapd.service snapd.socket
root@podman:~# resize2fs /dev/vda
root@podman:~# apt remove -y cloud-init cloud-initramfs-copymods cloud-initramfs-dyn-netconf cloud-guest-utils popularity-contest
看看它的内存占用:
果然很香!
MacOS 可以使用 launchctl 来管理服务,它可以控制启动计算机时需要开启的服务,也可以设置定时执行特定任务的脚本,就像 Linux crontab 一样, 通过加装 *.plist
文件执行相应命令。Launchd 脚本存储在以下位置, 默认需要自己创建个人的 LaunchAgents
目录:
~/Library/LaunchAgents
: 由用户自己定义的任务项/Library/LaunchAgents
: 由管理员为用户定义的任务项/Library/LaunchDaemons
: 由管理员定义的守护进程任务项/System/Library/LaunchAgents
: 由 MacOS 为用户定义的任务项/System/Library/LaunchDaemons
: 由 MacOS 定义的守护进程任务项我们选择在 ~/Library/LaunchAgents/
目录下创建 vftool.ubuntu.plist
文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>ubuntu</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>$HOME/bin/vm/start.sh</string>
</array>
<key>StandardOutPath</key>
<string>/var/log/vftool.ubuntu.stdout.log</string>
<key>StandardErrorPath</key>
<string>/var/log/vftool.ubuntu.stderr.log</string>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
创建启动脚本:
$ cd ~/bin/vm
$ cat <<EOF > start.sh
#!/bin/bash
/usr/local/bin/vftool \
-k $HOME/bin/vm/vmlinux \
-i $HOME/bin/vm/initrd \
-d $HOME/bin/vm/data.img \
-m 2048 \
-a "console=hvc0 root=/dev/vda" \
-t 0
EOF
$ chmod +x start.sh
创建日志文件:
$ touch /var/log/vftool.ubuntu.stdout.log
$ touch /var/log/vftool.ubuntu.stderr.log
$ sudo chmod a+rw /var/log/vftool.ubuntu.stdout.log
$ sudo chmod a+rw /var/log/vftool.ubuntu.stderr.log
设置开机自动启动 Ubuntu 虚拟机:
$ launchctl load -w ~/Library/LaunchAgents/vftool.ubuntu.plist
启动服务:
$ launchctl start ubuntu
查看服务:
$ launchctl list ubuntu
{
"StandardOutPath" = "/var/log/vftool.ubuntu.stdout.log";
"LimitLoadToSessionType" = "Aqua";
"StandardErrorPath" = "/var/log/vftool.ubuntu.stderr.log";
"Label" = "ubuntu";
"OnDemand" = false;
"LastExitStatus" = 256;
"PID" = 50797;
"Program" = "/bin/bash";
"ProgramArguments" = (
"/bin/bash";
"-c";
"$HOME/bin/vm/start.sh";
);
};
大功告成,现在就可以通过 ssh 连接虚拟机了:
$ ssh root@192.168.64.2
[1]
Virtualization Kit: https://developer.apple.com/documentation/virtualization
[2]
vftool: https://github.com/evansm7/vftool
[3]
vftool: https://github.com/evansm7/vftool
[4]
https://developer.apple.com/download/more/: https://developer.apple.com/download/more/
[5]
https://cloud-images.ubuntu.com/releases/focal/release/unpacked/ubuntu-20.04-server-cloudimg-amd64-vmlinuz-generic: https://cloud-images.ubuntu.com/releases/focal/release/unpacked/ubuntu-20.04-server-cloudimg-amd64-vmlinuz-generic
[6]
https://cloud-images.ubuntu.com/releases/focal/release/unpacked/ubuntu-20.04-server-cloudimg-amd64-initrd-generic: https://cloud-images.ubuntu.com/releases/focal/release/unpacked/ubuntu-20.04-server-cloudimg-amd64-initrd-generic
[7]
https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64.tar.gz: https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64.tar.gz
[8]
Building x86_64 Docker Containers on Apple Silicon: https://medium.com/swlh/building-x86-64-docker-containers-on-apple-silicon-a6d868a18f37
[9]
Containerized the Apple Silicon: https://bee42.com/de/blog/tutorials/containerized-the-apple-silicon/
[10]
Ubuntu Server fails: https://github.com/evansm7/vftool/issues/2