Restore di un database SQL Server in un container Docker

Qualche giorno fa un collega aveva la necessità di eseguire il restore di un database creato con Microsoft SQL Server 2016 in locale, in modo da poter eseguire la creazione di una dashboard in PowerBI.
La nostra scelta di team - ormai da anni - è stata quella di installare sui nostri computer meno strumenti possibili, e solo quelli essenziali per portare avanti il lavoro quotidiano. Meno strumenti su un computer = meno spazio disco consumato = più risorse disponibili; quindi la scelta è sempre quella di appoggiarci a risorse ospitate in cloud.
In questo caso lo scenario era più complesso, e il semplice restore del nostro backup di database nel cloud, non sembrava essere la soluzione più performante, specialmente per via dell'obiettivo che avevamo - ovvero un' analisi dei dati - in un ambiente di sviluppo.
Quindi quello che ho cercato di fare è semplicemente prendere il backup in questione - che nel nostro esempio sarà il file test.bak - e fare il suo restore in un container Docker equipaggiato con Microsoft SQL Server 2019, che gira un kernel Ubuntu versione 16.04.
Il container da cui partiremo è disponibile su Docker Hub, nello specifico alla pagina https://hub.docker.com/_/microsoft-mssql-server. Nonostante ci siano sempre versioni aggiornate, la mia scelta è stata quella di usare la "2019-GA".
Usando Powershell (o la commanline che preferite) eseguiamo prima di tutto lo scaricamento del container in questione, impostando la password amministrativa che sarà poi utilizzata anche per le operazioni di ripristino del backup dei dati:
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=YourP@ssw0rd" ` --name "mssql1" -p 1401:1433 ` -d mcr.microsoft.com/mssql/server:2019-GA-ubuntu-16.04
Attenzione! E' molto importante che non sia specificato alcun volume esterno nel momento in cui si avvia il container. In caso contrario, il vostro container finale non sarà "auto-consistente".
Se non avete ancora in locale l'immagine di SQL Server, dovreste avere un output di questo tipo:
Unable to find image 'mcr.microsoft.com/mssql/server:2019-GA-ubuntu-16.04' locally 2019-GA-ubuntu-16.04: Pulling from mssql/server 59ab41dd721a: Pull complete 57da90bec92c: Pull complete 06fe57530625: Pull complete 5a6315cba1ff: Pull complete 739f58768b3f: Pull complete fd449e8d7345: Pull complete 51d0933375e5: Pull complete 64f21ba81504: Pull complete 55b6919c0cc6: Pull complete Digest: sha256:c8fa22553ce421b0482febcafa712b29cbb933b0d97a8671686797b31cf157a9 Status: Downloaded newer image for mcr.microsoft.com/mssql/server:2019-GA-ubuntu-16.04 89e348fd2d5eafdce27d55bea8eacc0d01a21923b6f4b0a6bfc9a52323434efd
A questo punto, verefichiamo che il container sia "up & running" (abbreviato)...
CONTAINER ID IMAGE ... CREATED STATUS 89e348fd2d5e mcr.microsoft.c... 6 minutes ago Up 6 minutes
Usando SQL Server Management Studio (liberamente scaricabile da questo link https://aka.ms/ssmsfullsetup ), bisogna verificare se l'istanza di SQL Server che gira nel container Docker è effettivamente raggiungibile dal nostro host. Ricordiamoci che in fase di avvio, abbiamo rimappato la porta standard di SQL Server 1433 (esposta all'interno del container) con la porta della macchina locale 1401. Quindi i dati per accedere sono i seguenti:

A questo punto è necessario passare nuovamente a Powershell per eseguire il ripristino del file backup, che nel mio caso ho posizionato sotto in E:\mssql-backup\test.bak.
Il seguente comando avvia la creazione della cartella di destinazione (/var/opt/mssql/backup) dove sarà copiato il file di backup, all'interno del container Docker in esecuzione (denominato mssql1):
docker exec -it mssql1 mkdir /var/opt/mssql/backup
A seguire, avviamo la copia del file sorgente (E:\mssql-backup\test.bak) nel container mssql1, sotto la cartella appena creata (/var/opt/mssql/backup):
docker cp E:\mssql-backup\test.bak mssql1:/var/opt/mssql/backup
NOTA: la copia del file di backup nel container può richiedere più o meno tempo a seconda della dimensione del file. Durante la copia non sarà visualizzato nessun feedback, quindi armatevi di pazienza e attendete ;).
Una volta terminata la copia, dobbiamo semplicemente ripristinare il database dal file appena copiato nel server in esecuzione in Docker. Questa operazione si può fare alla "vecchia maniera", direttamente da SQL Management Studio:
  • tasto destro sulla cartella "Database"
  • selezione "Restore database"
  • selezione dell'opzione "Device"
  • scelta delle opzioni aggiuntive (pulsante "...")
  • selezione del file sorgente dalla cartella che lo contiene (nel nostro caso /var/opt/mssql/backup) e pressione del pulsante "refresh"
  • selezione del file test.bak e conferma
  • pressione del pulsante "Ok" per confermare il ripristino


Oppure, possiamo fare la stessa cosa usando la linea di comando:
docker exec -it mssql1 /opt/mssql-tools/bin/sqlcmd ` -S localhost -U SA -P "YourP@ssw0rd" ` -Q "RESTORE DATABASE NuovoTest FROM DISK = '/var/opt/mssql/backup/test.bak' ` WITH MOVE 'test' TO '/var/opt/mssql/data/NuovoTest.mdf', ` MOVE 'test_Log' TO '/var/opt/mssql/data/NuovoTest.ldf'"
Fate attenzione alle denominazione dei file e alias he userete per i ripristino; se il nome del database target finale (NuovoTest) e per i nomi dei corrispondenti files su disco (nel nostro caso .../NuovoTest.mdf e .../NuovoTest.ldf), è tutto puramente a vostra discrezione, per i nomi logici dei file sorgenti, non è così, e dovete rispettare quello che è contenuto nel backup: test e test_Log.
Ma se è andato tutto bene, dovreste avere il database perfettamente funzionante ed attivo. Lo potete facilmente verificare anche questa volta da SQL Management:

Bonus feature, esportazione di una immagine del container

Una volta che avete ripristinato in locale il vostro ambiente, se volete condividerlo con un collega - oppure semplicemente averne un backup locale, sempre pronto in caso di danno accidentale - è possibile creare una immagine Docker partendo dal container in esecuzione, contenente database e relativi dati.
Prima di tutto eseguiamo una operazione di commit, in modo che venga fatta una foto del container al momento dell'esecuzione del comando.
docker commit -p mssql1 my-mssql-with-db
Il comando prevede l'indicazione del container da cui partire per creare l'immagine, che nel nostro caso è mssql1, e il nome dell'immagine finale my-mssql-with-db.
Per verificare che l'immagine sia stata effettivamente geneata, utilizziamo il solito comando di inspection delle immagini docker:
docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-mssql-with-db latest 7b30daab90a7 4 seconds ago 1.57GB mcr.microsoft.com/mssql/server 2019-GA-ubuntu-16.04 76c7c66bff02 6 months ago 1.57GB
Se l'immagine my-mssql-with-db è presente, possiamo procedere con una esportazione del backup della stessa su disco locale, in un file Tarball .tar:
docker save -o my-mssql-with-db.tar my-mssql-with-db
Anche in questo caso, l'operazione di backup richiede molta pazienza; il file finale è infatti comprensivo sia dell'immagine originale di Microsoft SQL Server su container Ubuntu, sia delle nostre configurazioni, sia del database applicativo che abbiamo inserito nel container stesso.

Ripristino del container da file Tarball

Che significato ha fare un backup di una immagine, se non possiamo ripristinarla? Anche in questo caso è tutto molto semplice:
docker load -i E:\mssql-backup\my-mssql-with-db.tar
Al termine del ripristino, usando il solito docker images dovreste riuscire a vedere l'immagine my-mssql-with-db presente tra le immagini disponibili in locale per la creazione di nuovi container. Procediamo quindi all'avvio del container partendo dalla stessa immagine:
docker run --name "mssql1" -p 1401:1433 -d my-mssql-with-db
Chiudo con un'ultima nota, molto importante. In fase di generazione del primo container che contiene Microsoft SQL Server ("pulito", senza nessuna modifica) è importantissimo non specificare nessun volume esterno al container. Se questa cosa dovesse accedere, in fase di "backup" del container e generazione della sua immagine, i dati non saranno inclusi nel file Tarball. Evitando invece di specificare il volume, tutto quanto - funzioni applicative + dati - saranno inclusi in un unico pacchetto, rendendolo quindi esportabile e ripristinabile anche su macchine diverse da quella dove è stato creato.
Buon divertimento con Docker!
M.

Commenti

Post popolari in questo blog

Cancellazione fisica vs cancellazione logica dei dati

Code Coverage su .NET Core con Coverlet e ReportGenerator

RESTful Stress: misurare le performance di un servizio REST