Panoramica dei operatori PostgreSQL per Kubernetes: la nostra scelta e esperienza

Panoramica dei operatori PostgreSQL per Kubernetes: la nostra scelta e esperienza

Sempre più spesso riceviamo richieste dai clienti come: «Vogliamo qualcosa simile a Amazon RDS, ma più economico»; «Vogliamo qualcosa come RDS, ma ovunque, su qualsiasi infrastruttura». Per realizzare una soluzione gestita su Kubernetes, abbiamo esaminato lo stato attuale dei più popolari operatori per PostgreSQL (Stolon, operatori di Crunchy Data e Zalando) e abbiamo fatto la nostra scelta.

Questo articolo rappresenta la nostra esperienza, sia dal punto di vista teorico (una panoramica delle soluzioni) sia pratico (cosa è stato scelto e quali risultati sono stati ottenuti). Ma prima di tutto, definiamo quali sono i requisiti chiave per potenziali sostituti di RDS…

Cos'è RDS?

Quando le persone parlano di RDS, dalla nostra esperienza, si riferiscono a un servizio di database gestionato (managed) che:

  1. è facile da configurare;
  2. ha la possibilità di lavorare con snapshot e di ripristinarli (idealmente con supporto per PITR);
  3. permette di creare topologie master-slave;
  4. ha un ricco elenco di estensioni;
  5. fornisce audit e gestione degli utenti/accessi.

In generale, gli approcci per realizzare il compito assegnato possono essere molto diversi, tuttavia il metodo con Ansible non ci è familiare. (Colleghi di 2GIS sono giunti a una conclusione simile durante il loro tentativo di creare «uno strumento per il rapido deployment di un cluster a tolleranza di guasti basato su Postgres».)

Gli operatori sono l'approccio comunemente accettato per affrontare problemi simili nell'ecosistema Kubernetes. Abbiamo già parlato di loro in relazione a database eseguiti all'interno di Kubernetes durante una delle conferenze del CTO di «Flanta», distol, nel in uno dei suoi interventi.

NB: Per la creazione rapida di operatori semplici, ti consigliamo di prestare attenzione alla nostra utility Open Source shell-operator. Utilizzandola, puoi farlo senza conoscere Go, ma con metodi più familiari per gli amministratori di sistema: Bash, Python, ecc.

Per PostgreSQL esistono diversi operatori K8s popolari:

  • Stolon;
  • Crunchy Data PostgreSQL Operator;
  • Zalando Postgres Operator.

Esaminiamoli più da vicino.

Scelta dell'operatore

Oltre alle importanti funzionalità già menzionate sopra, noi — come ingegneri di operations nell'infrastruttura Kubernetes — ci aspettavamo anche dai operatori quanto segue:

  • deploy da Git e con Custom Resources;
  • supporto alla pod anti-affinity;
  • installazione di node affinity o node selector;
  • installazione di tolerations;
  • presenza di funzionalità di tuning;
  • tecnologie comprensibili e persino comandi.

Senza entrare nei dettagli di ciascun punto (chiedete nei commenti se avete domande su di essi dopo aver letto tutto l'articolo), vorrei sottolineare che questi parametri sono necessari per descrivere con maggiore precisione la specializzazione dei nodi del cluster, in modo da ordinarli in base a specifiche applicazioni. In questo modo possiamo ottenere un ottimale equilibrio tra prestazioni e costi.

Ora, passiamo agli operatori PostgreSQL.

1. Stolon

Stolon dall'azienda italiana Sorint.lab in già menzionato nel rapporto è stato considerato come un certo standard tra gli operatori per i DBMS. È un progetto piuttosto vecchio: la sua prima pubblica release risale a novembre 2015(!), e il repository GitHub può vantare quasi 3000 stelle e oltre 40 collaboratori.

E in effetti, Stolon è un ottimo esempio di architettura ben pensata:

Panoramica dei operatori PostgreSQL per Kubernetes: la nostra scelta e esperienza
Col dispositivo di questo operatore in dettaglio è possibile consultare il rapporto o la documentazione del progetto. In generale, basta dire che è in grado di fare tutto quanto descritto: failover, proxy per l'accesso trasparente ai clienti, backup... Inoltre, i proxy forniscono accesso tramite un singolo endpoint di servizio, a differenza delle due altre soluzioni discusse di seguito (che hanno due servizi per l'accesso al database).

Tuttavia, Stolon non ha Custom Resources, il che rende impossibile il deployment in modo semplice e veloce — "come pane appena sfornato" — per creare istanze di DBMS in Kubernetes. La gestione avviene tramite l'utility stolonctl, il deploy avviene tramite Helm chart, e le configurazioni personalizzate vengono definite nel ConfigMap.

Da un lato, sembra che l'operatore non sia effettivamente un operatore (dato che non utilizza CRD). Dall'altro lato, è un sistema flessibile che consente di configurare le risorse in K8s nel modo che preferisci.

In sintesi, per noi non è sembrata ottimale la strada di creare un chart separato per ogni DB. Pertanto, abbiamo iniziato a cercare alternative.

2. Crunchy Data PostgreSQL Operator

L'operatore di Crunchy Data, una giovane startup americana sembrava un'alternativa logica. La sua storia pubblica inizia con il primo rilascio di marzo 2017, da allora il repository su GitHub ha ricevuto poco meno di 1300 stelle e oltre 50 collaboratori. L'ultimo rilascio di settembre è stato testato per funzionare con Kubernetes 1.15—1.18, OpenShift 3.11+ e 4.4+, GKE e VMware Enterprise PKS 1.3+.

L'architettura del Crunchy Data PostgreSQL Operator soddisfa anche i requisiti dichiarati:

Panoramica dei operatori PostgreSQL per Kubernetes: la nostra scelta e esperienza

La gestione avviene tramite l'utility pgo, ma genera a sua volta Custom Resources per Kubernetes. Pertanto, abbiamo, come potenziali utenti, trovato lieto il fatto che l'operatore offre:

  • gestione tramite CRD;
  • gestione degli utenti facile (anche tramite CRD);
  • integrazione con altri componenti Crunchy Data Container Suite — una collezione specializzata di immagini container per PostgreSQL e utility per lavorarci (inclusi pgBackRest, pgAudit, estensioni da contrib, ecc.).

Tuttavia, i tentativi di iniziare a utilizzare l'operatore di Crunchy Data hanno rivelato alcuni problemi:

  • Non era disponibile la possibilità di tolerations — è previsto solo il nodeSelector.
  • I pod creati facevano parte del Deployment, anche se stavamo implementando un'applicazione stateful. A differenza degli StatefulSet, i Deployment non possono creare dischi.

L'ultimo difetto porta a situazioni divertenti: nell'ambiente di test siamo riusciti ad avviare 3 repliche con un solo disco. storage locale, il che ha fatto sì che l'operatore segnalasse che 3 repliche erano funzionanti (anche se non era così).

Un'altra caratteristica di questo operatore è la sua integrazione predefinita con vari sistemi ausiliari. Ad esempio, è facile installare pgAdmin e pgBounce, e nel documentazione si considerano Grafana e Prometheus preconfigurati. Nella recente release 4.5.0-beta1 si segnala il miglioramento dell'integrazione con il progetto pgMonitor, che consente all'operatore di offrire visualizzazioni chiare delle metriche PgSQL “out of the box”.

Tuttavia, la strana scelta delle risorse Kubernetes generate ci ha portato alla necessità di trovare un'altra soluzione.

3. Zalando Postgres Operator

I prodotti Zalando ci sono noti da tempo: abbiamo esperienza con Zalenium e, naturalmente, abbiamo provato Patroni — la loro popolare soluzione HA per PostgreSQL. Uno degli autori del Postgres Operator ha parlato di questo approccio — Alexey Klyukin — nella trasmissione Postgres Tuesday n. 5, e ci è piaciuto.

Questa è la soluzione più giovane tra quelle trattate nell'articolo: il primo rilascio è avvenuto nell'agosto del 2018. Tuttavia, nonostante il numero relativamente ridotto di rilasci formali, il progetto ha compiuto grandi progressi, superando già in popolarità la soluzione di Crunchy Data con oltre 1300 stelle su GitHub e il massimo numero di collaboratori (oltre 70).

«Sotto il cofano» di questo operatore si trovano soluzioni collaudate nel tempo:

  • Patroni e Spilo per la gestione,
  • WAL-E — per i backup,
  • PgBouncer — come pool di connessioni.

Ecco come è presentata l'architettura dell'operatore di Zalando:

Panoramica dei operatori PostgreSQL per Kubernetes: la nostra scelta e esperienza

L'operatore è completamente gestito tramite Custom Resources, crea automaticamente un StatefulSet di contenitori, che possono poi essere personalizzati aggiungendo vari sidecar nei pod. Tutto ciò rappresenta un notevole vantaggio rispetto all'operatore di Crunchy Data.

Poiché abbiamo scelto la soluzione di Zalando tra le 3 opzioni considerate, la descrizione delle sue possibilità sarà presentata di seguito, insieme alla pratica di applicazione.

Pratica con Postgres Operator di Zalando

Il deployment dell'operatore avviene in modo molto semplice: è sufficiente scaricare il rilascio attuale da GitHub e applicare i file YAML dalla directory. manifests. In alternativa, puoi anche utilizzare OperatorHub.

Dopo l'installazione, è consigliabile occuparsi della configurazione degli archivi per log e backup. Questa viene effettuata tramite ConfigMap postgres-operator nello spazio dei nomi in cui hai installato l'operatore. Una volta configurati gli archivi, puoi distribuire il primo cluster PostgreSQL.

Ad esempio, il nostro deployment standard appare come segue:

apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
 name: staging-db
spec:
 numberOfInstances: 3
 patroni:
   synchronous_mode: true
 postgresql:
   version: "12"
 resources:
   limits:
     cpu: 100m
     memory: 1Gi
   requests:
     cpu: 100m
     memory: 1Gi
 sidecars:
 - env:
   - name: DATA_SOURCE_URI
     value: 127.0.0.1:5432
   - name: DATA_SOURCE_PASS
     valueFrom:
       secretKeyRef:
         key: password
         name: postgres.staging-db.credentials
   - name: DATA_SOURCE_USER
     value: postgres
   image: wrouesnel/postgres_exporter
   name: prometheus-exporter
   resources:
     limits:
       cpu: 500m
       memory: 100Mi
     requests:
       cpu: 100m
       memory: 100Mi
 teamId: staging
 volume:
   size: 2Gi

Questo manifesto distribuisce un cluster di 3 istanze con un sidecar sotto forma di postgres_exporter, da cui raccogliamo le metriche dell'applicazione. Come vedi, è molto semplice e, se lo desideri, puoi creare letteralmente un numero illimitato di cluster.

Vale la pena prestare attenzione anche alla pannello web per la gestionepostgres-operator-ui. Viene fornito con l'operatore e consente di creare ed eliminare cluster, oltre a gestire i backup effettuati dall'operatore.

Panoramica dei operatori PostgreSQL per Kubernetes: la nostra scelta e esperienza
Elenco dei cluster PostgreSQL

Panoramica dei operatori PostgreSQL per Kubernetes: la nostra scelta e esperienza
Gestione dei backup

Un'altra interessante funzionalità è il supporto per Teams API. Questo meccanismo crea automaticamente ruoli in PostgreSQL, sulla base dell'elenco dei nomi utenti ricevuti. Successivamente, l'API consente di restituire l'elenco degli utenti per i quali i ruoli vengono creati automaticamente.

Problemi e soluzioni

Tuttavia, l'uso dell'operatore ha presto messo in evidenza alcuni difetti significativi:

  1. assenza di supporto per nodeSelector;
  2. impossibilità di disattivare i backup;
  3. quando si utilizza la funzione di creazione di database, non vengono assegnati privilegi di default;
  4. mancanza periodica di documentazione o documentazione obsoleta.

Fortunatamente, molti di questi problemi possono essere risolti. Cominciamo dalla fine — problemi con documentazione.

Probabilmente ti imbatterai nella difficoltà di capire come impostare un backup e come collegare il bucket di backup all'Operator UI. La documentazione lo menziona solo brevemente, mentre la descrizione reale si trova in PR:

  1. è necessario creare un segreto;
  2. trasmetterlo all'operatore come parametro pod_environment_secret_name In CRD con le impostazioni dell'operatore o in ConfigMap (a seconda di come hai deciso di installare l'operatore).

Tuttavia, al momento si è rivelato impossibile. È per questo che abbiamo raccolto la nostra versione dell'operatore con alcune implementazioni aggiuntive di terze parti. Maggiori dettagli di seguito.

Se si passano all'operatore parametrici per il backup, ossia — wal_s3_bucket e le chiavi di accesso in AWS S3, allora lui effettuerà il backup di tutto: non solo dei database in produzione, ma anche di staging. Questo non ci ha soddisfatto.

Nella descrizione dei parametri di Spilo, che è il wrapper Docker di base per PgSQL utilizzando l'operatore, è emerso: è possibile passare il parametro WAL_S3_BUCKET vuoto, disabilitando così i backup. Inoltre, con grande gioia è stato trovato anche un PR pronto, che abbiamo subito integrato nel nostro fork. Ora basta semplicemente aggiungere enableWALArchiving: false alle risorse del cluster PostgreSQL.

Sì, era possibile fare diversamente, avviando 2 operatori: uno per staging (senza backup) e l'altro per produzione. Ma in questo modo siamo riusciti a farne a meno di uno.

Ok, abbiamo imparato a dare accesso alle basi per S3 e i backup hanno cominciato a finire nel repository. Come far funzionare le pagine di backup nell'Operator UI?

Panoramica dei operatori PostgreSQL per Kubernetes: la nostra scelta e esperienza

Nell'UI di Operator sarà necessario aggiungere 3 variabili:

  • SPILO_S3_BACKUP_BUCKET
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

Dopo di ciò, la gestione dei backup sarà disponibile, il che nel nostro caso semplificherà il lavoro con lo staging, consentendo di consegnare snapshot dalla produzione senza ulteriori script.

Un ulteriore vantaggio menzionato è l'integrazione con l'API di Teams e le ampie possibilità di creare basi e ruoli tramite l'operatore. Tuttavia, i ruoli creati non avevano diritti di default. Pertanto, un utente con diritti in sola lettura non poteva visualizzare le nuove tabelle.

Perché? Nonostante nel codice ci siano necessari GRANT, questi non vengono applicati sempre. Ci sono 2 metodi: syncPreparedDatabases e syncDatabases. In syncPreparedDatabases — nonostante ci sia una condizione nella sezione preparedDatabases ci siano per i diritti defaultRoles e defaultUsers per la creazione dei ruoli, i diritti di default non vengono applicati. Stiamo preparando una patch affinché questi diritti vengano applicati automaticamente.

E l'ultimo punto nelle modifiche pertinenti per noi è — per correggere l'errore., aggiungendo Node Affinity nel StatefulSet creato. I nostri clienti spesso preferiscono ridurre i costi utilizzando istanze spot, e non è consigliabile ospitare servizi di database su di esse. Questo problema potrebbe essere risolto anche mediante tolerations, ma avere Node Affinity fornisce maggiore certezza.

Cosa è stato ottenuto?

In seguito alla risoluzione dei problemi elencati, abbiamo forkato il Postgres Operator di Zalando nel nostro repository, dove viene compilato con patch così utili. Per maggiore comodità, abbiamo anche immagine Docker.

Elenco delle PR accettate nel fork:

Sarebbe fantastico se la comunità supportasse queste PR affinché vengano integrate nell'upstream con la prossima versione dell'operatore (1.6).

Bonus! Storia di successo sulla migrazione in produzione

Se usate Patroni, è possibile migrare la produzione attiva all'operatore con un fermo minimo.

Spilo consente di creare cluster standby attraverso archiviazione S3 con Wal-E, quando il log binario PgSQL viene prima salvato in S3 e poi prelevato dalla replica. Ma cosa fare se non utilizzate Wal-E in una vecchia infrastruttura? La soluzione a questo problema è già è stata proposta su Habr.

A supporto arriva la replicazione logica di PostgreSQL. Tuttavia, non approfondiremo i dettagli su come creare pubblicazioni e iscrizioni, perché... il nostro piano ha subito un fallimento.

Il fatto è che nel database c'erano diverse tabelle molto cariche con milioni di righe, che inoltre venivano continuamente popolate e svuotate. Iscrizione semplice con copy_data, quando una nuova replica copia tutto il contenuto dal master, non riusciva proprio a tenere il passo. La copia dei contenuti è durata una settimana, ma non ha mai raggiunto il master. In definitiva, la soluzione al problema è stata fornita articolo da colleghi di Avito: è possibile trasferire i dati utilizzando pg_dump. Descriverò la nostra (leggermente rielaborata) variante di questo algoritmo.

L'idea è che si possa creare un'iscrizione disattivata, legata a uno specifico slot di replicazione, e poi correggere il numero della transazione. Erano disponibili repliche per il lavoro in produzione. È importante, poiché la replica aiuterà a creare un dump consistente e continuare a ricevere modifiche dal master.

Nei successivi comandi che descrivono il processo di migrazione, verranno utilizzate le seguenti designazioni per gli host:

  1. master — server di origine;
  2. replica1 — replica logica su produzione vecchia;
  3. replica2 — nuova replica logica.

Piano di migrazione

1. Creeremo un abbonamento a tutte le tabelle nello schema sul master pubblico database dbname:

psql -h master -d dbname -c "CREATE PUBLICATION dbname FOR ALL TABLES;"

2. Creeremo uno slot di replica sul master:

psql -h master -c "select pg_create_logical_replication_slot('repl', 'pgoutput');"

3. Fermiamo la replica sulla vecchia replica:

psql -h replica1 -c "select pg_wal_replay_pause();"

4. Otteniamo il numero della transazione dal master:

psql -h master -c "select replay_lsn from pg_stat_replication where client_addr = 'replica1';"

5. Faremo un dump dalla vecchia replica. Procederemo in più thread per velocizzare il processo:

pg_dump -h replica1 --no-publications --no-subscriptions -O -C -F d -j 8 -f dump/ dbname

6. Caricheremo il dump sul nuovo server:

pg_restore -h replica2 -F d -j 8 -d dbname dump/

7. Dopo il caricamento del dump, è possibile avviare la replica sulla replica logica:

psql -h replica1 -c "select pg_wal_replay_resume();"

7. Creeremo un abbonamento sulla nuova replica logica:

psql -h replica2 -c "create subscription oldprod connection 'host=replica1 port=5432 user=postgres password=secret dbname=dbname' publication dbname with (enabled = false, create_slot = false, copy_data = false, slot_name='repl');"

8. Otteniamo oid abbonamenti:

psql -h replica2 -d dbname -c "select oid, * from pg_subscription;"

9. Supponiamo che sia stato ottenuto oid=1000. Applicheremo il numero della transazione all'abbonamento:

psql -h replica2 -d dbname -c "select pg_replication_origin_advance('pg_1000', 'AA/AAAAAAAA');"

10. Avviamo la replica:

psql -h replica2 -d dbname -c "alter subscription oldprod enable;"

11. Verifichiamo lo stato dell'iscrizione; la replica dovrebbe essere attiva:

psql -h replica2 -d dbname -c "select * from pg_replication_origin_status;"
psql -h master -d dbname -c "select slot_name, restart_lsn, confirmed_flush_lsn from pg_replication_slots;"

12. Dopo aver avviato la replica e sincronizzato i database, è possibile effettuare il failover.

13. Dopo aver disattivato la replica, è necessario correggere le sequenze. Questo è ben descritto nell'articolo su wiki.postgresql.org.

Grazie a questo piano, il failover è avvenuto con ritardi minimi.

Conclusione

Gli operatori Kubernetes consentono di semplificare diverse azioni, riducendole alla creazione di risorse K8s. Tuttavia, avendo raggiunto una notevole automazione con il loro aiuto, è importante ricordare che essa può portare anche a una serie di imprevisti, quindi approcciate la scelta degli operatori con saggezza.

Dopo aver esaminato i tre operatori Kubernetes più popolari per PostgreSQL, abbiamo deciso di scegliere il progetto di Zalando. Abbiamo affrontato alcune difficoltà, ma il risultato è stato veramente soddisfacente, tanto che intendiamo ampliare questa esperienza ad alcune altre installazioni PgSQL. Se avete esperienza con soluzioni simili, saremo felici di conoscere i dettagli nei commenti!

P.S.

Leggete anche nel nostro blog:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster