4.5 KiB
Atlas Terraform
Terraform owns the declarative day-zero pieces that are not Flux workload state:
- Atlas host/node inventory used to generate Ananke config input.
- Required Kubernetes Node labels through
kubernetes_labels. - Optional render-only Flux day-zero manifests from
clusters/atlas/flux-system.
Terraform does not own Flux-managed workload manifests. Do not move services/, infrastructure/, or Flux Kustomization trees under Terraform. Do not make manual kubectl edits for durable Kubernetes state.
Ownership
Terraform owns:
- node names, IPs, roles, managed-node membership, ignored/unavailable markers
- default SSH user, port, config path, identity path emitted into Ananke inventory
startup.required_node_labelsvalues, applied as Kubernetes Node labels- generated
ananke.inventory.yaml
Flux owns:
- workloads, platform services, Helm releases, Flux
Kustomizationresources, and service manifests - steady-state reconciliation of objects under
clusters/atlas/flux-system,infrastructure/, andservices/
Ananke owns:
- UPS shutdown decisions
- SSH repair and host recovery
- k3s restart/reboot
- Longhorn/runtime recovery
- cordon/uncordon, pod recycling, Flux suspend/resume during recovery
- startup validation/reporting for Terraform-owned labels when
required_node_labels_mode: validate
Run
cd terraform/atlas
cp terraform.tfvars.example terraform.tfvars
terraform init
terraform plan
For local syntax/provider validation that does not touch the cluster:
terraform init -backend=false
terraform validate
Only run terraform apply after reviewing the plan and confirming label ownership. The Kubernetes provider uses var.kubeconfig_path, defaulting to ~/.kube/config; no kubeconfig or secret material belongs in this repo.
The backend is local by default. When remote state is ready, migrate state with terraform init -migrate-state after adding the remote backend configuration in a separate reviewed change.
Generated Ananke Fragment
The inventory module writes generated/ananke.inventory.yaml by default. It contains no secrets and is intended to be installed beside the main Ananke config:
sudo ANANKE_INVENTORY_FRAGMENT=/opt/titan-iac/terraform/atlas/generated/ananke.inventory.yaml /opt/ananke/scripts/install.sh
Ananke auto-loads /etc/ananke/ananke.inventory.yaml when present. The generated fragment sets:
ssh_node_hostsssh_managed_nodescontrol_planesworkersstartup.required_node_labelsstartup.required_node_labels_mode: validatestartup.ignore_unavailable_nodes
Node Labels
This tree uses the HashiCorp Kubernetes provider kubernetes_labels resource. That resource manages only labels declared in Terraform and ignores existing labels not declared here. Leave force_node_label_conflicts = false for normal plans. Set it true only during a deliberate adoption when field ownership conflicts are understood.
Flux Day-Zero
clusters/atlas/flux-system/gotk-components.yaml and gotk-sync.yaml already exist in the Flux bootstrap tree, so Terraform does not manage those objects by default.
The flux_day_zero module can render those artifacts into one file when render_flux_day_zero_manifests = true. Keep apply_flux_day_zero_manifests = false for steady state. Enabling apply runs kubectl apply --server-side and is only for an empty-cluster bootstrap with explicit operator intent.
Migration Plan
- Copy
terraform.tfvars.exampletoterraform.tfvarsand adjust only local paths. - Run
terraform init -backend=falseandterraform validate. - Run
terraform planin plan-only mode and review Node label changes. - Adopt existing label state with
kubernetes_labelsresources. This resource does not useterraform import; creating it against existing Nodes is the adoption step. - Install the generated Ananke fragment and confirm Ananke reads
required_node_labels_mode: validate. - Run
terraform applyfor labels after the plan is clean. - Run Ananke startup dry-run/status and confirm it reports label drift instead of applying labels.
- Enable in production after Ananke is validating only and Terraform is the only steady-state writer for these labels.
Conflict Rules
- Do not add Terraform resources for any object already in Flux unless it is a one-time day-zero bootstrap action and Terraform will not keep steady-state ownership.
- Do not add Flux manifests for Node labels Terraform manages here.
- Do not use Terraform for recovery behavior that Ananke performs imperatively.