Add Packer template for building Ubuntu 24.04 server image
Build a QCOW2 image locally with QEMU/KVM + autoinstall, then provision with the existing Ansible playbook. Allows testing changes locally before deploying to production. Outputs a ready-to-upload image for hosting providers. Usage: cp server.pkrvars.hcl.example server.pkrvars.hcl, fill in values, then run ./build.sh Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2236f60469
commit
06580f9db6
3
packer/.gitignore
vendored
Normal file
3
packer/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
output/
|
||||||
|
server.pkrvars.hcl
|
||||||
|
packer_cache/
|
||||||
35
packer/build.sh
Executable file
35
packer/build.sh
Executable file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
if [ ! -f server.pkrvars.hcl ]; then
|
||||||
|
echo "Error: server.pkrvars.hcl not found."
|
||||||
|
echo "Copy server.pkrvars.hcl.example to server.pkrvars.hcl and fill in your values."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Initializing Packer plugins ==="
|
||||||
|
packer init ubuntu-server.pkr.hcl
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Building image ==="
|
||||||
|
echo "This will take 15-30 minutes depending on your machine."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
packer build -var-file=server.pkrvars.hcl ubuntu-server.pkr.hcl
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==========================================="
|
||||||
|
echo " Image built successfully!"
|
||||||
|
echo "==========================================="
|
||||||
|
echo " Output: $SCRIPT_DIR/output/packer-ubuntu-server"
|
||||||
|
echo ""
|
||||||
|
echo " To test locally:"
|
||||||
|
echo " qemu-system-x86_64 -m 4096 -hda output/packer-ubuntu-server -enable-kvm"
|
||||||
|
echo ""
|
||||||
|
echo " To convert for other formats:"
|
||||||
|
echo " qemu-img convert -f qcow2 -O raw output/packer-ubuntu-server output/server.raw"
|
||||||
|
echo " qemu-img convert -f qcow2 -O vmdk output/packer-ubuntu-server output/server.vmdk"
|
||||||
|
echo "==========================================="
|
||||||
0
packer/http/meta-data
Normal file
0
packer/http/meta-data
Normal file
31
packer/http/user-data
Normal file
31
packer/http/user-data
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#cloud-config
|
||||||
|
autoinstall:
|
||||||
|
version: 1
|
||||||
|
locale: en_US.UTF-8
|
||||||
|
keyboard:
|
||||||
|
layout: us
|
||||||
|
network:
|
||||||
|
version: 2
|
||||||
|
ethernets:
|
||||||
|
id0:
|
||||||
|
match:
|
||||||
|
driver: virtio_net
|
||||||
|
dhcp4: true
|
||||||
|
storage:
|
||||||
|
layout:
|
||||||
|
name: lvm
|
||||||
|
sizing-policy: all
|
||||||
|
identity:
|
||||||
|
hostname: server
|
||||||
|
username: ubuntu
|
||||||
|
password: "$6$XjqGOA0giVyHdSZ0$9YqNQlsfuU5xo8uLqpnD49mS3KqyMSp.6imNnIQE18obgTyE0g8LOcL6hvg0sJQXgHv6S7HSIBpKY0.keMXKU."
|
||||||
|
ssh:
|
||||||
|
install-server: true
|
||||||
|
allow-pw: true
|
||||||
|
packages:
|
||||||
|
- openssh-server
|
||||||
|
- curl
|
||||||
|
- wget
|
||||||
|
late-commands:
|
||||||
|
- "echo 'ubuntu ALL=(ALL) NOPASSWD:ALL' > /target/etc/sudoers.d/ubuntu"
|
||||||
|
- "chmod 440 /target/etc/sudoers.d/ubuntu"
|
||||||
7
packer/server.pkrvars.hcl.example
Normal file
7
packer/server.pkrvars.hcl.example
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
base_domain = "example.com"
|
||||||
|
ssh_pubkey = "ssh-ed25519 AAAA... user@host"
|
||||||
|
juicefs_s3_endpoint = "https://s3.amazonaws.com"
|
||||||
|
juicefs_s3_bucket = "my-nextcloud-bucket"
|
||||||
|
juicefs_s3_access_key = "AKIAIOSFODNN7EXAMPLE"
|
||||||
|
juicefs_s3_secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
|
||||||
|
juicefs_cache_size = "50G"
|
||||||
173
packer/ubuntu-server.pkr.hcl
Normal file
173
packer/ubuntu-server.pkr.hcl
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
packer {
|
||||||
|
required_plugins {
|
||||||
|
qemu = {
|
||||||
|
version = "~> 1"
|
||||||
|
source = "github.com/hashicorp/qemu"
|
||||||
|
}
|
||||||
|
ansible = {
|
||||||
|
version = ">= 1.1.2"
|
||||||
|
source = "github.com/hashicorp/ansible"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- VM settings ---
|
||||||
|
|
||||||
|
variable "cpu" {
|
||||||
|
type = string
|
||||||
|
default = "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ram" {
|
||||||
|
type = string
|
||||||
|
default = "4096"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "disk_size" {
|
||||||
|
type = string
|
||||||
|
default = "50000"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "headless" {
|
||||||
|
type = bool
|
||||||
|
default = true
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Ubuntu ISO ---
|
||||||
|
|
||||||
|
variable "iso_url" {
|
||||||
|
type = string
|
||||||
|
default = "https://releases.ubuntu.com/24.04/ubuntu-24.04.2-live-server-amd64.iso"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "iso_checksum" {
|
||||||
|
type = string
|
||||||
|
default = "file:https://releases.ubuntu.com/24.04/SHA256SUMS"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- OS user (created by autoinstall) ---
|
||||||
|
|
||||||
|
variable "ssh_username" {
|
||||||
|
type = string
|
||||||
|
default = "ubuntu"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ssh_password" {
|
||||||
|
type = string
|
||||||
|
default = "ubuntu"
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Server config (passed to Ansible) ---
|
||||||
|
|
||||||
|
variable "base_domain" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ssh_pubkey" {
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "juicefs_s3_endpoint" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "juicefs_s3_bucket" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "juicefs_s3_access_key" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "juicefs_s3_secret_key" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "juicefs_cache_size" {
|
||||||
|
type = string
|
||||||
|
default = "50G"
|
||||||
|
}
|
||||||
|
|
||||||
|
source "qemu" "ubuntu-server" {
|
||||||
|
accelerator = "kvm"
|
||||||
|
boot_command = [
|
||||||
|
"c<wait>",
|
||||||
|
"linux /casper/vmlinuz --- autoinstall ds=\"nocloud;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/\"<enter><wait>",
|
||||||
|
"initrd /casper/initrd<enter><wait>",
|
||||||
|
"boot<enter><wait>"
|
||||||
|
]
|
||||||
|
boot_wait = "10s"
|
||||||
|
disk_cache = "none"
|
||||||
|
disk_compression = true
|
||||||
|
disk_discard = "unmap"
|
||||||
|
disk_interface = "virtio"
|
||||||
|
disk_size = var.disk_size
|
||||||
|
format = "qcow2"
|
||||||
|
headless = var.headless
|
||||||
|
http_directory = "http"
|
||||||
|
iso_checksum = var.iso_checksum
|
||||||
|
iso_url = var.iso_url
|
||||||
|
net_device = "virtio-net"
|
||||||
|
output_directory = "output"
|
||||||
|
qemu_binary = "/usr/bin/qemu-system-x86_64"
|
||||||
|
qemuargs = [
|
||||||
|
["-m", "${var.ram}M"],
|
||||||
|
["-smp", var.cpu],
|
||||||
|
["-cpu", "host"]
|
||||||
|
]
|
||||||
|
shutdown_command = "echo '${var.ssh_password}' | sudo -S shutdown -P now"
|
||||||
|
ssh_password = var.ssh_password
|
||||||
|
ssh_username = var.ssh_username
|
||||||
|
ssh_handshake_attempts = 500
|
||||||
|
ssh_timeout = "45m"
|
||||||
|
ssh_wait_timeout = "45m"
|
||||||
|
}
|
||||||
|
|
||||||
|
build {
|
||||||
|
sources = ["source.qemu.ubuntu-server"]
|
||||||
|
|
||||||
|
provisioner "shell" {
|
||||||
|
execute_command = "echo '${var.ssh_password}' | sudo -S bash -c '{{ .Vars }} {{ .Path }}'"
|
||||||
|
inline = [
|
||||||
|
"apt-get update",
|
||||||
|
"apt-get install -y ansible-core python3-pip"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "file" {
|
||||||
|
source = "../playbook.yml"
|
||||||
|
destination = "/tmp/playbook.yml"
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "file" {
|
||||||
|
source = "../resources"
|
||||||
|
destination = "/tmp/resources"
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "shell" {
|
||||||
|
execute_command = "echo '${var.ssh_password}' | sudo -S bash -c '{{ .Vars }} {{ .Path }}'"
|
||||||
|
environment_vars = [
|
||||||
|
"ANSIBLE_FORCE_COLOR=1"
|
||||||
|
]
|
||||||
|
inline = [
|
||||||
|
"ansible-playbook -i localhost, -c local /tmp/playbook.yml -e 'base_domain=${var.base_domain} ssh_pubkey=\"${var.ssh_pubkey}\" juicefs_s3_endpoint=${var.juicefs_s3_endpoint} juicefs_s3_bucket=${var.juicefs_s3_bucket} juicefs_s3_access_key=${var.juicefs_s3_access_key} juicefs_s3_secret_key=${var.juicefs_s3_secret_key} juicefs_cache_size=${var.juicefs_cache_size}'"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
provisioner "shell" {
|
||||||
|
execute_command = "echo '${var.ssh_password}' | sudo -S bash -c '{{ .Vars }} {{ .Path }}'"
|
||||||
|
inline = [
|
||||||
|
"rm -rf /tmp/playbook.yml /tmp/resources",
|
||||||
|
"apt-get clean",
|
||||||
|
"rm -rf /var/lib/apt/lists/*",
|
||||||
|
"cloud-init clean --logs",
|
||||||
|
"truncate -s 0 /etc/machine-id",
|
||||||
|
"rm -f /var/lib/dbus/machine-id",
|
||||||
|
"fstrim -av || true"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue