Initial commit: MAAS-deployable Proxmox VE images with cluster automation
Builds a Proxmox VE image that MAAS can deploy to bare metal, plus first-boot
automation that configures the node and joins it to a Proxmox cluster with no
manual steps.
The image starts from the official Debian cloud image and installs proxmox-ve
on top of it, rather than capturing a raw disk from the Proxmox ISO. That keeps
MAAS in control of partitioning, networking, SSH keys and cloud-init, and makes
moving between Proxmox releases a variable change instead of a rewrite.
Contents:
* Makefile driving the whole flow: build, verify, preseed, upload
* customize-proxmox.sh, run inside the Packer build VM, which layers Proxmox
onto the Debian cloud image and resets the pmxcfs node identity so one image
can produce many nodes
* pve-maas-init, a first-boot state machine covering /etc/hosts, node-unique
identifiers, the root password, vmbr0 conversion, cluster create/join and
the local-lvm thin pool; each stage is resumable across reboots
* curtin-hooks, which stops curtin installing a kernel over APT and pins
interface names by MAC so they match what MAAS recorded at commissioning
* a MAAS curtin preseed template and cloud-init examples
* deploy-cluster.sh, which builds a whole cluster through the MAAS API
* verify-image.sh, 22 static checks on the produced tarball
Cluster identity lives entirely in deploy-time cloud-init user-data, so a single
image and preseed can build any number of independent clusters.
Verified end to end against MAAS 3.7.2: proxmox-ve 9.2.0 / pve-manager 9.2.11 /
kernel 7.0.14-15-pve, deployed to two machines that formed a quorate cluster with
local-lvm on both, with no manual intervention.
The README documents four failure modes found along the way that all fail
silently: curtin rejecting "kernel: null", pvenetcommit overwriting the network
configuration at boot, interface renaming leaving the link down, and a systemd
ordering cycle that made systemd delete the service's start job.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
57
maas/curtin_userdata_custom.in
Normal file
57
maas/curtin_userdata_custom.in
Normal file
@@ -0,0 +1,57 @@
|
||||
#cloud-config
|
||||
#
|
||||
# MAAS curtin preseed - Proxmox VE ozel imaji icin
|
||||
#
|
||||
# Dosya adi: curtin_userdata_custom_@@ARCH@@_generic_@@IMAGE_NAME@@
|
||||
# Kopyalanacak yer (MAAS snap): /var/snap/maas/current/preseeds/
|
||||
# (MAAS deb paketi): /etc/maas/preseeds/
|
||||
#
|
||||
# Bu ad yalnizca 'custom/@@IMAGE_NAME@@' adiyla, '@@ARCH@@/generic' mimarisiyle
|
||||
# yuklenen imaja uygulanir; diger ozel imajlariniz etkilenmez.
|
||||
|
||||
# Cekirdek kurulumu imajdaki /curtin/curtin-hooks tarafindan devre disi
|
||||
# birakilir (Proxmox cekirdegi imajda hazir gelir). Asagidaki blok yalnizca
|
||||
# kanca herhangi bir nedenle calismazsa devreye giren yedek yoldur.
|
||||
#
|
||||
# DIKKAT: burada 'kernel: null' KULLANMAYIN. MAAS ile gelen curtin
|
||||
# surumlerinin bir kismi bunu desteklemiyor ve kurulum su hatayla basarisiz
|
||||
# oluyor: install_kernel -> AttributeError: 'NoneType' object has no
|
||||
# attribute 'get'
|
||||
kernel:
|
||||
package: proxmox-default-kernel
|
||||
fallback-package: proxmox-default-kernel
|
||||
mapping: {}
|
||||
|
||||
apt:
|
||||
preserve_sources_list: true
|
||||
|
||||
debconf_selections:
|
||||
maas: |
|
||||
{{for line in str(curtin_preseed).splitlines()}}
|
||||
{{line}}
|
||||
{{endfor}}
|
||||
|
||||
late_commands:
|
||||
maas: [wget, '--no-proxy', '{{node_disable_pxe_url}}', '--post-data', '{{node_disable_pxe_data}}', '-O', '/dev/null']
|
||||
|
||||
# Hedef sistemi /mnt altina bagla
|
||||
late_01: mount --bind $TARGET_MOUNT_POINT /mnt
|
||||
|
||||
# MAAS datasource tanimini hedef sisteme tasi
|
||||
late_02: grep -A2 datasource /etc/cloud/cloud.cfg.d/91_kernel_cmdline_url.cfg | sed 's/curtin//' | tee /mnt/etc/cloud/cloud.cfg.d/91_maas_datasource.cfg
|
||||
|
||||
# Debian cloud-init sablonundaki Ubuntu referanslarini duzelt
|
||||
late_03: sed -i 's@ubuntu.com/ubuntu@debian.org/debian@g;s@archive@deb@g;s@ubuntu@debian@g;s@Ubuntu@Debian@g;s@security.debian.org/debian@security.debian.org@g' /mnt/etc/cloud/cloud.cfg
|
||||
|
||||
# zz-update-grub kancasindaki 'set -e' tuzagini kaldir
|
||||
late_04: sed -i '/^set -e/{n;N;d}' /mnt/etc/kernel/postinst.d/zz-update-grub
|
||||
|
||||
# packer-maas'in netplan.io kontrolunu atlatmak icin koydugu sarmalayicilari sil
|
||||
late_05: rm -f /usr/local/bin/dpkg-query /usr/local/bin/netplan
|
||||
late_06: rm -f /mnt/usr/local/bin/dpkg-query /mnt/usr/local/bin/netplan
|
||||
|
||||
# Guvenlik agi: ilk acilis servisi kesin etkin olsun
|
||||
late_07: chroot /mnt systemctl enable pve-maas-init.service || true
|
||||
|
||||
# Onceki calistirmadan kalan durum dosyalari varsa temizle
|
||||
late_08: rm -f /mnt/var/lib/pve-maas/*.done /mnt/var/lib/pve-maas/complete
|
||||
25
maas/examples/01-first-node.yaml
Normal file
25
maas/examples/01-first-node.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
#cloud-config
|
||||
# Kumenin ILK dugumu: yeni bir kume olusturur.
|
||||
#
|
||||
# MAAS ile deploy:
|
||||
# maas $PROFILE machine deploy $SYSTEM_ID \
|
||||
# osystem=custom distro_series=proxmox-ve-9 \
|
||||
# user_data="$(base64 -w0 01-first-node.yaml)"
|
||||
|
||||
write_files:
|
||||
- path: /etc/pve-maas/conf.d/50-pve.conf
|
||||
permissions: "0600"
|
||||
owner: root:root
|
||||
content: |
|
||||
# root@pam parolasi - web arayuzu ve diger dugumlerin katilimi icin sart.
|
||||
# Hash uretmek icin: openssl passwd -6
|
||||
PVE_ROOT_PASSWORD_HASH='$6$DEGISTIRIN$REPLACE.WITH.YOUR.OWN.HASH'
|
||||
|
||||
PVE_CLUSTER_MODE=create
|
||||
PVE_CLUSTER_NAME=pve-cluster-01
|
||||
|
||||
# Corosync icin ayri bir ag kullaniyorsaniz:
|
||||
# PVE_CLUSTER_LINK0=198.51.100.11
|
||||
|
||||
PVE_NET_APPLY=reboot
|
||||
PVE_THINPOOL=auto
|
||||
31
maas/examples/02-join-node.yaml
Normal file
31
maas/examples/02-join-node.yaml
Normal file
@@ -0,0 +1,31 @@
|
||||
#cloud-config
|
||||
# Mevcut bir kumeye katilan dugum.
|
||||
|
||||
write_files:
|
||||
- path: /etc/pve-maas/conf.d/50-pve.conf
|
||||
permissions: "0600"
|
||||
owner: root:root
|
||||
content: |
|
||||
PVE_ROOT_PASSWORD_HASH='$6$DEGISTIRIN$REPLACE.WITH.YOUR.OWN.HASH'
|
||||
|
||||
PVE_CLUSTER_MODE=join
|
||||
|
||||
# Kumede zaten bulunan bir dugumun IP'si
|
||||
PVE_CLUSTER_PEER=192.0.2.11
|
||||
|
||||
# O dugumun root@pam parolasi (duz metin olmak zorunda - API dogrulamasi icin)
|
||||
PVE_CLUSTER_PEER_PASSWORD='degistirin'
|
||||
|
||||
# Onerilen: parmak izini onceden verin (TOFU riskini kaldirir)
|
||||
# openssl s_client -connect 192.0.2.11:8006 </dev/null 2>/dev/null | \
|
||||
# openssl x509 -noout -fingerprint -sha256 | cut -d= -f2
|
||||
# PVE_CLUSTER_FINGERPRINT='AA:BB:CC:...'
|
||||
PVE_CLUSTER_FINGERPRINT_DISCOVER=true
|
||||
|
||||
# PVE_CLUSTER_LINK0=198.51.100.12
|
||||
|
||||
# Katilimdan sonra bu dosyadaki parolalar silinir
|
||||
PVE_CLUSTER_WIPE_SECRETS=true
|
||||
|
||||
PVE_NET_APPLY=reboot
|
||||
PVE_THINPOOL=auto
|
||||
17
maas/examples/03-standalone.yaml
Normal file
17
maas/examples/03-standalone.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
#cloud-config
|
||||
# Tek basina (kumesiz) Proxmox VE dugumu.
|
||||
|
||||
write_files:
|
||||
- path: /etc/pve-maas/conf.d/50-pve.conf
|
||||
permissions: "0600"
|
||||
owner: root:root
|
||||
content: |
|
||||
PVE_ROOT_PASSWORD_HASH='$6$DEGISTIRIN$REPLACE.WITH.YOUR.OWN.HASH'
|
||||
PVE_CLUSTER_MODE=none
|
||||
|
||||
# VLAN farkindalikli kopru isteniyorsa:
|
||||
# PVE_NET_VLAN_AWARE=true
|
||||
|
||||
# Ikinci diski VM depolamasi olarak kullan:
|
||||
# PVE_THINPOOL_DISK=/dev/sdb
|
||||
# PVE_THINPOOL_VG=pve
|
||||
49
maas/examples/04-advanced-network.yaml
Normal file
49
maas/examples/04-advanced-network.yaml
Normal file
@@ -0,0 +1,49 @@
|
||||
#cloud-config
|
||||
# Karmasik ag: bond + VLAN. Otomatik vmbr0 donusumunu kapatip
|
||||
# /etc/network/interfaces dosyasini kendimiz yaziyoruz.
|
||||
|
||||
write_files:
|
||||
- path: /etc/pve-maas/conf.d/50-pve.conf
|
||||
permissions: "0600"
|
||||
owner: root:root
|
||||
content: |
|
||||
PVE_ROOT_PASSWORD_HASH='$6$DEGISTIRIN$REPLACE.WITH.YOUR.OWN.HASH'
|
||||
PVE_NET_MANAGE=false
|
||||
PVE_CLUSTER_MODE=none
|
||||
|
||||
- path: /etc/network/interfaces
|
||||
permissions: "0644"
|
||||
owner: root:root
|
||||
content: |
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
iface eno1 inet manual
|
||||
iface eno2 inet manual
|
||||
|
||||
auto bond0
|
||||
iface bond0 inet manual
|
||||
bond-slaves eno1 eno2
|
||||
bond-mode 802.3ad
|
||||
bond-xmit-hash-policy layer3+4
|
||||
bond-miimon 100
|
||||
|
||||
auto vmbr0
|
||||
iface vmbr0 inet static
|
||||
address 192.0.2.20/24
|
||||
gateway 192.0.2.1
|
||||
bridge-ports bond0
|
||||
bridge-stp off
|
||||
bridge-fd 0
|
||||
bridge-vlan-aware yes
|
||||
bridge-vids 2-4094
|
||||
|
||||
source /etc/network/interfaces.d/*
|
||||
|
||||
- path: /etc/cloud/cloud.cfg.d/99-pve-maas-disable-network.cfg
|
||||
permissions: "0644"
|
||||
content: |
|
||||
network: {config: disabled}
|
||||
|
||||
runcmd:
|
||||
- [ systemctl, enable, networking.service ]
|
||||
Reference in New Issue
Block a user