Packer制作ubuntu cloud image
Ubuntu官方提供3种镜像,desktop、server和cloud image,其中cloud image就是用于public cloud或者openstack上,便于自动化部署安装。
有时候我们想在官方cloud image上做一些定制,产生一个新的image。
首先假设我们已经下载了官方镜像:
ubuntu-22.04-server-cloudimg-amd64.img
其实,这里有很多种方法都可以对它进行定制,包括使用openstack的disk builder,很遗憾我没有把这个跑通,还可以使用libguestfs,libguestfs customize OS image非常简单,但制作的时候有两个问题,一是自带的官方的OS image disk size有限制,需要resize disk,二是用这个工具制作的镜像会非常大,具体原因我没有调查。
最终,我选择了用packer进行制作,实际上,kubernetes的image builder也用了packer。
使用packer制作镜像,最主要是编写一个template文件,如下:
$ cat template.json
{
"builders": [
{
"type": "qemu",
"iso_url": "ubuntu-22.04-server-cloudimg-amd64.img",
"iso_checksum": "md5:9688fc9011dcd4d960620d2ebb98a639",
"ssh_username": "ubuntu",
"ssh_password": "a",
"ssh_timeout": "1m",
"ssh_port": 2222,
"skip_nat_mapping": true,
"disk_size": "40G",
"disk_image": true,
"disk_compression": true,
"format": "qcow2",
"headless": true,
"accelerator": "kvm",
"output_directory": "images",
"qemuargs": [
[ "-machine", "accel=kvm,type=q35" ],
[ "-cpu", "host" ],
[ "-m", "2G" ],
[ "-smp", "2" ],
[ "-nographic" ],
[ "-device", "virtio-net-pci,netdev=net0" ],
[ "-netdev", "user,id=net0,", "hostfwd=tcp::2222-:22" ],
[ "-cdrom", "seed.img" ]
],
"shutdown_command": "echo a |sudo -S shutdown -P now",
"boot_command": [],
"vm_name": "jammy-k8s-containerd-1.6.15.qcow2"
}
],
"provisioners": [
{
"type": "file",
"source": "files/crictl.yaml",
"destination": "/tmp/crictl.yaml"
},
{
"execute_command": "echo a | {{.Vars}} sudo -E -S bash '{{.Path}}'",
"scripts": [
"prepare_k8s.sh"
],
"type": "shell"
}
]
}以上的字段含义都可以在packer官方文档中找到解释,唯一需要注意的就是qemuargs 和ssh_port 字段是有关联的,如果qemuargs设置的不对,build image一定会失败,这里
-machine 表示使用kvm方式启动qemu
-device表示给这个qemu启动的vm配置一块叫net0的网络设备
-netdev和-device对应,它会使用net0设备,并且把host机器的2222端口和qemu启动的vm内的22端口做了映射,所以如果想要ssh访问qemu启动的vm,从host上就应该使用2222端口
-cdrom表示把cloud-init需要用的文件通过cdrom image的方式挂载到vm内,这样当vm启动的时候,就会使用seed.img中的文件,从而可以给这个vm添加一些简单的cloud-init user-data,此处seed.img如何制作呢?最简单的使用cloud-localds工具
$ cat user-data.yaml
#cloud-config
ssh_pwauth: true
user:
lock_passwd: false
hashed_passwd: $6$rounds=4096$D8xCAW1zbWkn6LDM$/UG31JlD7CZJiaGRZpwwdDWQqLe7tFpt4yxQPATf3x5M9qYx4o/EsB82pueNXMPTKk3slyMGvg3cSxxrNt054/
### make hashed_passwd: mkpasswd --method=SHA-512 --rounds=4096
$ cloud-localds seed.img user-data.yaml
user-data.yaml从cloud-init官方网站可以找到很多示例代码,而cloud-localds命令也非常简单,它也可以接收meta-data.yaml作为输入.
最后,provisioners里的prepare_k8s.sh脚本内可以是任何内容,比如:
$ cat prepare_k8s.sh
#!/bin/bash
# Install crictl
wget -q -c https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.26.0/crictl-v1.26.0-linux-amd64.tar.gz -O - | tar -xz -C /usr/bin
这样,我们就给这个image里安装了crictl工具,并且配置了默认的runtime是containerd。
最终我们使用如下命令
export PACKER_LOG=1
packer build template.json
它就会output_directory目录下生成一个名字为vm_name的文件。我们这里就是
images/jammy-k8s-containerd-1.6.15.qcow2对于生成的文件,可以使用qemu进行测试运行:
qemu-system-x86_64 \
-machine accel=kvm,type=q35 \
-cpu host \
-m 2G \
-nographic \
-device virtio-net-pci,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::2222-:22 \
-drive if=virtio,format=qcow2,index=0,file=images/jammy-k8s-containerd-1.6.15.qcow2
#-drive if=virtio,format=raw,index=1,file=seed.img
#-fda seed.img
此处比较有意思的是,如果我想测试seed.img,既可以使用-drive参数,也可以使用-fda参数,但它们在packer里都不能用,却只能使用-cdrom。
Comments