initial commit

This commit is contained in:
0x1d
2025-02-23 14:40:45 +01:00
commit cf5357b43c
11 changed files with 380 additions and 0 deletions

3
.env.example Normal file
View File

@@ -0,0 +1,3 @@
export PROXMOX_VE_USERNAME="root@pam"
export PROXMOX_VE_PASSWORD="super-secure-password"
export PROXMOX_VE_ENDPOINT="https://<proxmox-ip>:8006/"

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.env
target/
.terraform/
*.tfstate
*.tfstate.backup

48
.terraform.lock.hcl generated Normal file
View File

@@ -0,0 +1,48 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/bpg/proxmox" {
version = "0.72.0"
constraints = "0.72.0"
hashes = [
"h1:LCNKZG6lVHdf9LTkHgM8CPUbiFxLI8k208Tz9ajz46c=",
"zh:031d0ade16874fe111055b9417b4f9c73efe7c755ba39aa28bd697ee77dc5e0e",
"zh:095320d9cfb1e1f1b42d0d31f7aef5380323ab5e0d428606c43c9a30bf3b40db",
"zh:11b9ccfc249e150a174f1aa0dd63b8f96296fcb94353902e807da2da20035822",
"zh:24aa2cb7362db5ffebdcc45b0f53897fdd102f322ec7d9e0e4ef60a87955c182",
"zh:334d6d6c2c12803b530ca7fcafe25def317333582dca531ae889bdc1dcbf966a",
"zh:383376b3ce17877f78168270f14a4401093cfee464adf85dd88214d09951e6a2",
"zh:762d16fefdf4af471fe11ba315c7a0a3e5ff04c4f6e8431cd541b2f78cd518ae",
"zh:7c455e70d262e26c3fda8859ed67b0118d12f72416397fc8fbf5b5b90f2f02c3",
"zh:8401a38d10e1aacc7c3f75ae41f42c88647ab7e0974010c616b69095c7a719c1",
"zh:b7bdc53cdd6a21f208fc15bbbd0502fd39bee268801fd2b9ce89e18b38138bc0",
"zh:c3741939ceb5fbd4c00f9aa541a3e9cb68222c39890ca5ed3602a0ca3fa98a53",
"zh:d0d49355b2d1dc847028c96328f8e0ffc4ce39c3641940f9136684a7177d008f",
"zh:ed137c25a20912962413ea1972aa15931f54dcb922a9c4451d08237b6cad2037",
"zh:f26e0763dbe6a6b2195c94b44696f2110f7f55433dc142839be16b9697fa5597",
"zh:f3e38e9c63ef9b295c7e4d2e302d85700f2e8dbff49285e364457b999b927a72",
]
}
provider "registry.terraform.io/siderolabs/talos" {
version = "0.7.1"
constraints = "0.7.1"
hashes = [
"h1:tzxgHnsmjdkgn82pO+LZAmIOyw6AnbyDyqIB+nl22hY=",
"zh:0fa82a384b25a58b65523e0ea4768fa1212b1f5cfc0c9379d31162454fedcc9d",
"zh:162436bf80a53c4bb0e3cd592699129264092c47e2abf01e05cbccfb66ac86de",
"zh:435b0b7e1dddb51fa40acce72f52ca7d4602ad1995912c51028542a5609bb511",
"zh:4566884b49adbb94e7b234b572215266eb6807ec668cd49fbe0840b138046bd2",
"zh:4abf5e1ab2a25740f4ff4e3ecfa57d3fe5c31ed15b4b1d0365227d1f1d32aa40",
"zh:59884c612645ecd74c25abc83ea87d34a32f737fd261ae291f6ef83c22254bd1",
"zh:6d3d44db2e87f5b55c321f4b2434d1280df98ce80127ef534a14b28c5e20c54a",
"zh:73aea54a4283828016463fd8324f8f8fcb0b65e637a80839c719cb3805801062",
"zh:7f6bcdf202e573a7fd3ff28bce0d02c0d1286db9e23985c3ef476b2580bf5339",
"zh:8a5fcfe56265be6d996b112dee7d909ae54cf39e8f50b701bc649a37fe546f6b",
"zh:985113de5713922aab4a1a85edf563669b41c916fdd4c90a7c52f6b3abedb761",
"zh:9c101adc33fc05042029cb113feb7be811938deefe9dd3db58709f8715084a5e",
"zh:bdeb34b2d6b6704a2dd8d04321887502f71aeb6c5673ff30f6e8c039b5797630",
"zh:ce674170f89481e44e20e3f442595104f809cecca666a9703515b28dbcbfc099",
"zh:f8efb1b8abd656c4a4043bed64c09b8b31698319ce49a187a79bdbb7aef051f3",
]
}

24
README.md Normal file
View File

@@ -0,0 +1,24 @@
# Terraform Proxmox Talos
This Terraform module provisions a [Talos Linux](https://www.talos.dev/) cluster on a [Proxmox Virtual Environment](https://www.proxmox.com/).
It is is based on a greate article by [Olav S. Thoresen: Talos cluster on Proxmox with Terraform](https://olav.ninja/talos-cluster-on-proxmox-with-terraform).
In addition to the configuration provided by the article, this module enables you to provision a HA control plane and any number of worker nodes.
## Setup
Configure `.env`:
```shell
export PROXMOX_VE_USERNAME="root@pam"
export PROXMOX_VE_PASSWORD="super-secure-password"
export PROXMOX_VE_ENDPOINT="https://<proxmox-ip>:8006/"
```
Apply configuration:
```
terraform apply
```
Write Kubeconfig (caution, this will override you existing Kubeconfig):
```
terraform output -raw kubeconfig > ~/.kube/config
```

59
cluster.tf Normal file
View File

@@ -0,0 +1,59 @@
resource "talos_machine_secrets" "machine_secrets" {}
data "talos_client_configuration" "talosconfig" {
cluster_name = var.cluster_name
client_configuration = talos_machine_secrets.machine_secrets.client_configuration
endpoints = [for config in var.talos_controlplane_config : config.ip]
}
data "talos_machine_configuration" "machineconfig_cp" {
for_each = { for machine in var.talos_controlplane_config : machine.name => machine }
cluster_name = var.cluster_name
cluster_endpoint = "https://${each.value.ip}:6443"
machine_type = "controlplane"
machine_secrets = talos_machine_secrets.machine_secrets.machine_secrets
}
resource "talos_machine_configuration_apply" "cp_config_apply" {
for_each = { for machine in var.talos_controlplane_config : machine.name => machine }
depends_on = [proxmox_virtual_environment_vm.talos_cp]
client_configuration = talos_machine_secrets.machine_secrets.client_configuration
machine_configuration_input = data.talos_machine_configuration.machineconfig_cp[each.value.name].machine_configuration
node = each.value.ip
}
data "talos_machine_configuration" "machineconfig_worker" {
for_each = { for machine in var.talos_worker_config : machine.name => machine }
cluster_name = var.cluster_name
cluster_endpoint = "https://${var.talos_controlplane_config[0].ip}:6443"
machine_type = "worker"
machine_secrets = talos_machine_secrets.machine_secrets.machine_secrets
}
resource "talos_machine_configuration_apply" "worker_config_apply" {
for_each = { for machine in var.talos_worker_config : machine.name => machine }
depends_on = [proxmox_virtual_environment_vm.talos_worker]
client_configuration = talos_machine_secrets.machine_secrets.client_configuration
machine_configuration_input = data.talos_machine_configuration.machineconfig_worker[each.value.name].machine_configuration
node = each.value.ip
}
resource "talos_machine_bootstrap" "bootstrap" {
depends_on = [talos_machine_configuration_apply.cp_config_apply]
client_configuration = talos_machine_secrets.machine_secrets.client_configuration
node = var.talos_controlplane_config[0].ip
}
data "talos_cluster_health" "health" {
depends_on = [talos_machine_configuration_apply.cp_config_apply, talos_machine_configuration_apply.worker_config_apply]
client_configuration = data.talos_client_configuration.talosconfig.client_configuration
control_plane_nodes = [for config in var.talos_controlplane_config : config.ip]
worker_nodes = [for config in var.talos_worker_config : config.ip]
endpoints = data.talos_client_configuration.talosconfig.endpoints
}
resource "talos_cluster_kubeconfig" "kubeconfig" {
depends_on = [talos_machine_bootstrap.bootstrap, data.talos_cluster_health.health]
client_configuration = talos_machine_secrets.machine_secrets.client_configuration
node = var.talos_controlplane_config[0].ip
}

11
files.tf Normal file
View File

@@ -0,0 +1,11 @@
# The image is generated on https://factory.talos.dev/ with QEMU guest addon enabled
resource "proxmox_virtual_environment_download_file" "talos_nocloud_image" {
for_each = toset(var.proxmox_nodes)
content_type = "iso"
datastore_id = "local"
node_name = each.value
file_name = "talos-v${var.talos_version}-nocloud-amd64.img"
url = "https://factory.talos.dev/image/ce4c980550dd2ab1b17bbf2b08801c7eb59418eafe8f279833297925d67c7515/v${var.talos_version}/nocloud-amd64.raw.gz"
decompression_algorithm = "gz"
overwrite = false
}

104
machines.tf Normal file
View File

@@ -0,0 +1,104 @@
resource "proxmox_virtual_environment_vm" "talos_cp" {
for_each = { for machine in var.talos_controlplane_config : machine.name => machine }
name = each.value.name
node_name = each.value.node
vm_id = each.value.id
description = "Managed by Terraform"
tags = ["terraform"]
on_boot = true
cpu {
cores = each.value.cpu_cores
type = "x86-64-v2-AES"
}
memory {
dedicated = each.value.memory
}
agent {
enabled = true
}
network_device {
bridge = "vmbr0"
}
disk {
datastore_id = "local-lvm"
file_id = proxmox_virtual_environment_download_file.talos_nocloud_image[each.value.node].id
file_format = "raw"
interface = "virtio0"
size = each.value.disk_size
}
operating_system {
type = "l26" # Linux Kernel 2.6 - 5.X.
}
initialization {
datastore_id = "local-lvm"
ip_config {
ipv4 {
address = "${each.value.ip}/24"
gateway = var.default_gateway
}
ipv6 {
address = "dhcp"
}
}
}
}
resource "proxmox_virtual_environment_vm" "talos_worker" {
for_each = { for machine in var.talos_worker_config : machine.name => machine }
depends_on = [proxmox_virtual_environment_vm.talos_cp]
name = each.value.name
node_name = each.value.node
vm_id = each.value.id
description = "Managed by Terraform"
tags = ["terraform"]
on_boot = true
cpu {
cores = each.value.cpu_cores
type = "x86-64-v2-AES"
}
memory {
dedicated = each.value.memory
}
agent {
enabled = true
}
network_device {
bridge = "vmbr0"
}
disk {
datastore_id = "local-lvm"
file_id = proxmox_virtual_environment_download_file.talos_nocloud_image[each.value.node].id
file_format = "raw"
interface = "virtio0"
size = each.value.disk_size
}
operating_system {
type = "l26" # Linux Kernel 2.6 - 5.X.
}
initialization {
datastore_id = "local-lvm"
ip_config {
ipv4 {
address = "${each.value.ip}/24"
gateway = var.default_gateway
}
ipv6 {
address = "dhcp"
}
}
}
}

3
main.tf Normal file
View File

@@ -0,0 +1,3 @@
provider "proxmox" {
insecure = true
}

9
outputs.tf Normal file
View File

@@ -0,0 +1,9 @@
output "talosconfig" {
value = data.talos_client_configuration.talosconfig.talos_config
sensitive = true
}
output "kubeconfig" {
value = talos_cluster_kubeconfig.kubeconfig.kubeconfig_raw
sensitive = true
}

12
providers.tf Normal file
View File

@@ -0,0 +1,12 @@
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "0.72.0"
}
talos = {
source = "siderolabs/talos"
version = "0.7.1"
}
}
}

102
variables.tf Normal file
View File

@@ -0,0 +1,102 @@
variable "cluster_name" {
type = string
default = "homelab"
}
variable "talos_version" {
type = string
default = "1.9.4"
}
variable "default_gateway" {
type = string
default = "192.168.1.1"
}
variable "proxmox_nodes" {
description = "Names of the Proxmox nodes, used to download and reference node images"
type = list(string)
default = ["ms-01"]
}
variable "talos_controlplane_config" {
description = "Machine configuration of control-plane nodes"
type = list(object({
id = number
ip = string
name = string
node = string
cpu_cores = number
memory = number
disk_size = number
}))
default = [{
id = 101
name = "talos-cp-01"
ip = "192.168.1.181"
node = "ms-01"
cpu_cores = 2
memory = 2048
disk_size = 20
}, {
id = 102
name = "talos-cp-02"
ip = "192.168.1.182"
node = "ms-01"
cpu_cores = 2
memory = 2048
disk_size = 20
}, {
id = 103
name = "talos-cp-03"
ip = "192.168.1.183"
node = "ms-01"
cpu_cores = 2
memory = 2048
disk_size = 20
}]
}
variable "talos_worker_config" {
description = "Machine configuration of worker nodes"
type = list(object({
id = number
ip = string
name = string
node = string
cpu_cores = number
memory = number
disk_size = number
}))
default = [{
id = 111
name = "talos-worker-01"
ip = "192.168.1.191"
node = "ms-01"
cpu_cores = 4
memory = 4096
disk_size = 100
}, {
id = 112
name = "talos-worker-02"
ip = "192.168.1.192"
node = "ms-01"
cpu_cores = 4
memory = 4096
disk_size = 100
}, {
id = 113
name = "talos-worker-03"
ip = "192.168.1.193"
node = "ms-01"
cpu_cores = 4
memory = 4096
disk_size = 100
}, {
id = 114
name = "talos-worker-04"
ip = "192.168.1.194"
node = "ms-01"
cpu_cores = 4
memory = 4096
disk_size = 100
}]
}