[Proxmox] Kubernetes w kontenerach LXC

Featured image for [Proxmox] Kubernetes w kontenerach LXC

Kubernetes od lat stanowi standard zarządzania konteneryzowanymi aplikacjami w środowiskach produkcyjnych i deweloperskich. Jednak jego domyślna architektura – zakładająca osobne maszyny wirtualne lub fizyczne serwery dla każdego węzła – często prowadzi do znacznego marnowania zasobów, szczególnie w małych i średnich wdrożeniach. Z drugiej strony, Proxmox VE, jako potężna platforma do zarządzania wirtualizacją opartą na KVM oraz kontenerami LXC, oferuje lekką i elastyczną alternatywę dla klasycznych hiperwizorów. Połączenie tych dwóch technologii – czyli uruchomienie klastra Kubernetes wewnątrz kontenerów Proxmox LXC – może przynieść wymierne korzyści: mniejsze zużycie pamięci i CPU, szybszy start węzłów oraz większą gęstość upakowania usług. Jednak taka konfiguracja nie jest oczywista. Kontenery LXC, choć bardzo wydajne, nakładają ograniczenia związane z dostępem do modułów jądra, konfiguracją cgroups czy uprawnieniami. W tym artykule pokażemy, jak krok po kroku przygotować środowisko Proxmox, skonfigurować kontenery LXC pod kątem wymagań Kubernetesa (w tym obsługę kubelet, containerd lub dockera) oraz postawić działający klaster – wszystko bez nadmiarowej wirtualizacji.

Przygotowanie serwera Proxmox

Zaczynamy od przygotowania hiperwizora od załadowania niezbędnych modułów jądra Linuxa do obsługi mostka sieciowego (bridge) oraz br_netfilter, który umożliwia iptables przetwarzanie ruchu sieciowego przechodzącego przez mostek. Należy także załadować moduł overlay (OverlayFS), to moduł jądra systemu Linux, który umożliwia stworzenie jednego, ujednoliconego systemu plików poprzez nałożenie jednego katalogu (lub systemu plików) na drugi.

cat <<EOF | cat >> /etc/modules
modprobe bridge
modprobe br_netfilter
modprobe overlay
overlay
EOF

Oryginalny kod Proxmox HA zawierał linię forceStop => 1 w pliku PVECT.pm, która, jak stwierdzono, powodowała nieoczekiwane i agresywne zamykanie kontenerów. Zmieniamy sposób zamykania kontenerów LXC zarządzanych przez HA, zmieniając wartość parametru forceStop z 1 (prawda) na 0 (fałsz).

sed -i 's/forceStop => 1/forceStop => 0/' /usr/share/perl5/PVE/HA/Resources/PVECT.pm

Template systemu operacyjnego dla kontenerów LXC

Będziemy potrzebowali templatki systemu operacyjnego, w tym przypadku debian-12-standard_12.7-1_amd64.tar.zst. Należy pobrać z http://download.proxmox.com/images/system/ i umieścić w lokalnym katalogu, np. local:vztmpl/ lub pobrać template do lokalnego storage przez UI proxmox-a:

post-image

Użyjemy go później w Terrafoemie:

ostemplate          = "local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst"

Użytkownik Proxmox i rola dla terraforma

Tworzymy urzytkownika i rolę w Proxmox na potrzeby Terraforma. Nadajemy mu odpowiednie uprawniena.

pveum role add TerraformProv -privs "Datastore.AllocateSpace Datastore.AllocateTemplate Datastore.Audit Pool.Allocate Pool.Audit Sys.Audit Sys.Console Sys.Modify VM.Allocate VM.Audit VM.Clone VM.Config.CDROM VM.Config.Cloudinit VM.Config.CPU VM.Config.Disk VM.Config.HWType VM.Config.Memory VM.Config.Network VM.Config.Options VM.Migrate VM.PowerMgmt SDN.Use"
pveum user add terraform-prov@pve --password <password>
pveum aclmod / -user terraform-prov@pve -role TerraformProv

Terraform

Do terraforma użyjemy provider-a Telmate/proxmox, który jest odpowiedzialny za interakcję z API Proxmox-a i udostępnianie zasobów proxmox_vm_qemu i proxmox_lxc. Przykładowa konfiguracja providera:

terraform {
  required_providers {
    proxmox = {
      source  = "Telmate/proxmox"
      version = "3.0.1-rc8"
    }
  }
}

provider "proxmox" {
  pm_api_url = var.pm_api_url
  pm_api_token_secret = var.pm_api_token_secret
  pm_api_token_id     = var.pm_api_token_id
  pm_debug        = true
  pm_log_enable   = true
  pm_tls_insecure = true
  pm_timeout      = 3000
  pm_log_file = "terraform-plugin-proxmox.log"
}

Całość kodu tarraform znajduje się w repozytorium GitHub:

https://github.com/krdian/kubernetes-proxmox-lxc

Terraform Plan i apply

Przed uruchomieniem terraform możemy przygotować plik .auto.tfvars: zawierający zmienne dla naszego klastra Proxmox i kubernetes, między innymi URL API Proxmoxa, utworziny uprzednio token, adres IP proxmox-a, rozmiar dysku dla węzła Kubernetes.

Przykładowy plik *.auto.tfvars:

pm_api_token_secret = "<token>"
pm_api_token_id     = "terraform-prov@pve!terraform"
nameserver          = "192.168.32.1"
ssh_public_keys     = <<EOT
<ssh_public_key>
EOT
nodes               = ["02", "03"]
ostemplate          = "local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst"
memory              = 4096
swap                = 0
rootfs              = "local-lvm"
rootfs_size         = "32G"
network_name        = "eth0"
network_bridge      = "vmbr0"
network_ip          = "dhcp"
target_node         = "pve"
target_node_ip      = "192.168.32.140"
pm_api_url          = "https://192.168.32.140:8006/api2/json"
k8s_version         = "v1.33"
private_key_path    = "/Users/<user>/.ssh/id_rsa"

Inicjujemy Terraform-a:

terraform init

Następnie puszczamy plan terraforma i jak wszystko przebiegnie pomyslnie to zatwierdzamy plan:

terraform plan 
terraform apply

Po zakończeniu działania terraforma powinny pojawić się node-y k8s i klaster powinien zacząć działać:

post-image

post-image

W następnym artykule opiszę jak dodać do naszego klastra Cillium, MetalLb i Traefic.