Overview e motivazione
Il lavoro di sviluppo intende affrontare alcune necessità comuni nella organizzazione di laboratori informatici o computazionali:
- gli studenti devono poter utilizzare le risorse di Ateneo, i.e. gli strumenti devono essere disponibili nelle aule informatiche riducendo pero il carico di lavoro del personale di assistenza alle aule (installazione e test di nuovi strumenti);
- gli strumenti dovrebbero essere accessibili agli studenti anche da casa e/o sui loro computers per esigenze di studio ed esercitazione individuale;
- gli ambienti di lavoro potrebbero essere utilizzati su servizi disponibili al pubblico gratuitamente o in abbonamento;
- gli ambienti di lavoro devono essere utilizzati per eventuali esercitazione di esame;
- gli ambienti di lavoro possono essere eseguiti sul Cloud, ed idealmente accessibili solamente tramite un browser, riducendo cosi la pressione sulle aule informatiche che hanno posti limitati e non possono sempre servire le crescenti esigenze di laboratori computazionali.
Portabilità e scalabilità sono quindi caratteristiche essenziali della scelta da effettuare.
La soluzione qui descritta utilizza l’ambiente di containerizzazione Docker, che rappresenta una scelta ideale per i seguenti motivi:
- puo essere eseguito su qualsiasi piattaforma individuale, consentendo sia a docente che studente di installare l’applicativo sul proprio computer e sviluppare o far correre un ambiente di lavoro;
- puo essere eseguito sui desktop delle aule informatiche, utilizzando podman (soluzione rootless sicura in ambienti di rete);
- puo essere eseguito nel cloud;
- puo essere aggiornato in modo molto agile e in corso d’opera se necessario, aggiornando l’immagine nel registro pubblico;
- build e pubblicazione possono essere automatizzati tramite GitHub Actions.
Strumenti utilizzati
Docker
Docker puo essere scaricato su qualsiasi piattaforma e usato per costruire containers dotati di numerosi strumenti.
Nel mio caso, ho preferito costruire containers che esponessero dei servizi via web, in modo da rendere gli strumenti accessibili tramite browser.
VSCode Server
Usando ad esempio VScode Server, una implementazione di Visual Studio Code via web, si puo dare accesso sia ad un editor che ad un terminale tramite browser e da qui le possibilita sono infinite: tramite il terminale, il container puo mettere a disposizione il piu ampio ventaglio di strumenti disponibili in ambiente unix.
Terraform
Terraform è uno strumento di gestione di infrastrutture cloud, agnostico rispetto al provider dei servizi. È spesso definito infrastructure-as-a-code perché consente usando dei file strutturati in formato JSON di descrivere le infrastrutture che si vogliono creare, e con pochi comandi costruire, avviare, monitorare e distruggere tutte queste infrastrutture e i servizi loro associati senza rischio di lasciare elementi in funzione che consumano costi e risorse.
Tramite Terraform si possono avviare un numero flessibile di strumenti contemporaneamente, e spegnerli tutti assieme quando non servono piu, come nel caso di laboratori virtuali.
Deployment
Per gestire l’infrastruttura con Terraform bisogna creare un file con estensione .tf e denominazione a piacere.
Nel file si indicherà il provider da utilizzare, come segue:
provider "aws" {
region = "eu-central-1" ## choose the region you want to run the VM on
}
Si indicherà il gruppo di sicurezza da creare (o eventualmente il nome di uno già) esistente, come segue:
resource "aws_security_group" "name_vm_security_group" {
name = "name_vm_security_group"
ingress { ## adjust this block according to needs
from_port = 8787
to_port = 8787
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Allowing traffic in from all sources
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
si possono stabilire numerose policy in ingress, ripetendo il blocco ingress piu volte.
Successivamnte si definisce la macchina virtuale, in questo caso utilizzando una AMI semplicissima che contiene una installazione di docker ma niente altro:
resource "aws_instance" "vmname" { ## choose the name of your VM
count = var.instance_count
ami = "ami-00ad5641b98c7c624" ## this is a bare minimal VM with docker installed
instance_type = var.instance_type
security_groups = ["${aws_security_group.name_vm_security_group.name}"] ## <- make sure name resources match
}
All’interno della risosa descritta sopra si puo anche inserire un blocco chiamato provisioner di tipo remote-exec, che consente di eseguire comandi in remoto sulla macchina appena creata.
Usando questa possibilità, si possono avviare uno o piu container docker sulla macchina virtuale e quindi consentire l’accesso ai loro servizi sulle porte aperte nella macchina
provisioner "remote-exec" { ## <- this is used to execute commands on your VM before releasing them
inline = [
"mkdir -p /home/ubuntu/exam", ## you can create folders
"docker run -d --name rstudio -p 0.0.0.0:8787:8787 -v /home/ubuntu/exam:/home/rstudio/datiesame -e DISABLE_AUTH=true ghcr.io/lescai-teaching/rstudio-docker-amd64:latest", ## <- run containers
"docker run -d --name vscode -p 0.0.0.0:8443:8443 -v /home/ubuntu/exam:/config/workspace/datiesame ghcr.io/lescai-teaching/vscode-docker-amd64:latest", ## <- as many as you need
"docker exec -it rstudio groupadd -g 911 dockershare" ## <- and also execute commands inside the container of choice
]
connection {
host = "${self.public_ip}"
type = "ssh"
user = "ubuntu"
private_key = "${file("####")}" ## <- here you need to specify the path to your private key
}
}
A questo punto per avviare l’infrastruttura (si presuppone che terraform sia installato e che le credenziali AWS siano state inizializzate), è sufficiente prima inizializzare la cartella
terraform init
Poi creare il piano:
terraform plan -out infrastructure.plan
E infine applicarlo: questo aprirà una comunicazione con AWS, creerà l’infrastruttura e comunicherà le informazioni richieste nel file outputs.tf
terraform apply infrastructure.plan
In particolare due files aggiuntivi, il cui nome è predefinito possono essere utilizzati:
- terraform.tfvars
instance_count = 1
instance_type = "t2.large"
questo file indica i parametri specificati come variabili nel codice principale e consente senza modificare il codice di adattare numero e tipo di istanze da avviare
- outputs.tf
questo file cattura le informazioni che vengono descritte nel file
output "instance_id" {
description = "ID of the EC2 instance"
value = ["${aws_instance.examvm.*.id}"]
}
output "instance_public_ip" {
description = "Public IP address of the EC2 instance"
value = ["${aws_instance.examvm.*.public_ip}"]
}
E le stampa a schermo ma anche in un file denominato terraform.tfstate: si tratta di un file JSON che puo essere processato per catturare gli outputs e utilizzarli, ad esempio, per inviare a ciascuno studente le credenziali della macchina a cui collegarsi.
Codice e Automazione
Il codice che puo essere utilizzato come template si trova in questo repository.
L’uso di GitHub Actions consente di automatizzare sia il build multipiattaforma che la pubblicazione dei containers usando Github. Un esempio di workflow si trova all’indirizzo del repository.