В кластере Kubernetes я хотел бы иметь возможность запланировать задание (с помощью CronJob), которое будет монтировать те же тома, что и 1 Pod данного StatefulSet. Решение о том, какой именно модуль будет выполняться, зависит от меток, установленных на модуле во время планирования задания.
Думаю, многие люди задаются вопросом, почему, поэтому описание того, что мы делаем и пытаемся сделать:
Текущая настройка
У нас есть StatefulSet, который обслуживает базу данных PostgreSQL. (одна основная, несколько реплик) Мы хотим иметь возможность создавать резервную копию из одного из модулей StatefulSet.
Для PostgreSQL мы уже можем делать резервные копии по сети с pg_basebackup
, однако мы используем базы данных PostgreSQL с несколькими ТБ, что означает, что полное потоковое резервное копирование (с pg_basebackup
) невозможно.
В настоящее время мы используем pgBackRest
для резервного копирования баз данных, что позволяет создавать инкрементные резервные копии.
Поскольку для инкрементного резервного копирования pgBackRest
требуется доступ к тому данных и тому WAL, нам нужно запустить контейнер резервного копирования на том же узле Kubernetes, что и экземпляр PostgreSQL, в настоящее время мы даже запускаем его внутри того же модуля в отдельном контейнере.
Внутри контейнера небольшой api оборачивается вокруг pgBackRest
и может быть запущен путем отправки POST
запросов к api, этот запуск в настоящее время выполняется с помощью CronJobs.
Минусы
- Каждый экземпляр PostgreSQL имеет несколько контейнеров в модуле: 1 для обслуживания Postgres, 1 для обслуживания крошечной оболочки вокруг
pgBackRest
- Журналы заданий показывают только успешные триггеры резервного копирования, фактические журналы резервного копирования являются частью контейнера резервного копирования.
- Pod, который будет запускать резервное копирование, может работать в относительно старой конфигурации, изменение конфигурации резервного копирования требует перепланирования Pod, что может означать отказоустойчивость основного PostgreSQL.
Предлагаемая установка
Сделайте CronJob графиком для модуля, имеющего тот же том, что и у 1 из модулей StatefulSet. Это позволит резервной копии использовать эти тома.
Однако решение о том, какие тома ему нужны, принимается во время выполнения: мы можем захотеть запустить резервное копирование на томах, подключенных к основному, или мы можем захотеть выполнить резервное копирование с использованием томов реплики. Первичная реплика / первичная реплика может измениться в любой момент, поскольку автоматическое переключение на отказ первичного сервера PostgreSQL является частью решения.
В настоящее время это невозможно, так как в спецификации CronJob я не могу найти способ использовать информацию из k8s api.
Что работает, но не очень приятно:
- Используйте CronJob, который планирует задание
- Это задание запрашивает API k8s и планирует другое задание
Например, вот что мы можем сделать, чтобы задание создавало другое задание, используя эту информацию времени выполнения:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: schedule-backup
spec:
schedule: "13 03 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup-trigger
image: bitnami/kubectl
command:
- sh
- -c
- |
PRIMARYPOD=$(kubectl get pods -l cluster-name=<NAME>,role=master -o custom-columns=":metadata.name" --no-headers)
kubectl apply -f - <<__JOB__
apiVersion: batch/v1
kind: Job
metadata:
name: test
spec:
volumes:
name: storage-volume
persistentVolumeClaim:
claimName:
data-volume-${PRIMARYPOD}
[...]
__JOB__
Вышеупомянутое может быть лучше всего обслужено оператором, а не просто CronJob, но мне интересно, есть ли у кого-нибудь решение для вышеперечисленного.
Минусы
- В журналах заданий отображаются только успешные триггеры резервного копирования, фактические журналы резервного копирования являются частью другого задания.
- Для задания требуются разрешения для планирования работы Pod, что требует еще одной роли / привязки ролей.
- Использование heredocs в Bash затрудняет чтение / синтаксический анализ / понимание
Резюме
Долгая история, но мы хотим удовлетворить следующие ограничения:
- Запустить резервную копию базы данных PostgreSQL
- Это базы данных на несколько ТБ
- Следовательно, требуется инкрементное резервное копирование.
- Следовательно, нам нужно смонтировать тот же PV уже запущенного Pod'а.
- Следовательно, нам нужно запустить Pod (или контейнер) на том же узле K8s, что и PV.
- Мы хотим иметь возможность выразить это в спецификации CronJob, вместо того, чтобы выполнять вызовы api kubernetes во время выполнения.