feat(fastpass): Talos cluster provisioning and bootstrap
- Terraform: VM provisioning, Unifi DHCP, Technitium DNS - talhelper: cluster config for 6-node Talos cluster - Cilium 1.19.4 CNI with Talos-compatible security context - docs: city-hall setup guide and bootstrap runbook
This commit is contained in:
94
terraform/talos/modules/node/main.tf
Normal file
94
terraform/talos/modules/node/main.tf
Normal file
@@ -0,0 +1,94 @@
|
||||
# ─── Talos Node Resource ─────────────────────────────────────────────────────
|
||||
# Creates a Proxmox VM booting from the Talos ISO.
|
||||
# No cloud-init, no template clone — Talos is configured via the Talos API
|
||||
# after boot using talhelper-generated machine configs from city-hall.
|
||||
#
|
||||
# Boot sequence:
|
||||
# 1. Terraform creates VM (stopped) + DHCP reservation
|
||||
# 2. Unifi assigns reserved IP when VM starts
|
||||
# 3. talhelper applies machine config via Talos API (port 50000)
|
||||
# 4. Cluster bootstraps; ISO is no longer needed after first boot
|
||||
# (Talos installs itself to disk on first config apply)
|
||||
|
||||
resource "proxmox_virtual_environment_vm" "node" {
|
||||
name = var.hostname
|
||||
vm_id = var.vm_id
|
||||
node_name = var.target_node
|
||||
|
||||
description = "Talos ${var.node_role} node — fastpass cluster. Managed by mk-labs Terraform."
|
||||
tags = ["managed", "talos", "fastpass", var.node_role]
|
||||
bios = "ovmf"
|
||||
|
||||
# ─── EFI Disk ─────────────────────────────────────────────────────────────
|
||||
# Required for OVMF/UEFI boot. Stores EFI variables.
|
||||
efi_disk {
|
||||
datastore_id = var.datastore
|
||||
file_format = "raw"
|
||||
type = "4m"
|
||||
}
|
||||
|
||||
# ─── Boot: Talos ISO ──────────────────────────────────────────────────────
|
||||
# Talos boots from ISO, applies machine config via API, then installs
|
||||
# itself to the disk. After first boot the ISO is not needed.
|
||||
cdrom {
|
||||
file_id = var.iso_file_id
|
||||
interface = "ide2"
|
||||
}
|
||||
|
||||
boot_order = ["scsi0", "ide2"]
|
||||
|
||||
# ─── Disk ─────────────────────────────────────────────────────────────────
|
||||
# Single disk — Talos manages its own partition layout.
|
||||
# No separate data disk; persistent app storage comes from Pure Storage CSI.
|
||||
disk {
|
||||
datastore_id = var.datastore
|
||||
size = var.disk_size
|
||||
interface = "scsi0"
|
||||
file_format = "raw"
|
||||
ssd = true
|
||||
discard = "on"
|
||||
}
|
||||
|
||||
# ─── CPU ──────────────────────────────────────────────────────────────────
|
||||
cpu {
|
||||
cores = var.cpu_cores
|
||||
type = "x86-64-v2-AES"
|
||||
}
|
||||
|
||||
# ─── Memory ───────────────────────────────────────────────────────────────
|
||||
memory {
|
||||
dedicated = var.memory_mb
|
||||
}
|
||||
|
||||
# ─── Network ──────────────────────────────────────────────────────────────
|
||||
# Single NIC on VLAN 71 (Server Trusted).
|
||||
# MAC is deterministic via Terraform so Unifi DHCP reservation matches.
|
||||
network_device {
|
||||
bridge = var.bridge
|
||||
model = "virtio"
|
||||
}
|
||||
|
||||
# ─── QEMU Guest Agent ─────────────────────────────────────────────────────
|
||||
# Requires the qemu-guest-agent Talos system extension (set in talhelper).
|
||||
agent {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
# ─── Start Behavior ───────────────────────────────────────────────────────
|
||||
# VM starts immediately — Talos needs to boot to accept machine configs.
|
||||
# Unifi DHCP reservation is created before this resource so the IP is
|
||||
# already reserved when the NIC first broadcasts a DHCP request.
|
||||
started = true
|
||||
|
||||
# ─── Lifecycle ────────────────────────────────────────────────────────────
|
||||
lifecycle {
|
||||
ignore_changes = [
|
||||
description,
|
||||
tags,
|
||||
# cdrom can be ejected manually after first boot without Terraform drift
|
||||
cdrom,
|
||||
# node_name changes after HA migrates VMs to their intended hosts
|
||||
node_name,
|
||||
]
|
||||
}
|
||||
}
|
||||
18
terraform/talos/modules/node/outputs.tf
Normal file
18
terraform/talos/modules/node/outputs.tf
Normal file
@@ -0,0 +1,18 @@
|
||||
# ─── Node Outputs ────────────────────────────────────────────────────────────
|
||||
# Consumed by the cluster root module to wire up DHCP reservations and
|
||||
# DNS records without hardcoding MAC addresses.
|
||||
|
||||
output "vm_id" {
|
||||
description = "Proxmox VM ID."
|
||||
value = proxmox_virtual_environment_vm.node.vm_id
|
||||
}
|
||||
|
||||
output "mac_address" {
|
||||
description = "MAC address of the primary network interface. Used to create the Unifi DHCP reservation."
|
||||
value = proxmox_virtual_environment_vm.node.network_device[0].mac_address
|
||||
}
|
||||
|
||||
output "hostname" {
|
||||
description = "Node hostname. Passed through for convenience when building DNS records."
|
||||
value = proxmox_virtual_environment_vm.node.name
|
||||
}
|
||||
8
terraform/talos/modules/node/providers.tf
Normal file
8
terraform/talos/modules/node/providers.tf
Normal file
@@ -0,0 +1,8 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
proxmox = {
|
||||
source = "bpg/proxmox"
|
||||
version = ">= 0.74.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
71
terraform/talos/modules/node/variables.tf
Normal file
71
terraform/talos/modules/node/variables.tf
Normal file
@@ -0,0 +1,71 @@
|
||||
# ─── Provider Authentication ─────────────────────────────────────────────────
|
||||
# Passed through from the cluster root module — not declared here since
|
||||
# provider config lives in the root module's providers.tf.
|
||||
|
||||
# ─── Node Identity ───────────────────────────────────────────────────────────
|
||||
|
||||
variable "hostname" {
|
||||
type = string
|
||||
description = "Node hostname (e.g., space-mountain). Used as the Proxmox VM name."
|
||||
}
|
||||
|
||||
variable "vm_id" {
|
||||
type = number
|
||||
description = "Proxmox VM ID. Convention: {third_octet}{fourth_octet:03d} (e.g., 10.1.71.66 → 71066)."
|
||||
}
|
||||
|
||||
variable "node_role" {
|
||||
type = string
|
||||
description = "Role of the node in the cluster. Used for tagging."
|
||||
|
||||
validation {
|
||||
condition = contains(["controlplane", "worker"], var.node_role)
|
||||
error_message = "node_role must be 'controlplane' or 'worker'."
|
||||
}
|
||||
}
|
||||
|
||||
# ─── Proxmox Placement ───────────────────────────────────────────────────────
|
||||
|
||||
variable "target_node" {
|
||||
type = string
|
||||
description = "Proxmox node to place this VM on (e.g., main-street-usa, tomorrowland, fantasyland)."
|
||||
}
|
||||
|
||||
variable "datastore" {
|
||||
type = string
|
||||
description = "Proxmox storage pool for the VM disk."
|
||||
default = "liberty-tree"
|
||||
}
|
||||
|
||||
# ─── Boot Image ──────────────────────────────────────────────────────────────
|
||||
|
||||
variable "iso_file_id" {
|
||||
type = string
|
||||
description = "Proxmox file ID for the Talos ISO (e.g., local:iso/talos-v1.9.5-metal-amd64.iso). Output from proxmox_virtual_environment_download_file."
|
||||
}
|
||||
|
||||
# ─── Hardware ────────────────────────────────────────────────────────────────
|
||||
|
||||
variable "cpu_cores" {
|
||||
type = number
|
||||
description = "Number of vCPU cores."
|
||||
}
|
||||
|
||||
variable "memory_mb" {
|
||||
type = number
|
||||
description = "RAM in megabytes."
|
||||
}
|
||||
|
||||
variable "disk_size" {
|
||||
type = number
|
||||
description = "OS disk size in gigabytes. Talos manages its own partition layout."
|
||||
}
|
||||
|
||||
# ─── Network ─────────────────────────────────────────────────────────────────
|
||||
|
||||
variable "bridge" {
|
||||
type = string
|
||||
description = "Proxmox network bridge."
|
||||
default = "vmbr0"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user