Add 2nd box (libvirt with UEFI)

This commit is contained in:
Hoang Nguyen 2022-08-30 10:02:26 +07:00
parent e2f3d03b1d
commit 26cba165dc
No known key found for this signature in database
GPG Key ID: 813CF484F4993419
9 changed files with 314 additions and 25 deletions

22
.editorconfig Normal file
View File

@ -0,0 +1,22 @@
root = true
[*]
tab_width = 8
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
# HCL2
[{*.pkr.hcl,*.tf,*.tfvars}]
indent_style = space
indent_size = 2
[{Makefile,*.sh}]
indent_style = tab
tab_width = 2
[*.md]
indent_style = space
indent_size = 2
trim_trailing_whitespace = false

View File

@ -2,12 +2,22 @@ VM_STATE_RUNNING ?= true
all: build_all alpine-qemu
build_all: iso_checksum alpine-qemu.pkr.hcl
build_all: checksum alpine-qemu.pkr.hcl alpine-libvirt.pkr.hcl
alpine-qemu.pkr.hcl:
alpine-qemu.pkr.hcl: clean
@packer validate $@
@packer build -on-error=abort $@
# By default Packer will build all sources at the same time
# We explicitly make it build in order here
alpine-libvirt.pkr.hcl: clean
@packer init -upgrade $@
@packer validate $@
@echo "==> Building QEMU box ..."
@packer build -on-error=abort -only="*.alpine-qemu-uefi" $@
@echo "==> Importing QEMU box as libvirt domain ..."
@packer build -on-error=abort -only="*.alpine-libvirt" $@
alpine-qemu:
@terraform -chdir=./terraform/alpine-qemu init -upgrade -migrate-state
@terraform -chdir=./terraform/alpine-qemu validate
@ -25,7 +35,7 @@ clean:
destroy:
@find ./terraform/* -prune -exec terraform -chdir={} apply -destroy \;
iso_checksum:
checksum:
@find . -name *.pkr.hcl -type f -exec sh update_iso_checksum.sh {} \;
.PHONY: all build_all alpine-qemu.pkr.hcl alpine-qemu format-packer format-terraform clean destroy iso_checksum
.PHONY: all build_all alpine-qemu.pkr.hcl alpine-libvirt.pkr.hcl alpine-qemu format-packer format-terraform clean destroy checksum

View File

@ -1,19 +1,44 @@
# packer-templates
# Packer templates
This repository holds Packer's VM templates I use. Most (if not all) of them run [AlpineLinux](https://alpinelinux.org).
## Dependencies
For [update_iso_checksum.sh](./update_iso_checksum.sh) script:
- [hcl2json](https://github.com/tmccombs/hcl2json)
- [jq](https://github.com/stedolan/jq) ([gojq](https://github.com/itchyny/gojq) and [jaq](https://github.com/01mf02/jaq) also work)
Other:
- [packer](https://www.packer.io/) (of course)
- [terraform](https://www.terraform.io/)
- [make](https://www.gnu.org/software/make/) (for convenience sake)
- [qemu](http://www.qemu.org/) + [libvirt](https://libvirt.org/)
Note that libvirt plugins (for both Packer and Terraform) do not support modular daemons so running `libvirtd` service is required. Issue filled at <https://github.com/digitalocean/go-libvirt/issues/171>.
## VM boxes
- [alpine-qemu.pkr.hcl](./alpine-qemu.pkr.hcl): libvirt-compatible VM on local machine running Alpine edge.
- [alpine-qemu.pkr.hcl](./alpine-qemu.pkr.hcl): libvirt-compatible VM on local machine running Alpine edge
```bash
# Build the VM box
make alpine-qemu.pkr.hcl
# Import the built box to libvirt volume and launch it
VM_STATE_RUNNING=true terraform -chdir=terraform/alpine-qemu apply
# Build the VM box and launch it as a libvirt domain
VM_STATE_RUNNING=true make alpine-qemu.pkr.hcl alpine-qemu
```
- [alpine-libvirt.pkr.hcl](./alpine-libvirt.pkr.hcl): a variation of `alpine-qemu` box with UEFI, using [packer-plugin-libvirt](https://github.com/thomasklein94/packer-plugin-libvirt) instead of [terraform-provider-libvirt](https://github.com/dmacvicar/terraform-provider-libvirt)
```bash
# Build the box and import it into `default` libvirt pool
make alpine-libvirt.pkr.hcl
# You'll have to start the VM manually
virsh -c qemu:///system start packer-alpine-edge-uefi-libvirt-x86_64
```
## Acknowledge
- [rgl/alpine-vagrant](https://github.com/rgl/alpine-vagrant)
## License
MIT

150
alpine-libvirt.pkr.hcl Normal file
View File

@ -0,0 +1,150 @@
packer {
required_plugins {
libvirt = {
version = ">= 0.3.3"
source = "github.com/thomasklein94/libvirt"
}
}
}
variable "headless" {
type = bool
default = true
}
variable "iso_url" {
type = string
default = "https://dl-cdn.alpinelinux.org/alpine/v3.16/releases/x86_64/alpine-standard-3.16.2-x86_64.iso"
}
variable "iso_checksum" {
type = string
default = "sha512:b4dcc47b28390c20348d14643863ce41fb9ad55755a1ec00af0117c3dd09c9d03c2c722b005534abece67baa2a017bd78a65c18d2dccd525491d679fe13cd615"
}
variable "disk_size" {
type = string
default = "20G"
}
variable "ram" {
type = number
default = 2048
}
variable "cpus" {
type = number
default = 2
}
variable "rootfstype" {
type = string
default = "ext4"
}
variable "ssh_username" {
type = string
default = "kawaii"
}
variable "ssh_password" {
type = string
default = "kawaii"
}
variable "vm_name" {
type = string
default = "packer-alpine-edge-uefi-libvirt-x86_64"
}
source "qemu" "alpine-qemu-uefi" {
accelerator = "kvm"
boot_command = [
"root<enter>",
"ifconfig eth0 up && udhcpc -i eth0<enter><wait10s>",
"wget -qO answers http://{{.HTTPIP}}:{{.HTTPPort}}/answers/alpine-libvirt<enter><wait5s>",
"echo 'USEROPTS=\"-a -u ${var.ssh_username}\"' >> answers<enter>",
"ERASE_DISKS=/dev/vda ROOTFS=${var.rootfstype} setup-alpine -ef answers<enter><wait10m>",
"wget -qO- http://{{.HTTPIP}}:{{.HTTPPort}}/scripts/reset-uefi-bootloaders.sh | sh -s /dev/vda<enter><wait30s>",
"reboot<enter><wait40s>",
"root<enter>",
"echo '${var.ssh_username}:${var.ssh_password}' | chpasswd<enter>",
"sed -i 's/^permit persist/permit nopass/' /etc/doas.d/doas.conf<enter>",
"apk add dropbear-scp<enter>",
"passwd -l root<enter>",
"reboot<enter>"
]
boot_wait = "30s"
disk_cache = "none"
disk_compression = true
disk_discard = "unmap"
disk_interface = "virtio"
disk_size = var.disk_size
format = "qcow2"
headless = var.headless
http_directory = "."
iso_checksum = var.iso_checksum
iso_url = var.iso_url
net_device = "virtio-net"
output_directory = "artifacts/libvirt"
qemu_binary = "/usr/bin/qemu-system-x86_64"
qemuargs = [
["-bios", "/usr/share/OVMF/OVMF.fd"],
["-m", "${var.ram}"],
["-display", "none"],
["-smp", "${var.cpus}"]
]
shutdown_command = "doas /sbin/poweroff"
ssh_password = var.ssh_password
ssh_username = var.ssh_username
ssh_wait_timeout = "30m"
vm_name = "${var.vm_name}.qcow2"
}
source "libvirt" "alpine-libvirt" {
libvirt_uri = "qemu:///system"
domain_name = var.vm_name
domain_type = "kvm"
vcpu = var.cpus
memory = var.ram
network_address_source = "agent"
shutdown_mode = "guest"
network_interface {
type = "bridge"
bridge = "virbr0"
model = "virtio"
}
communicator {
communicator = "none"
}
volume {
alias = "artifact"
target_dev = "vda"
bus = "virtio"
format = "qcow2"
pool = "default"
name = "${var.vm_name}.qcow2"
capacity = var.disk_size
source {
type = "external"
urls = ["./artifacts/libvirt/${var.vm_name}.qcow2"]
}
}
}
build {
sources = ["source.qemu.alpine-qemu-uefi"]
provisioner "shell" {
execute_command = "{{.Vars}} doas sh {{.Path}}"
scripts = ["scripts/provision-generic.sh"]
}
}
build {
sources = ["source.libvirt.alpine-libvirt"]
}

View File

@ -19,13 +19,13 @@ variable "disk_size" {
}
variable "ram" {
type = string
default = "2048M"
type = number
default = 2048
}
variable "cpus" {
type = string
default = "2"
type = number
default = 2
}
variable "rootfstype" {
@ -89,11 +89,7 @@ build {
sources = ["source.qemu.alpine-qemu"]
provisioner "shell" {
execute_command = "doas sh {{.Path}}"
inline_shebang = "/bin/sh -e"
inline = [
"apk add qemu-guest-agent",
"rc-update add qemu-guest-agent"
]
execute_command = "{{.Vars}} doas sh {{.Path}}"
script = "scripts/provision-generic.sh"
}
}

33
answers/alpine-libvirt Normal file
View File

@ -0,0 +1,33 @@
# Answer file for alpine-libvirt.pkr.hcl template
KEYMAPOPTS="us us"
HOSTNAMEOPTS="alpine-libvirt"
DEVDOPTS="mdev"
INTERFACESOPTS="auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
hostname alpine-libvirt
"
DNSOPTS=""
TIMEZONEOPTS="UTC"
PROXYOPTS="none"
APKREPOSOPTS="https://download.nus.edu.sg/mirror/alpine/edge/main
https://download.nus.edu.sg/mirror/alpine/edge/community
https://download.nus.edu.sg/mirror/alpine/edge/testing
"
SSHDOPTS="dropbear"
NTPOPTS="busybox"
DISKOPTS="-s 0 -m sys /dev/vda"

View File

@ -0,0 +1,16 @@
#!/bin/sh
set -eux
# Install qemu-guest-agent for graceful libvirt shutdown
apk add qemu-guest-agent
rc-update add qemu-guest-agent
# Configure GA_PATH for qemu-guest-agent
sed -i -E 's,#?(GA_PATH=).+,\1"/dev/vport0p1",' /etc/conf.d/qemu-guest-agent
# Zero out empty space (slower build), make the result image a little bit smaller
dd if=/dev/zero of=/zero.fill bs=1M || true && sync && sleep 1 && sync && rm -f /zero.fill
# Discard unused blocks
fstrim -v /

View File

@ -0,0 +1,37 @@
#!/bin/sh
set -eux
if [ $# -ne 1 ]; then
echo "Required 1 argument."
exit 1
fi
device="$1"
if [ -d /sys/firmware/efi/efivars ]; then
# install the efi boot manager.
apk add efibootmgr
# show the boot options.
efibootmgr -v
# remove all the boot options.
efibootmgr \
| sed -nE 's,^Boot([0-9A-F]{4}).*,\1,gp' \
| xargs -I% efibootmgr --quiet --delete-bootnum --bootnum %
# create the boot option.
# NB if we do not set any boot option, the firmware will recover/discover them
# at the next boot. the firmware will find the shimx64.efi. when the shim
# runs for the first time in a system with an enabled TPM, it will do an
# extra reboot. when we are connected to the machine using AMT Remote
# Desktop, that extra reboot messes with the ethernet speed by switching it
# to a crawling 10 Mbps. to prevent all this we have to create this boot
# option.
# see https://github.com/coreos/fedora-coreos-tracker/issues/563
# see https://github.com/rhboot/shim
efibootmgr \
-c \
-d "$device" \
-p 1 \
-L Alpine \
-l '\EFI\alpine\grubx64.efi'
fi

View File

@ -3,14 +3,14 @@
set -e
if [ $# -ne 1 ]; then
echo "Required only 1 argument."
exit 1
echo "Required only 1 argument."
exit 1
fi
filename="$1"
if [ ! -r "$filename" ]; then
echo "File $filename cannot be read."
exit 1
echo "File $filename cannot be read."
exit 1
fi
iso_url=$(hcl2json "$filename" | jq -r '.variable.iso_url[].default')