1. Introduzione ad Atlas

atlas

Atlas è uno strumento indipendente dal linguaggio progettato specificamente per gestire e migrare schemi di database utilizzando i moderni principi DevOps. Fornisce due opzioni di flusso di lavoro:

  • Dichiarativo: Simile a Terraform, Atlas confronta lo stato attuale del database con lo stato desiderato definito utilizzando HCL, SQL o ORM schema. Sulla base di questo confronto, genera ed esegue un piano di migrazione per trasferire il database al suo stato desiderato.
  • Versionato: A differenza di altri strumenti, Atlas pianifica automaticamente le migrazioni dello schema per te. Gli utenti possono descrivere lo schema del database desiderato utilizzando HCL, SQL o il proprio ORM scelto e, con Atlas, pianificare, esaminare e applicare le migrazioni necessarie al database.

Un vantaggio chiave di Atlas è la sua semplificazione della complessità della gestione del database, rendendolo facile per il controllo delle versioni, la collaborazione e l'implementazione.

2. Installazione di Atlas

Prima di utilizzare Atlas per gestire le versioni del database, è necessario installarlo. Di seguito sono riportati i passaggi di installazione per piattaforme diverse.

2.1 Installazione macOS + Linux

Sui sistemi macOS o Linux, è possibile scaricare e installare l'ultima versione di Atlas utilizzando il seguente comando da riga di comando:

curl -sSf https://atlasgo.sh | sh

Questo comando rileverà automaticamente la versione del sistema operativo, scaricherà la versione idonea e posizionerà il file binario di Atlas nel percorso eseguibile.

2.2 Installazione tramite Homebrew

Se si sta utilizzando macOS e si è già installato il gestore di pacchetti Homebrew, l'installazione di Atlas è semplice come l'esecuzione del comando:

brew install ariga/tap/atlas

Questo recupererà l'ultima versione di Atlas dal repository Homebrew e l'installerà.

2.3 Installazione tramite Docker

L'installazione e l'esecuzione di Atlas tramite Docker è un metodo rapido e conveniente, specialmente per test temporanei o per utenti che preferiscono non installare software aggiuntivo sul proprio sistema host.

Prima, recuperare l'immagine Docker di Atlas:

docker pull arigaio/atlas

Poi, è possibile eseguire un comando di aiuto per confermare un'installazione riuscita:

docker run --rm arigaio/atlas --help

Se il contenitore ha bisogno di accedere alla rete host o alle directory locali, utilizzare il flag --net=host e montare le directory richieste:

docker run --rm --net=host \
  -v $(pwd)/migrations:/migrations \
  arigaio/atlas migrate apply \
  --url "mysql://root:pass@:3306/test"

2.4 Installazione Windows

Scaricare il file binario, https://release.ariga.io/atlas/atlas-windows-amd64-latest.exe, e aggiungere il percorso di installazione alla variabile di ambiente PATH del sistema.

3. Esportare la Struttura della Tabella del Database Esistente Utilizzando Atlas

Atlas fornisce il comando atlas schema inspect, che può essere usato per esportare la struttura di un database esistente. Questo comando supporta la lettura delle descrizioni del database dall'URL del database e le restituisce in tre diversi formati: il formato predefinito Atlas HCL, il formato SQL e il formato JSON. In questa guida, mostreremo come utilizzare i formati Atlas HCL e SQL, in quanto il formato JSON è tipicamente utilizzato per elaborare l'output con jq.

Per ispezionare un'istanza MySQL in esecuzione in locale e scrivere l'output in un file chiamato schema.hcl, utilizzare il seguente comando:

atlas schema inspect -u "mysql://root:pass@localhost:3306/example" > schema.hcl

Aprire il file schema.hcl per visualizzare la definizione della struttura della tabella Atlas che descrive il database (HCL è un formato di configurazione della struttura delle tabelle indipendente dal database definito da Atlas). Ad esempio, questo file conterrà il seguente contenuto:

table "users" {
  schema = schema.example
  column "id" {
    null = false
    type = int
  }
  column "name" {
    null = true
    type = varchar(100)
  }
  primary_key {
    columns = [column.id]
  }
}

Questo blocco di codice rappresenta una struttura tabellare con colonne id e name. Il campo schema fa riferimento alla definizione del modello example definito altrove in questo documento. Inoltre, il sotto-blocco primary_key specifica la colonna id come chiave primaria per la tabella. Atlas si sforza di mimare la sintassi del database su cui si sta operando. In questo esempio, la colonna id ha un tipo int, mentre la colonna name ha un tipo varchar(100).

Analogamente, per esportare una definizione del modello SQL del database, è possibile utilizzare il seguente comando:

atlas schema inspect -u "mysql://root:pass@localhost:3306/example" --format '{{ sql . }}' > schema.sql

Aprire il file schema.sql per visualizzare la descrizione SQL del database, contenente tipicamente alcune istruzioni CREATE TABLE.

Questo approccio semplifica la comprensione dei dettagli della struttura della tabella del database esistente e fornisce un riferimento accurato per le migrazioni versionate successive.

4.1 Workflow Dichiarativo

Il Workflow Dichiarativo di Atlas consente agli utenti di definire in modo dichiarativo lo stato finale desiderato del database. Gli utenti devono solo descrivere quale dovrebbe essere lo stato finale dello schema del database, e lo strumento Atlas genererà ed eseguirà automaticamente piani di migrazione per passare in modo sicuro lo schema del database dallo stato attuale a questo stato atteso.

Di seguito è riportato come utilizzare il Workflow Dichiarativo per definire e raggiungere lo stato desiderato del database:

4.1.1 Definizione della Struttura della Tabella di Destinazione

Prima di tutto, è necessario creare un file che definisca la struttura del database prevista, che può essere in formato HCL, SQL o ORM (Object-Relational Mapping).

Prendendo come esempio il formato HCL, definire una nuova tabella blog_posts:

table "blog_posts" {
  schema = schema.example
  column "id" {
    null = false
    type = int
  }
  column "title" {
    null = true
    type = varchar(100)
  }
  column "body" {
    null = true
    type = text
  }
  column "author_id" {
    null = true
    type = int
  }
  primary_key {
    columns = [column.id]
  }
  foreign_key "author_fk" {
    columns     = [column.author_id]
    ref_columns = [table.users.column.id]
  }
}

Suggerimento: Il formato sintattico di HCL verrà trattato in una sezione successiva.

4.1.2 Eseguire la Migrazione Utilizzando lo Strumento Atlas

Una volta completata la definizione della struttura della tabella del database, è possibile utilizzare il comando schema apply di Atlas per eseguire la migrazione.

atlas schema apply \
  -u "mysql://root:pass@localhost:3306/example" \
  --to file://schema.hcl

Dopo aver eseguito il comando sopra, Atlas confronterà lo schema del database esistente con lo schema definito nel file, genererà un piano di migrazione e chiederà all'utente di confermare l'esecuzione. Una volta confermato il piano di esecuzione, Atlas eseguirà la migrazione sul database e lo aggiornerà allo stato desiderato.

4.2 Workflow Versionato

Il Workflow Versionato è un altro modo di utilizzo supportato da Atlas, talvolta chiamato "migrazione basata su modifiche". È adatto per scenari in cui le modifiche dello schema del database devono essere controllate in base alla versione e valutate nel processo di revisione del codice.

I passaggi del workflow versionato includono:

4.2.1 Calcola le Differenze

Prima di iniziare la migrazione, è necessario confrontare la struttura del database attuale con lo stato desiderato e determinare le differenze tra i due. Questo può essere fatto eseguendo il comando atlas migrate diff.

atlas migrate diff create_blog_posts \
  --dir "file://migrations" \
  --to "file://schema.hcl" \
  --dev-url "docker://mysql/8/example"

Il parametro --dir specifica l'URL della cartella di migrazione, predefinito a file://migrations. Il parametro --to specifica l'URL dello stato desiderato (ad esempio, il database dell'ambiente di sviluppo), e --dev-url fornisce un URL per un database di sviluppo utilizzato per calcolare le differenze (nota che questo --dev-url deve specificare un database vuoto che Atlas utilizza per calcolare le differenze).

Suggerimento: Se si desidera generare file SQL, fare riferimento alla sezione precedente per impostare il formato utilizzando il parametro --format.

4.2.2 Applica le Modifiche della Migrazione

Dopo che il calcolo delle differenze è completato, Atlas genererà due file di migrazione salvati nella cartella migrations. Ad esempio, se il formato selezionato è SQL, i file generati dal comando diff, come il seguente file SQL, contengono comandi di migrazione per creare una nuova tabella:

-- crea la tabella "blog_posts"
CREATE TABLE `blog_posts` (
  `id` int NOT NULL,
  `title` varchar(100) DEFAULT NULL,
  `body` text DEFAULT NULL,
  `author_id` int NULL REFERENCES `users`(id),
  PRIMARY KEY (`id`)
);

Una volta generati i file di migrazione, è possibile utilizzare strumenti di controllo della versione (ad esempio, Git) per gestire queste modifiche. Questo approccio consente di apportare numerose modifiche alla struttura della tabella del database nell'ambiente di sviluppo e, quando è il momento di rilasciare, confrontare l'ambiente di sviluppo e l'ambiente UAT utilizzando i comandi di Atlas per generare i file di migrazione della struttura della tabella del database. Questi file di migrazione possono poi essere applicati agli ambienti UAT e di produzione per aggiornare il database.

Questi due flussi di lavoro, Dichiarativo e Versionato, offrono flessibilità per diversi modalità di sviluppo e distribuzione, consentendo ai team di scegliere il metodo che meglio si adatta alle esigenze del progetto per gestire le modifiche dello schema del database.

5. Descrizione del Formato HCL

5.1 Introduzione

HCL è un linguaggio dichiarativo utilizzato per descrivere le definizioni della struttura della tabella del database. Atlas utilizza il formato HCL per scrivere gli schemi del database, fornendo una struttura ricca per descrivere diversi aspetti del database. Il vantaggio di HCL risiede nella sua leggibilità, facilità di manutenzione e supporto per funzionalità come l'iniezione di variabili e annotazioni aggiuntive.

Suggerimento: Se il tuo progetto deve adattarsi a più database, descrivere le strutture delle tabelle in modo indipendente dal database utilizzando HCL può essere molto conveniente.

5.2 Oggetto schema

L'oggetto schema è utilizzato per descrivere uno schema del database. In MySQL e SQLite, rappresenta il DATABASE, mentre in PostgreSQL rappresenta lo SCHEMA. Un file HCL può contenere uno o più oggetti schema.

schema "public" {
  comment = "Un commento dello schema"
}

schema "private" {}

5.3 Oggetto table

L'oggetto table è utilizzato per descrivere una tabella in un database SQL, inclusi colonne, indici, vincoli e varie proprietà aggiuntive supportate da diversi driver di database.

table "users" {
  schema = schema.public
  column "id" {
    type = int
  }
  column "name" {
    type = varchar(255)
  }
  column "manager_id" {
    type = int
  }
  primary_key {
    columns = [
      column.id
    ]
  }
  index "idx_name" {
    columns = [
      column.name
    ]
    unique = true
  }
  foreign_key "manager_fk" {
    columns     = [column.manager_id]
    ref_columns = [table.users.column.id]
    on_delete   = CASCADE
    on_update   = NO_ACTION
  }
}

5.4 Oggetto column

La column è una sotto-risorsa di table utilizzata per definire le colonne nella tabella.

column "name" {
  type = text
  null = false
}

column "age" {
  type = integer
  default = 42
}

column "active" {
  type = tinyint(1)
  default = true
}

5.5 Oggetto primary_key

Il primary_key è una sotto risorsa di table che definisce la chiave primaria della tabella.

primary_key {
  columns = [column.id]
}

5.6 Oggetto foreign_key

Il foreign_key è una sotto risorsa di table che definisce le colonne che fanno riferimento alle colonne in altre tabelle.

table "orders" {
  schema = schema.market
  // ...
  column "owner_id" {
    type = integer
  }
  foreign_key "owner_id" {
    columns     = [column.owner_id]
    ref_columns = [table.users.column.id]
    on_update   = NO_ACTION
    on_delete   = NO_ACTION
  }
}

5.7 Oggetto index

L'oggetto index rappresenta un indice sulla tabella.

index "idx_name" {
  columns = [
    column.name
  ]
  unique = true
}