{"id":95322,"date":"2020-09-28T07:42:39","date_gmt":"2020-09-28T05:42:39","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt"},"modified":"2020-09-28T07:42:39","modified_gmt":"2020-09-28T05:42:39","slug":"kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt","title":{"rendered":"Kr\u00f3tki przegl\u0105d operator\u00f3w PostgreSQL dla Kubernetes, nasz wyb\u00f3r i do\u015bwiadczenie","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Kr\u00f3tki przegl\u0105d operator\u00f3w PostgreSQL dla Kubernetes, nasz wyb\u00f3r i do\u015bwiadczenie\" src=\"\/wp-content\/uploads\/2020\/09\/23b2db49941fa5bd5000358c8ffb991b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nCoraz cz\u0119\u015bciej klienci sk\u0142adaj\u0105 takie pro\u015bby: \u201eChcemy co\u015b jak Amazon RDS, ale taniej\u201d; \u201eChcemy co\u015b jak RDS, ale wsz\u0119dzie, w ka\u017cdej infrastrukturze\u201d. Aby zrealizowa\u0107 takie rozwi\u0105zanie managed na Kubernetes, przyjrzeli\u015bmy si\u0119 obecnemu stanowi najpopularniejszych operator\u00f3w dla PostgreSQL (Stolon, operatorzy od Crunchy Data i Zalando) i dokonali\u015bmy swojego wyboru.<\/p>\n<p>Ten artyku\u0142 to nasze do\u015bwiadczenie zdobyte zar\u00f3wno z teoretycznego punktu widzenia (przegl\u0105d rozwi\u0105za\u0144), jak i praktycznego (co zosta\u0142o wybrane i co z tego wysz\u0142o). Na pocz\u0105tek ustalmy, jakie w og\u00f3le wymagania stawiane s\u0105 potencjalnemu zamiennikowi RDS...<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Czym w\u0142a\u015bciwie jest RDS<\/h2>\n<p>\nKiedy ludzie m\u00f3wi\u0105 o RDS, z naszego do\u015bwiadczenia wynika, \u017ce maj\u0105 na my\u015bli zarz\u0105dzan\u0105 us\u0142ug\u0119 bazy danych (DBaaS), kt\u00f3ra:<\/p>\n<ol>\n<li>\u0142atwo si\u0119 konfiguruje;<\/li>\n<li>ma mo\u017cliwo\u015b\u0107 pracy z migawkami i ich przywracania (najlepiej z wsparciem <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Point-in-time_recovery\">PITR<\/a><\/noindex>);<\/li>\n<li>pozwala na tworzenie topologii master-slave;<\/li>\n<li>ma bogat\u0105 list\u0119 rozszerze\u0144;<\/li>\n<li>zapewnia audyt i zarz\u0105dzanie u\u017cytkownikami\/dost\u0119pami.<\/li>\n<\/ol>\n<p>\nM\u00f3wi\u0105c og\u00f3lnie, podej\u015bcia do realizacji postawionego zadania mog\u0105 by\u0107 bardzo r\u00f3\u017cne, jednak droga z warunkowym Ansible nie jest dla nas bliska. (Do podobnego wniosku doszli r\u00f3wnie\u017c koledzy z 2GIS w wyniku <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/509926\/\">swojej pr\u00f3by<\/a><\/noindex> stworzenia \u201enarz\u0119dzia do szybkiego wdra\u017cania klastr\u00f3w odpornych na b\u0142\u0119dy w oparciu o Postgres\u201d.)<\/p>\n<p>To w\u0142a\u015bnie operatorzy \u2014 powszechnie akceptowane podej\u015bcie do rozwi\u0105zywania tego typu zada\u0144 w ekosystemie Kubernetes. Szczeg\u00f3\u0142y na ich temat w odniesieniu do baz danych uruchamianych wewn\u0105trz Kubernetes ju\u017c omawia\u0142 dyrektor techniczny \u201eFlanta\u201d, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/users\/distol\/\" class=\"user_link\">distol<\/a><\/noindex>, w <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/431500\/\">w jednym ze swoich wyst\u0105pie\u0144<\/a><\/noindex>.<\/p>\n<p><i><strong>NB<\/strong><\/i><i>: Aby szybko tworzy\u0107 proste operatory, zach\u0119camy do zwr\u00f3cenia uwagi na nasze narz\u0119dzie Open Source <\/i><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/shell-operator\"><i>shell-operator<\/i><\/a><\/noindex><i>. U\u017cywaj\u0105c go, mo\u017cna to robi\u0107 bez znajomo\u015bci Go, a bardziej znanymi dla administrator\u00f3w sposobami: w Bash, Python itd.<\/i><\/p>\n<p>Dla PostgreSQL istnieje kilka popularnych operator\u00f3w K8s:<\/p>\n<ul>\n<li>Stolon;<\/li>\n<li>Operator PostgreSQL Crunchy Data;<\/li>\n<li>Operator Postgres Zalando.<\/li>\n<\/ul>\n<p>\nPrzyjrzyjmy si\u0119 im bli\u017cej.<\/p>\n<h2>Wyb\u00f3r operatora<\/h2>\n<p>\nOpr\u00f3cz tych wa\u017cnych mo\u017cliwo\u015bci, kt\u00f3re zosta\u0142y ju\u017c wymienione, my \u2014 jako in\u017cynierowie ds. infrastruktury w Kubernetes \u2014 r\u00f3wnie\u017c oczekiwali\u015bmy od operator\u00f3w nast\u0119puj\u0105cych funkcji:<\/p>\n<ul>\n<li> wdro\u017cenie z Gita i z <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/concepts\/extend-kubernetes\/operator\/#deploying-operators\">Custom Resources<\/a><\/noindex>;<\/li>\n<li> wsparcie dla pod anti-affinity;<\/li>\n<li> instalacja node affinity lub node selector;<\/li>\n<li> instalacja tolerancji;<\/li>\n<li> mo\u017cliwo\u015bci tuningu;<\/li>\n<li> zrozumia\u0142e technologie i nawet komendy.<\/li>\n<\/ul>\n<p>\nNie wnikaj\u0105c w szczeg\u00f3\u0142y ka\u017cdego z punkt\u00f3w (zapytaj w komentarzach, je\u015bli masz pytania po przeczytaniu ca\u0142ego artyku\u0142u), zauwa\u017c\u0119, \u017ce te parametry s\u0105 potrzebne do dok\u0142adniejszego opisu specjalizacji w\u0119z\u0142\u00f3w klastra, aby zamawia\u0107 je pod konkretne aplikacje. W ten spos\u00f3b mo\u017cemy osi\u0105gn\u0105\u0107 optymaln\u0105 r\u00f3wnowag\u0119 w kwestiach wydajno\u015bci i koszt\u00f3w.<\/p>\n<p>Teraz przejd\u017amy do operator\u00f3w PostgreSQL.<\/p>\n<h3>1. Stolon<\/h3>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/sorintlab\/stolon\">Stolon<\/a><\/noindex> od w\u0142oskiej firmy Sorint.lab w <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/431500\/\">ju\u017c wspomnianym raporcie<\/a><\/noindex> by\u0142 omawiany jako pewnego rodzaju wzorzec w\u015br\u00f3d operator\u00f3w dla DBMS. To do\u015b\u0107 stary projekt: jego pierwsza publiczna wersja mia\u0142a miejsce w listopadzie 2015 roku(!), a repozytorium GitHub mo\u017ce pochwali\u0107 si\u0119 prawie 3000 gwiazdek i 40+ wsp\u00f3\u0142tw\u00f3rcami.<\/p>\n<p>I rzeczywi\u015bcie, Stolon to doskona\u0142y przyk\u0142ad przemy\u015blanej architektury:<\/p>\n<p><img decoding=\"async\" alt=\"Kr\u00f3tki przegl\u0105d operator\u00f3w PostgreSQL dla Kubernetes, nasz wyb\u00f3r i do\u015bwiadczenie\" src=\"\/wp-content\/uploads\/2020\/09\/a34625c130bfd29c5645cf2417042de2.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nZ konstrukcj\u0105 tego operatora mo\u017cna zapozna\u0107 si\u0119 w raportach lub <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/sorintlab\/stolon\/blob\/master\/doc\/architecture.md\">dokumentacji projektu<\/a><\/noindex>. Og\u00f3lnie mo\u017cna powiedzie\u0107, \u017ce potrafi wszystko, co zosta\u0142o opisane: failover, proxy do transparentnego dost\u0119pu klient\u00f3w, kopie zapasowe\u2026 Przy czym proxy zapewniaj\u0105 dost\u0119p przez jeden punkt ko\u0144cowy us\u0142ugi \u2014 w przeciwie\u0144stwie do dw\u00f3ch innych rozwi\u0105za\u0144 om\u00f3wionych poni\u017cej (maj\u0105 po dwa us\u0142ugi do dost\u0119pu do bazy danych).<\/p>\n<p>Jednak Stolon <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/sorintlab\/stolon\/issues\/463#issuecomment-379666733\">nie ma zasob\u00f3w niestandardowych<\/a><\/noindex>, przez co nie mo\u017cna go tak wdra\u017ca\u0107, aby \u0142atwo i szybko \u2014 \u201ejak gor\u0105ce bu\u0142eczki\u201d \u2014 tworzy\u0107 instancje DBMS w Kubernetes. Zarz\u0105dzanie odbywa si\u0119 za pomoc\u0105 narz\u0119dzia <code>stolonctl<\/code>, wdro\u017cenie \u2014 przez wykres Helm, a u\u017cytkownicy definiuj\u0105 zasoby w ConfigMap.<\/p>\n<p>Z jednej strony, okazuje si\u0119, \u017ce operator nie jest w pe\u0142ni operatorem (bowiem nie u\u017cywa CRD). Z drugiej strony \u2014 to elastyczny system, kt\u00f3ry pozwala dostosowa\u0107 zasoby w K8s tak, jak ci wygodnie.<\/p>\n<p>Podsumowuj\u0105c, osobi\u015bcie wydaje si\u0119, \u017ce nie by\u0142o optymalnym rozwi\u0105zaniem zak\u0142adanie oddzielnego wykresu dla ka\u017cdej bazy danych. Dlatego zacz\u0119li\u015bmy szuka\u0107 alternatyw.<\/p>\n<h3>2. Operator PostgreSQL Crunchy Data<\/h3>\n<p>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CrunchyData\/postgres-operator\">Operator od Crunchy Data<\/a><\/noindex>, m\u0142odego ameryka\u0144skiego startupu, wydawa\u0142 si\u0119 logiczn\u0105 alternatyw\u0105. Jego publiczna historia zaczyna si\u0119 od pierwszego wydania w marcu 2017 roku, od tego czasu repozytorium GitHub otrzyma\u0142o nieco mniej ni\u017c 1300 gwiazdek i 50+ wsp\u00f3\u0142tw\u00f3rc\u00f3w. Ostatnia wersja z wrze\u015bnia zosta\u0142a przetestowana pod k\u0105tem wsp\u00f3\u0142pracy z Kubernetes 1.15\u20141.18, OpenShift 3.11+ i 4.4+, GKE oraz VMware Enterprise PKS 1.3+.<\/p>\n<p>Architektura operatora PostgreSQL Crunchy Data r\u00f3wnie\u017c spe\u0142nia zadeklarowane wymagania:<\/p>\n<p><img decoding=\"async\" alt=\"Kr\u00f3tki przegl\u0105d operator\u00f3w PostgreSQL dla Kubernetes, nasz wyb\u00f3r i do\u015bwiadczenie\" src=\"\/wp-content\/uploads\/2020\/09\/343cd0494abae42fcf5b47c5bb4eb310.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZarz\u0105dzanie odbywa si\u0119 za pomoc\u0105 narz\u0119dzia <code>pgo<\/code>, jednak w swoim przypadku generuje Custom Resources dla Kubernetes. Dlatego operator zaskoczy\u0142 nas jako potencjalnych u\u017cytkownik\u00f3w:<\/p>\n<ul>\n<li> jest zarz\u0105dzanie przez CRD;<\/li>\n<li> wygodne zarz\u0105dzanie u\u017cytkownikami (te\u017c przez CRD);<\/li>\n<li> integracja z innymi komponentami <noindex><a rel=\"nofollow\" href=\"https:\/\/access.crunchydata.com\/documentation\/crunchy-postgres-containers\/4.3.1\/\">Crunchy Data Container Suite<\/a><\/noindex> \u2014 specjalizowany zbi\u00f3r obraz\u00f3w kontener\u00f3w dla PostgreSQL oraz narz\u0119dzi do pracy z nimi (w tym pgBackRest, pgAudit, rozszerzenia z contrib itd.).<\/li>\n<\/ul>\n<p>\nJednak pr\u00f3by rozpocz\u0119cia korzystania z operatora od Crunchy Data ujawni\u0142y kilka problem\u00f3w:<\/p>\n<ul>\n<li>Nie by\u0142o mo\u017cliwo\u015bci tolerancji \u2014 przewidziany by\u0142 tylko nodeSelector.<\/li>\n<li>Tworzone pod\u2019y by\u0142y cz\u0119\u015bci\u0105 Deployment\u2019u, mimo \u017ce wdra\u017cali\u015bmy aplikacj\u0119 stateful. W przeciwie\u0144stwie do StatefulSet, Deployment\u2019y nie potrafi\u0105 tworzy\u0107 dysk\u00f3w.<\/li>\n<\/ul>\n<p>\nOstatnia wada prowadzi do zabawnych sytuacji: w \u015brodowisku testowym uda\u0142o si\u0119 uruchomi\u0107 3 repliki z jednym dyskiem <i>local storage<\/i>, w wyniku czego operator informowa\u0142, \u017ce 3 repliki dzia\u0142aj\u0105 (chocia\u017c tak nie by\u0142o).<\/p>\n<p>Kolejn\u0105 cech\u0105 tego operatora jest jego gotowa integracja z r\u00f3\u017cnymi systemami pomocniczymi. Na przyk\u0142ad, \u0142atwo zainstalowa\u0107 pgAdmin i pgBounce, a w <noindex><a rel=\"nofollow\" href=\"https:\/\/access.crunchydata.com\/documentation\/postgres-operator\/4.4.0\/installation\/other\/ansible\/installing-metrics\/\">dokumentacji<\/a><\/noindex> rozwa\u017ca si\u0119 wst\u0119pnie skonfigurowane Grafana i Prometheus. W niedawnym <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CrunchyData\/postgres-operator\/releases\/tag\/v4.5.0-beta.1\">wydaniu 4.5.0-beta1<\/a><\/noindex> z osobna zauwa\u017cono lepsz\u0105 integracj\u0119 z projektem <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CrunchyData\/pgmonitor\">pgMonitor<\/a><\/noindex>, dzi\u0119ki czemu operator oferuje intuicyjn\u0105 wizualizacj\u0119 metryk PgSQL \u201eprosto z pude\u0142ka\u201d.<\/p>\n<p>Jednak\u017ce dziwny wyb\u00f3r generowanych zasob\u00f3w Kubernetes doprowadzi\u0142 nas do konieczno\u015bci znalezienia innego rozwi\u0105zania.<\/p>\n<h3>3. Zalando Postgres Operator<\/h3>\n<p>\nProdukty Zalando s\u0105 nam znane od dawna: mamy do\u015bwiadczenie w korzystaniu z Zalenium i oczywi\u015bcie pr\u00f3bowali\u015bmy <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/patroni\">Patroni<\/a><\/noindex> \u2014 ich popularne rozwi\u0105zanie HA dla PostgreSQL. O podej\u015bciu firmy do stworzenia <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\">Postgres Operator<\/a><\/noindex> opowiada\u0142 jeden z jego autor\u00f3w \u2014 Aleksiej Kljukin \u2014 w programie <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/479438\/\">Postgres-wtorek \u21165<\/a><\/noindex>, i bardzo nam si\u0119 spodoba\u0142.<\/p>\n<p>To najm\u0142odsze rozwi\u0105zanie z rozwa\u017canych w artykule: pierwszy release odby\u0142 si\u0119 w sierpniu 2018 roku. Jednak, mimo niewielkiej liczby formalnych wyda\u0144, projekt przeszed\u0142 d\u0142ug\u0105 drog\u0119, wyprzedzaj\u0105c ju\u017c pod wzgl\u0119dem popularno\u015bci rozwi\u0105zanie od Crunchy Data z 1300+ gwiazdkami na GitHub i maksymaln\u0105 liczb\u0105 wsp\u00f3\u0142tw\u00f3rc\u00f3w (70+).<\/p>\n<p>\u201ePod mask\u0105\u201d tego operatora stosowane s\u0105 rozwi\u0105zania,kt\u00f3re przetrwa\u0142y pr\u00f3b\u0119 czasu:<\/p>\n<ul>\n<li> Patroni i <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/spilo\">Spilo<\/a><\/noindex> do zarz\u0105dzania,<\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wal-e\/wal-e\">WAL-E<\/a><\/noindex> \u2014 do backup\u00f3w,<\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgbouncer\/pgbouncer\">PgBouncer<\/a><\/noindex> \u2014 jako pul po\u0142\u0105cze\u0144.<\/li>\n<\/ul>\n<p>\nOto jak przedstawiona jest architektura operatora od Zalando:<\/p>\n<p><img decoding=\"async\" alt=\"Kr\u00f3tki przegl\u0105d operator\u00f3w PostgreSQL dla Kubernetes, nasz wyb\u00f3r i do\u015bwiadczenie\" src=\"\/wp-content\/uploads\/2020\/09\/c66f10c1a818592ecaacd2db4ce5ace5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOperator jest w pe\u0142ni zarz\u0105dzany przez Custom Resources, automatycznie tworzy StatefulSet z kontener\u00f3w, kt\u00f3re nast\u0119pnie mo\u017cna dostosowywa\u0107, dodaj\u0105c do pod r\u00f3\u017cne sidecary. To wszystko stanowi istotn\u0105 przewag\u0119 w por\u00f3wnaniu do operatora od Crunchy Data.<\/p>\n<p>Poniewa\u017c to rozwi\u0105zanie od Zalando wybrali\u015bmy spo\u015br\u00f3d 3 rozwa\u017canych opcji, dalszy opis jego mo\u017cliwo\u015bci zostanie przedstawiony poni\u017cej, od razu wraz z praktyk\u0105 zastosowania.<\/p>\n<h2>Praktyka z Postgres Operatorem od Zalando<\/h2>\n<p>\nWdro\u017cenie operatora odbywa si\u0119 bardzo prosto: wystarczy pobra\u0107 aktualn\u0105 wersj\u0119 z GitHub i zastosowa\u0107 pliki YAML z katalogu. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/tree\/master\/manifests\">manifests<\/a><\/noindex>. Alternatywnie mo\u017cna r\u00f3wnie\u017c skorzysta\u0107 z <noindex><a rel=\"nofollow\" href=\"https:\/\/operatorhub.io\/operator\/postgres-operator\">OperatorHub<\/a><\/noindex>.<\/p>\n<p>Po zainstalowaniu warto zadba\u0107 o konfiguracj\u0119 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/docs\/reference\/operator_parameters.md#aws-or-gcp-interaction\">magazyn\u00f3w dla log\u00f3w i kopii zapasowych<\/a><\/noindex>. Realizuje si\u0119 j\u0105 przez ConfigMap <code>postgres-operator<\/code> w przestrzeni nazw, do kt\u00f3rej zainstalowano operatora. Gdy magazyny s\u0105 skonfigurowane, mo\u017cna uruchomi\u0107 pierwszy klaster PostgreSQL.<\/p>\n<p>Na przyk\u0142ad, standardowe wdro\u017cenie wygl\u0105da nast\u0119puj\u0105co:<\/p>\n<pre><code class=\"plaintext\">apiVersion: acid.zalan.do\/v1\nkind: postgresql\nmetadata:\n name: staging-db\nspec:\n numberOfInstances: 3\n patroni:\n   synchronous_mode: true\n postgresql:\n   version: &quot;12&quot;\n resources:\n   limits:\n     cpu: 100m\n     memory: 1Gi\n   requests:\n     cpu: 100m\n     memory: 1Gi\n sidecars:\n - env:\n   - name: DATA_SOURCE_URI\n     value: 127.0.0.1:5432\n   - name: DATA_SOURCE_PASS\n     valueFrom:\n       secretKeyRef:\n         key: password\n         name: postgres.staging-db.credentials\n   - name: DATA_SOURCE_USER\n     value: postgres\n   image: wrouesnel\/postgres_exporter\n   name: prometheus-exporter\n   resources:\n     limits:\n       cpu: 500m\n       memory: 100Mi\n     requests:\n       cpu: 100m\n       memory: 100Mi\n teamId: staging\n volume:\n   size: 2Gi\n<\/code><\/pre>\n<p>\nTen manifest wdra\u017ca klaster z 3 instancjami z sidecarem w postaci <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wrouesnel\/postgres_exporter\">postgres_exporter<\/a><\/noindex>, z kt\u00f3rego zbieramy metryki aplikacji. Jak wida\u0107, wszystko jest bardzo proste, a w razie potrzeby mo\u017cna utworzy\u0107 praktycznie nieograniczon\u0105 liczb\u0119 klastr\u00f3w.<\/p>\n<p>Warto r\u00f3wnie\u017c zwr\u00f3ci\u0107 uwag\u0119 na <b>panel webowy do administracji<\/b> \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/docs\/operator-ui.md\">postgres-operator-ui<\/a><\/noindex>. Dostarczany jest razem z operatorem i pozwala na tworzenie i usuwanie klastr\u00f3w, a tak\u017ce na prac\u0119 z kopiami zapasowymi, kt\u00f3re wykonuje operator.<\/p>\n<p><img decoding=\"async\" alt=\"Kr\u00f3tki przegl\u0105d operator\u00f3w PostgreSQL dla Kubernetes, nasz wyb\u00f3r i do\u015bwiadczenie\" src=\"\/wp-content\/uploads\/2020\/09\/2e9ae033a9817d101c843ce061aafdb5.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Lista klastr\u00f3w PostgreSQL<\/i><\/p>\n<p><img decoding=\"async\" alt=\"Kr\u00f3tki przegl\u0105d operator\u00f3w PostgreSQL dla Kubernetes, nasz wyb\u00f3r i do\u015bwiadczenie\" src=\"\/wp-content\/uploads\/2020\/09\/74a65f7f301da14a0cb7bea6d5ef84ec.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Zarz\u0105dzanie kopiami zapasowymi<\/i><\/p>\n<p>Inn\u0105 interesuj\u0105c\u0105 funkcj\u0105 jest wsparcie dla <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/docs\/user.md#teams-api-roles\">Teams API<\/a><\/noindex>. Ten mechanizm automatycznie tworzy <b>role w PostgreSQL<\/b>, na podstawie otrzymanej listy nazw u\u017cytkownik\u00f3w. Nast\u0119pnie API pozwala zwr\u00f3ci\u0107 list\u0119 u\u017cytkownik\u00f3w, dla kt\u00f3rych automatycznie tworzone s\u0105 role.<\/p>\n<h3>Problemy i ich rozwi\u0105zanie<\/h3>\n<p>\nJednak u\u017cycie operatora wkr\u00f3tce ujawni\u0142o kilka istotnych wad:<\/p>\n<ol>\n<li> brak wsparcia dla nodeSelector;<\/li>\n<li> niemo\u017cno\u015b\u0107 wy\u0142\u0105czenia kopii zapasowych;<\/li>\n<li> przy korzystaniu z funkcji tworzenia baz nie pojawiaj\u0105 si\u0119 domy\u015blne uprawnienia;<\/li>\n<li> czasami brakuje dokumentacji lub jest ona nieaktualna.<\/li>\n<\/ol>\n<p>\nNa szcz\u0119\u015bcie wiele z nich mo\u017cna rozwi\u0105za\u0107. Zacznijmy od ko\u0144ca \u2014 problem\u00f3w z <strong>dokumentacj\u0105<\/strong>. <\/p>\n<p>Najprawdopodobniej napotkasz sytuacj\u0119, w kt\u00f3rej nie zawsze jasne jest, jak skonfigurowa\u0107 kopi\u0119 zapasow\u0105 i jak pod\u0142\u0105czy\u0107 kopi\u0119 zapasow\u0105 do Operator UI. W dokumentacji jest to wspomniane mimochodem, a szczeg\u00f3\u0142owy opis znajduje si\u0119 w <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/481\">PR<\/a><\/noindex>:<\/p>\n<ol>\n<li>trzeba utworzy\u0107 sekret;<\/li>\n<li>przekaza\u0107 go operatorowi w parametrze <code>pod_environment_secret_name<\/code> w CRD z ustawieniami operatora lub w ConfigMap (zale\u017cnie od tego, jak zdecydowa\u0142e\u015b si\u0119 zainstalowa\u0107 operatora).<\/li>\n<\/ol>\n<p>\nJednak jak si\u0119 okaza\u0142o, w tej chwili to niemo\u017cliwe. Dlatego zebrali\u015bmy <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/postgres-operator\">nasz\u0105 wersj\u0119 operatora<\/a><\/noindex> z dodatkowymi zewn\u0119trznymi rozwi\u0105zaniami. Wi\u0119cej informacji \u2014 patrz poni\u017cej.<\/p>\n<p>Je\u015bli przekazujesz operatorowi parametry dla kopii zapasowej, a dok\u0142adniej \u2014 <code>wal_s3_bucket<\/code> i klucze dost\u0119pu do AWS S3, to on <strong>b\u0119dzie robi\u0107 kopie zapasowe wszystkiego<\/strong>: nie tylko baz w produkcji, ale tak\u017ce staging. Nas to nie satysfakcjonowa\u0142o.<\/p>\n<p>W opisie parametr\u00f3w do Spilo, kt\u00f3re jest podstawowym opakowaniem Docker dla PgSQL przy u\u017cyciu operatora, wykazano: mo\u017cna przekaza\u0107 parametr <code>WAL_S3_BUCKET<\/code> jako pusty, tym samym wy\u0142\u0105czaj\u0105c kopie zapasowe. Co wi\u0119cej, z wielk\u0105 rado\u015bci\u0105 znalaz\u0142 si\u0119 tak\u017ce <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/908\">gotowy PR<\/a><\/noindex>, kt\u00f3ry natychmiast przyj\u0119li\u015bmy do naszego fork'a. Teraz wystarczy po prostu doda\u0107 <code>enableWALArchiving: false<\/code> do zasobu klastra PostgreSQL.<\/p>\n<p>Tak, istnia\u0142a mo\u017cliwo\u015b\u0107 zrobienia inaczej, uruchamiaj\u0105c 2 operator\u00f3w: jeden dla staging (bez kopii zapasowych), a drugi \u2014 dla produkcji. Ale w ten spos\u00f3b mogli\u015bmy obej\u015b\u0107 si\u0119 jednym.<\/p>\n<p>Dobrze, nauczyli\u015bmy si\u0119 przekazywa\u0107 dost\u0119p do S3 dla baz i kopie zapasowe zacz\u0119\u0142y trafia\u0107 do magazynu. Jak sprawi\u0107, by strony kopii zapasowych dzia\u0142a\u0142y w Operator UI?<\/p>\n<p><img decoding=\"async\" alt=\"Kr\u00f3tki przegl\u0105d operator\u00f3w PostgreSQL dla Kubernetes, nasz wyb\u00f3r i do\u015bwiadczenie\" src=\"\/wp-content\/uploads\/2020\/09\/46169b53707b0bbb686798c655022f40.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nW Operator UI nale\u017cy doda\u0107 3 zmienne:<\/p>\n<ul>\n<li> <code>SPILO_S3_BACKUP_BUCKET<\/code><\/li>\n<li> <code>AWS_ACCESS_KEY_ID<\/code><\/li>\n<li> <code>AWS_SECRET_ACCESS_KEY<\/code><\/li>\n<\/ul>\n<p>\nPo tym zarz\u0105dzanie kopiami zapasowymi stanie si\u0119 dost\u0119pne, co w naszym przypadku upro\u015bci prac\u0119 ze staging, umo\u017cliwiaj\u0105c dostarczanie tam migawk\u00f3w z produkcji bez dodatkowych skrypt\u00f3w.<\/p>\n<p>Jako dodatkowy plus wymieniano wsp\u00f3\u0142prac\u0119 z Teams API oraz szerokie mo\u017cliwo\u015bci tworzenia baz i r\u00f3l za pomoc\u0105 operatora. Jednak tworzone <strong>role nie mia\u0142y domy\u015blnych uprawnie\u0144.<\/strong>W zwi\u0105zku z tym u\u017cytkownik z uprawnieniami do odczytu nie m\u00f3g\u0142 odczytywa\u0107 nowych tabel.<\/p>\n<p>Dlaczego tak? Pomimo, \u017ce w kodzie <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/pkg\/cluster\/database.go#L42\">jest<\/a><\/noindex> s\u0105 niezb\u0119dne, <code>GRANT<\/code>nie s\u0105 stosowane zbyt cz\u0119sto. S\u0105 2 metody: <code>syncPreparedDatabases<\/code> i <code>syncDatabases<\/code>. W <code>syncPreparedDatabases<\/code> \u2014 mimo \u017ce w sekcji <code>preparedDatabases<\/code> <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/blob\/master\/manifests\/complete-postgres-manifest.yaml#L26\">jest<\/a><\/noindex> jest warunek <code>defaultRoles<\/code> i <code>defaultUsers<\/code> do tworzenia r\u00f3l, \u2014 prawa domy\u015blne nie s\u0105 stosowane. Jeste\u015bmy w trakcie przygotowywania aktualizacji, aby te prawa by\u0142y stosowane automatycznie.<\/p>\n<p>I ostatnia kwestia w aktualnych dla nas usprawnieniach \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/975\">\u0142atk\u0119<\/a><\/noindex>, dodaj\u0105cy Node Affinity do tworzonego StatefulSet. Nasi klienci cz\u0119sto wol\u0105 ogranicza\u0107 koszty, korzystaj\u0105c z instancji spot, a na nich zdecydowanie nie nale\u017cy umieszcza\u0107 us\u0142ug DB. Ten problem mo\u017cna by\u0142oby rozwi\u0105za\u0107 r\u00f3wnie\u017c poprzez tolerancje, ale obecno\u015b\u0107 Node Affinity daje wi\u0119ksz\u0105 pewno\u015b\u0107.<\/p>\n<h3>Co uda\u0142o si\u0119 osi\u0105gn\u0105\u0107?<\/h3>\n<p>\nW wyniku rozwi\u0105zania wymienionych problem\u00f3w wzi\u0119li\u015bmy Postgres Operator od Zalando do <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/postgres-operator\">swojego repozytorium<\/a><\/noindex>, gdzie jest zbierany z tak przydatnymi poprawkami. A dla wi\u0119kszej wygody zebrali\u015bmy i <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/r\/flant\/postgres-operator\">obraz Dockera<\/a><\/noindex>.<\/p>\n<p>Lista PR-\u00f3w przyj\u0119tych do forka:<\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/1066\">budowa w Dockerze bezpiecznego, lekkiego obrazu dla operatora<\/a><\/noindex>;<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/908\">wy\u0142\u0105czenie kopii zapasowych<\/a><\/noindex>;<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/1121\">aktualizacja wersji zasob\u00f3w dla bie\u017c\u0105cych wersji k8s<\/a><\/noindex>;<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/postgres-operator\/pull\/975\">wdro\u017cenie Node Affinity<\/a><\/noindex>.<\/li>\n<\/ul>\n<p>\nB\u0119dzie \u015bwietnie, je\u015bli spo\u0142eczno\u015b\u0107 wesprze te PR-y, aby trafi\u0142y do upstream z nast\u0119pn\u0105 wersj\u0105 operatora (1.6).<\/p>\n<h2>Bonus! Historia sukcesu z migracj\u0105 produkcji<\/h2>\n<p>\nJe\u015bli u\u017cywasz Patroni, mo\u017cna migrowa\u0107 dzia\u0142aj\u0105c\u0105 produkcj\u0119 na operatora z minimalnym przestojem.<\/p>\n<p>Spilo umo\u017cliwia tworzenie klastr\u00f3w standby przez przechowywanie w S3 z <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/wal-e\/wal-e\">Wal-E<\/a><\/noindex>, gdy binarny log PgSQL najpierw jest przechowywany w S3, a nast\u0119pnie pobierany przez replik\u0119. Ale co zrobi\u0107, je\u015bli masz <i>nie<\/i> u\u017cywasz Wal-E w starej infrastrukturze? Rozwi\u0105zanie tego problemu ju\u017c <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/true_engineering\/blog\/437318\/\">zosta\u0142o zaproponowane<\/a><\/noindex> na Habrze.<\/p>\n<p>Na pomoc przychodzi logiczna replikacja PostgreSQL. Jednak nie wchod\u017amy w szczeg\u00f3\u0142y, jak tworzy\u0107 publikacje i subskrypcje, poniewa\u017c\u2026 nasz plan si\u0119 nie powi\u00f3d\u0142.<\/p>\n<p>Chodzi o to, \u017ce w DB by\u0142o kilka obci\u0105\u017conych tabel z milionami wierszy, kt\u00f3re dodatkowo by\u0142y stale zasilane i usuwane. <noindex><a rel=\"nofollow\" href=\"https:\/\/postgrespro.ru\/docs\/postgrespro\/12\/sql-createsubscription\">Prosta subskrypcja<\/a><\/noindex> z <code>copy_data<\/code>, gdy nowa replika kopiuje ca\u0142\u0105 zawarto\u015b\u0107 z mastera, po prostu nie zd\u0105\u017ca\u0142a za masterem. Kopiowanie tre\u015bci dzia\u0142a\u0142o przez tydzie\u0144, ale wci\u0105\u017c nie dogoni\u0142o mastera. W ko\u0144cu, aby rozwi\u0105za\u0107 problem, pomogli <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/avitotech\/recovery-use-cases-for-logical-replication-in-postgresql-10-a1e6bab03072\">artyku\u0142<\/a><\/noindex> koledzy z Avito: mo\u017cna przenie\u015b\u0107 dane, u\u017cywaj\u0105c <code>pg_dump<\/code>. Opisz\u0119 nasz\u0105 (nieco poprawion\u0105) wersj\u0119 tego algorytmu.<\/p>\n<p>Pomys\u0142 polega na tym, \u017ce mo\u017cna utworzy\u0107 wy\u0142\u0105czon\u0105 subskrypcj\u0119 powi\u0105zan\u0105 z danym slotem replikacji, a nast\u0119pnie naprawi\u0107 numer transakcji. By\u0142y dost\u0119pne repliki do pracy w \u015brodowisku produkcyjnym. To wa\u017cne, poniewa\u017c replika pomo\u017ce stworzy\u0107 sp\u00f3jny zrzut i kontynuowa\u0107 odbieranie zmian z g\u0142\u00f3wnego serwera.<\/p>\n<p>W kolejnych poleceniach opisuj\u0105cych proces migracji b\u0119d\u0105 u\u017cywane nast\u0119puj\u0105ce oznaczenia dla host\u00f3w:<\/p>\n<ol>\n<li><i>master<\/i> \u2014 serwer \u017ar\u00f3d\u0142owy;<\/li>\n<li><i>replica1<\/i> \u2014 strumieniowa replika na starym \u015brodowisku produkcyjnym;<\/li>\n<li><i>replica2<\/i> \u2014 nowa logiczna replika.<\/li>\n<\/ol>\n<p><\/p>\n<h3>Plan migracji<\/h3>\n<p>\n1. Utworzymy na g\u0142\u00f3wnym serwerze subskrypcj\u0119 na wszystkie tabele w schemacie <code>public<\/code> bazy <code>dbname<\/code>:<\/p>\n<pre><code class=\"bash\">psql -h master -d dbname -c &quot;CREATE PUBLICATION dbname FOR ALL TABLES;&quot;\n<\/code><\/pre>\n<p>\n2. Utworzymy slot replikacji na g\u0142\u00f3wnym serwerze:<\/p>\n<pre><code class=\"bash\">psql -h master -c &quot;select pg_create_logical_replication_slot('repl', 'pgoutput');&quot;\n<\/code><\/pre>\n<p>\n3. Zatrzymamy replikacj\u0119 na starej reprlikcie:<\/p>\n<pre><code class=\"bash\">psql -h replica1 -c &quot;select pg_wal_replay_pause();&quot;\n<\/code><\/pre>\n<p>\n4. Odbierzemy numer transakcji z g\u0142\u00f3wnego serwera:<\/p>\n<pre><code class=\"bash\">psql -h master -c &quot;select replay_lsn from pg_stat_replication where client_addr = 'replica1';&quot;\n<\/code><\/pre>\n<p>\n5. Zrobimy zrzut ze starej repliki. B\u0119dziemy to robi\u0107 w kilku w\u0105tkach, co pomo\u017ce przyspieszy\u0107 proces:<\/p>\n<pre><code class=\"bash\">pg_dump -h replica1 --no-publications --no-subscriptions -O -C -F d -j 8 -f dump\/ dbname\n<\/code><\/pre>\n<p>\n6. Za\u0142adujemy zrzut na nowy serwer:<\/p>\n<pre><code class=\"bash\">pg_restore -h replica2 -F d -j 8 -d dbname dump\/\n<\/code><\/pre>\n<p>\n7. Po za\u0142adowaniu zrzutu, mo\u017cna uruchomi\u0107 replikacj\u0119 na strumieniowej replice:<\/p>\n<pre><code class=\"bash\">psql -h replica1 -c &quot;select pg_wal_replay_resume();&quot;\n<\/code><\/pre>\n<p>\n7. Utworzymy subskrypcj\u0119 na nowej logicznej replicie:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -c &quot;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');&quot;\n<\/code><\/pre>\n<p>\n8. Odbierzemy <code>oid<\/code> subskrypcji:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -d dbname -c &quot;select oid, * from pg_subscription;&quot;\n<\/code><\/pre>\n<p>\n9. Za\u0142\u00f3\u017cmy, \u017ce otrzymali\u015bmy <code>oid=1000<\/code>. Zastosujemy numer transakcji do subskrypcji:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -d dbname -c &quot;select pg_replication_origin_advance('pg_1000', 'AA\/AAAAAAAA');&quot;\n<\/code><\/pre>\n<p>\n10. Uruchomimy replikacj\u0119:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -d dbname -c &quot;alter subscription oldprod enable;&quot;\n<\/code><\/pre>\n<p>\n11. Sprawdzimy status subskrypcji, replikacja powinna dzia\u0142a\u0107:<\/p>\n<pre><code class=\"bash\">psql -h replica2 -d dbname -c &quot;select * from pg_replication_origin_status;&quot;\npsql -h master -d dbname -c &quot;select slot_name, restart_lsn, confirmed_flush_lsn from pg_replication_slots;&quot;\n<\/code><\/pre>\n<p>\n12. Po uruchomieniu replikacji i synchronizacji baz, mo\u017cna przeprowadzi\u0107 prze\u0142\u0105czenie.<\/p>\n<p>13. Po wy\u0142\u0105czeniu replikacji nale\u017cy naprawi\u0107 sekwencje. Jest to dobrze opisane <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.postgresql.org\/wiki\/Fixing_Sequences\">w artykule na wiki.postgresql.org<\/a><\/noindex>.<\/p>\n<p>Dzi\u0119ki takiemu planowi prze\u0142\u0105czenie przebieg\u0142o z minimalnymi op\u00f3\u017anieniami.<\/p>\n<h2>Podsumowanie<\/h2>\n<p>\nOperatory Kubernetes umo\u017cliwiaj\u0105 uproszczenie r\u00f3\u017cnych dzia\u0142a\u0144, sprowadzaj\u0105c je do tworzenia zasob\u00f3w K8s. Jednak osi\u0105gaj\u0105c wspania\u0142\u0105 automatyzacj\u0119 dzi\u0119ki nim, warto pami\u0119ta\u0107, \u017ce mo\u017ce to przynie\u015b\u0107 tak\u017ce szereg nieoczekiwanych niuans\u00f3w, dlatego podejd\u017a z rozwag\u0105 do wyboru operator\u00f3w.<\/p>\n<p>Po zbadaniu trzech najbardziej popularnych operator\u00f3w Kubernetes dla PostgreSQL, zdecydowali\u015bmy si\u0119 na projekt od Zalando. Napotkali\u015bmy pewne trudno\u015bci, ale efekt naprawd\u0119 nas ucieszy\u0142, wi\u0119c planujemy rozszerzy\u0107 to do\u015bwiadczenie na inne instalacje PgSQL. Je\u015bli masz do\u015bwiadczenie w korzystaniu z podobnych rozwi\u0105za\u0144 \u2014 ch\u0119tnie zobaczymy szczeg\u00f3\u0142y w komentarzach!<\/p>\n<h2>P.S.<\/h2>\n<p>\nPrzeczytaj tak\u017ce na naszym blogu:<\/p>\n<ul>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/431500\/\">Bazy danych i Kubernetes (przegl\u0105d i wideo wyst\u0105pienia)<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/479438\/\">Postgres-wtorek Nr 5: PostgreSQL i Kubernetes. CI\/CD. Automatyzacja test\u00f3w.<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/480722\/\">Jedna historia z operatorem Redis w K8s oraz mini-przegl\u0105d narz\u0119dzi do analizy danych tej bazy danych.<\/a><\/noindex>\u00bb.<\/li>\n<\/ul>\n<p>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/520616\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u0441\u0451 \u0447\u0430\u0449\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0442 \u0442\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b: \u00ab\u0425\u043e\u0442\u0438\u043c \u043a\u0430\u043a Amazon RDS, \u043d\u043e \u0434\u0435\u0448\u0435\u0432\u043b\u0435\u00bb; \u00ab\u0425\u043e\u0442\u0438\u043c \u043a\u0430\u043a RDS, \u043d\u043e \u0432\u0435\u0437\u0434\u0435, \u0432 \u043b\u044e\u0431\u043e\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435\u00bb. \u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 managed-\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 Kubernetes, \u043c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0434\u043b\u044f PostgreSQL (Stolon, \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u043e\u0442 Crunchy Data \u0438 Zalando) \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0441\u0432\u043e\u0439 \u0432\u044b\u0431\u043e\u0440. \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u2014 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043d\u0430\u043c\u0438 \u043e\u043f\u044b\u0442 \u0438 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":95323,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-95322","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u0441\u0451 \u0447\u0430\u0449\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041a\u0440\u0430\u0442\u043a\u0438\u0439 \u043e\u0431\u0437\u043e\u0440 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 PostgreSQL \u0434\u043b\u044f Kubernetes, \u043d\u0430\u0448 \u0432\u044b\u0431\u043e\u0440 \u0438 \u043e\u043f\u044b\u0442 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u0441\u0451 \u0447\u0430\u0449\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-09-28T05:42:39+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-09-28T05:42:39+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Kr\u00f3tki przegl\u0105d operator\u00f3w PostgreSQL dla Kubernetes, nasz wyb\u00f3r i do\u015bwiadczenie | ProHoster","description":"Coraz cz\u0119\u015bciej od klient\u00f3w.","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041a\u0440\u0430\u0442\u043a\u0438\u0439 \u043e\u0431\u0437\u043e\u0440 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 PostgreSQL \u0434\u043b\u044f Kubernetes, \u043d\u0430\u0448 \u0432\u044b\u0431\u043e\u0440 \u0438 \u043e\u043f\u044b\u0442 | ProHoster","og:description":"\u0412\u0441\u0451 \u0447\u0430\u0449\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/kratkij-obzor-operatorov-postgresql-dlya-kubernetes-nash-vybor-i-opyt","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-09-28T05:42:39+00:00","article:modified_time":"2020-09-28T05:42:39+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"95322","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 11:08:22","updated":"2022-09-30 21:12:08","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/95322","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=95322"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/95322\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/95323"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=95322"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=95322"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=95322"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}