Add Debian templates for Worldskills VMs

This commit is contained in:
2026-04-15 15:31:29 +02:00
parent 2c026b3e05
commit 005213ac7f
6 changed files with 940 additions and 0 deletions

View File

@@ -0,0 +1,298 @@
packer {
required_version = ">= 1.9.0"
required_plugins {
vsphere = {
source = "github.com/hashicorp/vsphere"
version = "~> 1"
}
}
}
# ── vCenter connection ───────────────────────────────────────────────────────
variable "vcenter_server" {
type = string
description = "vCenter server hostname or IP address"
}
variable "vcenter_username" {
type = string
description = "vCenter username (e.g. administrator@vsphere.local)"
}
variable "vcenter_password" {
type = string
description = "vCenter password"
sensitive = true
}
variable "vcenter_insecure_connection" {
type = bool
description = "Skip TLS certificate verification (set false in production)"
default = true
}
# ── vSphere placement ────────────────────────────────────────────────────────
variable "datacenter" {
type = string
description = "vSphere datacenter name"
}
variable "cluster" {
type = string
description = "vSphere cluster or standalone ESXi host name"
}
variable "datastore" {
type = string
description = "Datastore name where the VM will be stored"
}
variable "network" {
type = string
description = "Port group / network name (used for Packer SSH — not saved in template)"
}
variable "vm_folder" {
type = string
description = "VM inventory folder path (empty = root datacenter folder)"
default = ""
}
# ── VM hardware ──────────────────────────────────────────────────────────────
variable "vm_name" {
type = string
description = "Name of the resulting VM template"
default = "debian-13-template"
}
variable "vm_cpus" {
type = number
description = "Number of vCPUs"
default = 2
}
variable "vm_memory_mb" {
type = number
description = "RAM in MB"
default = 2048
}
variable "vm_disk_size_mb" {
type = number
description = "System disk size in MB"
default = 40960 # 40 GB
}
# ── ISO paths on the vSphere datastore ──────────────────────────────────────
# Format: "[<datastore-name>] <folder/filename.iso>"
# All five BDs are mounted simultaneously so apt can resolve packages from any
# disc without manual disc swapping. BD-1 is the only bootable disc.
variable "iso_bd1" {
type = string
description = "Datastore path to debian-13-amd64-BD-1.iso (bootable installer)"
}
variable "iso_bd2" {
type = string
description = "Datastore path to debian-13-amd64-BD-2.iso"
}
variable "iso_bd3" {
type = string
description = "Datastore path to debian-13-amd64-BD-3.iso"
}
variable "iso_bd4" {
type = string
description = "Datastore path to debian-13-amd64-BD-4.iso"
}
variable "iso_bd5" {
type = string
description = "Datastore path to debian-13-amd64-BD-5.iso"
}
variable "iso_bd6" {
type = string
description = "Datastore path to debian-13-amd64-BD-6.iso"
}
# ── Preseed / SSH credentials ────────────────────────────────────────────────
# Must match the values in http/preseed.cfg
variable "ssh_username" {
type = string
default = "root"
}
variable "ssh_password" {
type = string
sensitive = true
default = "packer"
}
# ── Source definition ────────────────────────────────────────────────────────
source "vsphere-iso" "debian" {
# vCenter
vcenter_server = var.vcenter_server
username = var.vcenter_username
password = var.vcenter_password
insecure_connection = var.vcenter_insecure_connection
datacenter = var.datacenter
cluster = var.cluster
datastore = var.datastore
folder = var.vm_folder
# VM identity
vm_name = var.vm_name
guest_os_type = "debian10_64Guest" # highest Debian guest ID recognised by ESXi 6.5
notes = "Debian 13 (Trixie) — built with Packer on ${formatdate("YYYY-MM-DD", timestamp())}"
firmware = "efi"
# CPU / RAM
CPUs = var.vm_cpus
RAM = var.vm_memory_mb
RAM_reserve_all = false
# Disk — thin-provisioned on a PVSCSI controller (best practice for vSphere)
disk_controller_type = ["pvscsi"]
storage {
disk_size = var.vm_disk_size_mb
disk_thin_provisioned = true
disk_controller_index = 0
}
# Network adapter — needed only so Packer can SSH in after install.
# The preseed does not write any persistent network configuration.
network_adapters {
network = var.network
network_card = "vmxnet3"
}
# SATA CD-ROM drives — SATA supports up to 30 slots, avoiding the 4-device
# IDE limit. All five BD ISOs are mounted simultaneously so apt-cdrom can
# scan every disc without manual swapping.
cdrom_type = "sata"
iso_paths = [
var.iso_bd1, # CD-ROM 0 — bootable installer disc
var.iso_bd2, # CD-ROM 1
var.iso_bd3, # CD-ROM 2
var.iso_bd4, # CD-ROM 3
var.iso_bd5, # CD-ROM 4
var.iso_bd6, # CD-ROM 5
]
# Packer starts a local HTTP server to serve the preseed file.
http_directory = "${path.root}/http"
http_port_min = 8100
http_port_max = 8199
# Boot sequence (UEFI / GRUB edit mode):
# 1. Wait for the GRUB menu to appear.
# 2. Press down once — default is "Graphical install"; one down selects
# the plain "Install" (TUI) entry.
# 3. Press 'e' to open the entry editor.
# 4. Navigate down to the linux kernel line (3rd line in the entry) and
# jump to its end, then append preseed parameters.
# 5. Press Ctrl+X to boot.
boot_wait = "10s"
boot_command = [
"<down><wait>",
"e<wait2>",
"<down><down><down><end>",
" auto=true priority=critical",
" locale=en_US.UTF-8",
" keymap=us",
" keyboard-configuration/xkb-keymap=us",
" keyboard-configuration/layoutcode=us",
" preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg",
"<wait><leftCtrlOn>x<leftCtrlOff>"
]
# SSH communicator — Packer waits here until the VM finishes installing,
# reboots, and becomes reachable (open-vm-tools reports the DHCP address).
communicator = "ssh"
ssh_username = var.ssh_username
ssh_password = var.ssh_password
ssh_timeout = "120m"
ssh_handshake_attempts = 100
# Keep the five CD-ROM drives in the template so the discs can be remounted
# later (e.g. to install additional packages on cloned VMs).
# ISOs remain attached; disconnect them in the vSphere UI if not needed.
remove_cdrom = false
# Power off and snapshot once the build completes
convert_to_template = false
create_snapshot = true
snapshot_name = "Start"
}
# ── Build ─────────────────────────────────────────────────────────────────────
build {
name = "debian-13-template"
sources = ["source.vsphere-iso.debian"]
# Generalise the VM so every clone starts with a clean identity
provisioner "shell" {
inline = [
# Remove SSH host keys — regenerated on first boot of each clone
"sudo rm -f /etc/ssh/ssh_host_*",
# Generate root SSH key
"sudo mkdir -p /root/.ssh",
"sudo chmod 700 /root/.ssh",
"sudo ssh-keygen -t ed25519 -N '' -f /root/.ssh/id_ed25519",
"sudo chmod 600 /root/.ssh/id_ed25519",
"sudo chmod 644 /root/.ssh/id_ed25519.pub",
"sudo cp /root/.ssh/id_ed25519.pub /root/.ssh/authorized_keys",
"sudo chmod 600 /root/.ssh/authorized_keys",
# Clear machine-id — systemd and DHCP clients use it as a unique identifier
"sudo truncate -s0 /etc/machine-id",
"sudo rm -f /var/lib/dbus/machine-id",
"sudo ln -s /etc/machine-id /var/lib/dbus/machine-id",
# ── Network config wipe ─────────────────────────────────────────────────
# Remove persistent interface naming rules
"sudo rm -f /etc/udev/rules.d/70-persistent-net.rules",
# Blank ifupdown config — Debian server uses this exclusively
"echo '' | sudo tee /etc/network/interfaces",
# Clear hostname and DHCP leases
"sudo truncate -s0 /etc/hostname",
"sudo rm -f /var/lib/dhcp/*.leases",
# ── cloud-init ──────────────────────────────────────────────────────────
# Set VMware as the preferred datasource (open-vm-tools is installed)
"echo 'datasource_list: [VMware, NoCloud, None]' | sudo tee /etc/cloud/cloud.cfg.d/99-datasource.cfg",
# Remove any cloud-init state so it runs fresh on first boot of each clone
# Services are enabled automatically by the package — no explicit enable needed
"sudo cloud-init clean --logs",
# ── Cleanup ─────────────────────────────────────────────────────────────
# Clean apt package cache
"sudo apt-get clean -y",
"sudo apt-get autoremove --purge -y",
# Truncate log files (keep the files so rsyslog doesn't complain)
"sudo find /var/log -type f | sudo xargs truncate -s0",
"sudo truncate -s0 /var/log/wtmp",
"sudo truncate -s0 /var/log/lastlog",
# Clear shell histories
"sudo truncate -s0 /root/.bash_history",
"truncate -s0 ~/.bash_history",
]
}
}

View File

@@ -0,0 +1,34 @@
# Copy this file to debian.pkrvars.hcl and fill in the values for your
# environment. Never commit the real file — it contains credentials.
#
# Usage:
# packer init .
# packer build -var-file=debian.pkrvars.hcl .
vcenter_server = "vcsa.example.local"
vcenter_username = "administrator@vsphere.local"
vcenter_password = "Password!"
# Set to false if your vCenter has a valid CA-signed certificate
vcenter_insecure_connection = true
datacenter = ""
cluster = "" # standalone ESXi host
datastore = "datastore1"
network = "VM Network" # port group used during build (DHCP required)
vm_folder = "Templates"
vm_name = "debian-13-template"
vm_cpus = 2
vm_memory_mb = 2048
vm_disk_size_mb = 30720
iso_bd1 = "[datastore1] ISOs/debian-13.4.0-amd64-BD-1.iso"
iso_bd2 = "[datastore1] ISOs/debian-13.4.0-amd64-BD-2.iso"
iso_bd3 = "[datastore1] ISOs/debian-13.4.0-amd64-BD-3.iso"
iso_bd4 = "[datastore1] ISOs/debian-13.4.0-amd64-BD-4.iso"
iso_bd5 = "[datastore1] ISOs/debian-13.4.0-amd64-BD-5.iso"
iso_bd6 = "[datastore1] ISOs/debian-13.4.0-amd64-BD-6.iso"
ssh_username = "root"
ssh_password = "Passw0rd!"

View File

@@ -0,0 +1,142 @@
# Debian 13 (Trixie) — fully automated preseed for vSphere template builds
# All packages are resolved from the six mounted BD ISOs; no internet access
# is required during installation.
# ── Locale & keyboard ────────────────────────────────────────────────────────
d-i debian-installer/locale string en_US.UTF-8
d-i localechooser/supported-locales multiselect en_US.UTF-8
d-i keyboard-configuration/model string pc105
d-i keyboard-configuration/layoutcode string us
d-i keyboard-configuration/variantcode string
d-i keyboard-configuration/xkb-keymap select us
d-i keyboard-configuration/options string
d-i console-setup/ask_detect boolean false
d-i console-setup/layoutcode string us
d-i console-setup/variantcode string
# ── Network ──────────────────────────────────────────────────────────────────
# DHCP is used during installation so Packer can reach the VM over SSH.
# No static IP, hostname, or domain is written to the installed system —
# each clone from the template configures its own network on first boot.
d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string debian
d-i netcfg/get_domain string local
d-i netcfg/hostname string debian
d-i netcfg/wireless_wep string
# ── Mirror / apt sources ──────────────────────────────────────────────────────
# Disable network mirror entirely. All packages come from the six BD ISOs
# that are mounted as CD-ROM drives. The installer scans every optical drive
# automatically and registers them as apt sources.
d-i apt-setup/use_mirror boolean false
d-i apt-setup/no_mirror boolean true
d-i apt-setup/cdrom/set-first boolean true
d-i apt-setup/cdrom/set-next boolean true
d-i apt-setup/cdrom/set-failed boolean true
d-i apt-setup/services-select multiselect
# ── Clock ─────────────────────────────────────────────────────────────────────
d-i clock-setup/utc boolean true
d-i time/zone string UTC
d-i clock-setup/ntp boolean false
# ── Partitioning ──────────────────────────────────────────────────────────────
# GPT layout required for UEFI. Three partitions:
# 1. EFI System Partition — 512 MB fat32
# 2. Swap — 2 GB
# 3. Root — remainder of disk, xfs
d-i partman-auto/disk string /dev/sda
d-i partman-auto/method string regular
d-i partman-partitioning/choose_label string gpt
d-i partman-partitioning/default_label string gpt
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman/default_filesystem string xfs
d-i partman-auto/choose_recipe select boot-root
d-i partman-auto/expert_recipe string \
boot-root :: \
512 512 512 fat32 \
$primary{ } \
method{ efi } \
format{ } \
. \
2048 2048 2048 linux-swap \
$primary{ } \
method{ swap } \
format{ } \
. \
1000 30000 -1 xfs \
$primary{ } \
method{ format } \
format{ } \
use_filesystem{ } \
filesystem{ xfs } \
mountpoint{ / } \
.
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
# ── Users ─────────────────────────────────────────────────────────────────────
# Root only — no regular user created; cloud-init handles user provisioning.
d-i passwd/root-login boolean true
d-i passwd/root-password password Passw0rd!
d-i passwd/root-password-again password Passw0rd!
d-i passwd/make-user boolean false
# ── Package selection ─────────────────────────────────────────────────────────
tasksel tasksel/first multiselect standard
d-i pkgsel/include string \
sudo \
openssh-server \
open-vm-tools \
cloud-init \
smbclient \
curl \
lynx \
dnsutils \
ldap-utils \
ftp \
lftp \
wget \
nfs-common \
rsync \
telnet \
traceroute \
tcptraceroute \
tcpdump \
net-tools \
cifs-utils \
resolvconf \
nmap \
vim
d-i pkgsel/upgrade select full-upgrade
popularity-contest popularity-contest/participate boolean false
# ── Boot loader ───────────────────────────────────────────────────────────────
# On UEFI, grub-efi installs to the EFI System Partition automatically —
# do not specify bootdev or it will conflict with EFI installation.
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean false
# ── Late command ──────────────────────────────────────────────────────────────
# Runs inside the installed system (chroot) just before the first reboot.
# 1. Configure SSH to allow root login and password authentication.
# 2. Enable the SSH service.
# 3. Remove any DHCP lease files so the template has no saved network state.
d-i preseed/late_command string \
in-target sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config; \
in-target sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config; \
in-target systemctl enable ssh; \
rm -f /target/var/lib/dhcp/*.leases; \
rm -f /target/etc/resolv.conf; \
in-target ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
# ── Finish ────────────────────────────────────────────────────────────────────
d-i finish-install/reboot_in_progress note