Un tuffo nel mondo dell’Infrastructure as Code. Introduzione a Terraform.

DevOps

12 Gennaio 2022


Condividi :

| |

Cos’è e quali sono i suoi punti di forza ed i suoi punti deboli.

Oggi parleremo di Terraform di HashiCorp.
Terraform è uno strumento molto interessante che consente di specificare l’infrastruttura di rete attraverso un linguaggio di alto livello.

Terraform permette di interagire con tutti i servizi cloud più rilevanti come Aws, Google Cloud Platform, Digital Ocean e Cloudflare. Tali integrazioni sono fornite da plugin che una volta installati permettono di interfacciarsi con il relativo provider.

Core

La vera forza di Terraform è nel sistema di gestione dell’infrastruttura.

Innanzi tutto poiché l’infrastruttura è definita con del codice questo può essere “versionato”. Il versioning rende facile la collaborazione tra i membri del team e riproducibile la creazione dell’infrastruttura, infatti per un membro del team è sufficiente ottenere il codice per poter riprodurre esattamente la stessa infrastruttura.

La creazione dell’infrastruttura è molto veloce ed efficiente. Terraform crea una grafo delle dipendenze tra i vari elementi dell’infrastruttura, ciò’ permette di avviare in parallelo la creazione di elementi indipendenti, abbreviando di molto i tempi di creazione e di modifiche.

In caso di modifiche Terraform è in grado di calcolare le differenze tra l’infrastruttura già deployata e quella modificata e di minimizzare il numero di modifiche da fare per aggiornare l’infrastruttura corrente.

Terraform mette a disposizione il linguaggio di configurazione HCL per dichiarare l’infrastruttura.
Eccone un piccolo esempio:

resource "aws_instance" "bastion" {
    ami           = "ami-007934628a8fcdec0" # Ubuntu Server 18.04 LTS (HVM), SSD Volume Type
    key_name        = "${aws_key_pair.bastion_key.key_name}"
    instance_type      = "t2.micro"
    vpc_security_group_ids = ["${aws_security_group.bastion-sg.id}"]
    subnet_id        = "${module.vpc.public_subnets.0}"
    associate_public_ip_address = true
    user_data        = "${data.template_file.userdata_bastion.rendered}"
    tags = {
    Name = "${var.environment}-bastion"
    Environment = "${var.environment}"
}

Similarmente ai linguaggi di programmazione, sono presenti variabili, costrutti logici e cicli, questi ultimi sono particolarmente utili in quanto permettono di generare parti del vostro sistema in poche istruzioni.

È possibile inoltre referenziare altre risorse dichiarate, permettendo di inizializzare nodi con il valori di altri nodi. La string interpolation inoltre e’ molto potente e sono presenti tutte le funzioni per poter fare tutto ciò che serve: regex matching, replace, lower/upper case etc.

La documentazione inoltre è scritta ragionevolmente bene, per ogni risorsa supportata vengono forniti anche degli esempi di utilizzo, spesso gli esempi forniti sono dotati di tutti i parametri che utilizzerai rendendoli particolarmente utili per cominciare.

Un vero punto di forza di Terraform e l’interprete in quanto è molto potente e gli errori che restituisce, nel 99% dei casi, sono molto descrittivi.

Downsides

Più che delle critiche qualche prospetto sul futuro.

Non me la sento in verità di muovere alcuna critica in quanto essendo solo alla versione 0.12 è ancora immaturo sotto alcuni aspetti. Più che delle critiche vorrei condividere con voi qualche prospetto sul futuro.

La prima cosa è che Terraform è molto promettente in quanto costituisce un livello di indirezione tra l’utente ed il cloud provider. Questo livello di indirezione è costituito dal linguaggio di configurazione HCL, e se sfruttato permette di rendere la creazione di infrastrutture di rete estremamente potente. Per fare qualche esempio molto specifico:

  • Terraform permette di specificare lo user_data quando si creano delle istanze ec2 ovvero uno script che viene fatto avviare dopo che la macchina è stata avviata. AWS non permette di specificare più di uno user script ma Terraform potrebbe tranquillamente fornire questa funzionalità magari concatenando i diversi script specificati nella configurazione. Ad essere completamente sinceri esiste un modo, ovvero specificando una risorsa cloudinit_config la quale permette di specificare un file configurazione potenzialmente composto da molti script. Il problema e’ che normalmente tali script scritti sotto forma di template, ovvero file ai quali puoi passare delle variabili che vengono sostituite nei punti specificati. Il problema e’ che le risorse cloudinit_config non permettono di passare le variabili sconfiggendo lo scopo dei template. Se non si vuole usare i template si e’ costretti a creare uno script apposito per ogni nodo (per esempio lavorando su un’infrastruttura con 35 istanze ec2, creare 35 script è infattibile)
  • Il costrutto if-then-else è presente solo sotto forma di ternary-if ovvero:
var.environment == "prod" ? do_prod_stuff : do_staging_stuff

E’ bello averlo ma non è sufficiente per implementtare logiche più’ complesse.

Un altro difetto è che nella documentazione non sono evidenziati molto bene i campi obbligatori e spesso sono sparsi, quindi a volte bisogna procedere per tentativi prima di passare il processo di validazione.

Major problem assenza di hook per i lifecycle delle risorse. Ad ora non esiste un modo per poter eseguire azioni arbitrarie durante la fase di creazione delle risorse. Per esempio, non esiste un modo per poter eseguire del codice quando e’ terminata la creazione di tutta l’infrastruttura.

Esempio reale: ora non è possibile creare automaticamente i record Route53 per le istanze ec2 che si dichiarano (chiaramente il problema puo’ essere aggirato ma bisogna ricorrere a delle soluzioni non ottimali). Per sopperire a tale mancanza si è costretti a delegare la creazione dei record ad uno script bash/python/whatever esterno da Terraform. Il problema nasce dal fatto che non esiste un hook chiamato da Terraform quando ha finito di creare la rete quindi le possibilità sono due, la prima lanciare due comandi, ma è molto scomodo, la seconda ricorrere per esempio a Terragrunt, un wrapper che tra le tante cose mette a disposizione degli hook per ogni comando di Terraform.

Mentre il terraform state può essere memorizzato in posti diversi come un bucket s3 oppure il Terraform Cloud rimane il fatto che non viene esposto all’esterno, script bash esterni non possono usufruire di tutte le info possedute da Terraform sulla propria struttura. Magari in un futuro verranno rilasciati qualche sdk per i linguaggi più popolari per potersi interfacciare con il remote state

Security tip: evitate di mettere in output le credenziali e i secrets, in quanto lo state file è in chiaro.

Conclusioni

Terraform e’ decisamente un tool ad integrare nel proprio ecosistema. I presupposti sono molti promettenti e le piccole mancanze, che verranno sicuramente colmate dal tempo, possono essere sempre e comunque aggirate.

La curva di apprendimento e’ piuttosto piatta, il linguaggio di Terraform e’ molto semplice e dopo pochi minuti si entra nella logica del “tutto e’ una resource”.

In The I ci piace molto scommettere sulle tecnologie innovative, ddifatti Terraform è il protagonista di svariati progetti con clienti importanti che presentano infrastrutture cloud composte da molteplici risorse e servizi. In entrambi i casi siamo stati estremamente soddisfatti, Terraform si è dimostrato essere uno strumento affidabile ed adatto a coprire la maggior parte dei casi d’uso, inoltre ci ha permesso di ridurre notevolmente i tempi di sviluppo ed i team di sviluppo delle due aziende ora sono in grado di riprodurre l’ambiente di production con un click.


Ciao a tutti io sono Alberto, lavoro per The I e sono un DevOps Engineer. Il mio lavoro consiste principalmente nel progettare processi di deployment che si inseriscono nel processi già attivi dei nostri client in modo da rendere efficienti i processi che portano il codice in produzione.