Vai al contenuto principale
Categorie articolo: Code

Utilizzare Terraform per creare un cluster Kubernetes

13 Ottobre 2025 - 8 minuti di lettura

Negli ultimi anni, l’infrastruttura come codice (in inglese Infrastructure as Code, o IaC) è diventata una delle pratiche cardine nel mondo DevOps e cloud-native. Tra gli strumenti disponibili, Terraform si è imposto come una soluzione solida e flessibile per definire, versionare e gestire infrastrutture in modo dichiarativo.

Sebbene i principali provider cloud offrano strumenti integrati — come AWS CloudFormation o Azure Resource Manager — queste soluzioni presentano spesso limiti e differenze significative: ciascun servizio segue infatti una propria logica, senza un linguaggio unificato e condiviso. Questo approccio frammentato può rallentare i team e rendere complessa la gestione degli aggiornamenti infrastrutturali.

Ed è proprio qui che Terraform mostra tutta la sua forza: uno strumento indipendente dai provider, con un linguaggio coerente e portabile.

In questo tutorial ti guideremo passo dopo passo nella creazione di un cluster Kubernetes con Terraform, pronto all’uso e facilmente scalabile.

Terraform e tutto ciò che serve

Cosa serve per iniziare:

  1. Terraform
  2. Un account AWS
  3. Un IDE (consiglio Intellj con il plugin “Terraform and HCL”)

Installazione di Terraform

Per installare Terraform segui le istruzioni a questo link: https://developer.hashicorp.com/terraform/install.

Per gli utenti Windows consiglio di usare Chocolatey – uno dei package manager disponibili – digitando il comando choco install terraform -y.

Nel caso in cui tu abbia già installato Terraform, esegui l’aggiornamento tramite il comando choco upgrade terraform -y.

Per avere conferma dell’installazione/aggiornamento, apri un terminale e scrivi terraform -version per leggere in risposta, se tutto ok, l’informazione sulla versione di Terraform installata.

Effettuare l’accesso

Segui questa guida per installare AWS CLI (necessario per connettersi ad AWS): https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html.

Per ottenere le chiavi:

  1. Accedi alla Console di gestione AWS.
  2. Clicca su “IAM” (Identity and Access Management).
  3. Seleziona “Utenti” e scegli il tuo utente.
  4. Clicca “Scheda Sicurezza” e poi “Crea nuova chiave di accesso”.
  5. Scegli “Command Line Interface (CLI)”.
  6. Salva i valori di Access Key ID e Secret Access Key in un posto sicuro.

Esegui il comando aws configure e inserire i due codici appena generati.

Ora sei pronti a iniziare la creazione, con Terraform, del cluster Kubernetes.

Let’s get started!

Due note importanti:

  1. Seguendo questo processo probabilmente dovrai mettere in conto di pagare qualche Euro dato che Amazon EKS non è un servizio gratuito.
  2. Esistono dei moduli già fatti di AWS o Azure, tuttavia ne sconsiglio l’utilizzo perché spesso non sono aggiornati. Inoltre, il controllo di componenti installare e quali no risulta faticoso.

1. Creazione del progetto

Crea un progetto vuoto, al suo interno la cartella modules e la sottocartella eks. All’interno di modules andranno i vari “pezzi” del cloud che servono al nostro scopo.

Posizionati nella root del progetto e crea tre file:

  • providers.tf: le dichiarazioni dei provider ovvero i plugin che fanno da ponte fra Terraform e il cloud provider, nel caso AWS.
  • variables.tf: il file contiene, senza troppe sorprese, le variabili che puoi utilizzare nel codice.
  • main.tf: le risorse da installare, in questo punto scriverai solo le dichiarazioni dei moduli da importare.

Screenshot dell'alberatura del progetto Terraform

2. Il file providers.tf

Scriviamo il seguente codice all’interno del file providers.tf.

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.5.0"
    }
  }
}

provider "aws" {
  region = var.aws_region
}

3. Il file variables.tf

Inserisci la variabile che rappresenta la region (cambiala come meglio reputi opportuno).

variable "aws_region" {
    default = "eu-south-1"
}

Volendo, si può aggiungere la variabile che contiene il nome del cluster.

variable "cluster_name" {
  default = "demo-eks-cluster"
}

4. Il file main.tf

All’interno di questo file invece si configura il modulo di EKS che conterrà tutto quello che serve per far partire l’installazione del cluster.

module "eks" {
  source = "./modules/eks"
}

Ma non solo.

Con il seguente pezzo di codice definisci le availability zone della region specificata, per questo esempio eu-south-milan-1a, eu-south-milan-1b ecc.

data "aws_availability_zones" "available" {
  filter {
    name   = "opt-in-status"
    values = ["opt-in-not-required"]
  }
}

Ora invece aggiungi il VPC (Virtual Private Cloud); il cidr_block deve essere un intervallo privato, si può scegliere la maschera di subnet.

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

Utilizza il seguente blocco per creare le subnet; il codice cicla sulle availability zone e come indirizzi ip (cidr_block) fornisce 256 indirizzi per ogni availability zone, così da avere indirizzi unici.

resource "aws_subnet" "eks_subnet" {
  count = 2
  vpc_id = aws_vpc.main.id
  cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index)
  availability_zone = data.aws_availability_zones.available.names[count.index]
  map_public_ip_on_launch = true
}
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.eks_vpc.id
}

Inserisci poi il seguente codice per creare un gateway e una tabella di routing. Ciò permette al cluster (in realtà a qualunque risorsa dentro la vpc appena creata) di accedere a Internet, e l’ultima risorsa associa la tabella di routing alle subnet.

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }
}
resource "aws_route_table_association" "route_table" {
  count = 2
  subnet_id = aws_subnet.public_subnet.*.id[count.index]
  route_table_id = aws_route_table.public.id
}

Per gestire i ruoli dei cluster che hanno accesso sia a EKS che EC2 (i nodi del cluster sono delle macchine EC2), inserisci i seguenti blocchi di codice.

resource "aws_iam_role" "cluster" {
  name = "${var.cluster_name}-iam-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "sts:AssumeRole",
          "sts:TagSession"
        ]
        Effect = "Allow"
        Principal = {
          Service = "eks.amazonaws.com"
        }
      },
    ]
  })
}
resource "aws_iam_role" "node_group" {
  name = "${var.cluster_name}-iam-role-ng"
  assume_role_policy = jsonencode({
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {
          "Service": "ec2.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
      }
    ]
  })
}

5. Creazione del cluster

Con il seguente blocco di codice crei il cluster.

resource "aws_eks_cluster" "cluster" {
  name = var.cluster_name

  access_config {
    authentication_mode = "API"
  }

  role_arn = aws_iam_role.cluster.arn
  version  = "1.33"
  remote_network_config {
    remote_node_networks {
      cidrs = ["172.16.0.0/18"]
    }
    remote_pod_networks {
      cidrs = ["172.16.64.0/18"]
    }
 }

 vpc_config {
  endpoint_private_access = true
  endpoint_public_access  = true
  subnet_ids = aws_subnet.public_subnet.*.id
  }
depends_on = [aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy]
}

In questo passaggio viene creato il cluster specificando una versione precisa. Se la riga corrispondente viene rimossa, AWS provvederà a installare automaticamente la versione di default. Inoltre, vengono associati il ruolo, la VPC e le relative policy.

Questo step sarà con ogni probabilità il più lungo dell’intero processo di creazione.

resource "aws_eks_node_group" "node_group" {
  cluster_name = aws_eks_cluster.cluster.name
  node_group_name = "${var.cluster_name}-ng"

  node_role_arn   = aws_iam_role.node_group.arn
  subnet_ids      = aws_subnet.public_subnet.*.id

  scaling_config {
    desired_size = 1
    max_size = 2
    min_size = 1
  }

  update_config {
    max_unavailable = 1
  }

  depends_on = [
    aws_iam_role_policy_attachment.node_AmazonEKSWorkerNodePolicy,
    aws_iam_role_policy_attachment.node_AmazonEC2ContainerRegistryReadOnly,
    aws_iam_role_policy_attachment.node_AmazonEKS_CNI_Policy,
  ]
}

Questo blocco di codice serve a creare il node group collegato al nostro cluster, associandogli la subnet definita in precedenza. Il cluster sarà inizializzato con un solo nodo.

Siamo quasi alla fine!
L’unico elemento mancante riguarda i policy attachment, ovvero i collegamenti tra i ruoli e le policy di AWS.

resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSClusterPolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
  role  = aws_iam_role.cluster.name
}

resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSNetworkingPolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSNetworkingPolicy"
  role  = aws_iam_role.cluster.name
}

resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSLoadBalancingPolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSLoadBalancingPolicy"
  role = aws_iam_role.cluster.name
}

resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSComputePolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSComputePolicy"
  role  = aws_iam_role.cluster.name
}

resource "aws_iam_role_policy_attachment" "node_AmazonEC2ContainerRegistryReadOnly" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
  role = aws_iam_role.node_group.name
}

resource "aws_iam_role_policy_attachment" "node_AmazonEKSWorkerNodePolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
  role = aws_iam_role.node_group.name
}

resource "aws_iam_role_policy_attachment" "node_AmazonEKS_CNI_Policy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
  role = aws_iam_role.node_group.name
}

Alcune spiegazioni sulle configurazioni

Ti fornisco delle brevi spiegazioni per chiarire il motivo di tutte queste configurazioni. Esse sono necessarie affinché il control plane di EKS possa funzionare correttamente.

  1. AmazonEKSClusterPolicy
    • Permette al servizio EKS di creare e gestire le risorse necessarie al cluster.
    • Include permessi per interagire con EC2, IAM, ELB e altre risorse legate al cluster.
    • Senza questa policy, EKS non potrebbe orchestrare i nodi.
  2. AmazonEKSNetworkingPolicy
    • Permette al control plane di gestire le risorse di rete (VPC, subnet, ENI, Security Group).
    • Serve per garantire la comunicazione tra pod, nodi e il piano di controllo.
  3. AmazonEKSLoadBalancingPolicy
    • Dà ad EKS i permessi per interagire con i bilanciatori di carico AWS (ALB/NLB/CLB).
    • Necessaria quando usi LoadBalancer Service in Kubernetes per esporre le app.
  4. AmazonEKSComputePolicy
    • Permette ad EKS di gestire la parte di compute: scaling dei nodi, interazione con Auto Scaling Groups e risorse EC2.

Queste servono ai worker node (EC2) per operare nel cluster:

  1. AmazonEC2ContainerRegistryReadOnly
    • Permette ai nodi di scaricare immagini da Amazon ECR.
    • Essenziale se i tuoi pod usano container salvati su ECR.
  2. AmazonEKSWorkerNodePolicy
    • Consente ai nodi di comunicare con il control plane EKS.
    • Dà i permessi minimi ai worker per fare parte del cluster (join, heartbeat, registrazione, ecc.).
  3. AmazonEKS_CNI_Policy
    • Necessaria per il CNI plugin di EKS (Amazon VPC CNI).
    • Permette ai pod di ottenere indirizzi IP dal VPC e di configurare la rete (creare/modificare ENI, assegnare IP secondari).

Avviare il cluster con Terraform

Con il progetto e i file che hai creato sei pronto per eseguire il tutto. Esegui quindi il comando terraform init che serve a scaricare i provider plugin e a creare le varie risorse.

Digitando terraform plan hai informazioni sulle operazioni che farà Terraform.

Per installare il tutto, scrivi terraform apply (alla domanda “sei sicuro di proseguire”, rispondi “yes”).

[Come ho scritto all’inizio di questo articolo, ti ricordo che questa operazione non è gratuita.]

Attendi un po’ (il tutto può richiedere fino a 30 minuti), dopodiché avrai il tuo cluster diponibile e consultabile dall’interfaccia di AWS.

Screenshot di una parte della schermata di AWS che contiene la lista dei cluster.

Screenshot di una parte della schermata di AWS che mostra il gruppo di nodi.

Non rimane che connetterti!

Ti lascio un ultimo ma non meno importante comando: terraform destroy, che ti permette di rimuovere il cluster con tutti i suoi elementi (anche in questo caso, dovrai rispondere affermativamente per proseguire nell’operazione).

Conclusioni

Con questo primo articolo hai imparato come realizzare un cluster Kubernetes utilizzandoTerraform. Nel prossimo episodio ti mosterò come installare, da riga di comando, alcuni tool utili direttamente dentro il cluster e… molto altro!

Articolo scritto da