packer不生成跨hypervisor通用镜像,而是通过复用模板并行调用qemu、vmware等builder产出特定格式镜像;linux本地构建需确保qemu/kvm就绪,qemu builder必须配置source_path、format和http_directory三要素,且provisioner须避让cloud-init启动时序,最终镜像需验证ssh连通性、cloud-init状态及磁盘扩容效果。

能做,但“通用”二字要打引号——Packer 本身不生成跨 hypervisor 通吃的镜像,它按 builder 类型产出特定格式(如 qemu 出 .qcow2,vmware-iso 出 .vmdk),所谓“通用”实际是靠模板复用 + 多 builder 并行实现的多平台适配。
必须先确认本地 QEMU/KVM 是否就绪
绝大多数 Linux 下的本地标准化镜像构建走的是 qemu builder 路线,因为它轻量、免云账号、支持 cloud-init。但失败常卡在这一步:
-
lsmod | grep kvm返回空?说明内核模块没加载,需sudo modprobe kvm-intel(Intel)或sudo modprobe kvm-amd(AMD) -
ls -l /dev/kvm权限为crw-------?CI runner 或当前用户必须在kvm组里:sudo usermod -aG kvm $USER,然后重新登录 -
qemu-system-x86_64 --version报 command not found?Ubuntu/Debian 需装qemu-kvm,CentOS/RHEL 装qemu-kvm-core
template.json 里最关键的三个 builder 字段
一个能真正落地的 qemu builder 不只写个 type 就完事,下面三项漏任何一项都会导致启动失败或 cloud-init 不生效:
-
source_path必须指向一个可引导的原始镜像(如 Ubuntu Cloud Image 的ubuntu-24.04-server-cloudimg-amd64.img),不能是 ISO —— ISO 是安装介质,不是运行时镜像 -
format显式设为"qcow2"(别依赖默认值),否则 Packer 可能输出 raw 格式,Multipass 或 libvirt 加载时出错 -
http_directory必须指定含meta-data和user-data的目录路径(哪怕meta-data是空文件),这是 cloud-init 启动识别的硬性约定
示例片段:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
"builders": [{
"type": "qemu",
"source_path": "./ubuntu-24.04-server-cloudimg-amd64.img",
"format": "qcow2",
"http_directory": "./cloud-data",
"ssh_username": "ubuntu",
"ssh_password": "ubuntu",
"vm_name": "ubuntu-standard"
}]
provisioner 顺序和 cloud-init 冲突必须规避
很多人把 shell provisioner 放最前,结果发现预装的 Docker 启动不了——因为 cloud-init 在首次 boot 时会重置网络、重写 /etc/hosts、甚至重启 systemd,导致 provisioner 里启动的服务被干掉。
- 所有需要开机自启、且依赖网络/主机名的服务(如 Docker、Node.js、监控 agent),必须通过
user-data注入,而不是靠shellprovisioner 的systemctl enable -
shellprovisioner 只适合做离线操作:apt/yum 安装包、写配置文件、调优内核参数(sysctl)、禁用不需要的服务(systemctl disable snapd) - 若真要用
shell启服务,加"execute_command": "echo 'packer' | {{ .Vars }} sudo -S -E sh -c '{{ .Script }}'"确保以 root 执行,且避开 cloud-init 的 timing race
构建后镜像怎么才算“可交付”
跑完 packer build template.json 只是第一步。一个能进 CI 流水线的标准化镜像,必须满足三个验证点:
- 手动用
qemu-system-x86_64 -drive file=output-qemu/packer-qemu,format=qcow2 -netdev user,id=n1 -device virtio-net,netdev=n1启动,确认能 SSH 进去、cloud-init status --wait返回done - 检查
output-qemu/packer-qemu文件大小是否合理(Ubuntu 24.04 标准镜像压缩后约 400–600MB;如果只有 200MB,大概率没成功注入 cloud-init) - 运行
qemu-img info output-qemu/packer-qemu,确认virtual size是 20G+(不是 1.2G 这种原始 cloud image 大小),说明 resize 操作已生效(通常由 cloud-init 完成)
真正容易被忽略的是:你构建出的 .qcow2 文件,对 Multipass 是开箱即用的,但对 libvirt/virsh 需要额外 virt-install --import 并指定 --os-variant ubuntu24.04;对 VirtualBox 则必须转成 vmdk(qemu-img convert -f qcow2 -O vmdk ...)。所谓“通用”,从来不是格式通用,而是构建逻辑与验证标准通用。










