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