feat(tofu): updated kubernetes setup

tried to to some tidying while writing an article based on the current
setup.
This commit is contained in:
Vegard Hagen
2024-08-03 13:32:43 +02:00
parent 0a265cbfd5
commit c4ba7120dd
19 changed files with 211 additions and 234 deletions

View File

@@ -41,19 +41,19 @@ kubectl -n argocd get secret argocd-initial-admin-secret -ojson | jq -r ' .data.
```
```shell
kubectl kustomize infra | kubectl apply -f -
kubectl apply -k sets
```
# SBOM
* [x] Cilium
* [] Hubble
* [X] Hubble
* [x] Argo CD
* [x] Proxmox CSI Plugin
* [x] Cert-manager
* [X] Gateway
* [] CNPG
* [] Authentication (Keycloak, Authentik, ...)
* [X] Authentication (Keycloak, Authentik, ...)
* [] CNPG - Cloud Native PostGresSQL
# CRDs
@@ -63,13 +63,11 @@ kubectl kustomize infra | kubectl apply -f -
# TODO
* [] Remotely managed cloudflared tunnel
* [] Keycloak
* [X] Remotely managed cloudflared tunnel
* [X] Keycloak
* [] Argo CD sync-wave
```shell
commonAnnotations:
argocd.argoproj.io/sync-wave: "-1"
```
CNPG - Cloud Native PostGresSQL

View File

@@ -4,4 +4,4 @@ variable "proxmox" {
endpoint = string
insecure = bool
})
}
}

View File

@@ -17,7 +17,7 @@ resource "kubernetes_secret" "sealed-secrets-key" {
}
data = {
"tls.crt" = var.sealed_secrets_cert.cert
"tls.key" = var.sealed_secrets_cert.key
"tls.crt" = var.cert.cert
"tls.key" = var.cert.key
}
}

View File

@@ -1,4 +1,4 @@
variable "sealed_secrets_cert" {
variable "cert" {
type = object({
cert = string
key = string

View File

@@ -28,10 +28,10 @@ tofu state rm "module.volumes.module.proxmox-volume[\"pv-jellyfin-config\"].rest
tofu state rm "module.volumes.module.proxmox-volume[\"pv-qbittorrent-config\"].restapi_object.proxmox-volume"
```
## import
## import proxmox volume
```shell
tofu import "module.volumes.module.proxmox-volume[\"pv-lidarr-config\"].restapi_object.proxmox-volume" /api2/json/nodes/cantor/storage/local-zfs/content/local-zfs:vm-9999-pv-lidarr-config
tofu import 'module.volumes.module.proxmox-volume["pv-lidarr-config"].restapi_object.proxmox-volume' /api2/json/nodes/cantor/storage/local-zfs/content/local-zfs:vm-9999-pv-lidarr-config
tofu import "module.volumes.module.proxmox-volume[\"pv-radarr-config\"].restapi_object.proxmox-volume" /api2/json/nodes/cantor/storage/local-zfs/content/local-zfs:vm-9999-pv-radarr-config
tofu import "module.volumes.module.proxmox-volume[\"pv-sonarr-config\"].restapi_object.proxmox-volume" /api2/json/nodes/cantor/storage/local-zfs/content/local-zfs:vm-9999-pv-sonarr-config
@@ -39,4 +39,11 @@ tofu import "module.volumes.module.proxmox-volume[\"pv-qbittorrent-config\"].res
tofu import "module.volumes.module.proxmox-volume[\"pv-plex-config\"].restapi_object.proxmox-volume" /api2/json/nodes/abel/storage/local-zfs/content/local-zfs:vm-9999-pv-plex-config
tofu import "module.volumes.module.proxmox-volume[\"pv-jellyfin-config\"].restapi_object.proxmox-volume" /api2/json/nodes/abel/storage/local-zfs/content/local-zfs:vm-9999-pv-jellyfin-config
```
## import persistent volume
```shell
tofu import 'module.volumes.module.persistent-volume["pv-torrent-config"].kubernetes_persistent_volume.pv' pv-torrent-config
```

View File

@@ -1,21 +0,0 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: plex-config
spec:
storageClassName: proxmox-csi
accessModes:
- ReadWriteOnce
capacity:
storage: 12Gi
csi:
driver: csi.proxmox.sinextra.dev
fsType: ext4
volumeAttributes:
cache: writethrough
ssd: "true"
storage: local-zfs
volumeHandle: homelab/abel/local-zfs/vm-9999-plex-config
mountOptions:
- noatime
volumeMode: Filesystem

View File

@@ -5,65 +5,74 @@ module "talos" {
proxmox = proxmox
}
talos_image = {
version = "v1.7.5"
schematic = file("${path.module}/config/talos-image-schematic.yaml")
image = {
version = "v1.7.5"
schematic = file("${path.module}/talos/image/schematic.yaml")
}
cilium = {
values = file("${path.module}/../../k8s/infra/network/cilium/values.yaml")
install = file("${path.module}/bootstrap/cilium/install.yaml")
install = file("${path.module}/talos/inline-manifests/cilium-install.yaml")
}
cluster_config = {
cluster_name = "talos"
proxmox_cluster = "homelab"
endpoint = "https://192.168.1.100:6443"
cluster = {
name = "talos"
endpoint = "192.168.1.100"
gateway = "192.168.1.1"
talos_version = "v1.7"
nodes = {
"ctrl-00" = {
machine_type = "controlplane"
ip = "192.168.1.100"
mac_address = "BC:24:11:2E:C8:00"
host_node = "abel"
vm_id = 8000
cpu = 8
ram_dedicated = 20480
igpu = true
}
"ctrl-01" = {
host_node = "euclid"
machine_type = "controlplane"
ip = "192.168.1.101"
mac_address = "BC:24:11:2E:C8:01"
vm_id = 8001
cpu = 4
ram_dedicated = 20480
igpu = true
}
"ctrl-02" = {
host_node = "cantor"
machine_type = "controlplane"
ip = "192.168.1.102"
mac_address = "BC:24:11:2E:C8:02"
vm_id = 8002
cpu = 4
ram_dedicated = 4096
}
//"work-00" = {
// host_node = "abel"
// machine_type = "worker"
// ip = "192.168.1.110"
// mac_address = "BC:24:11:2E:08:00"
// vm_id = 8100
// cpu = 8
// ram_dedicated = 4096
//}
proxmox_cluster = "homelab"
}
nodes = {
"ctrl-00" = {
host_node = "abel"
machine_type = "controlplane"
ip = "192.168.1.100"
mac_address = "BC:24:11:2E:C8:00"
vm_id = 8000
cpu = 8
ram_dedicated = 20480
igpu = true
update = true
}
"ctrl-01" = {
host_node = "euclid"
machine_type = "controlplane"
ip = "192.168.1.101"
mac_address = "BC:24:11:2E:C8:01"
vm_id = 8001
cpu = 4
ram_dedicated = 20480
igpu = true
}
"ctrl-02" = {
host_node = "cantor"
machine_type = "controlplane"
ip = "192.168.1.102"
mac_address = "BC:24:11:2E:C8:02"
vm_id = 8002
cpu = 4
ram_dedicated = 4096
}
}
}
module "sealed_secrets" {
depends_on = [module.talos]
source = "./bootstrap/sealed-secrets"
providers = {
kubernetes = kubernetes
}
// openssl req -x509 -days 365 -nodes -newkey rsa:4096 -keyout sealed-secrets.key -out sealed-secrets.cert -subj "/CN=sealed-secret/O=sealed-secret"
cert = {
cert = file("${path.module}/bootstrap/sealed-secrets/certificate/sealed-secrets.cert")
key = file("${path.module}/bootstrap/sealed-secrets/certificate/sealed-secrets.key")
}
}
module "proxmox_csi_plugin" {
depends_on = [module.talos]
source = "./bootstrap/proxmox-csi-plugin"
@@ -76,21 +85,6 @@ module "proxmox_csi_plugin" {
proxmox = var.proxmox
}
module "sealed_secrets" {
depends_on = [module.talos]
source = "./bootstrap/sealed-secrets"
providers = {
kubernetes = kubernetes
}
// openssl req -x509 -days 365 -nodes -newkey rsa:4096 -keyout sealed-secrets.key -out sealed-secrets.cert -subj "/CN=sealed-secret/O=sealed-secret"
sealed_secrets_cert = {
cert = file("${path.module}/config/sealed-secrets.cert")
key = file("${path.module}/config/sealed-secrets.key")
}
}
module "volumes" {
depends_on = [module.proxmox_csi_plugin]
source = "./bootstrap/volumes"

View File

@@ -1,28 +1,28 @@
resource "local_file" "machine_configs" {
for_each = module.talos.talos_machine_config
for_each = module.talos.machine_config
content = each.value.machine_configuration
filename = "output/talos-machine-config-${each.key}.yaml"
file_permission = "0600"
}
resource "local_file" "talos_config" {
content = module.talos.talos_client_configuration.talos_config
content = module.talos.client_configuration.talos_config
filename = "output/talos-config.yaml"
file_permission = "0600"
}
resource "local_file" "kube_config" {
content = module.talos.talos_kube_config.kubeconfig_raw
content = module.talos.kube_config.kubeconfig_raw
filename = "output/kube-config.yaml"
file_permission = "0600"
}
output "kube_config" {
value = module.talos.talos_kube_config.kubeconfig_raw
value = module.talos.kube_config.kubeconfig_raw
sensitive = true
}
output "talos_config" {
value = module.talos.talos_client_configuration.talos_config
value = module.talos.client_configuration.talos_config
sensitive = true
}

View File

@@ -42,12 +42,8 @@ provider "restapi" {
}
provider "kubernetes" {
host = module.talos.talos_kube_config.kubernetes_client_configuration.host
client_certificate = base64decode(module.talos.talos_kube_config.kubernetes_client_configuration.client_certificate)
client_key = base64decode(module.talos.talos_kube_config.kubernetes_client_configuration.client_key)
cluster_ca_certificate = base64decode(module.talos.talos_kube_config.kubernetes_client_configuration.ca_certificate)
# ignore_labels = [
# "app.kubernetes.io/.*",
# "kustomize.toolkit.fluxcd.io/.*",
# ]
host = module.talos.kube_config.kubernetes_client_configuration.host
client_certificate = base64decode(module.talos.kube_config.kubernetes_client_configuration.client_certificate)
client_key = base64decode(module.talos.kube_config.kubernetes_client_configuration.client_key)
cluster_ca_certificate = base64decode(module.talos.kube_config.kubernetes_client_configuration.ca_certificate)
}

View File

@@ -0,0 +1,79 @@
resource "talos_machine_secrets" "this" {
talos_version = var.cluster.talos_version
}
data "talos_client_configuration" "this" {
cluster_name = var.cluster.name
client_configuration = talos_machine_secrets.this.client_configuration
nodes = [for k, v in var.nodes : v.ip]
endpoints = [for k, v in var.nodes : v.ip if v.machine_type == "controlplane"]
}
data "talos_machine_configuration" "this" {
for_each = var.nodes
cluster_name = var.cluster.name
cluster_endpoint = "https://${var.cluster.endpoint}:6443"
talos_version = var.cluster.talos_version
machine_type = each.value.machine_type
machine_secrets = talos_machine_secrets.this.machine_secrets
config_patches = each.value.machine_type == "controlplane" ? [
templatefile("${path.module}/machine-config/control-plane.yaml.tftpl", {
hostname = each.key
node_name = each.value.host_node
cluster_name = var.cluster.proxmox_cluster
cilium_values = var.cilium.values
cilium_install = var.cilium.install
})
] : [
templatefile("${path.module}/machine-config/worker.yaml.tftpl", {
hostname = each.key
node_name = each.value.host_node
cluster_name = var.cluster.proxmox_cluster
})
]
}
resource "talos_machine_configuration_apply" "this" {
depends_on = [proxmox_virtual_environment_vm.this]
for_each = var.nodes
node = each.value.ip
client_configuration = talos_machine_secrets.this.client_configuration
machine_configuration_input = data.talos_machine_configuration.this[each.key].machine_configuration
lifecycle {
# re-run config apply if vm changes
replace_triggered_by = [proxmox_virtual_environment_vm.this[each.key]]
}
}
resource "talos_machine_bootstrap" "this" {
node = [for k, v in var.nodes : v.ip if v.machine_type == "controlplane"][0]
endpoint = var.cluster.endpoint
client_configuration = talos_machine_secrets.this.client_configuration
}
data "talos_cluster_health" "this" {
depends_on = [
talos_machine_configuration_apply.this,
talos_machine_bootstrap.this
]
client_configuration = data.talos_client_configuration.this.client_configuration
control_plane_nodes = [for k, v in var.nodes : v.ip if v.machine_type == "controlplane"]
worker_nodes = [for k, v in var.nodes : v.ip if v.machine_type == "worker"]
endpoints = data.talos_client_configuration.this.endpoints
timeouts = {
read = "10m"
}
}
data "talos_cluster_kubeconfig" "this" {
depends_on = [
talos_machine_bootstrap.this,
data.talos_cluster_health.this
]
node = [for k, v in var.nodes : v.ip if v.machine_type == "controlplane"][0]
endpoint = var.cluster.endpoint
client_configuration = talos_machine_secrets.this.client_configuration
timeouts = {
read = "1m"
}
}

View File

@@ -1,38 +1,36 @@
locals {
version = var.talos_image.version
schematic = var.talos_image.schematic
version = var.image.version
schematic = var.image.schematic
schematic_id = jsondecode(data.http.schematic_id.response_body)["id"]
url = "${var.talos_image.factory_url}/image/${local.schematic_id}/${local.version}/${var.talos_image.platform}-${var.talos_image.arch}.raw.gz"
image_id = "${local.schematic_id}_${local.version}"
update_version = coalesce(var.talos_image.update_version, var.talos_image.version)
update_schematic = coalesce(var.talos_image.update_schematic, var.talos_image.schematic)
update_version = coalesce(var.image.update_version, var.image.version)
update_schematic = coalesce(var.image.update_schematic, var.image.schematic)
update_schematic_id = jsondecode(data.http.updated_schematic_id.response_body)["id"]
update_url = "${var.talos_image.factory_url}/image/${local.update_schematic_id}/${local.update_version}/${var.talos_image.platform}-${var.talos_image.arch}.raw.gz"
update_image_id = "${local.update_schematic_id}_${local.update_version}"
}
data "http" "schematic_id" {
url = "${var.talos_image.factory_url}/schematics"
url = "${var.image.factory_url}/schematics"
method = "POST"
request_body = local.schematic
}
data "http" "updated_schematic_id" {
url = "${var.talos_image.factory_url}/schematics"
url = "${var.image.factory_url}/schematics"
method = "POST"
request_body = local.update_schematic
}
resource "proxmox_virtual_environment_download_file" "talos_image" {
for_each = toset(distinct([for k, v in var.cluster_config.nodes : "${v.host_node}_${v.update == true ? local.update_image_id : local.image_id}"]))
resource "proxmox_virtual_environment_download_file" "this" {
for_each = toset(distinct([for k, v in var.nodes : "${v.host_node}_${v.update == true ? local.update_image_id : local.image_id}"]))
node_name = split("_", each.key)[0]
content_type = "iso"
datastore_id = var.talos_image.proxmox_datastore
datastore_id = var.image.proxmox_datastore
file_name = "talos-${split("_",each.key)[1]}-${split("_", each.key)[2]}-${var.talos_image.platform}-${var.talos_image.arch}.img"
url = "${var.talos_image.factory_url}/image/${split("_", each.key)[1]}/${split("_", each.key)[2]}/${var.talos_image.platform}-${var.talos_image.arch}.raw.gz"
file_name = "talos-${split("_",each.key)[1]}-${split("_", each.key)[2]}-${var.image.platform}-${var.image.arch}.img"
url = "${var.image.factory_url}/image/${split("_", each.key)[1]}/${split("_", each.key)[2]}/${var.image.platform}-${var.image.arch}.raw.gz"
decompression_algorithm = "gz"
overwrite = false
}

View File

@@ -1,13 +1,13 @@
output "talos_machine_config" {
value = data.talos_machine_configuration.machine_configuration
output "machine_config" {
value = data.talos_machine_configuration.this
}
output "talos_client_configuration" {
value = data.talos_client_configuration.talos_config
output "client_configuration" {
value = data.talos_client_configuration.this
sensitive = true
}
output "talos_kube_config" {
value = data.talos_cluster_kubeconfig.kubeconfig
output "kube_config" {
value = data.talos_cluster_kubeconfig.this
sensitive = true
}

View File

@@ -1,77 +0,0 @@
resource "talos_machine_secrets" "machine_secrets" {
talos_version = var.cluster_config.talos_version
}
data "talos_client_configuration" "talos_config" {
cluster_name = var.cluster_config.cluster_name
client_configuration = talos_machine_secrets.machine_secrets.client_configuration
endpoints = [for k, v in var.cluster_config.nodes : v.ip if v.machine_type == "controlplane"]
}
data "talos_machine_configuration" "machine_configuration" {
for_each = var.cluster_config.nodes
cluster_name = var.cluster_config.cluster_name
cluster_endpoint = var.cluster_config.endpoint
machine_type = each.value.machine_type
machine_secrets = talos_machine_secrets.machine_secrets.machine_secrets
talos_version = var.cluster_config.talos_version
config_patches = each.value.machine_type == "controlplane" ? [
templatefile("${path.module}/machine-config/control-plane.yaml.tftpl", {
hostname = each.key
cluster_name = var.cluster_config.proxmox_cluster
node_name = each.value.host_node
cilium_values = var.cilium.values
cilium_install = var.cilium.install
})
] : [
templatefile("${path.module}/machine-config/worker.yaml.tftpl", {
hostname = each.key
cluster_name = var.cluster_config.proxmox_cluster
node_name = each.value.host_node
})
]
}
resource "talos_machine_configuration_apply" "talos_config_apply" {
depends_on = [proxmox_virtual_environment_vm.talos_vm]
for_each = var.cluster_config.nodes
node = each.value.ip
client_configuration = talos_machine_secrets.machine_secrets.client_configuration
machine_configuration_input = data.talos_machine_configuration.machine_configuration[each.key].machine_configuration
lifecycle {
# re-run config apply if vm changes
replace_triggered_by = [proxmox_virtual_environment_vm.talos_vm[each.key]]
}
}
resource "talos_machine_bootstrap" "talos_bootstrap" {
depends_on = [talos_machine_configuration_apply.talos_config_apply]
client_configuration = talos_machine_secrets.machine_secrets.client_configuration
node = [for k, v in var.cluster_config.nodes : v.ip if v.machine_type == "controlplane"][0]
}
data "talos_cluster_health" "health" {
depends_on = [
talos_machine_configuration_apply.talos_config_apply,
talos_machine_bootstrap.talos_bootstrap
]
client_configuration = data.talos_client_configuration.talos_config.client_configuration
control_plane_nodes = [for k, v in var.cluster_config.nodes : v.ip if v.machine_type == "controlplane"]
worker_nodes = [for k, v in var.cluster_config.nodes : v.ip if v.machine_type == "worker"]
endpoints = data.talos_client_configuration.talos_config.endpoints
timeouts = {
read = "10m"
}
}
data "talos_cluster_kubeconfig" "kubeconfig" {
depends_on = [
talos_machine_bootstrap.talos_bootstrap,
data.talos_cluster_health.health
]
client_configuration = talos_machine_secrets.machine_secrets.client_configuration
node = [for k, v in var.cluster_config.nodes : v.ip if v.machine_type == "controlplane"][0]
timeouts = {
read = "1m"
}
}

View File

@@ -1,4 +1,5 @@
variable "talos_image" {
variable "image" {
description = "Talos image configuration"
type = object({
factory_url = optional(string, "https://factory.talos.dev")
schematic = string
@@ -11,32 +12,37 @@ variable "talos_image" {
})
}
variable "cluster_config" {
description = "Talos node configuration"
variable "cluster" {
description = "Cluster configuration"
type = object({
cluster_name = string
proxmox_cluster = string
name = string
endpoint = string
gateway = string
talos_version = string
nodes = map(object({
host_node = string
machine_type = string
ip = string
mac_address = string
vm_id = number
cpu = number
ram_dedicated = number
update = optional(bool, false)
igpu = optional(bool, false)
}))
proxmox_cluster = string
})
}
variable "nodes" {
description = "Configuration for cluster nodes"
type = map(object({
host_node = string
machine_type = string
datastore_id = optional(string, "local-zfs")
ip = string
mac_address = string
vm_id = number
cpu = number
ram_dedicated = number
update = optional(bool, false)
igpu = optional(bool, false)
}))
}
variable "cilium" {
description = "Cilium configuration"
type = object({
values = string
install = string
})
}
}

View File

@@ -1,5 +1,5 @@
resource "proxmox_virtual_environment_vm" "talos_vm" {
for_each = var.cluster_config.nodes
resource "proxmox_virtual_environment_vm" "this" {
for_each = var.nodes
node_name = each.value.host_node
@@ -32,7 +32,7 @@ resource "proxmox_virtual_environment_vm" "talos_vm" {
}
disk {
datastore_id = "local-zfs"
datastore_id = each.value.datastore_id
interface = "scsi0"
iothread = true
cache = "writethrough"
@@ -40,7 +40,7 @@ resource "proxmox_virtual_environment_vm" "talos_vm" {
ssd = true
file_format = "raw"
size = 20
file_id = proxmox_virtual_environment_download_file.talos_image["${each.value.host_node}_${each.value.update == true ? local.update_image_id : local.image_id}"].id
file_id = proxmox_virtual_environment_download_file.this["${each.value.host_node}_${each.value.update == true ? local.update_image_id : local.image_id}"].id
}
boot_order = ["scsi0"]
@@ -50,14 +50,11 @@ resource "proxmox_virtual_environment_vm" "talos_vm" {
}
initialization {
datastore_id = "local-zfs"
datastore_id = each.value.datastore_id
ip_config {
ipv4 {
address = "${each.value.ip}/24"
gateway = "192.168.1.1"
}
ipv6 {
address = "dhcp"
gateway = var.cluster.gateway
}
}
}