Krótki przegląd operatorów PostgreSQL dla Kubernetes, nasz wybór i doświadczenie

Krótki przegląd operatorów PostgreSQL dla Kubernetes, nasz wybór i doświadczenie

Coraz częściej klienci składają takie prośby: „Chcemy coś jak Amazon RDS, ale taniej”; „Chcemy coś jak RDS, ale wszędzie, w każdej infrastrukturze”. Aby zrealizować takie rozwiązanie managed na Kubernetes, przyjrzeliśmy się obecnemu stanowi najpopularniejszych operatorów dla PostgreSQL (Stolon, operatorzy od Crunchy Data i Zalando) i dokonaliśmy swojego wyboru.

Ten artykuł to nasze doświadczenie zdobyte zarówno z teoretycznego punktu widzenia (przegląd rozwiązań), jak i praktycznego (co zostało wybrane i co z tego wyszło). Na początek ustalmy, jakie w ogóle wymagania stawiane są potencjalnemu zamiennikowi RDS...

Czym właściwie jest RDS

Kiedy ludzie mówią o RDS, z naszego doświadczenia wynika, że mają na myśli zarządzaną usługę bazy danych (DBaaS), która:

  1. łatwo się konfiguruje;
  2. ma możliwość pracy z migawkami i ich przywracania (najlepiej z wsparciem PITR);
  3. pozwala na tworzenie topologii master-slave;
  4. ma bogatą listę rozszerzeń;
  5. zapewnia audyt i zarządzanie użytkownikami/dostępami.

Mówiąc ogólnie, podejścia do realizacji postawionego zadania mogą być bardzo różne, jednak droga z warunkowym Ansible nie jest dla nas bliska. (Do podobnego wniosku doszli również koledzy z 2GIS w wyniku swojej próby stworzenia „narzędzia do szybkiego wdrażania klastrów odpornych na błędy w oparciu o Postgres”.)

To właśnie operatorzy — powszechnie akceptowane podejście do rozwiązywania tego typu zadań w ekosystemie Kubernetes. Szczegóły na ich temat w odniesieniu do baz danych uruchamianych wewnątrz Kubernetes już omawiał dyrektor techniczny „Flanta”, distol, w w jednym ze swoich wystąpień.

NB: Aby szybko tworzyć proste operatory, zachęcamy do zwrócenia uwagi na nasze narzędzie Open Source shell-operator. Używając go, można to robić bez znajomości Go, a bardziej znanymi dla administratorów sposobami: w Bash, Python itd.

Dla PostgreSQL istnieje kilka popularnych operatorów K8s:

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

Przyjrzyjmy się im bliżej.

Wybór operatora

Oprócz tych ważnych możliwości, które zostały już wymienione, my — jako inżynierowie ds. infrastruktury w Kubernetes — również oczekiwaliśmy od operatorów następujących funkcji:

  • wdrożenie z Gita i z Custom Resources;
  • wsparcie dla pod anti-affinity;
  • instalacja node affinity lub node selector;
  • instalacja tolerancji;
  • możliwości tuningu;
  • zrozumiałe technologie i nawet komendy.

Nie wnikając w szczegóły każdego z punktów (zapytaj w komentarzach, jeśli masz pytania po przeczytaniu całego artykułu), zauważę, że te parametry są potrzebne do dokładniejszego opisu specjalizacji węzłów klastra, aby zamawiać je pod konkretne aplikacje. W ten sposób możemy osiągnąć optymalną równowagę w kwestiach wydajności i kosztów.

Teraz przejdźmy do operatorów PostgreSQL.

1. Stolon

Stolon od włoskiej firmy Sorint.lab w już wspomnianym raporcie był omawiany jako pewnego rodzaju wzorzec wśród operatorów dla DBMS. To dość stary projekt: jego pierwsza publiczna wersja miała miejsce w listopadzie 2015 roku(!), a repozytorium GitHub może pochwalić się prawie 3000 gwiazdek i 40+ współtwórcami.

I rzeczywiście, Stolon to doskonały przykład przemyślanej architektury:

Krótki przegląd operatorów PostgreSQL dla Kubernetes, nasz wybór i doświadczenie
Z konstrukcją tego operatora można zapoznać się w raportach lub dokumentacji projektu. Ogólnie można powiedzieć, że potrafi wszystko, co zostało opisane: failover, proxy do transparentnego dostępu klientów, kopie zapasowe… Przy czym proxy zapewniają dostęp przez jeden punkt końcowy usługi — w przeciwieństwie do dwóch innych rozwiązań omówionych poniżej (mają po dwa usługi do dostępu do bazy danych).

Jednak Stolon nie ma zasobów niestandardowych, przez co nie można go tak wdrażać, aby łatwo i szybko — „jak gorące bułeczki” — tworzyć instancje DBMS w Kubernetes. Zarządzanie odbywa się za pomocą narzędzia stolonctl, wdrożenie — przez wykres Helm, a użytkownicy definiują zasoby w ConfigMap.

Z jednej strony, okazuje się, że operator nie jest w pełni operatorem (bowiem nie używa CRD). Z drugiej strony — to elastyczny system, który pozwala dostosować zasoby w K8s tak, jak ci wygodnie.

Podsumowując, osobiście wydaje się, że nie było optymalnym rozwiązaniem zakładanie oddzielnego wykresu dla każdej bazy danych. Dlatego zaczęliśmy szukać alternatyw.

2. Operator PostgreSQL Crunchy Data

Operator od Crunchy Data, młodego amerykańskiego startupu, wydawał się logiczną alternatywą. Jego publiczna historia zaczyna się od pierwszego wydania w marcu 2017 roku, od tego czasu repozytorium GitHub otrzymało nieco mniej niż 1300 gwiazdek i 50+ współtwórców. Ostatnia wersja z września została przetestowana pod kątem współpracy z Kubernetes 1.15—1.18, OpenShift 3.11+ i 4.4+, GKE oraz VMware Enterprise PKS 1.3+.

Architektura operatora PostgreSQL Crunchy Data również spełnia zadeklarowane wymagania:

Krótki przegląd operatorów PostgreSQL dla Kubernetes, nasz wybór i doświadczenie

Zarządzanie odbywa się za pomocą narzędzia pgo, jednak w swoim przypadku generuje Custom Resources dla Kubernetes. Dlatego operator zaskoczył nas jako potencjalnych użytkowników:

  • jest zarządzanie przez CRD;
  • wygodne zarządzanie użytkownikami (też przez CRD);
  • integracja z innymi komponentami Crunchy Data Container Suite — specjalizowany zbiór obrazów kontenerów dla PostgreSQL oraz narzędzi do pracy z nimi (w tym pgBackRest, pgAudit, rozszerzenia z contrib itd.).

Jednak próby rozpoczęcia korzystania z operatora od Crunchy Data ujawniły kilka problemów:

  • Nie było możliwości tolerancji — przewidziany był tylko nodeSelector.
  • Tworzone pod’y były częścią Deployment’u, mimo że wdrażaliśmy aplikację stateful. W przeciwieństwie do StatefulSet, Deployment’y nie potrafią tworzyć dysków.

Ostatnia wada prowadzi do zabawnych sytuacji: w środowisku testowym udało się uruchomić 3 repliki z jednym dyskiem local storage, w wyniku czego operator informował, że 3 repliki działają (chociaż tak nie było).

Kolejną cechą tego operatora jest jego gotowa integracja z różnymi systemami pomocniczymi. Na przykład, łatwo zainstalować pgAdmin i pgBounce, a w dokumentacji rozważa się wstępnie skonfigurowane Grafana i Prometheus. W niedawnym wydaniu 4.5.0-beta1 z osobna zauważono lepszą integrację z projektem pgMonitor, dzięki czemu operator oferuje intuicyjną wizualizację metryk PgSQL „prosto z pudełka”.

Jednakże dziwny wybór generowanych zasobów Kubernetes doprowadził nas do konieczności znalezienia innego rozwiązania.

3. Zalando Postgres Operator

Produkty Zalando są nam znane od dawna: mamy doświadczenie w korzystaniu z Zalenium i oczywiście próbowaliśmy Patroni — ich popularne rozwiązanie HA dla PostgreSQL. O podejściu firmy do stworzenia Postgres Operator opowiadał jeden z jego autorów — Aleksiej Kljukin — w programie Postgres-wtorek №5, i bardzo nam się spodobał.

To najmłodsze rozwiązanie z rozważanych w artykule: pierwszy release odbył się w sierpniu 2018 roku. Jednak, mimo niewielkiej liczby formalnych wydań, projekt przeszedł długą drogę, wyprzedzając już pod względem popularności rozwiązanie od Crunchy Data z 1300+ gwiazdkami na GitHub i maksymalną liczbą współtwórców (70+).

„Pod maską” tego operatora stosowane są rozwiązania,które przetrwały próbę czasu:

Oto jak przedstawiona jest architektura operatora od Zalando:

Krótki przegląd operatorów PostgreSQL dla Kubernetes, nasz wybór i doświadczenie

Operator jest w pełni zarządzany za pomocą Custom Resources, automatycznie tworzy StatefulSet z kontenerów, które następnie można dostosować, dodając do pod różne sidecary. To wszystko to znacząca zaleta w porównaniu z operatorem od Crunchy Data.

Ponieważ to rozwiązanie od Zalando wybraliśmy spośród 3 rozważanych opcji, dalszy opis jego możliwości zostanie przedstawiony poniżej, od razu wraz z praktyką zastosowania.

Praktyka z Postgres Operatorem od Zalando

Wdrożenie operatora odbywa się bardzo prosto: wystarczy pobrać aktualną wersję z GitHub i zastosować pliki YAML z katalogu. manifests. Alternatywnie można również skorzystać z OperatorHub.

Po zainstalowaniu warto zadbać o konfigurację magazynów dla logów i kopii zapasowych. Realizuje się ją przez ConfigMap postgres-operator w przestrzeni nazw, do której zainstalowano operatora. Gdy magazyny są skonfigurowane, można uruchomić pierwszy klaster PostgreSQL.

Na przykład, standardowe wdrożenie wygląda następująco:

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

Ten manifest wdraża klaster z 3 instancjami z sidecarem w postaci postgres_exporter, z którego zbieramy metryki aplikacji. Jak widać, wszystko jest bardzo proste, a w razie potrzeby można utworzyć praktycznie nieograniczoną liczbę klastrów.

Warto również zwrócić uwagę na panel webowy do administracjipostgres-operator-ui. Dostarczany jest razem z operatorem i pozwala na tworzenie i usuwanie klastrów, a także na pracę z kopiami zapasowymi, które wykonuje operator.

Krótki przegląd operatorów PostgreSQL dla Kubernetes, nasz wybór i doświadczenie
Lista klastrów PostgreSQL

Krótki przegląd operatorów PostgreSQL dla Kubernetes, nasz wybór i doświadczenie
Zarządzanie kopiami zapasowymi

Inną interesującą funkcją jest wsparcie dla Teams API. Ten mechanizm automatycznie tworzy role w PostgreSQL, na podstawie otrzymanej listy nazw użytkowników. Następnie API pozwala zwrócić listę użytkowników, dla których automatycznie tworzone są role.

Problemy i ich rozwiązanie

Jednak użycie operatora wkrótce ujawniło kilka istotnych wad:

  1. brak wsparcia dla nodeSelector;
  2. niemożność wyłączenia kopii zapasowych;
  3. przy korzystaniu z funkcji tworzenia baz nie pojawiają się domyślne uprawnienia;
  4. czasami brakuje dokumentacji lub jest ona nieaktualna.

Na szczęście wiele z nich można rozwiązać. Zacznijmy od końca — problemów z dokumentacją.

Najprawdopodobniej napotkasz sytuację, w której nie zawsze jasne jest, jak skonfigurować kopię zapasową i jak podłączyć kopię zapasową do Operator UI. W dokumentacji jest to wspomniane mimochodem, a szczegółowy opis znajduje się w PR:

  1. trzeba utworzyć sekret;
  2. przekazać go operatorowi w parametrze pod_environment_secret_name w CRD z ustawieniami operatora lub w ConfigMap (zależnie od tego, jak zdecydowałeś się zainstalować operatora).

Jednak jak się okazało, w tej chwili to niemożliwe. Dlatego zebraliśmy naszą wersję operatora z dodatkowymi zewnętrznymi rozwiązaniami. Więcej informacji — patrz poniżej.

Jeśli przekazujesz operatorowi parametry dla kopii zapasowej, a dokładniej — wal_s3_bucket i klucze dostępu do AWS S3, to on będzie robić kopie zapasowe wszystkiego: nie tylko baz w produkcji, ale także staging. Nas to nie satysfakcjonowało.

W opisie parametrów do Spilo, które jest podstawowym opakowaniem Docker dla PgSQL przy użyciu operatora, wykazano: można przekazać parametr WAL_S3_BUCKET jako pusty, tym samym wyłączając kopie zapasowe. Co więcej, z wielką radością znalazł się także gotowy PR, który natychmiast przyjęliśmy do naszego fork'a. Teraz wystarczy po prostu dodać enableWALArchiving: false do zasobu klastra PostgreSQL.

Tak, istniała możliwość zrobienia inaczej, uruchamiając 2 operatorów: jeden dla staging (bez kopii zapasowych), a drugi — dla produkcji. Ale w ten sposób mogliśmy obejść się jednym.

Dobrze, nauczyliśmy się przekazywać dostęp do S3 dla baz i kopie zapasowe zaczęły trafiać do magazynu. Jak sprawić, by strony kopii zapasowych działały w Operator UI?

Krótki przegląd operatorów PostgreSQL dla Kubernetes, nasz wybór i doświadczenie

W Operator UI należy dodać 3 zmienne:

  • SPILO_S3_BACKUP_BUCKET
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

Po tym zarządzanie kopiami zapasowymi stanie się dostępne, co w naszym przypadku uprości pracę ze staging, umożliwiając dostarczanie tam migawków z produkcji bez dodatkowych skryptów.

Jako dodatkowy plus wymieniano współpracę z Teams API oraz szerokie możliwości tworzenia baz i ról za pomocą operatora. Jednak tworzone role nie miały domyślnych uprawnień.W związku z tym użytkownik z uprawnieniami do odczytu nie mógł odczytywać nowych tabel.

Dlaczego tak? Pomimo, że w kodzie jest są niezbędne, GRANTnie są stosowane zbyt często. Są 2 metody: syncPreparedDatabases i syncDatabases. W syncPreparedDatabases — mimo że w sekcji preparedDatabases jest jest warunek defaultRoles i defaultUsers do tworzenia ról, — prawa domyślne nie są stosowane. Jesteśmy w trakcie przygotowywania aktualizacji, aby te prawa były stosowane automatycznie.

I ostatnia kwestia w aktualnych dla nas usprawnieniach — łatkę, dodający Node Affinity do tworzonego StatefulSet. Nasi klienci często wolą ograniczać koszty, korzystając z instancji spot, a na nich zdecydowanie nie należy umieszczać usług DB. Ten problem można byłoby rozwiązać również poprzez tolerancje, ale obecność Node Affinity daje większą pewność.

Co udało się osiągnąć?

W wyniku rozwiązania wymienionych problemów wzięliśmy Postgres Operator od Zalando do swojego repozytorium, gdzie jest zbierany z tak przydatnymi poprawkami. A dla większej wygody zebraliśmy i obraz Dockera.

Lista PR-ów przyjętych do forka:

Będzie świetnie, jeśli społeczność wesprze te PR-y, aby trafiły do upstream z następną wersją operatora (1.6).

Bonus! Historia sukcesu z migracją produkcji

Jeśli używasz Patroni, można migrować działającą produkcję na operatora z minimalnym przestojem.

Spilo umożliwia tworzenie klastrów standby przez przechowywanie w S3 z Wal-E, gdy binarny log PgSQL najpierw jest przechowywany w S3, a następnie pobierany przez replikę. Ale co zrobić, jeśli masz nie używasz Wal-E w starej infrastrukturze? Rozwiązanie tego problemu już zostało zaproponowane na Habrze.

Na pomoc przychodzi logiczna replikacja PostgreSQL. Jednak nie wchodźmy w szczegóły, jak tworzyć publikacje i subskrypcje, ponieważ… nasz plan się nie powiódł.

Chodzi o to, że w DB było kilka obciążonych tabel z milionami wierszy, które dodatkowo były stale zasilane i usuwane. Prosta subskrypcja z copy_data, gdy nowa replika kopiuje całą zawartość z mastera, po prostu nie zdążała za masterem. Kopiowanie treści działało przez tydzień, ale wciąż nie dogoniło mastera. W końcu, aby rozwiązać problem, pomogli artykuł koledzy z Avito: można przenieść dane, używając pg_dump. Opiszę naszą (nieco poprawioną) wersję tego algorytmu.

Pomysł polega na tym, że można utworzyć wyłączoną subskrypcję powiązaną z danym slotem replikacji, a następnie naprawić numer transakcji. Były dostępne repliki do pracy w środowisku produkcyjnym. To ważne, ponieważ replika pomoże stworzyć spójny zrzut i kontynuować odbieranie zmian z głównego serwera.

W kolejnych poleceniach opisujących proces migracji będą używane następujące oznaczenia dla hostów:

  1. master — serwer źródłowy;
  2. replica1 — strumieniowa replika na starym środowisku produkcyjnym;
  3. replica2 — nowa logiczna replika.

Plan migracji

1. Utworzymy na głównym serwerze subskrypcję na wszystkie tabele w schemacie public bazy dbname:

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

2. Utworzymy slot replikacji na głównym serwerze:

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

3. Zatrzymamy replikację na starej reprlikcie:

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

4. Odbierzemy numer transakcji z głównego serwera:

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

5. Zrobimy zrzut ze starej repliki. Będziemy to robić w kilku wątkach, co pomoże przyspieszyć proces:

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

6. Załadujemy zrzut na nowy serwer:

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

7. Po załadowaniu zrzutu, można uruchomić replikację na strumieniowej replice:

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

7. Utworzymy subskrypcję na nowej logicznej replicie:

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. Odbierzemy oid subskrypcji:

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

9. Załóżmy, że otrzymaliśmy oid=1000. Zastosujemy numer transakcji do subskrypcji:

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

10. Uruchomimy replikację:

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

11. Sprawdzimy status subskrypcji, replikacja powinna działać:

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. Po uruchomieniu replikacji i synchronizacji baz, można przeprowadzić przełączenie.

13. Po wyłączeniu replikacji należy naprawić sekwencje. Jest to dobrze opisane w artykule na wiki.postgresql.org.

Dzięki takiemu planowi przełączenie przebiegło z minimalnymi opóźnieniami.

Podsumowanie

Operatory Kubernetes umożliwiają uproszczenie różnych działań, sprowadzając je do tworzenia zasobów K8s. Jednak osiągając wspaniałą automatyzację dzięki nim, warto pamiętać, że może to przynieść także szereg nieoczekiwanych niuansów, dlatego podejdź z rozwagą do wyboru operatorów.

Po zbadaniu trzech najbardziej popularnych operatorów Kubernetes dla PostgreSQL, zdecydowaliśmy się na projekt od Zalando. Napotkaliśmy pewne trudności, ale efekt naprawdę nas ucieszył, więc planujemy rozszerzyć to doświadczenie na inne instalacje PgSQL. Jeśli masz doświadczenie w korzystaniu z podobnych rozwiązań — chętnie zobaczymy szczegóły w komentarzach!

P.S.

Przeczytaj także na naszym blogu:

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster