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:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -55,3 +55,9 @@ boilerplates/**/.env
|
||||
|
||||
# Misc
|
||||
doppler-token.yaml
|
||||
|
||||
# talhelper generated machine configs — contain secrets, never commit
|
||||
talos/talhelper/clusterconfig/
|
||||
# talenv.yaml plaintext — only commit the SOPS-encrypted version
|
||||
talos/talhelper/talenv.yaml
|
||||
!talos/talhelper/talenv.sops.yaml
|
||||
3
.sops.yaml
Normal file
3
.sops.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
creation_rules:
|
||||
- path_regex: talos/talhelper/talenv.yaml
|
||||
age: age1xkyuv8r8ce6lu3d64jfspz4e50k6pxlaxwmuplzrtnpfnnrnycaq6mfsrn
|
||||
321
docs/city-hall-setup.md
Normal file
321
docs/city-hall-setup.md
Normal file
@@ -0,0 +1,321 @@
|
||||
# city-hall Setup Guide
|
||||
|
||||
`city-hall` (`10.1.71.38`) is the Ansible/Terraform control node and admin jump box
|
||||
for the `mk-labs` homelab. This document is the authoritative list of required software
|
||||
and configuration.
|
||||
|
||||
## System
|
||||
|
||||
- **OS**: Ubuntu 24.04
|
||||
- **User**: `wed` (passwordless sudo)
|
||||
- **SSH key**: `~/.ssh/ansible` (used by Ansible and Terraform SSH agent)
|
||||
- **Repo**: `/opt/git/homelab` (cloned from `git.mk-labs.cloud/rblundon/homelab`)
|
||||
|
||||
---
|
||||
|
||||
## Required Software
|
||||
|
||||
### Core Tools
|
||||
|
||||
| Tool | Purpose | Install |
|
||||
|---|---|---|
|
||||
| `git` | Source control | `sudo apt install git -y` |
|
||||
| `terraform` | Infrastructure provisioning | See below |
|
||||
| `ansible` | Configuration management | See below |
|
||||
| `packer` | VM template creation | See below |
|
||||
|
||||
#### Terraform
|
||||
|
||||
```bash
|
||||
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
|
||||
sudo apt update && sudo apt install terraform -y
|
||||
```
|
||||
|
||||
#### Ansible
|
||||
|
||||
```bash
|
||||
sudo apt install pipx -y
|
||||
pipx install ansible
|
||||
pipx inject ansible netaddr
|
||||
ansible-galaxy collection install effectivelywild.technitium_dns
|
||||
```
|
||||
|
||||
#### Packer
|
||||
|
||||
```bash
|
||||
sudo apt update && sudo apt install packer -y
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Talos Cluster Tools
|
||||
|
||||
Required for provisioning and managing the `fastpass` Talos Kubernetes cluster.
|
||||
|
||||
| Tool | Purpose | Install |
|
||||
|---|---|---|
|
||||
| `talhelper` | Talos cluster config generation | See below |
|
||||
| `talosctl` | Talos cluster CLI | See below |
|
||||
| `kubectl` | Kubernetes CLI | See below |
|
||||
| `helm` | Kubernetes package manager | See below |
|
||||
| `age` | Encryption key generation (used by SOPS) | `sudo apt install age -y` |
|
||||
| `sops` | Secret encryption for `talsecret.sops.yaml` | See below |
|
||||
|
||||
#### talhelper
|
||||
|
||||
```bash
|
||||
curl -fsSL https://i.jpillora.com/budimanjojo/talhelper! | bash
|
||||
```
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
talhelper --version
|
||||
```
|
||||
|
||||
#### talosctl
|
||||
|
||||
```bash
|
||||
curl -sL https://talos.dev/install | sh
|
||||
```
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
talosctl version --client
|
||||
```
|
||||
|
||||
#### kubectl
|
||||
|
||||
```bash
|
||||
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
|
||||
chmod +x kubectl
|
||||
sudo mv kubectl /usr/local/bin/
|
||||
```
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
kubectl version --client
|
||||
```
|
||||
|
||||
#### Helm
|
||||
|
||||
```bash
|
||||
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||
```
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
helm version
|
||||
```
|
||||
|
||||
#### SOPS
|
||||
|
||||
```bash
|
||||
SOPS_VERSION=$(curl -s https://api.github.com/repos/getsops/sops/releases/latest | grep tag_name | cut -d '"' -f 4)
|
||||
curl -LO "https://github.com/getsops/sops/releases/download/${SOPS_VERSION}/sops-${SOPS_VERSION}.linux.amd64"
|
||||
chmod +x "sops-${SOPS_VERSION}.linux.amd64"
|
||||
sudo mv "sops-${SOPS_VERSION}.linux.amd64" /usr/local/bin/sops
|
||||
```
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
sops --version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SSH Agent
|
||||
|
||||
The SSH agent must be running and loaded with the Ansible key before running Terraform
|
||||
or Ansible. Add to `~/.bashrc`:
|
||||
|
||||
```bash
|
||||
eval $(ssh-agent) > /dev/null
|
||||
ssh-add ~/.ssh/ansible 2>/dev/null
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SOPS / age Setup (first time only)
|
||||
|
||||
Required before running `talhelper genconfig` for the first time.
|
||||
|
||||
```bash
|
||||
# Generate an age key pair
|
||||
age-keygen -o ~/.config/sops/age/keys.txt
|
||||
|
||||
# Note the public key from the output, e.g.:
|
||||
# Public key: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# Create a .sops.yaml at the repo root referencing your public key
|
||||
cat > /opt/git/homelab/.sops.yaml << EOF
|
||||
creation_rules:
|
||||
- path_regex: talos/talhelper/talsecret.sops.yaml
|
||||
age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
EOF
|
||||
```
|
||||
|
||||
Generate and encrypt the secrets file (talhelper looks for `talsecret.sops.yaml` by default):
|
||||
|
||||
```bash
|
||||
cd talos/talhelper
|
||||
talhelper gensecret > talsecret.sops.yaml
|
||||
sops -e -i talsecret.sops.yaml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Terraform Notes
|
||||
|
||||
- Always run from the relevant module directory (e.g., `terraform/talos/cluster/`)
|
||||
- State files live in `states/` within each module — never committed to git
|
||||
- Sensitive vars passed via CLI, never in committed tfvars files
|
||||
- The `!` in the Proxmox API token requires single quotes to prevent bash history expansion:
|
||||
|
||||
```bash
|
||||
terraform apply \
|
||||
-var-file="tfvars/fastpass.tfvars" \
|
||||
-state="states/fastpass.tfstate" \
|
||||
-var='proxmox_api_token=terraform@pve!terraform-token=<secret>' \
|
||||
-var='unifi_password=<secret>' \
|
||||
-var='technitium_api_token=<secret>'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ansible Notes
|
||||
|
||||
- Always run from the `ansible/` directory
|
||||
- Roles path: `ansible/playbooks/roles/`
|
||||
- SSH user: `wed`
|
||||
- Vault password file: `~/.vault_pass` (not committed)
|
||||
|
||||
---
|
||||
|
||||
## Talos / talhelper Notes
|
||||
|
||||
- Config lives at `talos/talhelper/` in the repo
|
||||
- Secrets file is named `talsecret.sops.yaml` (talhelper default) — SOPS-encrypted
|
||||
- Network interface on Proxmox VMs is `ens18` (not `eth0`)
|
||||
- `talosctl` config (`~/.talos/config`) is generated by talhelper — keep a backup
|
||||
- Cluster endpoint: `https://10.1.71.65:6443` (VIP)
|
||||
- Talos API endpoint: `https://10.1.71.65:50000`
|
||||
- Initial `apply-config` requires `--extra-flags="--insecure"` (maintenance mode only)
|
||||
- `bootstrap` only runs once — bootstraps etcd on `space-mountain`
|
||||
|
||||
---
|
||||
|
||||
## fastpass Cluster Bootstrap Runbook
|
||||
|
||||
Run from `talos/talhelper/` unless otherwise noted.
|
||||
|
||||
### 1. Provision VMs (Terraform)
|
||||
|
||||
```bash
|
||||
cd terraform/talos/cluster
|
||||
terraform apply \
|
||||
-var-file="tfvars/fastpass.tfvars" \
|
||||
-state="states/fastpass.tfstate" \
|
||||
-var='proxmox_api_token=terraform@pve!terraform-token=<secret>' \
|
||||
-var='unifi_password=<secret>' \
|
||||
-var='technitium_api_token=<secret>'
|
||||
```
|
||||
|
||||
### 2. Generate Talos Machine Configs
|
||||
|
||||
```bash
|
||||
cd talos/talhelper
|
||||
|
||||
# First time only — generate and encrypt secrets
|
||||
talhelper gensecret > talsecret.sops.yaml
|
||||
sops -e -i talsecret.sops.yaml
|
||||
|
||||
# Generate machine configs (uses talsecret.sops.yaml automatically)
|
||||
talhelper genconfig
|
||||
```
|
||||
|
||||
### 3. Verify Nodes are in Maintenance Mode
|
||||
|
||||
```bash
|
||||
talosctl -n 10.1.71.66 get discoveredvolumes \
|
||||
--talosconfig clusterconfig/talosconfig --insecure
|
||||
```
|
||||
|
||||
Confirm install disk is `/dev/sda`.
|
||||
|
||||
### 4. Apply Machine Configs
|
||||
|
||||
```bash
|
||||
talhelper gencommand apply --extra-flags="--insecure" | bash
|
||||
```
|
||||
|
||||
Nodes will install Talos to disk and reboot automatically.
|
||||
|
||||
### 5. Monitor Install
|
||||
|
||||
```bash
|
||||
talosctl -n 10.1.71.66 --talosconfig clusterconfig/talosconfig dashboard
|
||||
```
|
||||
|
||||
Wait until all nodes show `Running` state.
|
||||
|
||||
### 6. Bootstrap etcd (once only)
|
||||
|
||||
```bash
|
||||
talhelper gencommand bootstrap | bash
|
||||
```
|
||||
|
||||
Only run once — bootstraps etcd on `space-mountain`.
|
||||
|
||||
### 7. Get kubeconfig
|
||||
|
||||
```bash
|
||||
talosctl --talosconfig clusterconfig/talosconfig \
|
||||
--nodes 10.1.71.66 kubeconfig ~/.kube/config
|
||||
```
|
||||
|
||||
### 8. Approve Worker CSRs
|
||||
|
||||
```bash
|
||||
kubectl get csr
|
||||
kubectl certificate approve $(kubectl get csr --no-headers | awk '{print $1}')
|
||||
```
|
||||
|
||||
### 9. Install Cilium (CNI)
|
||||
|
||||
```bash
|
||||
helm repo add cilium https://helm.cilium.io/
|
||||
helm repo update
|
||||
|
||||
helm install cilium cilium/cilium \
|
||||
--namespace kube-system \
|
||||
--set ipam.mode=kubernetes \
|
||||
--set routingMode=tunnel \
|
||||
--set tunnelProtocol=vxlan \
|
||||
--set kubeProxyReplacement=true \
|
||||
--set k8sServiceHost=10.1.71.65 \
|
||||
--set k8sServicePort=6443 \
|
||||
--set securityContext.capabilities.ciliumAgent="{CHOWN,KILL,NET_ADMIN,NET_RAW,IPC_LOCK,SYS_ADMIN,SYS_RESOURCE,DAC_OVERRIDE,FOWNER,SETGID,SETUID}" \
|
||||
--set securityContext.capabilities.cleanCiliumState="{NET_ADMIN,SYS_ADMIN,SYS_RESOURCE}" \
|
||||
--set cgroup.autoMount.enabled=false \
|
||||
--set cgroup.hostRoot=/sys/fs/cgroup
|
||||
```
|
||||
|
||||
Note: The explicit `securityContext.capabilities` flags are required for Talos — Talos
|
||||
restricts privileged container capabilities by default. The `cgroup.autoMount.enabled=false`
|
||||
and `cgroup.hostRoot` flags are required because Talos manages cgroups itself.
|
||||
|
||||
### 10. Verify Cluster
|
||||
|
||||
```bash
|
||||
kubectl get nodes
|
||||
kubectl get pods -n kube-system
|
||||
```
|
||||
|
||||
All nodes should show `Ready`. Cilium pods should be `Running`.
|
||||
|
||||
### 11. Post-Install HA Setup
|
||||
|
||||
See output of `terraform output` for the full HA registration commands.
|
||||
Register VMs with Proxmox HA and add to node-affinity rules once the
|
||||
cluster is stable and the ISO is no longer needed for boot.
|
||||
188
talos/talhelper/talconfig.yaml
Normal file
188
talos/talhelper/talconfig.yaml
Normal file
@@ -0,0 +1,188 @@
|
||||
# ─── fastpass Talos Cluster Configuration ────────────────────────────────────
|
||||
# Managed by talhelper on city-hall (10.1.71.38)
|
||||
# Generate configs: talhelper genconfig
|
||||
# Generate secrets: talhelper gensecret > talenv.yaml && sops -e -i talenv.yaml
|
||||
# Apply configs: talhelper gencommand apply | bash
|
||||
# Bootstrap: talhelper gencommand bootstrap | bash
|
||||
|
||||
clusterName: fastpass
|
||||
talosVersion: v1.13.2
|
||||
kubernetesVersion: v1.32.3
|
||||
|
||||
# ─── Cluster Endpoint ────────────────────────────────────────────────────────
|
||||
# Points at the Talos native VIP (10.1.71.65) which floats across
|
||||
# control plane nodes. All kubectl and talosctl traffic goes here.
|
||||
endpoint: https://10.1.71.65:6443
|
||||
|
||||
# ─── Domain ──────────────────────────────────────────────────────────────────
|
||||
domain: cluster.local
|
||||
|
||||
# ─── CNI ─────────────────────────────────────────────────────────────────────
|
||||
# Cilium is installed post-bootstrap via Helm.
|
||||
# Talos ships with flannel by default — disable it so Cilium takes over.
|
||||
cniConfig:
|
||||
name: none
|
||||
|
||||
# ─── Patches applied to ALL nodes ────────────────────────────────────────────
|
||||
patches:
|
||||
- |-
|
||||
machine:
|
||||
time:
|
||||
servers:
|
||||
- 10.1.71.21
|
||||
sysctls:
|
||||
net.ipv4.ip_forward: "1"
|
||||
kernel:
|
||||
modules:
|
||||
- name: br_netfilter
|
||||
- name: ip_tables
|
||||
kubelet:
|
||||
extraArgs:
|
||||
rotate-server-certificates: "true"
|
||||
|
||||
# ─── Nodes ───────────────────────────────────────────────────────────────────
|
||||
|
||||
nodes:
|
||||
|
||||
# ── Control Plane ──────────────────────────────────────────────────────────
|
||||
|
||||
- hostname: space-mountain
|
||||
ipAddress: 10.1.71.66
|
||||
controlPlane: true
|
||||
installDisk: /dev/sda
|
||||
networkInterfaces:
|
||||
- interface: ens18
|
||||
addresses:
|
||||
- 10.1.71.66/24
|
||||
routes:
|
||||
- network: 0.0.0.0/0
|
||||
gateway: 10.1.71.1
|
||||
vip:
|
||||
ip: 10.1.71.65
|
||||
patches:
|
||||
- |-
|
||||
machine:
|
||||
network:
|
||||
nameservers:
|
||||
- 10.1.71.32
|
||||
|
||||
- hostname: big-thunder-mountain
|
||||
ipAddress: 10.1.71.67
|
||||
controlPlane: true
|
||||
installDisk: /dev/sda
|
||||
networkInterfaces:
|
||||
- interface: ens18
|
||||
addresses:
|
||||
- 10.1.71.67/24
|
||||
routes:
|
||||
- network: 0.0.0.0/0
|
||||
gateway: 10.1.71.1
|
||||
patches:
|
||||
- |-
|
||||
machine:
|
||||
network:
|
||||
nameservers:
|
||||
- 10.1.71.32
|
||||
|
||||
- hostname: splash-mountain
|
||||
ipAddress: 10.1.71.68
|
||||
controlPlane: true
|
||||
installDisk: /dev/sda
|
||||
networkInterfaces:
|
||||
- interface: ens18
|
||||
addresses:
|
||||
- 10.1.71.68/24
|
||||
routes:
|
||||
- network: 0.0.0.0/0
|
||||
gateway: 10.1.71.1
|
||||
patches:
|
||||
- |-
|
||||
machine:
|
||||
network:
|
||||
nameservers:
|
||||
- 10.1.71.32
|
||||
|
||||
# ── Workers ────────────────────────────────────────────────────────────────
|
||||
|
||||
- hostname: jungle-cruise
|
||||
ipAddress: 10.1.71.69
|
||||
controlPlane: false
|
||||
installDisk: /dev/sda
|
||||
networkInterfaces:
|
||||
- interface: ens18
|
||||
addresses:
|
||||
- 10.1.71.69/24
|
||||
routes:
|
||||
- network: 0.0.0.0/0
|
||||
gateway: 10.1.71.1
|
||||
patches:
|
||||
- |-
|
||||
machine:
|
||||
network:
|
||||
nameservers:
|
||||
- 10.1.71.32
|
||||
|
||||
- hostname: haunted-mansion
|
||||
ipAddress: 10.1.71.70
|
||||
controlPlane: false
|
||||
installDisk: /dev/sda
|
||||
networkInterfaces:
|
||||
- interface: ens18
|
||||
addresses:
|
||||
- 10.1.71.70/24
|
||||
routes:
|
||||
- network: 0.0.0.0/0
|
||||
gateway: 10.1.71.1
|
||||
patches:
|
||||
- |-
|
||||
machine:
|
||||
network:
|
||||
nameservers:
|
||||
- 10.1.71.32
|
||||
|
||||
- hostname: peter-pans-flight
|
||||
ipAddress: 10.1.71.71
|
||||
controlPlane: false
|
||||
installDisk: /dev/sda
|
||||
networkInterfaces:
|
||||
- interface: ens18
|
||||
addresses:
|
||||
- 10.1.71.71/24
|
||||
routes:
|
||||
- network: 0.0.0.0/0
|
||||
gateway: 10.1.71.1
|
||||
patches:
|
||||
- |-
|
||||
machine:
|
||||
network:
|
||||
nameservers:
|
||||
- 10.1.71.32
|
||||
|
||||
# ─── Control Plane Config ────────────────────────────────────────────────────
|
||||
controlPlane:
|
||||
patches:
|
||||
- |-
|
||||
machine:
|
||||
features:
|
||||
kubernetesTalosAPIAccess:
|
||||
enabled: true
|
||||
allowedRoles:
|
||||
- os:reader
|
||||
allowedKubernetesNamespaces:
|
||||
- kube-system
|
||||
cluster:
|
||||
etcd:
|
||||
advertisedSubnets:
|
||||
- 10.1.71.64/26
|
||||
coreDNS:
|
||||
disabled: false
|
||||
proxy:
|
||||
disabled: true
|
||||
|
||||
# ─── Worker Config ───────────────────────────────────────────────────────────
|
||||
worker:
|
||||
patches:
|
||||
- |-
|
||||
machine:
|
||||
kubelet:
|
||||
extraArgs: {}
|
||||
43
talos/talhelper/talsecret.sops.yaml
Normal file
43
talos/talhelper/talsecret.sops.yaml
Normal file
File diff suppressed because one or more lines are too long
60
terraform/talos/cluster/.terraform.lock.hcl
generated
Normal file
60
terraform/talos/cluster/.terraform.lock.hcl
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/bpg/proxmox" {
|
||||
version = "0.106.0"
|
||||
constraints = ">= 0.74.0"
|
||||
hashes = [
|
||||
"h1:CnUVTBB9ZlJRH9xhyxPIAY++4gSRqMeLMZokzgN1V2A=",
|
||||
"zh:1a8d717dada526bf0aab51683352390e194bf5c05c8c69464e00befd113121d6",
|
||||
"zh:31db845b45df5839b442104e31aa41f832eb1f363f5278df290f1a906b731150",
|
||||
"zh:36af78f4395ac64e5a997fad6cfb18f369e5cae7e4895086ef7d39c65e3d6324",
|
||||
"zh:526e87482db9a0f8c7a22b430214886a3df4fd08c6949b7235d9a088850fd736",
|
||||
"zh:6c99f833606527b86fed0ef74bf8723e118b98a8067ff9f3745e90b095a4bc2b",
|
||||
"zh:7aa85292c4891e85a817821dd31d736e977eabe3a04d29913d1cb5dfca2020ef",
|
||||
"zh:879dc2b315093c2818c8ff289fcb20d6925dab57e7d758b5e646c6b35860ac37",
|
||||
"zh:955eb04b8df5438a717af9766f02b48e919c0a33c97590905ee04f3106adb299",
|
||||
"zh:981eb203d9cfbc735bd792a7654319a5a9b8d68a485d0399b4f018557550f0ce",
|
||||
"zh:a0e3b74af3976aa4f9e68a7c8bde620abda2d4f0d29859032f9d6d2df3e4c200",
|
||||
"zh:b767b70e56dc47238ef9f541c29a16e97e7f19b63b303d551593b620d0c9f609",
|
||||
"zh:edf48f3699cf8597d07d7ab8923e5353da4337dfa9462c07c289643309bf7494",
|
||||
"zh:f26e0763dbe6a6b2195c94b44696f2110f7f55433dc142839be16b9697fa5597",
|
||||
"zh:faf3b240bce18a4cf91359b0bdb017f9b2a8f4c38202c4c959c3149f69bf321e",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/darkhonor/technitium" {
|
||||
version = "1.1.0"
|
||||
constraints = ">= 0.3.0"
|
||||
hashes = [
|
||||
"h1:+PIjpgfSqFxA3893Jvd8Xs4xiuoiGr/4Lu4QXOZWW2g=",
|
||||
"zh:0855bb0e2a5bd9ec68a6a7cf117980189b2f2030232ef7ae6815c97118eb0908",
|
||||
"zh:1cbca86ce5f77e8aa32f863f2f40046a12b32f4d94860f7f0a03d24a6091ffd4",
|
||||
"zh:268dc7849a9fee58efcfbe662fc4a0f915bb5a4e1f55746228926a02bcbde408",
|
||||
"zh:6e878f8bdf8b468166774766879094d39626bd03995b0942ce156448c22988f9",
|
||||
"zh:7006c9b909905f5fe8cee43610d4676ec555666ff26862b8821122e428327cd3",
|
||||
"zh:97d3c059d8a44d7525232f1471b49f638ea071a85955d82630d1c7682a58dab2",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/paultyng/unifi" {
|
||||
version = "0.41.0"
|
||||
constraints = "0.41.0"
|
||||
hashes = [
|
||||
"h1:vE4C9E7NtYUC7otQrAvNNkDFBHqEMxkUlcqJhLWchLY=",
|
||||
"zh:03ddd3aee05a08e1446f75a7b3f52810181d3307728cba08ce8fb67f109a9c00",
|
||||
"zh:11b14b79ad02b0a55fd6116b10c0eb6fab432dd7d1f3527af0e2055adf292451",
|
||||
"zh:18c0eb19889927f115a1e05d64f59b4e8d530ccdf1a8b574940a86be20973564",
|
||||
"zh:2df9ca0c21830d2757758e574b19d0d4e54965ce80dbbfb3f124db1dac3d7e8f",
|
||||
"zh:36274af3b7e8b08ba69c04a226c63e0dd2ec386c583288ebd7bc2a30e349ee8f",
|
||||
"zh:413eb222ef30889bab33ccbfc46c9fb64307555da34eac4625d51e696ac72e1d",
|
||||
"zh:4839814ff9f405a13397ffadd6f1052c770b88802280a4d8cde066f9a19718c7",
|
||||
"zh:9547b7831852cc5b9c0fd13ab447d48539eae94582c8725ad255af36e31fb5d9",
|
||||
"zh:a855c89b12326eb1c89bbf292a2bb1de3651794e3409d5012076ada89aabdc8a",
|
||||
"zh:aef12a33b90fd77a9bf4e9d397966ccbfa4a037a648a1725074aff2db2d90fb0",
|
||||
"zh:b3c72a6a02e29b4d21aa0d0831a272ca7cb82c3f8c2c3c7f09fcc2d2dcd78752",
|
||||
"zh:c8354eaaab5f526e8e530b098544c7583a0f0b5b27d67500c7b3e9da56a3a7e5",
|
||||
"zh:dc29f1e70f20ce86d3c6a66c7a817616f993a1cf9d941604dfd5222a06992c4c",
|
||||
"zh:e772779333419f34d2c6da333c7f7d235a5a34f21ea47636b548e132aed74f3b",
|
||||
]
|
||||
}
|
||||
151
terraform/talos/cluster/main.tf
Normal file
151
terraform/talos/cluster/main.tf
Normal file
@@ -0,0 +1,151 @@
|
||||
# ─── fastpass Talos Cluster ───────────────────────────────────────────────────
|
||||
#
|
||||
# Provisions all infrastructure for the fastpass Kubernetes cluster:
|
||||
# - Talos ISO download to Proxmox
|
||||
# - 3 control plane VMs (space-mountain, big-thunder-mountain, splash-mountain)
|
||||
# - 3 worker VMs (jungle-cruise, haunted-mansion, peter-pans-flight)
|
||||
# - Unifi DHCP reservations (MAC → IP) for all 6 nodes
|
||||
# - Technitium DNS A records for all 6 nodes + cluster VIP
|
||||
#
|
||||
# After apply:
|
||||
# Run talhelper from city-hall to generate and apply machine configs.
|
||||
# See talos/talhelper/ for cluster configuration.
|
||||
#
|
||||
# IP Allocation (10.1.71.64/26 — Container Orchestration):
|
||||
# .65 — Kubernetes API VIP (Talos native VIP, not a VM)
|
||||
# .66 — space-mountain (control plane, main-street-usa)
|
||||
# .67 — big-thunder-mountain (control plane, tomorrowland)
|
||||
# .68 — splash-mountain (control plane, fantasyland)
|
||||
# .69 — jungle-cruise (worker, main-street-usa)
|
||||
# .70 — haunted-mansion (worker, tomorrowland)
|
||||
# .71 — peter-pans-flight (worker, fantasyland)
|
||||
# .80-.99 — Cilium LB pool (managed by Cilium, not Terraform)
|
||||
|
||||
locals {
|
||||
# Node definitions — single source of truth for the entire cluster.
|
||||
# VM ID convention: {third_octet}{fourth_octet:03d}
|
||||
nodes = {
|
||||
"space-mountain" = {
|
||||
role = "controlplane"
|
||||
target_node = "main-street-usa"
|
||||
ip_address = "10.1.71.66"
|
||||
vm_id = 71066
|
||||
cpu_cores = 4
|
||||
memory_mb = 8192
|
||||
disk_size = 50
|
||||
}
|
||||
"big-thunder-mountain" = {
|
||||
role = "controlplane"
|
||||
target_node = "tomorrowland"
|
||||
ip_address = "10.1.71.67"
|
||||
vm_id = 71067
|
||||
cpu_cores = 4
|
||||
memory_mb = 8192
|
||||
disk_size = 50
|
||||
}
|
||||
"splash-mountain" = {
|
||||
role = "controlplane"
|
||||
target_node = "fantasyland"
|
||||
ip_address = "10.1.71.68"
|
||||
vm_id = 71068
|
||||
cpu_cores = 4
|
||||
memory_mb = 8192
|
||||
disk_size = 50
|
||||
}
|
||||
"jungle-cruise" = {
|
||||
role = "worker"
|
||||
target_node = "main-street-usa"
|
||||
ip_address = "10.1.71.69"
|
||||
vm_id = 71069
|
||||
cpu_cores = 8
|
||||
memory_mb = 16384
|
||||
disk_size = 100
|
||||
}
|
||||
"haunted-mansion" = {
|
||||
role = "worker"
|
||||
target_node = "tomorrowland"
|
||||
ip_address = "10.1.71.70"
|
||||
vm_id = 71070
|
||||
cpu_cores = 8
|
||||
memory_mb = 16384
|
||||
disk_size = 100
|
||||
}
|
||||
"peter-pans-flight" = {
|
||||
role = "worker"
|
||||
target_node = "fantasyland"
|
||||
ip_address = "10.1.71.71"
|
||||
vm_id = 71071
|
||||
cpu_cores = 8
|
||||
memory_mb = 16384
|
||||
disk_size = 100
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ─── Talos ISO ───────────────────────────────────────────────────────────────
|
||||
# ISO is pre-uploaded to the shared 'templates' datastore (Ceph-backed,
|
||||
# visible to all nodes). File ID format: <datastore>:iso/<filename>
|
||||
|
||||
locals {
|
||||
talos_iso_file_id = "${var.iso_datastore}:iso/metal-amd64.iso"
|
||||
}
|
||||
|
||||
# ─── Cluster Nodes ───────────────────────────────────────────────────────────
|
||||
# Iterate over the node map and call the node module for each.
|
||||
|
||||
module "nodes" {
|
||||
source = "../modules/node"
|
||||
for_each = local.nodes
|
||||
|
||||
hostname = each.key
|
||||
vm_id = each.value.vm_id
|
||||
node_role = each.value.role
|
||||
target_node = each.value.target_node
|
||||
iso_file_id = local.talos_iso_file_id
|
||||
cpu_cores = each.value.cpu_cores
|
||||
memory_mb = each.value.memory_mb
|
||||
disk_size = each.value.disk_size
|
||||
datastore = var.datastore
|
||||
bridge = var.bridge
|
||||
}
|
||||
|
||||
# ─── Unifi DHCP Reservations ─────────────────────────────────────────────────
|
||||
# Create a static MAC→IP reservation for each node.
|
||||
# Reservations are created before VMs start so the IP is guaranteed
|
||||
# on first DHCP broadcast.
|
||||
|
||||
resource "unifi_user" "nodes" {
|
||||
for_each = local.nodes
|
||||
|
||||
name = each.key
|
||||
mac = lower(module.nodes[each.key].mac_address)
|
||||
fixed_ip = each.value.ip_address
|
||||
|
||||
note = "Managed by mk-labs Terraform — fastpass cluster ${each.value.role}"
|
||||
|
||||
depends_on = [module.nodes]
|
||||
}
|
||||
|
||||
# ─── DNS A Records ───────────────────────────────────────────────────────────
|
||||
# Create A records for all 6 nodes in the internal zone.
|
||||
# The cluster VIP (.65) is managed by Talos natively — no VM, but still
|
||||
# needs a DNS entry for kubectl and talhelper to resolve the endpoint.
|
||||
|
||||
resource "technitium_record" "nodes" {
|
||||
for_each = local.nodes
|
||||
|
||||
zone = var.dns_zone
|
||||
name = "${each.key}.${var.dns_zone}"
|
||||
type = "A"
|
||||
ttl = 300
|
||||
value = each.value.ip_address
|
||||
}
|
||||
|
||||
resource "technitium_record" "vip" {
|
||||
zone = var.dns_zone
|
||||
name = "${var.cluster_name}-api.${var.dns_zone}"
|
||||
type = "A"
|
||||
ttl = 300
|
||||
value = "10.1.71.65"
|
||||
}
|
||||
|
||||
43
terraform/talos/cluster/outputs.tf
Normal file
43
terraform/talos/cluster/outputs.tf
Normal file
@@ -0,0 +1,43 @@
|
||||
# ─── Post-Apply Reminders ────────────────────────────────────────────────────
|
||||
|
||||
output "ha_rule_instructions" {
|
||||
description = "Manual steps required after the Talos cluster is fully installed and the ISO is no longer needed."
|
||||
value = <<-EOT
|
||||
|
||||
── Post-Cluster-Install: HA Setup ──────────────────────────────────────────
|
||||
|
||||
Once Talos is fully installed and running (ISO no longer needed for boot),
|
||||
complete the following steps:
|
||||
|
||||
1. Register each VM with the Proxmox HA manager:
|
||||
ha-manager add vm:71066 --state started
|
||||
ha-manager add vm:71067 --state started
|
||||
ha-manager add vm:71068 --state started
|
||||
ha-manager add vm:71069 --state started
|
||||
ha-manager add vm:71070 --state started
|
||||
ha-manager add vm:71071 --state started
|
||||
|
||||
2. Add VMs to the existing node-affinity rules (check current resources
|
||||
first with pvesh get /cluster/ha/rules/<rule>):
|
||||
|
||||
prefer_main-street-usa (space-mountain:71066, jungle-cruise:71069):
|
||||
pvesh set /cluster/ha/rules/prefer_main-street-usa \
|
||||
--type node-affinity \
|
||||
--resources "<existing>,vm:71066,vm:71069"
|
||||
|
||||
prefer_tomorrowland (big-thunder-mountain:71067, haunted-mansion:71070):
|
||||
pvesh set /cluster/ha/rules/prefer_tomorrowland \
|
||||
--type node-affinity \
|
||||
--resources "<existing>,vm:71067,vm:71070"
|
||||
|
||||
prefer_fantasyland (splash-mountain:71068, peter-pans-flight:71071):
|
||||
pvesh set /cluster/ha/rules/prefer_fantasyland \
|
||||
--type node-affinity \
|
||||
--resources "<existing>,vm:71068,vm:71071"
|
||||
|
||||
3. Eject the Talos ISO from each VM in the Proxmox UI or via:
|
||||
qm set <vmid> --ide2 none
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────
|
||||
EOT
|
||||
}
|
||||
48
terraform/talos/cluster/providers.tf
Normal file
48
terraform/talos/cluster/providers.tf
Normal file
@@ -0,0 +1,48 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5.0"
|
||||
|
||||
required_providers {
|
||||
proxmox = {
|
||||
source = "bpg/proxmox"
|
||||
version = ">= 0.74.0"
|
||||
}
|
||||
|
||||
unifi = {
|
||||
source = "paultyng/unifi"
|
||||
version = "0.41.0"
|
||||
}
|
||||
|
||||
technitium = {
|
||||
source = "darkhonor/technitium"
|
||||
version = ">= 0.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ─── Proxmox Provider ────────────────────────────────────────────────────────
|
||||
|
||||
provider "proxmox" {
|
||||
endpoint = var.proxmox_api_url
|
||||
api_token = var.proxmox_api_token
|
||||
insecure = true
|
||||
|
||||
ssh {
|
||||
agent = true
|
||||
}
|
||||
}
|
||||
|
||||
# ─── Unifi Provider ──────────────────────────────────────────────────────────
|
||||
|
||||
provider "unifi" {
|
||||
username = var.unifi_username
|
||||
password = var.unifi_password
|
||||
api_url = var.unifi_api_url
|
||||
allow_insecure = true
|
||||
}
|
||||
|
||||
# ─── Technitium DNS Provider ─────────────────────────────────────────────────
|
||||
|
||||
provider "technitium" {
|
||||
server_url = var.technitium_url
|
||||
api_token = var.technitium_api_token
|
||||
}
|
||||
32
terraform/talos/cluster/tfvars/fastpass.tfvars
Normal file
32
terraform/talos/cluster/tfvars/fastpass.tfvars
Normal file
@@ -0,0 +1,32 @@
|
||||
# ─── fastpass Cluster — Variable Values ──────────────────────────────────────
|
||||
# Copy to fastpass.tfvars and populate.
|
||||
# Sensitive values (passwords, tokens) are passed via CLI or environment:
|
||||
#
|
||||
# terraform apply \
|
||||
# -var-file="tfvars/fastpass.tfvars" \
|
||||
# -state="states/fastpass.tfstate" \
|
||||
# -var="proxmox_api_token=terraform@pve!terraform-token=<secret>" \
|
||||
# -var="unifi_password=<secret>" \
|
||||
# -var="technitium_password=<secret>"
|
||||
|
||||
# ─── Proxmox ─────────────────────────────────────────────────────────────────
|
||||
proxmox_api_url = "https://fantasyland.local.mk-labs.cloud:8006"
|
||||
|
||||
# ─── Unifi ───────────────────────────────────────────────────────────────────
|
||||
unifi_api_url = "https://10.1.71.1:443"
|
||||
unifi_username = "terraform"
|
||||
|
||||
# ─── Technitium DNS ───────────────────────────────────────────────────────────
|
||||
technitium_url = "http://monorail.local.mk-labs.cloud:5380"
|
||||
|
||||
# ─── Cluster ─────────────────────────────────────────────────────────────────
|
||||
cluster_name = "fastpass"
|
||||
talos_version = "v1.13.2"
|
||||
dns_zone = "local.mk-labs.cloud"
|
||||
|
||||
# ─── ISO ─────────────────────────────────────────────────────────────────────
|
||||
iso_datastore = "templates"
|
||||
|
||||
# ─── VM Defaults ─────────────────────────────────────────────────────────────
|
||||
datastore = "liberty-tree"
|
||||
bridge = "vmbr0"
|
||||
40
terraform/talos/cluster/tfvars/fastpass.tfvars.example
Normal file
40
terraform/talos/cluster/tfvars/fastpass.tfvars.example
Normal file
@@ -0,0 +1,40 @@
|
||||
# ─── fastpass Cluster — Variable Values ──────────────────────────────────────
|
||||
# Copy to fastpass.tfvars and populate.
|
||||
# Sensitive values (passwords, tokens) are passed via CLI or environment:
|
||||
#
|
||||
# terraform apply \
|
||||
# -var-file="tfvars/fastpass.tfvars" \
|
||||
# -state="states/fastpass.tfstate" \
|
||||
# -var="proxmox_api_token=terraform@pve!terraform-token=<secret>" \
|
||||
# -var="unifi_password=<secret>" \
|
||||
# -var="technitium_password=<secret>"
|
||||
|
||||
# ─── Proxmox ─────────────────────────────────────────────────────────────────
|
||||
proxmox_api_url = "https://fantasyland.local.mk-labs.cloud:8006"
|
||||
proxmox_api_token = "terraform@pve!terraform-token=REPLACE_ME"
|
||||
|
||||
# ─── Unifi ───────────────────────────────────────────────────────────────────
|
||||
unifi_api_url = "https://10.1.71.1"
|
||||
unifi_username = "terraform"
|
||||
unifi_password = "REPLACE_ME"
|
||||
# Retrieve with: curl -sk -X GET https://10.1.71.1/api/network | jq '.data[] | select(.name=="Server Trusted") | ._id'
|
||||
unifi_network_id = "REPLACE_ME"
|
||||
|
||||
# ─── Technitium DNS ───────────────────────────────────────────────────────────
|
||||
technitium_url = "http://10.1.71.32:5380"
|
||||
technitium_username = "admin"
|
||||
technitium_password = "REPLACE_ME"
|
||||
|
||||
# ─── Cluster ─────────────────────────────────────────────────────────────────
|
||||
cluster_name = "fastpass"
|
||||
talos_version = "v1.9.5"
|
||||
dns_zone = "local.mk-labs.cloud"
|
||||
|
||||
# ─── ISO ─────────────────────────────────────────────────────────────────────
|
||||
iso_node = "fantasyland"
|
||||
iso_datastore = "local"
|
||||
|
||||
# ─── VM Defaults ─────────────────────────────────────────────────────────────
|
||||
datastore = "liberty-tree"
|
||||
bridge = "vmbr0"
|
||||
vlan_id = 71
|
||||
79
terraform/talos/cluster/variables.tf
Normal file
79
terraform/talos/cluster/variables.tf
Normal file
@@ -0,0 +1,79 @@
|
||||
# ─── Proxmox Authentication ──────────────────────────────────────────────────
|
||||
|
||||
variable "proxmox_api_url" {
|
||||
type = string
|
||||
description = "Proxmox API endpoint URL (e.g., https://fantasyland.local.mk-labs.cloud:8006)."
|
||||
}
|
||||
|
||||
variable "proxmox_api_token" {
|
||||
type = string
|
||||
description = "Proxmox API token. Format: user@realm!token-name=token-secret."
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# ─── Unifi Authentication ────────────────────────────────────────────────────
|
||||
|
||||
variable "unifi_api_url" {
|
||||
type = string
|
||||
description = "Unifi controller API URL (e.g., https://10.1.71.1:443)."
|
||||
}
|
||||
|
||||
variable "unifi_username" {
|
||||
type = string
|
||||
description = "Unifi controller username."
|
||||
}
|
||||
|
||||
variable "unifi_password" {
|
||||
type = string
|
||||
description = "Unifi controller password."
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# ─── Technitium DNS Authentication ───────────────────────────────────────────
|
||||
|
||||
variable "technitium_url" {
|
||||
type = string
|
||||
description = "Technitium DNS server URL (e.g., http://10.1.71.32:5380)."
|
||||
}
|
||||
|
||||
variable "technitium_api_token" {
|
||||
type = string
|
||||
description = "Technitium API token. Create under Administration → API Tokens."
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# ─── Cluster Configuration ───────────────────────────────────────────────────
|
||||
|
||||
variable "cluster_name" {
|
||||
type = string
|
||||
description = "Talos cluster name."
|
||||
default = "fastpass"
|
||||
}
|
||||
|
||||
variable "dns_zone" {
|
||||
type = string
|
||||
description = "Internal DNS zone for A record creation."
|
||||
default = "local.mk-labs.cloud"
|
||||
}
|
||||
|
||||
# ─── ISO Storage ─────────────────────────────────────────────────────────────
|
||||
|
||||
variable "iso_datastore" {
|
||||
type = string
|
||||
description = "Proxmox datastore for ISO storage. Must be visible to all nodes — use a shared/Ceph-backed datastore, not node-local storage."
|
||||
default = "templates"
|
||||
}
|
||||
|
||||
# ─── Shared VM Defaults ──────────────────────────────────────────────────────
|
||||
|
||||
variable "datastore" {
|
||||
type = string
|
||||
description = "Proxmox storage pool for VM disks."
|
||||
default = "liberty-tree"
|
||||
}
|
||||
|
||||
variable "bridge" {
|
||||
type = string
|
||||
description = "Proxmox network bridge."
|
||||
default = "vmbr0"
|
||||
}
|
||||
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