Vai al contenuto principale

Infrastructure as Code con Hikube

Hikube essendo basato su Kubernetes, potete utilizzare Terraform per gestire la vostra infrastruttura in modo dichiarativo e riproducibile. Questo approccio vi permette di versionare, testare e distribuire la vostra infrastruttura Hikube in modo automatizzato.


Configurazione​

Prerequisiti​

  • Terraform (versione >= 1.0)
  • kubectl
  • Accesso a un tenant Hikube
  • Kubeconfig configurato

Provider Kubernetes​

main.tf
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.24"
}
kubectl = {
source = "gavinbunney/kubectl"
version = "~> 1.14"
}
}
}

provider "kubernetes" {
config_path = "~/.kube/config"
}

provider "kubectl" {
config_path = "~/.kube/config"
}

Variabili​

variables.tf
variable "ssh_public_key" {
description = "Chiave SSH pubblica per l'accesso alle VM"
type = string
}

variable "cluster_name" {
description = "Nome del cluster Kubernetes"
type = string
default = "terraform-cluster"
}

variable "vm_name" {
description = "Nome della macchina virtuale"
type = string
default = "terraform-vm"
}

Esempi​

Distribuire un Cluster Kubernetes​

kubernetes.tf
resource "kubectl_manifest" "kubernetes_cluster" {
yaml_body = yamlencode({
apiVersion = "apps.cozystack.io/v1alpha1"
kind = "Kubernetes"
metadata = {
name = var.cluster_name
namespace = "default"
}
spec = {
version = "v1.34"
storageClass = "replicated"

controlPlane = {
replicas = 2
}

nodeGroups = {
general = {
minReplicas = 1
maxReplicas = 5
instanceType = "s1.large"
ephemeralStorage = "50Gi"
roles = ["ingress-nginx"]
}
# Esempio di gruppo GPU (richiede l'addon gpuOperator qui sotto)
# gpu = {
# minReplicas = 0
# maxReplicas = 4
# instanceType = "u1.2xlarge"
# ephemeralStorage = "200Gi"
# gpus = [{ name = "nvidia.com/AD102GL_L40S" }]
# roles = []
# }
}

addons = {
certManager = {
enabled = true
}
ingressNginx = {
enabled = true
hosts = [
"${var.cluster_name}.example.com"
]
}
# Richiesto per esporre le GPU ai pod di un gruppo di nodi GPU
# gpuOperator = {
# enabled = true
# }
}
}
})
}

# Recuperare il kubeconfig
data "kubernetes_secret" "cluster_kubeconfig" {
depends_on = [kubectl_manifest.kubernetes_cluster]

metadata {
name = "${var.cluster_name}-admin-kubeconfig"
namespace = "default"
}
}

# Salvare il kubeconfig
resource "local_file" "kubeconfig" {
content = base64decode(
data.kubernetes_secret.cluster_kubeconfig.data["super-admin.conf"]
)
filename = "${path.module}/${var.cluster_name}-kubeconfig.yaml"
file_permission = "0600"
}

Distribuire una Macchina Virtuale​

virtual-machine.tf
# Il disco Γ¨ una risorsa VMDisk separata, referenziata dalla VM
resource "kubectl_manifest" "vm_disk" {
yaml_body = yamlencode({
apiVersion = "apps.cozystack.io/v1alpha1"
kind = "VMDisk"
metadata = {
name = "${var.vm_name}-disk"
}
spec = {
source = {
image = {
name = "ubuntu-2404"
}
}
storage = "50Gi"
storageClass = "replicated"
}
})
}

resource "kubectl_manifest" "virtual_machine" {
depends_on = [kubectl_manifest.vm_disk]

yaml_body = yamlencode({
apiVersion = "apps.cozystack.io/v1alpha1"
kind = "VMInstance"
metadata = {
name = var.vm_name
}
spec = {
runStrategy = "Always"
instanceProfile = "ubuntu"
instanceType = "u1.xlarge"

disks = [
{
name = "${var.vm_name}-disk"
}
]

external = true
externalMethod = "PortList"
externalPorts = [22, 80, 443]

sshKeys = [var.ssh_public_key]

cloudInit = <<-EOT
#cloud-config
users:
- name: ubuntu
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ${var.ssh_public_key}

package_update: true
packages:
- curl
- wget
- git
- docker.io

runcmd:
- systemctl enable docker
- systemctl start docker
- usermod -aG docker ubuntu
EOT
}
})
}

Distribuire una VM con GPU​

vm-gpu.tf
resource "kubectl_manifest" "vm_gpu_disk" {
yaml_body = yamlencode({
apiVersion = "apps.cozystack.io/v1alpha1"
kind = "VMDisk"
metadata = {
name = "gpu-vm-disk"
}
spec = {
source = {
image = {
name = "ubuntu-2404"
}
}
storage = "100Gi"
storageClass = "replicated"
}
})
}

resource "kubectl_manifest" "vm_gpu" {
depends_on = [kubectl_manifest.vm_gpu_disk]

yaml_body = yamlencode({
apiVersion = "apps.cozystack.io/v1alpha1"
kind = "VMInstance"
metadata = {
name = "gpu-vm"
}
spec = {
runStrategy = "Always"
instanceProfile = "ubuntu"
instanceType = "u1.xlarge"

gpus = [
{
# Modelli: nvidia.com/AD102GL_L40S, nvidia.com/GA100_A100_PCIE_80GB,
# nvidia.com/GA100_A100_SXM4_80GB, nvidia.com/GB202GL_RTX_PRO_6000_BLACKWELL_SERVER_EDITION
name = "nvidia.com/AD102GL_L40S"
}
]

disks = [
{
name = "gpu-vm-disk"
}
]

external = true
externalMethod = "PortList"
externalPorts = [22, 8888]

sshKeys = [var.ssh_public_key]

cloudInit = <<-EOT
#cloud-config
users:
- name: ubuntu
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash

package_update: true
packages:
- curl
- wget
- build-essential

runcmd:
# Installazione driver NVIDIA
- wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb
- dpkg -i cuda-keyring_1.0-1_all.deb
- apt-get update
- apt-get install -y cuda-toolkit nvidia-driver-535
- nvidia-smi -pm 1
EOT
}
})
}

Distribuire PostgreSQL​

postgresql.tf
resource "kubectl_manifest" "postgres" {
yaml_body = yamlencode({
apiVersion = "apps.cozystack.io/v1alpha1"
kind = "Postgres"
metadata = {
name = "terraform-postgres"
}
spec = {
external = false
size = "20Gi"
replicas = 2
storageClass = "replicated"

users = {
admin = {
password = var.postgres_password
}
}

databases = {
myapp = {
roles = {
admin = ["admin"]
}
}
}
}
})
}

variable "postgres_password" {
description = "Password per l'utente admin di PostgreSQL"
type = string
sensitive = true
}

Output e Variabili​

Output utili​

outputs.tf
output "cluster_kubeconfig" {
description = "Percorso del kubeconfig del cluster"
value = local_file.kubeconfig.filename
}

output "vm_status" {
description = "Comando per verificare lo stato della VM"
value = "kubectl get vminstance ${var.vm_name}"
}

output "postgres_connection" {
description = "Comando per connettersi a PostgreSQL"
value = "kubectl exec -it postgres-terraform-postgres-0 -- psql -U admin -d myapp"
sensitive = true
}

File terraform.tfvars​

terraform.tfvars
# Configurazione di base
cluster_name = "my-prod-cluster"
vm_name = "my-app-vm"

# La vostra chiave SSH pubblica
ssh_public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQ... user@hostname"

# Password PostgreSQL
postgres_password = "your-secure-password-here"

Buone Pratiche​

Struttura del progetto​

hikube-terraform/
β”œβ”€β”€ environments/
β”‚ β”œβ”€β”€ dev/
β”‚ β”œβ”€β”€ staging/
β”‚ └── production/
β”œβ”€β”€ modules/
β”‚ β”œβ”€β”€ kubernetes/
β”‚ β”œβ”€β”€ vm/
β”‚ └── database/
└── shared/
β”œβ”€β”€ variables.tf
└── outputs.tf

Comandi utili​

# Inizializzare Terraform
terraform init

# Pianificare le modifiche
terraform plan

# Applicare la configurazione
terraform apply

# Verificare le risorse create
terraform show

# Pulire le risorse
terraform destroy

Riferimenti​