Come abbiamo visto nella prima parte di questo blog, un cluster di database fortemente coerente come Galera non funziona bene con strumenti di orchestrazione di container come Kubernetes o Swarm. Ti abbiamo mostrato come distribuire Galera e configurare la gestione dei processi per Docker, in modo da mantenere il pieno controllo del comportamento. Questo post sul blog ne è la continuazione, esamineremo il funzionamento e la manutenzione del cluster.
Per ricapitolare alcuni dei punti principali della parte 1 di questo blog, abbiamo distribuito un cluster Galera a tre nodi, con ProxySQL e Keepalived su tre diversi host Docker, in cui tutte le istanze MariaDB vengono eseguite come contenitori Docker. Il diagramma seguente illustra la distribuzione finale:
Chiusura Graziosa
Per eseguire un corretto arresto di MySQL, il modo migliore è inviare SIGTERM (segnale 15) al container:
$ docker kill -s 15 {db_container_name}
Se desideri arrestare il cluster, ripeti il comando precedente su tutti i contenitori di database, un nodo alla volta. Quanto sopra è simile all'esecuzione di "systemctl stop mysql" nel servizio systemd per MariaDB. L'uso del comando "docker stop" è piuttosto rischioso per il servizio database perché attende un timeout di 10 secondi e Docker forzerà SIGKILL se questa durata viene superata (a meno che non si utilizzi un --timeout corretto valore).
L'ultimo nodo che si chiude in modo regolare avrà il seqno diverso da -1 e safe_to_bootstrap flag è impostato su 1 in /{datadir volume}/grastate.dat dell'host Docker, ad esempio su host2:
$ cat /containers/mariadb2/datadir/grastate.dat
# GALERA saved state
version: 2.1
uuid: e70b7437-645f-11e8-9f44-5b204e58220b
seqno: 7099
safe_to_bootstrap: 1
Rilevamento del nodo più avanzato
Se il cluster non si è spento correttamente o il nodo che stavi tentando di avviare non è stato l'ultimo nodo a lasciare il cluster, probabilmente non saresti in grado di avviare uno dei nodi Galera e potresti riscontrare il seguente errore :
2016-11-07 01:49:19 5572 [ERROR] WSREP: It may not be safe to bootstrap the cluster from this node.
It was not the last one to leave the cluster and may not contain all the updates.
To force cluster bootstrap with this node, edit the grastate.dat file manually and set safe_to_bootstrap to 1 .
Galera onora il nodo che ha safe_to_bootstrap flag impostato su 1 come primo nodo di riferimento. Questo è il modo più sicuro per evitare la perdita di dati e garantire che il nodo corretto venga sempre avviato.
Se hai ricevuto l'errore, dobbiamo prima scoprire il nodo più avanzato prima di prendere il nodo come primo a essere avviato. Crea un contenitore transitorio (con --rm flag), mappalo alla stessa datadir e directory di configurazione del contenitore del database effettivo con due flag di comando MySQL, --wsrep_recover e --wsrep_cluster_address . Ad esempio, se vogliamo conoscere l'ultimo numero impegnato di mariadb1, dobbiamo eseguire:
$ docker run --rm --name mariadb-recover \
--env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
--volume /containers/mariadb1/datadir:/var/lib/mysql \
--volume /containers/mariadb1/conf.d:/etc/mysql/conf.d \
mariadb:10.2.15 \
--wsrep_recover \
--wsrep_cluster_address=gcomm://
2018-06-12 4:46:35 139993094592384 [Note] mysqld (mysqld 10.2.15-MariaDB-10.2.15+maria~jessie) starting as process 1 ...
2018-06-12 4:46:35 139993094592384 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
...
2018-06-12 4:46:35 139993094592384 [Note] Plugin 'FEEDBACK' is disabled.
2018-06-12 4:46:35 139993094592384 [Note] Server socket created on IP: '::'.
2018-06-12 4:46:35 139993094592384 [Note] WSREP: Recovered position: e70b7437-645f-11e8-9f44-5b204e58220b:7099
L'ultima riga è quello che stiamo cercando. MariaDB stampa l'UUID del cluster e il numero di sequenza dell'ultima transazione sottoposta a commit. Il nodo che detiene il numero più alto è considerato il nodo più avanzato. Poiché abbiamo specificato --rm , il contenitore verrà rimosso automaticamente una volta uscito. Ripeti il passaggio precedente su ogni host Docker sostituendo il --volume percorso ai rispettivi volumi del contenitore del database.
Dopo aver confrontato il valore riportato da tutti i contenitori di database e aver deciso quale contenitore è il nodo più aggiornato, modificare safe_to_bootstrap contrassegnare a 1 all'interno di /{datadir volume}/grastate.dat manualmente. Diciamo che tutti i nodi stanno segnalando lo stesso numero di sequenza esatto, possiamo semplicemente selezionare mariadb3 da avviare cambiando safe_to_bootstrap valore a 1:
$ vim /containers/mariadb3/datadir/grasate.dat
...
safe_to_bootstrap: 1
Salva il file e avvia il bootstrap del cluster da quel nodo, come descritto nel capitolo successivo.
Avvio del cluster
Il bootstrap del cluster è simile al primo comando di esecuzione della finestra mobile che abbiamo utilizzato quando si avvia il cluster per la prima volta. Se mariadb1 è il nodo bootstrap scelto, possiamo semplicemente rieseguire il container bootstrap creato:
$ docker start mariadb0 # on host1
Altrimenti, se il container bootstrap non esiste sul nodo scelto, diciamo su host2, esegui il comando bootstrap container e mappa i volumi di mariadb2 esistenti. Stiamo usando mariadb0 come nome del contenitore su host2 per indicare che è un contenitore bootstrap:
$ docker run -d \
--name mariadb0 \
--hostname mariadb0.weave.local \
--net weave \
--publish "3306" \
--publish "4444" \
--publish "4567" \
--publish "4568" \
$(weave dns-args) \
--env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
--volume /containers/mariadb2/datadir:/var/lib/mysql \
--volume /containers/mariadb2/conf.d:/etc/mysql/mariadb.conf.d \
mariadb:10.2.15 \
--wsrep_cluster_address=gcomm:// \
--wsrep_sst_auth="root:PM7%[email protected]^1" \
--wsrep_node_address=mariadb0.weave.local
Potresti notare che questo comando è leggermente più breve rispetto al precedente comando bootstrap descritto in questa guida. Poiché abbiamo già creato l'utente proxysql nel nostro primo comando bootstrap, possiamo saltare queste due variabili di ambiente:
- --env MYSQL_USER=proxysql
- --env MYSQL_PASSWORD=proxysqlpassword
Quindi, avvia i restanti contenitori MariaDB, rimuovi il contenitore bootstrap e avvia il contenitore MariaDB esistente sull'host bootstrap. Fondamentalmente l'ordine dei comandi sarebbe:
$ docker start mariadb1 # on host1
$ docker start mariadb3 # on host3
$ docker stop mariadb0 # on host2
$ docker start mariadb2 # on host2
A questo punto, il cluster viene avviato e funziona a piena capacità.
Controllo delle risorse
La memoria è una risorsa molto importante in MySQL. È qui che vengono archiviati i buffer e le cache ed è fondamentale per MySQL ridurre l'impatto di colpire il disco troppo spesso. D'altra parte, lo scambio è negativo per le prestazioni di MySQL. Per impostazione predefinita, non ci saranno vincoli di risorse sui contenitori in esecuzione. I contenitori utilizzano tutta una determinata risorsa consentita dal kernel dell'host. Un'altra cosa importante è il limite del descrittore di file. Puoi aumentare il limite del descrittore di file aperti o "nofile" a qualcosa di più alto per soddisfare il numero di file che il server MySQL può aprire contemporaneamente. Impostarlo su un valore alto non farà male.
Per limitare l'allocazione della memoria e aumentare il limite del descrittore di file al nostro contenitore di database, si aggiunge --memory , --scambio di memoria e --ulimit parametri nel comando "docker run":
$ docker kill -s 15 mariadb1
$ docker rm -f mariadb1
$ docker run -d \
--name mariadb1 \
--hostname mariadb1.weave.local \
--net weave \
--publish "3306:3306" \
--publish "4444" \
--publish "4567" \
--publish "4568" \
$(weave dns-args) \
--memory 16g \
--memory-swap 16g \
--ulimit nofile:16000:16000 \
--env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
--volume /containers/mariadb1/datadir:/var/lib/mysql \
--volume /containers/mariadb1/conf.d:/etc/mysql/mariadb.conf.d \
mariadb:10.2.15 \
--wsrep_cluster_address=gcomm://mariadb0.weave.local,mariadb1.weave.local,mariadb2.weave.local,mariadb3.weave.local \
--wsrep_sst_auth="root:PM7%[email protected]^1" \
--wsrep_node_address=mariadb1.weave.local
Tieni presente che se --memory-swap è impostato sullo stesso valore di --memory e --memoria è impostato su un numero intero positivo, il contenitore non avrà accesso allo scambio. Se --scambio di memoria non è impostato, lo scambio del contenitore sarà predefinito su --memory moltiplicare per 2. Se --memoria e --scambio di memoria sono impostati sullo stesso valore, ciò impedirà ai contenitori di utilizzare qualsiasi scambio. Questo perché --memory-swap è la quantità di memoria combinata e di scambio che può essere utilizzata, mentre --memory è solo la quantità di memoria fisica che può essere utilizzata.
Alcune delle risorse del contenitore come la memoria e la CPU possono essere controllate dinamicamente tramite il comando "docker update", come mostrato nell'esempio seguente per aggiornare al volo la memoria del contenitore mariadb1 a 32G:
$ docker update \
--memory 32g \
--memory-swap 32g \
mariadb1
Non dimenticare di sintonizzare my.cnf di conseguenza per adattarlo alle nuove specifiche. La gestione della configurazione è spiegata nella sezione successiva.
Gestione della configurazione
La maggior parte dei parametri di configurazione di MySQL/MariaDB può essere modificata durante il runtime, il che significa che non è necessario riavviare per applicare le modifiche. Consulta la pagina della documentazione di MariaDB per i dettagli. Il parametro elencato con "Dynamic:Yes" significa che la variabile viene caricata immediatamente dopo la modifica senza la necessità di riavviare il server MariaDB. In caso contrario, imposta i parametri all'interno del file di configurazione personalizzato nell'host Docker. Ad esempio, su mariadb3, apporta le modifiche al seguente file:
$ vim /containers/mariadb3/conf.d/my.cnf
E quindi riavvia il contenitore del database per applicare la modifica:
$ docker restart mariadb3
Verifica che il contenitore avvii il processo esaminando i log della finestra mobile. Esegui questa operazione su un nodo alla volta se desideri apportare modifiche a livello di cluster.
Backup
Fare un backup logico è piuttosto semplice perché l'immagine MariaDB viene fornita anche con mysqldump binary. È sufficiente utilizzare il comando "docker exec" per eseguire mysqldump e inviare l'output a un file relativo al percorso dell'host. Il comando seguente esegue il backup di mysqldump su mariadb2 e lo salva in /backups/mariadb2 all'interno di host2:
$ docker exec -it mariadb2 mysqldump -uroot -p --single-transaction > /backups/mariadb2/dump.sql
Il backup binario come Percona Xtrabackup o MariaDB Backup richiede che il processo acceda direttamente alla directory dei dati di MariaDB. Devi installare questo strumento all'interno del contenitore o tramite l'host della macchina o utilizzare un'immagine dedicata a questo scopo come l'immagine "perconalab/percona-xtrabackup" per creare il backup e archiviarlo all'interno di /tmp/backup sull'host Docker:
$ docker run --rm -it \
-v /containers/mariadb2/datadir:/var/lib/mysql \
-v /tmp/backup:/xtrabackup_backupfiles \
perconalab/percona-xtrabackup \
--backup --host=mariadb2 --user=root --password=mypassword
Puoi anche fermare il contenitore con innodb_fast_shutdown impostare su 0 e copiare il volume datadir in un'altra posizione nell'host fisico:
$ docker exec -it mariadb2 mysql -uroot -p -e 'SET GLOBAL innodb_fast_shutdown = 0'
$ docker kill -s 15 mariadb2
$ cp -Rf /containers/mariadb2/datadir /backups/mariadb2/datadir_copied
$ docker start mariadb2
Ripristina
Il ripristino è piuttosto semplice per mysqldump. Puoi semplicemente reindirizzare lo stdin nel contenitore dall'host fisico:
$ docker exec -it mariadb2 mysql -uroot -p < /backups/mariadb2/dump.sql
Puoi anche utilizzare la riga di comando del client mysql standard in remoto con il nome host e il valore della porta corretti invece di usare questo comando "docker exec":
$ mysql -uroot -p -h127.0.0.1 -P3306 < /backups/mariadb2/dump.sql
Per Percona Xtrabackup e MariaDB Backup, dobbiamo preparare il backup in anticipo. Questo farà avanzare il backup al momento in cui il backup è stato completato. Diciamo che i nostri file Xtrabackup si trovano in /tmp/backup dell'host Docker, per prepararlo basta:
$ docker run --rm -it \
-v mysql-datadir:/var/lib/mysql \
-v /tmp/backup:/xtrabackup_backupfiles \
perconalab/percona-xtrabackup \
--prepare --target-dir /xtrabackup_backupfiles
Il backup preparato in /tmp/backup dell'host Docker può quindi essere utilizzato come datadir MariaDB per un nuovo container o cluster. Diciamo che vogliamo solo verificare il ripristino su un contenitore MariaDB autonomo, eseguiremo:
$ docker run -d \
--name mariadb-restored \
--env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
-v /tmp/backup:/var/lib/mysql \
mariadb:10.2.15
Se hai eseguito un backup utilizzando l'approccio stop and copy, puoi semplicemente duplicare la directory dei dati e utilizzare la directory duplicata come mappa del volume alla directory dei dati di MariaDB per l'esecuzione su un altro contenitore. Supponiamo che il backup sia stato copiato in /backups/mariadb2/datadir_copied, possiamo eseguire un nuovo contenitore eseguendo:
$ mkdir -p /containers/mariadb-restored/datadir
$ cp -Rf /backups/mariadb2/datadir_copied /containers/mariadb-restored/datadir
$ docker run -d \
--name mariadb-restored \
--env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
-v /containers/mariadb-restored/datadir:/var/lib/mysql \
mariadb:10.2.15
MYSQL_ROOT_PASSWORD deve corrispondere alla password di root effettiva per quel particolare backup.
Multiplenines MySQL su Docker:come containerizzare il tuo databaseScopri tutto ciò che devi capire quando consideri di eseguire un servizio MySQL oltre alla virtualizzazione del container DockerScarica il whitepaperAggiornamento versione database
Esistono due tipi di aggiornamento:aggiornamento sul posto o aggiornamento logico.
L'aggiornamento sul posto comporta l'arresto del server MariaDB, la sostituzione dei vecchi binari con i nuovi binari e quindi l'avvio del server nella vecchia directory dei dati. Una volta avviato, devi eseguire mysql_upgrade script per controllare e aggiornare tutte le tabelle di sistema e anche per controllare le tabelle utente.
L'aggiornamento logico prevede l'esportazione di SQL dalla versione corrente utilizzando un'utilità di backup logico come mysqldump, l'esecuzione del nuovo contenitore con i binari della versione aggiornata e quindi l'applicazione dell'SQL alla nuova versione di MySQL/MariaDB. È simile all'approccio di backup e ripristino descritto nella sezione precedente.
Tuttavia, è un buon approccio eseguire sempre il backup del database prima di eseguire operazioni distruttive. I seguenti passaggi sono necessari quando si esegue l'aggiornamento dall'immagine corrente, MariaDB 10.1.33 a un'altra versione principale, MariaDB 10.2.15 su mariadb3 risiede su host3:
-
Eseguire il backup del database. Non importa il backup fisico o logico, ma quest'ultimo è consigliato utilizzando mysqldump.
-
Scarica l'ultima immagine a cui vorremmo aggiornare:
$ docker pull mariadb:10.2.15
-
Imposta innodb_fast_shutdown su 0 per il nostro contenitore di database:
$ docker exec -it mariadb3 mysql -uroot -p -e 'SET GLOBAL innodb_fast_shutdown = 0'
-
Arresta con grazia il contenitore del database:
$ docker kill --signal=TERM mariadb3
-
Crea un nuovo contenitore con la nuova immagine per il nostro contenitore di database. Mantieni intatto il resto dei parametri tranne che usando il nuovo nome del contenitore (altrimenti sarebbe in conflitto):
$ docker run -d \ --name mariadb3-new \ --hostname mariadb3.weave.local \ --net weave \ --publish "3306:3306" \ --publish "4444" \ --publish "4567" \ --publish "4568" \ $(weave dns-args) \ --env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \ --volume /containers/mariadb3/datadir:/var/lib/mysql \ --volume /containers/mariadb3/conf.d:/etc/mysql/mariadb.conf.d \ mariadb:10.2.15 \ --wsrep_cluster_address=gcomm://mariadb0.weave.local,mariadb1.weave.local,mariadb2.weave.local,mariadb3.weave.local \ --wsrep_sst_auth="root:PM7%[email protected]^1" \ --wsrep_node_address=mariadb3.weave.local
-
Esegui lo script mysql_upgrade:
$ docker exec -it mariadb3-new mysql_upgrade -uroot -p
-
Se non si sono verificati errori, rimuovere il vecchio contenitore, mariadb3 (il nuovo è mariadb3-new):
$ docker rm -f mariadb3
-
Altrimenti, se il processo di aggiornamento non riesce nel frattempo, possiamo tornare al contenitore precedente:
$ docker stop mariadb3-new $ docker start mariadb3
L'aggiornamento della versione principale può essere eseguito in modo simile all'aggiornamento della versione secondaria, tranne per il fatto che devi tenere presente che MySQL/MariaDB supporta solo l'aggiornamento principale dalla versione precedente. Se utilizzi MariaDB 10.0 e desideri eseguire l'aggiornamento a 10.2, devi prima eseguire l'aggiornamento a MariaDB 10.1, seguito da un altro passaggio di aggiornamento a MariaDB 10.2.
Prendi nota delle modifiche alla configurazione introdotte e deprecate tra le versioni principali.
Failover
In Galera, tutti i nodi sono padroni e ricoprono lo stesso ruolo. Con ProxySQL nell'immagine, le connessioni che passano attraverso questo gateway verranno automaticamente sottoposte a failover finché è presente un componente primario in esecuzione per Galera Cluster (ovvero, la maggior parte dei nodi è attiva). L'applicazione non noterà alcuna differenza se un nodo del database si interrompe perché ProxySQL reindirizzerà semplicemente le connessioni agli altri nodi disponibili.
Se l'applicazione si connette direttamente a MariaDB bypassando ProxySQL, il failover deve essere eseguito sul lato applicazione puntando al successivo nodo disponibile, a condizione che il nodo del database soddisfi le seguenti condizioni:
- Stato wsrep_local_state_comment è sincronizzato (è possibile anche lo stato "Non sincronizzato/donatore", solo se wsrep_sst_method è xtrabackup, xtrabackup-v2 o mariabackup).
- Stato wsrep_cluster_status è Primario.
In Galera, un nodo disponibile non significa che sia integro fino a quando non viene verificato lo stato di cui sopra.
Ridimensionamento
Per aumentare la scalabilità orizzontale, possiamo creare un nuovo contenitore nella stessa rete e utilizzare lo stesso file di configurazione personalizzato per il contenitore esistente su quel particolare host. Ad esempio, supponiamo di voler aggiungere il quarto contenitore MariaDB su host3, possiamo utilizzare lo stesso file di configurazione montato per mariadb3, come illustrato nel diagramma seguente:
Esegui il comando seguente su host3 per aumentare la scalabilità orizzontale:
$ docker run -d \
--name mariadb4 \
--hostname mariadb4.weave.local \
--net weave \
--publish "3306:3307" \
--publish "4444" \
--publish "4567" \
--publish "4568" \
$(weave dns-args) \
--env MYSQL_ROOT_PASSWORD="PM7%[email protected]^1" \
--volume /containers/mariadb4/datadir:/var/lib/mysql \
--volume /containers/mariadb3/conf.d:/etc/mysql/mariadb.conf.d \
mariadb:10.2.15 \
--wsrep_cluster_address=gcomm://mariadb1.weave.local,mariadb2.weave.local,mariadb3.weave.local,mariadb4.weave.local \
--wsrep_sst_auth="root:PM7%[email protected]^1" \
--wsrep_node_address=mariadb4.weave.local
Una volta creato, il contenitore si unirà al cluster ed eseguirà SST. È possibile accedervi sulla porta 3307 esternamente o al di fuori della rete Weave, o sulla porta 3306 all'interno dell'host o all'interno della rete Weave. Non è più necessario includere mariadb0.weave.local nell'indirizzo del cluster. Una volta che il cluster è stato ridimensionato, è necessario aggiungere il nuovo contenitore MariaDB nel set di bilanciamento del carico ProxySQL tramite la console di amministrazione:
$ docker exec -it proxysql1 mysql -uadmin -padmin -P6032
mysql> INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (10,'mariadb4.weave.local',3306);
mysql> INSERT INTO mysql_servers(hostgroup_id,hostname,port) VALUES (20,'mariadb4.weave.local',3306);
mysql> LOAD MYSQL SERVERS TO RUNTIME;
mysql> SAVE MYSQL SERVERS TO DISK;
Ripeti i comandi precedenti sulla seconda istanza ProxySQL.
Infine, per l'ultimo passaggio, (puoi saltare questa parte se hai già eseguito l'istruzione "SAVE .. TO DISK" in ProxySQL), aggiungi la seguente riga in proxysql.cnf per renderlo persistente nel riavvio del contenitore su host1 e host2:
$ vim /containers/proxysql1/proxysql.cnf # host1
$ vim /containers/proxysql2/proxysql.cnf # host2
E aggiungi le righe relative a mariadb4 nella direttiva mysql_server:
mysql_servers =
(
{ address="mariadb1.weave.local" , port=3306 , hostgroup=10, max_connections=100 },
{ address="mariadb2.weave.local" , port=3306 , hostgroup=10, max_connections=100 },
{ address="mariadb3.weave.local" , port=3306 , hostgroup=10, max_connections=100 },
{ address="mariadb4.weave.local" , port=3306 , hostgroup=10, max_connections=100 },
{ address="mariadb1.weave.local" , port=3306 , hostgroup=20, max_connections=100 },
{ address="mariadb2.weave.local" , port=3306 , hostgroup=20, max_connections=100 },
{ address="mariadb3.weave.local" , port=3306 , hostgroup=20, max_connections=100 },
{ address="mariadb4.weave.local" , port=3306 , hostgroup=20, max_connections=100 }
)
Salva il file e dovremmo essere a posto al prossimo riavvio del contenitore.
Ridimensionamento
Per ridimensionare, arresta semplicemente il contenitore con grazia. Il comando migliore sarebbe:
$ docker kill -s 15 mariadb4
$ docker rm -f mariadb4
Ricorda, se il nodo del database ha lasciato il cluster in modo non corretto, non faceva parte del ridimensionamento e avrebbe influito sul calcolo del quorum.
Per rimuovere il contenitore da ProxySQL, esegui i seguenti comandi su entrambi i contenitori ProxySQL. Ad esempio, su proxysql1:
$ docker exec -it proxysql1 mysql -uadmin -padmin -P6032
mysql> DELETE FROM mysql_servers WHERE hostname="mariadb4.weave.local";
mysql> LOAD MYSQL SERVERS TO RUNTIME;
mysql> SAVE MYSQL SERVERS TO DISK;
Puoi quindi rimuovere la voce corrispondente all'interno di proxysql.cnf o semplicemente lasciarla così. Verrà comunque rilevato come OFFLINE dal punto di vista ProxySQL.
Riepilogo
Con Docker, le cose cambiano leggermente rispetto al modo convenzionale di gestire i server MySQL o MariaDB. La gestione di servizi con stato come Galera Cluster non è facile come le applicazioni senza stato e richiede test e pianificazione adeguati.
Nel nostro prossimo blog su questo argomento, valuteremo i pro ei contro dell'esecuzione di Galera Cluster su Docker senza strumenti di orchestrazione.