Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza

Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza

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

Questo articolo rappresenta la nostra esperienza acquisita sia dal punto di vista teorico (panoramica delle soluzioni) che pratico (cosa è stato scelto e cosa ne è venuto fuori). Ma prima di tutto, definiamo quali sono le esigenze richieste per una potenziale sostituzione di RDS...

Cos'è RDS

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

  1. è facilmente configurabile;
  2. ha la possibilità di lavorare con snapshot e di ripristinarli (preferibilmente con supporto per PITR);
  3. consente di creare topologie master-slave;
  4. ha un'ampia lista di estensioni;
  5. fornisce audit e gestione degli utenti/accessi.

Parlando in generale, gli approcci per affrontare la questione possono essere molto diversi, tuttavia la strada con il presunto Ansible non ci si addice. (Nello stesso modo sono giunti a una conclusione simile anche i colleghi di 2GIS a seguito della loro tentativo di creare uno «strumento per il rapido dispiegamento di un cluster ad alta disponibilità basato su Postgres».)

Gli operatori sono l'approccio convenzionale per affrontare tali questioni nell'ecosistema Kubernetes. Abbiamo già parlato di questo in relazione ai database eseguiti all'interno di Kubernetes, il CTO di «Flanta» distol, in in una delle sue relazioni.

NB: Per creare rapidamente operatori semplici, ti consigliamo di dare un'occhiata alla nostra utilità Open Source shell-operator. Utilizzando essa, puoi farlo senza conoscere Go, attraverso modi più familiari per i sistemi, come Bash, Python, ecc.

Per PostgreSQL esistono diversi popolari operatori K8s:

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

Esaminiamoli più da vicino.

Scelta dell'operatore

Oltre alle importanti funzionalità già menzionate, noi – come ingegneri di gestione dell'infrastruttura in Kubernetes – ci aspettavamo anche dai nostri operatori quanto segue:

  • deploy da Git e con Custom Resources;
  • supporto per pod anti-affinity;
  • installazione di node affinity o node selector;
  • installazione di tolerations;
  • disponibilità di opzioni di tuning;
  • tecnologie comprensibili e anche comandi.

Senza entrare nei dettagli su ciascun punto (chiedi nei commenti se hai domande dopo aver letto l'intero articolo), vorrei sottolineare in generale che questi parametri sono necessari per una descrizione più dettagliata della specializzazione dei nodi del cluster, in modo da poterli ordinare per applicazioni specifiche. In questo modo possiamo raggiungere un equilibrio ottimale tra prestazioni e costi.

Ora passiamo agli operatori PostgreSQL.

1. Stolon

Stolon dall'azienda italiana Sorint.lab in già citato nella relazione è stato considerato un certo standard tra gli operatori per DBMS. Questo è un progetto piuttosto vecchio: la sua prima versione pubblica risale a novembre 2015 (!), e il repository su GitHub può vantare quasi 3000 stelle e oltre 40 collaboratori.

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

Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza
Puoi approfondire il funzionamento di questo operatore nella relazione o documentazione del progetto. In generale, basta dire che è in grado di fare tutto ciò che è descritto: failover, proxy per accesso trasparente ai client, backup... Inoltre, i proxy forniscono accesso tramite un unico endpoint di servizio - a differenza delle due altre soluzioni esaminate più avanti (che hanno due servizi per accedere al database).

Tuttavia, Stolon non ha Custom Resources, il che rende impossibile implementarlo in modo che si possano creare istanze di DBMS in Kubernetes in modo semplice e veloce - "come panini caldi". La gestione avviene tramite l'utilità stolonctl, mentre il deploy avviene tramite un chart Helm e le definizioni utente sono impostate in ConfigMap.

Da un lato, sembra che l'operatore non sia proprio un operatore (dopotutto non utilizza CRD). D'altra parte, è un sistema flessibile che consente di configurare le risorse in K8s come preferisci.

In sintesi, non ci è sembrato ottimale avere un chart separato per ogni DB. Pertanto, abbiamo cominciato 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 nel 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 breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza

La gestione avviene tramite l'utilità pgo, tuttavia essa a sua volta genera Custom Resources per Kubernetes. Pertanto, come potenziali utenti, l'operatore ci ha soddisfatto:

  • c'è gestione tramite CRD;
  • comoda gestione degli utenti (anch'essa tramite CRD);
  • integrazione con altri componenti Crunchy Data Container Suite — una collezione specializzata di immagini di container per PostgreSQL e utilità per lavorarci (incluso pgBackRest, pgAudit, estensioni da contrib, ecc.).

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

  • Non c'era la possibilità di tolerations — era previsto solo nodeSelector.
  • I pod creati facevano parte di un Deployment, nonostante stessimo deployando un'applicazione stateful. A differenza di StatefulSet, i Deployment non possono creare dischi.

Questo ultimo difetto porta a momenti divertenti: nell'ambiente di test siamo riusciti a far partire 3 repliche con un solo disco storage locale, con il risultato che l'operatore riportava che 3 repliche stavano funzionando (anche se non era così).

Un'altra caratteristica di questo operatore è la sua integrazione pronta con vari sistemi ausiliari. Ad esempio, è facile installare pgAdmin e pgBounce, e in documentazione sono considerate Grafana e Prometheus preconfigurate. Nel recente rilascio 4.5.0-beta1 si segnala un miglioramento dell'integrazione con il progetto pgMonitor, il che consente all'operatore di offrire una visualizzazione chiara delle metriche PgSQL «out of the box».

Tuttavia, la strana scelta di 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 nell'utilizzo di Zalenium e, naturalmente, abbiamo provato Patroni — la loro soluzione HA popolare per PostgreSQL. Uno degli autori, Alexey Klukin, ha parlato dell'approccio dell'azienda nella creazione del Postgres Operator nella diretta del Postgres Tuesday #5, e ci è piaciuto.

Questa è la soluzione più recente tra quelle considerate nell'articolo: il primo rilascio è avvenuto nell'agosto 2018. Tuttavia, nonostante il numero ridotto di rilasci formali, il progetto ha fatto molta strada, superando già la soluzione di Crunchy Data con oltre 1300 stelle su GitHub e il numero massimo di contributori (oltre 70).

Sotto il cofano, questo operatore utilizza soluzioni collaudate nel tempo:

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

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

Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza

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

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

Pratica con Postgres Operator di Zalando

Il deploy dell'operatore avviene in modo molto semplice: è sufficiente scaricare l'ultima versione da GitHub e applicare i file YAML dalla directory. manifestsIn alternativa, è possibile anche utilizzare OperatorHub.

Dopo l'installazione, è opportuno preoccuparsi della configurazione di archiviazione per i log e i backup. Si effettua tramite ConfigMap postgres-operator nello spazio dei nomi in cui hai installato l'operatore. Una volta configurati gli archivi, puoi avviare il primo cluster PostgreSQL.

Ad esempio, il deploy 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
 sidecar:
 - 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 deploya un cluster di 3 istanze con un sidecar in forma di postgres_exporter, dal quale raccogliamo le metriche dell'applicazione. Come puoi vedere, è tutto molto semplice e, se lo desideri, puoi creare un numero praticamente illimitato di cluster.

Vale la pena prestare attenzione anche alla interfaccia web per la gestionepostgres-operator-ui. Viene fornita insieme all'operatore e consente di creare ed eliminare cluster, così come di gestire i backup effettuati dall'operatore.

Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza
Elenco dei cluster PostgreSQL

Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza
Gestione dei backup

Un'altra caratteristica interessante è il supporto per Teams API. Questo meccanismo crea automaticamente ruoli in PostgreSQL, basandosi sull'elenco ricevuto di nomi degli utenti. Successivamente, l'API consente di restituire l'elenco degli utenti per i quali vengono creati automaticamente i ruoli.

Problemi e loro soluzione

Tuttavia, l'uso dell'operatore ha presto rivelato alcuni significativi svantaggi:

  1. mancanza di supporto per nodeSelector;
  2. impossibilità di disattivare i backup;
  3. quando si utilizza la funzione di creazione delle basi non compaiono privilegi di default;
  4. periodicamente manca la documentazione o questa è obsoleta.

Fortunatamente, molti di essi possono essere risolti. Iniziamo dalla fine: problemi con documentazione.

Probabilmente vi imbatterete nel fatto che non è sempre chiaro come specificare il backup e come collegare il bucket di backup all'Operator UI. Questo viene citato brevemente nella documentazione, ma la descrizione reale si trova in PR:

  1. è necessario creare un segreto;
  2. passarlo all'operatore nel parametro pod_environment_secret_name nel CRD con le impostazioni dell'operatore o nel ConfigMap (dipende da come avete deciso di installare l'operatore).

Tuttavia, come si è rivelato, attualmente non è possibile. Ecco perché abbiamo raccolto la nostra versione dell'operatore con alcune funzionalità aggiuntive di terze parti. Maggiori dettagli su di essa — vedi sotto.

Se si passano all'operatore parametri per il backup, in particolare — wal_s3_bucket e le chiavi di accesso in AWS S3, allora lui effettuerà il backup di tutto: non solo le basi in produzione, ma anche quelle di staging. Questo non ci ha soddisfatti.

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

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

Ok, abbiamo imparato a fornire accesso alle basi per S3 e i backup hanno iniziato a essere memorizzati. Come far funzionare le pagine dei backup nell'Operator UI?

Panoramica breve degli operatori PostgreSQL per Kubernetes, la nostra scelta e esperienza

Nell'Operator UI sarà necessario aggiungere 3 variabili:

  • SPILO_S3_BACKUP_BUCKET
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

Dopo di che la gestione dei backup diventerà disponibile, il che nel nostro caso semplificherà il lavoro con lo staging, consentendo di portare lì tagli dalla produzione senza script aggiuntivi.

Come ulteriore vantaggio, è stata menzionata la gestione con l'API Teams e le ampie possibilità per la creazione di basi e ruoli tramite l'operatore. Tuttavia, i ruoli creati non avevano diritti di default. Di conseguenza, un utente con diritti di lettura non poteva leggere nuove tabelle.

Perché è così? Nonostante nel codice ci siano c'è necessari GRANT, non vengono applicati sempre. Ci sono 2 metodi: syncPreparedDatabases e syncDatabases. In syncPreparedDatabases — nonostante che nella sezione preparedDatabases c'è ci sia una condizione defaultRoles e defaultUsers per la creazione di ruoli, i permessi predefiniti non vengono applicati. Siamo nel processo di preparazione di una patch affinché questi diritti vengano applicati automaticamente.

E l'ultimo punto nelle modifiche per noi rilevanti è patch, che aggiunge Node Affinity nel StatefulSet creato. I nostri clienti spesso preferiscono ridurre i costi utilizzando istanze spot, e su di esse chiaramente non si dovrebbero collocare servizi DB. Questo problema potrebbe essere risolto anche tramite tolerations, ma la presenza di Node Affinity offre maggiore sicurezza.

Cosa è emerso?

A seguito della risoluzione dei problemi elencati, abbiamo forkato il Postgres Operator di Zalando nel nostro repository, dove viene compilato con patch così utili. E per maggior comodità abbiamo raccolto anche Docker image.

Elenco delle PR accettate nel fork:

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

Bonus! Storia di successo con la migrazione della produzione

Se utilizzi Patroni, puoi migrare una produzione live con un minimo di downtime.

Spilo consente la creazione di cluster standby tramite archiviazione S3 con Wal-E, quando il log binario PgSQL viene prima salvato in S3 e poi estratto dal replica. Ma cosa fare se hai non Wal-E utilizzato nella tua vecchia infrastruttura? La soluzione a questo problema è già stata proposta su Habr.

La replica logica di PostgreSQL viene in soccorso. Tuttavia, non ci addentreremo nei dettagli su come creare pubblicazioni e sottoscrizioni, perché... il nostro piano ha subito un fallimento.

Il fatto è che nel DB c'erano alcune tabelle sovraccariche con milioni di righe, che, inoltre, venivano continuamente riempite e svuotate. Una semplice sottoscrizione con copy_data, in cui il nuovo replica copia tutto il contenuto dal master, semplicemente non riusciva a stare dietro al master. La copia del contenuto ha funzionato per una settimana, ma non ha mai raggiunto il master. Alla fine, per risolvere il problema ci hanno aiutato su Habr. colleghi di Avito: è possibile trasferire i dati utilizzando pg_dump. Descriverò la nostra versione (leggermente modificata) di questo algoritmo.

L'idea è quella di poter creare una sottoscrizione disattivata, legata a uno specifico slot di replica, e poi correggere il numero della transazione. Erano disponibili repliche per il lavoro di produzione. Questo è importante perché la replica aiuterà a creare un dump coerente e a continuare a ricevere modifiche dal master.

Nelle successive istruzioni che descrivono il processo di migrazione, verranno utilizzate le seguenti designazioni per gli host:

  1. master — server sorgente;
  2. replica1 — replica in streaming sulla vecchia produzione;
  3. replica2 — nuova replica logica.

Piano di migrazione

1. Creiamo sul master una sottoscrizione per tutte le tabelle nello schema pubblico del database dbname:

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

2. Creiamo uno slot di replica sul master:

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

3. Fermeremo 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. Eseguiremo un dump dalla vecchia replica. Lo faremo in più thread, il che aiuterà ad accelerare 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 aver caricato il dump, possiamo avviare la replica sulla replica in streaming:

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

7. Creiamo una sottoscrizione 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 della sottoscrizione:

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

9. Supponiamo di aver ottenuto oid=1000. Applicheremo il numero della transazione alla sottoscrizione:

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. Controlliamo lo stato della sottoscrizione; la replica dovrebbe funzionare:

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 che la replica è stata avviata e i database sono stati sincronizzati, si può effettuare il switch.

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

Grazie a questo piano, il passaggio è avvenuto con minime attese.

Conclusione

I operator di Kubernetes semplificano diverse operazioni, riducendole alla creazione di risorse K8s. Tuttavia, una volta raggiunta una straordinaria automazione con il loro aiuto, è importante ricordare che possono portare anche una serie di sfide inaspettate, quindi scegliete gli operatori con saggezza.

Esaminando i tre operatori Kubernetes più popolari per PostgreSQL, abbiamo deciso di optare per il progetto di Zalando. Con questo abbiamo dovuto affrontare alcune difficoltà, ma il risultato è stato davvero soddisfacente, tanto che prevediamo di estendere questa esperienza ad alcune altre installazioni PgSQL. Se avete esperienza con soluzioni simili, saremo felici di vedere i dettagli nei commenti!

P.S.

Leggi 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