Короткий огляд операторів PostgreSQL для Kubernetes, наш вибір та досвід

Короткий огляд операторів PostgreSQL для Kubernetes, наш вибір та досвід

Все частіше від клієнтів надходять такі запити: "Хочемо як Amazon RDS, але дешевше"; "Хочемо як RDS, але скрізь, у будь-якій інфраструктурі". Щоб реалізувати подібне managed рішення на Kubernetes, ми подивилися на поточний стан найбільш популярних операторів для PostgreSQL (Stolon, оператори від Crunchy Data і Zalando) і зробили свій вибір.

Ця стаття — набутий нами досвід і з теоретичної точки зору (огляд рішень), і з практичної сторони (що було обрано і що з цього вийшло). Але спочатку давайте визначимося, які взагалі вимоги пред'являються до потенційної заміни RDS…

Що ж таке RDS

Коли люди говорять про RDS, на наш досвід, вони мають на увазі керований (managed) сервіс СУБД, яка:

  1. легко налаштовується;
  2. має можливість роботи зі снапшотами та відновлюватись з них (бажано — з підтримкою PITR);
  3. дозволяє створювати топологію master-slave;
  4. має багатий перелік розширень;
  5. надає аудит та керування користувачами/доступами.

Якщо говорити взагалі, то підходи до реалізації поставленого завдання можуть бути дуже різними, проте шлях з умовним Ansible нам не близький. (До такого висновку дійшли і колеги з 2GIS в результаті своєї спроби створити інструмент для швидкого розгортання відмовостійкого кластера на основі Postgres.

Саме оператори є загальноприйнятим підходом для вирішення подібних завдань в екосистемі Kubernetes. Докладніше про них стосовно баз даних, що запускаються всередині Kubernetes, вже розповідав техдир «Фланта», distol, в одній зі своїх доповідей.

NB: Для швидкого створення нескладних операторів рекомендуємо звернути увагу на нашу Open Source-утиліту shell-operator. Використовуючи її, можна це робити без знань Go, а звичнішими для сисадмінів способами: на Bash, Python і т.п.

Для PostgreSQL існує декілька популярних K8s-операторів:

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

Подивимося на них уважніше.

вибір оператора

Окрім тих важливих можливостей, що вже були згадані вище, ми, як інженери з експлуатації інфраструктури в Kubernetes, також очікували від операторів наступного:

  • деплой з Git та з Custom Resources;
  • підтримку pod anti-affinity;
  • встановлення node affinity або node selector;
  • встановлення толерацій;
  • наявність можливостей тюнінгу;
  • зрозумілі технології та навіть команди.

Не вдаючись у деталі по кожному з пунктів (питайте в коментарях, якщо залишаться питання щодо них після прочитання всієї статті), зазначу загалом, що ці параметри потрібні для більш тонкого опису спеціалізації вузлів кластера для того, щоб замовляти їх під конкретні програми. Так ми можемо досягти оптимального балансу у питаннях продуктивності та вартості.

Тепер - до самих операторів PostgreSQL.

1. Stolon

Столон від італійської компанії Sorint.lab в вже згаданій доповіді розглядався як еталон серед операторів для СУБД. Це досить старий проект: перший його публічний реліз відбувся ще в листопаді 2015 року (!), а GitHub-репозиторій може похвалитися майже 3000 зірками та 40+ контріб'юторами.

Stolon — чудовий приклад продуманої архітектури:

Короткий огляд операторів PostgreSQL для Kubernetes, наш вибір та досвід
З пристроєм цього оператора у подробицях можна ознайомитись у доповіді або документації проекту. Загалом, досить сказати, що він вміє все описане: failover, проксі для прозорого доступу клієнтів, бекапи… Причому проксі надають доступ через один сервіс endpoint — на відміну від двох інших рішень, розглянутих далі (у них по два сервіси для доступу до базі).

Однак у Stolon ні Custom Resources, через що його не можна так деплоїти, щоб просто і швидко — «як гарячі пиріжки» створювати екземпляри СУБД у Kubernetes. Управління здійснюється через утиліту stolonctl, деплой - через Helm-чарт, а користувачі визначаються задаються в ConfigMap.

З одного боку, виходить, що оператор не є оператором (адже він не використовує CRD). Але з іншого боку - це гнучка система, яка дозволяє налаштовувати ресурси в K8s так, як вам зручно.

Резюмуючи, особисто нам не видався оптимальним шлях заводити окремий чарт під кожну БД. Тому ми почали шукати альтернативи.

2. Crunchy Data PostgreSQL Operator

Оператор від Crunchy Data, молодого американського стартапу, виглядав логічною альтернативою Його публічна історія починається з першого релізу в березні 2017 року, відтоді GitHub-репозиторій отримав трохи менше 1300 зірок та 50+ контріб'юторів. Останній реліз від вересня був протестований на роботу з Kubernetes 1.15-1.18, OpenShift 3.11+ та 4.4+, GKE та VMware Enterprise PKS 1.3+.

Архітектура Crunchy Data PostgreSQL Operator також відповідає заявленим вимогам:

Короткий огляд операторів PostgreSQL для Kubernetes, наш вибір та досвід

Управління відбувається через утиліту pgo, проте вона у свою чергу генерує Custom Resources для Kubernetes. Тому нас як потенційних користувачів оператор порадував:

  • є керування через CRD;
  • зручне керування користувачами (теж через CRD);
  • інтеграція з іншими компонентами Crunchy Data Container Suite - Спеціалізована колекція образів контейнерів для PostgreSQL і утиліт для роботи з нею (включаючи pgBackRest, pgAudit, розширення з contrib і т.д.).

Проте спроби почати використовувати оператор від Crunchy Data виявили кілька проблем:

  • Не виявилося можливості tolerations — передбачено лише nodeSelector.
  • Створювані pod'и були частиною Deployment'а, незважаючи на те, що ми деплоїли stateful-додаток. На відміну від StatefulSet, Deployment'и не вміють створювати диски.

Останній недолік призводить до кумедних моментів: на тестовому середовищі вдалося запустити 3 репліки з одним диском локальне сховищеУ результаті оператор повідомляв, що 3 репліки працюють (хоча це було не так).

Ще однією особливістю цього оператора є готова інтеграція з різними допоміжними системами. Наприклад, легко встановити pgAdmin і pgBounce, а в документації розглядаються передналаштовані Grafana та Prometheus. У недавньому релізі 4.5.0-beta1 окремо відзначається покращена інтеграція з проектом pgMonitor, Завдяки чому оператор пропонує наочну візуалізацію метрик по PgSQL «з коробки».

Проте дивний вибір генерованих Kubernetes-ресурсів привів нас до необхідності знайти інше рішення.

3. Zalando Postgres Operator

Продукти Zalando нам відомі давно: є досвід використання Zalenium і, звісно, ​​ми пробували Патрони — їхнє популярне HA-рішення для PostgreSQL. Про підхід компанії до створення Postgres Operator розповідав один із його авторів — Олексій Клюкін — в ефірі Postgres-вівторка №5, і нам він сподобався.

Це наймолодше рішення з тих, що розглядаються у статті: перший реліз відбувся в серпні 2018 року. Однак, навіть незважаючи на невелику кількість формальних релізів, проект пройшов великий шлях, вже випередивши за популярністю рішення від Crunchy Data з 1300+ зірками на GitHub та максимальною кількістю контриб'юторів (70+).

Під капотом цього оператора використовуються рішення, перевірені часом:

  • Patroni та Спило для керування,
  • WAL-E - для бекапів,
  • PgBouncer - Як пул підключень.

Ось як представлена ​​архітектура оператора від Zalando:

Короткий огляд операторів PostgreSQL для Kubernetes, наш вибір та досвід

Оператор повністю управляється через Custom Resources, автоматично створює StatefulSet з контейнерів, які потім можна кастомізувати, додаючи в pod різні sidecar'и. Все це значний плюс у порівнянні з оператором від Crunchy Data.

Оскільки саме рішення від Zalando ми вибрали серед 3 варіантів, подальший опис його можливостей буде представлений нижче, відразу разом з практикою застосування.

Практика з Postgres Operator від Zalando

Деплой оператора відбувається дуже просто: достатньо завантажити актуальний реліз з GitHub та застосувати YAML-файли з директорії маніфести. Як варіант, можна також скористатися OperatorHub.

Після встановлення варто подбати про налаштування сховищ для логів та бекапів. Вона провадиться через ConfigMap postgres-operator у просторі імен, куди ви встановили оператор. Коли сховища налаштовані, можна розгорнути перший кластер PostgreSQL.

Наприклад, стандартний деплой у нас виглядає так:

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

Даний маніфест деплоїть кластер з 3 екземплярів з sidecar у вигляді postgres_exporterз якого ми знімаємо метрики програми. Як бачите, все дуже просто, і за бажання можна зробити буквально необмежену кількість кластерів.

Варто звернути увагу і на веб-панель для адміністрування - postgres-operator-ui. Вона поставляється разом з оператором і дозволяє створювати та видаляти кластери, а також працювати з бекапами, які робить оператор.

Короткий огляд операторів PostgreSQL для Kubernetes, наш вибір та досвід
Список кластерів PostgreSQL

Короткий огляд операторів PostgreSQL для Kubernetes, наш вибір та досвід
Управління бекапами

Іншою цікавою особливістю є підтримка API команд. Цей механізм автоматично створює ролі в PostgreSQL, виходячи з отриманого списку імен користувачів. Після цього API дає змогу повернути список користувачів, для яких автоматично створюються ролі.

Проблеми та їх вирішення

Однак використання оператора незабаром виявило кілька вагомих недоліків:

  1. відсутність підтримки nodeSelector;
  2. неможливість вимкнути бекапи;
  3. при використанні функції створення баз не з'являються стандартні привілеї;
  4. періодично не вистачає документації або вона перебуває в неактуальному стані.

На щастя, багато хто з них може бути вирішений. Почнемо з кінця - проблем з документацією.

Швидше за все, ви зіткнетеся з тим, що не завжди ясно, як прописати бекап і як підключити бекапний бакет до Operator UI. Про це в документації йдеться побіжно, а реальний опис є в PR:

  1. потрібно зробити секрет;
  2. передати його оператору в параметр pod_environment_secret_name у CRD з налаштуваннями оператора або ConfigMap (залежить від того, як ви вирішили встановлювати оператор).

Однак, як виявилось, на даний момент це неможливо. Саме тому ми зібрали свою версію оператора з деякими додатковими сторонніми напрацюваннями. Докладніше про неї див. нижче.

Якщо передавати оператору параметри для бекапу, а саме — wal_s3_bucket та ключі доступу в AWS S3, то він буде бекапит все: не лише бази в production, а й staging. Нас це не влаштувало.

В описі параметрів Spilo, що є базовою Docker-оберткою для PgSQL при використанні оператора, з'ясувалося: можна передати параметр WAL_S3_BUCKET порожнім, тим самим відключивши бекапи. Більше того, на велику радість знайшовся і готовий PR, який ми одразу прийняли у свій форк. Тепер досить просто додати enableWALArchiving: false ресурс кластера PostgreSQL.

Так, була можливість зробити інакше, запустивши 2 оператори: один для staging (без бекапів), а другий для production. Але так ми змогли обійтися одним.

Ок, ми навчилися передавати бази доступ для S3 і бекапи почали потрапляти в сховище. Як змусити працювати сторінки бекапів у Operator UI?

Короткий огляд операторів PostgreSQL для Kubernetes, наш вибір та досвід

У Operator UI потрібно додати 3 змінні:

  • SPILO_S3_BACKUP_BUCKET
  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

Після цього управління бекапами стане доступним, що в нашому випадку спростить роботу зі staging, дозволивши доставляти туди зрізи з production без додаткових скриптів.

Як ще один плюс називалася робота з Teams API і широкі можливості для створення баз і ролей засобами оператора. Проте створювані ролі не мали прав за умовчанням. Відповідно, користувач із правами читання було читати нові таблиці.

Чому так? Незважаючи на те, що в коді є необхідні GRANTВони застосовуються далеко не завжди. Є 2 методи: syncPreparedDatabases и syncDatabases. У syncPreparedDatabases — незважаючи на те, що у секції preparedDatabases є є умова defaultRoles и defaultUsers для створення ролей — права за замовчуванням не застосовуються. Ми в процесі підготовки патчу, щоб ці права автоматично застосовувалися.

І останній момент в актуальних для нас доробках. патч, що додає Node Affinity у створюваний StatefulSet. Наші клієнти часто вважають за краще скорочувати витрати, використовуючи spot-інстанси, а на них явно не варто розміщувати послуги БД. Це питання можна було б вирішити і через tolerations, але наявність Node Affinity дає більшу впевненість.

Що вийшло?

За підсумками вирішення перерахованих проблем ми форкнули Postgres Operator від Zalando в свій репозиторійде він збирається з настільки корисними патчами. А для більшої зручності зібрали і Docker-образ.

Список PR, прийнятих у форк:

Буде чудово, якщо спільнота підтримає ці PR, щоб вони потрапили до upstream з наступною версією оператора (1.6).

Бонус! Історія успіху з міграцією production

Якщо ви використовуєте Patroni, оператор може мігрувати живий production з мінімальним простоєм.

Spilo дозволяє робити standby-кластери через S3-сховища з Wal-Eколи бінарний лог PgSQL спочатку зберігається в S3, а потім викачується реплікою. Але що робити, якщо у вас НЕ використовується Wal-E у старій інфраструктурі? Вирішення цієї проблеми вже було запропоновано на хабрі.

На допомогу приходить логічна реплікація PostgreSQL. Однак не вдаватимемося до деталей, як створювати публікації та підписки, бо… наш план зазнав фіаско.

Справа в тому, що в БД було кілька навантажених таблиць з мільйонами рядків, які до того ж постійно поповнювалися і видалялися. Проста передплата с copy_dataКоли нова репліка копіює весь вміст з майстра, просто не встигала за майстром. Копіювання контенту працювало тиждень, але так і не наздогнало майстер. У результаті розібратися з проблемою допомогла стаття колег з Avito: можна перенести дані, використовуючи pg_dump. Опишу наш (трохи доопрацьований) варіант цього алгоритму.

Ідея полягає в тому, що можна зробити вимкнену передплату, прив'язану до конкретного слота реплікації, а потім виправити номер транзакції. В наявності були репліки для роботи production'а. Це важливо, тому що репліка допоможе створити консистентний dump та продовжити отримувати зміни з майстра.

У наступних командах, що описують процес міграції, будуть використовуватися такі позначення для хостів:

  1. майстер - Вихідний сервер;
  2. репліка1 - Потокова репліка на старому production;
  3. репліка2 - Нова логічна репліка.

План міграції

1. Створимо на майстрі передплату на всі таблиці у схемі public бази dbname:

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

2. Створимо слот реплікації на майстрі:

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

3. Зупинимо реплікацію на старій репліці:

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

4. Отримаємо номер транзакції з майстра:

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

5. Знімемо dump зі старої репліки. Робитимемо це в кілька потоків, що допоможе прискорити процес:

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

6. Завантажимо dump на новий сервер:

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

7. Після завантаження дампа можна запустити реплікацію на потоковій репліці:

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

7. Створимо передплату на новій логічній репліці:

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. Отримаємо oid передплати:

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

9. Припустимо, було отримано oid=1000. Застосуємо номер транзакції до передплати:

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

10. Запустимо реплікацію:

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

11. Перевіримо статус передплати, реплікація має працювати:

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. Після того, як реплікація запущена та бази синхронізовані, можна здійснювати перемикання.

13. Після вимкнення реплікації треба виправити послідовності. Це добре описано у статті на wiki.postgresql.org.

Завдяки такому плану перемикання пройшло із мінімальними затримками.

Висновок

Оператори Kubernetes дозволяють спростити різні дії, звівши їх до створення K8s-ресурсів. Проте, домігшись чудової автоматизації з їх допомогою, варто пам'ятати, що вона може принести й низку несподіваних нюансів, тому підходьте до вибору операторів з розумом.

Розглянувши три найпопулярніші Kubernetes-оператори для PostgreSQL, ми зупинили свій вибір на проекті від Zalando. І з ним довелося подолати певні труднощі, але результат справді порадував, тому ми плануємо розширити цей досвід і на деякі інші інсталяції PgSQL. Якщо у вас є досвід використання подібних рішень - будемо раді побачити подробиці у коментарях!

PS

Читайте також у нашому блозі:

Джерело: habr.com

Додати коментар або відгук