В этой статье я не буду объяснять, зачем вот это всё нужно, или обсуждать достоинства и недостатки этого решения. Воспринимайте эту статью как инструкцию (заметку) для быстрого развертывания базы и очереди в dev-кластере Kubernetes.
Содержание
Введение
Установки PostgresSQL, Redis и RabbitMQ очень похожи друг на друга. Можно выделить три основных этапа:
Создание
Persistent Volume
(PV) иPersistent Volume Claim
(PVC).Установка
Helm
-чарта целевого приложения.Проверка работы.
Я не буду объяснять, что такое PV и PVC. Есть отличная лекция на эту тему, после которой можете смело возвращаться к моей инструкции. Перед началом работ нужно минимально настроить кластер Kubernetes. Вот небольшие требования:
Версия Kubernetes 1.20+.
Одна master-нода и одна worker-нода.
Настроенный Ingress-controller.
Если кластер развернут на bare-metal, то необходимо заменить внешний балансировщик. Например, поставить MetalLB или PorterLB.
На виртуальной машине установлен Helm.
Как создать свой ламповый dev-кластер на голом железе подробно рассказано в предыдущей статье.
Установка PostgreSQL
Создадим ресурс StorageClass
, для этого в файл storage.yaml вставьте следующую конфигурацию:
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
Применим манифест:
Создадим ресурс Persistent Volume
. Для этого в файл pv.yaml вставьте следующий манифест:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-for-pg
labels:
type: local
spec:
capacity:
storage: 4Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /devkube/postgresql
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- 457344.cloud4box.ru
В matchExpressions
указываем название ноды, на которой будет монтироваться диск. Посмотреть имя доступных узлов можно с помощью команды:
kubectl get nodes
Для удобства будем монтировать диск сразу на мастер-ноде, хотя это можно сделать на любой из доступных в списке. Монтировать будем директорию /devkube/postgresql. Заходим на удалённую машину и создаём директорию такой командой:
mkdir -p /devkube/postgresql
Создадим ресурс Persistent Volume
:
kubectl apply -f pv.yaml
Проверим состояние:
kubectl get pv
Применим манифест с Persistent Volume Claim
:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pg-pvc
spec:
storageClassName: "local-storage"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 4Gi
Посмотрим состояние ресурса:
Ресурс PVC
в ожидании привязки. Настало время развернуть Postgres в кластере. Подтягиваем к себе репозиторий Bitnami:
helm repo add bitnami https://charts.bitnami.com/bitnami
Устанавливаем чарт Helm с Postgres:
helm install dev-pg bitnami/postgresql --set primary.persistence.existingClaim=pg-pvc,auth.postgresPassword=pgpass
Посмотрим на состояние PVC
:
kubectl get pvc
Ресурс в статусе bound
, теперь pod с Postgres будет писать данные в директорию /devkube/postgresql. Посмотрим на состояние pod, statefulset
:
kubectl get pod,statefulset
База успешно развёрнута, теперь попробуем подключиться к ней: создать пользователя, таблицу и настроить доступы. После установки чарта в консоли будут показаны некоторые способы подключения к БД. Есть два способа:
1. Пробросить порт на локальную машину
Для этого требуется установить на машину утилиту psql. Проверим, что она установлена:
psql -V
Экспортируем пароль от админ-пользователя в переменную окружения:
export POSTGRES_PASSWORD=$(kubectl get secret --namespace default dev-pg-postgresql -o jsonpath="{.data.postgres-password}" | base64 --decode)
Выполним проброс порта:
kubectl port-forward --namespace default svc/dev-pg-postgresql 5432:5432
Консоль после выполнения команды будет заблокирована. В другом окне подключитесь к этой же машине и выполните подключение к БД:
PGPASSWORD="$POSTGRES_PASSWORD" psql --host 127.0.0.1 -U postgres -d postgres -p 5432
Или так, но тогда придётся ввести пароль вручную:
psql --host 127.0.0.1 -U postgres -d postgres -p 5432
2. Создать поду с psql клиентом
Экспортируем пароль от админ-пользователя в переменную окружения:
export POSTGRES_PASSWORD=$(kubectl get secret --namespace default dev-pg-postgresql -o jsonpath="{.data.postgres-password}" | base64 --decode)
Создадим под с утилитой psql и выполним в ней команду подключения к БД:
kubectl run dev-pg-postgresql-client --rm --tty -i --restart='Never' --namespace default --image docker.io/bitnami/postgresql:14.2.0-debian-10-r22 --env="PGPASSWORD=$POSTGRES_PASSWORD" \
--command -- psql --host dev-pg-postgresql -U postgres -d postgres -p 5432
Создадим роль (пользователя) и пароль для неё:
CREATE ROLE qa_user WITH LOGIN ENCRYPTED PASSWORD 'qa-pg-pass';
Посмотреть список ролей:
\du
Создадим базу, владельцем которой будет пользователь qa_user:
CREATE DATABASE qa_db OWNER qa_user;
Теперь отключимся:
\q
И подключимся к базе с данными нового пользователя (вторым способом):
kubectl run dev-pg-postgresql-client --rm --tty -i --restart='Never' --namespace default --image docker.io/bitnami/postgresql:14.2.0-debian-10-r22 --env="PGPASSWORD=qa-pg-pass" --command -- psql --host dev-pg-postgresql -U qa_user -d qa_db -p 5432
Создадим небольшую табличку:
CREATE TABLE qa_table (id int, name varchar(255));
Добавим запись:
INSERT INTO qa_table VALUES (1, 'first');
Теперь сделаем select
, чтобы убедиться в работоспособности:
SELECT * FROM qa_table;
Посмотреть список таблиц в базе:
\dt+
Готово, база успешно развёрнута! В приложении нужно указывать такой адрес БД:
DATABASE_URI=postgresql://qa_user:qa-pg-pass@dev-pg-postgresql:5432/qa_db
Установка Redis
Redis можно установить в нескольких конфигурациях. Мы развернём вариант с двумя репликами на чтение и одной репликой на запись в базу. Прежде всего применим манифест со StorageClass
:
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
kubectl apply -f storage.yaml
У меня уже был установлен этот ресурс, поэтому манифест не применился.
Дальше настроим Persistent Volumes
. Зарезервируем 2 Гб для каждой slave-реплики и 4 Гб для мастер-реплики. Создадим файлы pv-slave1.yaml, pv-slave2.yaml и pv-master.yaml и вставим в них эти конфигурации:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-redis-slave1
labels:
type: local
spec:
capacity:
storage: 2Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /devkube/redis/slave1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- 457344.cloud4box.ru
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-redis-slave2
labels:
type: local
spec:
capacity:
storage: 2Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /devkube/redis/slave2
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- 457344.cloud4box.ru
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-redis-master
labels:
type: local
spec:
capacity:
storage: 4Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /devkube/redis/master
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- 457344.cloud4box.ru
Все реплики будут складывать свои данные на ноде 457344.cloud4box.ru, хотя, конечно, можно монтировать диски на разных виртуальных машинах. Создадим три директории:
mkdir -p /devkube/redis/slave1
mkdir -p /devkube/redis/slave2
mkdir -p /devkube/redis/master
Применим конфигурации:
kubectl apply -f .
Проверим созданные ресурсы:
kubectl get pv
Созданные PV
ещё свободны и ждут заявки на использование пространства. А Persistent Volumes Postgres
уже связан со своим Persistent Volumes Сlaim
(так осталось после поднятия Postgres-базы в Kubernetes).
Создадим PVC
для мастер-реплики. Их нужно обязательно создавать в том namespace, в котором вы развернёте базу. Redis будет развёрнут в пространстве dev-redis. Создадим пространство:
kubectl create ns dev-redis
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc-for-master-redis
namespace: dev-redis
spec:
storageClassName: "local-storage"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 4Gi
kubectl apply -f pvc-master.yaml
Для slave-реплик создавать PVC
не будем, они будут автоматически созданы при установке чарта Helm.
Пришло время установить Redis. Подтягиваем к себе репозиторий Bitnami, если ещё этого не сделали (у меня уже добавлен):
helm repo add bitnami https://charts.bitnami.com/bitnami
Устанавливаем чарт Helm с Redis:
helm install dev-redis-chart bitnami/redis --namespace dev-redis --set global.redis.password=redispass,master.persistence.existingClaim=pvc-for-master-redis,replica.replicaCount=2,replica.persistence.storageClass=local-storage,replica.persistence.size=2Gi
В этой команде указываю:
password=redispass
— пароль для авторизации;existingClaim=pvc-for-master-redis
— название созданного вышеPVC
для мастер-реплики;replicaCount, storageClass, size
— количество slave-реплик, название ресурсаStorageClass
и размерPV
. Это всё нужно для автоматического созданияPVC
.
После выполнения команды в консоль будет выведено несколько способов подключения к Redis. Но сначала проверим состояние Persistent Volumes
:
kubectl get pv
Все ресурсы стали связаны с конкретным PVC
. И посмотрим на созданные ресурсы:
kubectl get pod,svc,statefulset -n dev-redis
Всё успешно развернуто, пора подключиться и попинговать базу. Экспортируем пароль авторизации в переменную окружения:
export REDIS_PASSWORD=$(kubectl get secret --namespace dev-redis dev-redis-chart -o jsonpath="{.data.redis-password}" | base64 --decode)
Создадим под с redis-cli на борту:
kubectl run --namespace dev-redis redis-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image docker.io/bitnami/redis:6.2.6-debian-10-r146 --command -- sleep infinity
Проходим внутрь созданного пода:
kubectl exec --tty -i redis-client \
--namespace dev-redis -- bash
И теперь можно подключиться к master- или slave-реплике на выбор:
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h dev-redis-chart-master
или
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h dev-redis-chart-replicas
Подключимся к master-реплике:
Пинганём базу:
Записать данные можно в любую из 15 автоматически созданных баз (по умолчанию база под номером ноль). Выберем, например, вторую:
Запишем некоторые данные:
И запросим их же:
Готово! Redis успешно развёрнут и готов к использованию. В приложении нужно указывать такой адрес:
REDIS=redis://redispass@dev-redis-chart-master:6379/0
Установка RabbitMQ
Запишем манифест с ресурсом StorageClass
в файл storage.yaml:
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
И применим его:
kubectl apply -f storage.yaml
У меня уже был установлен этот ресурс, поэтому манифест не применился.
Создадим Persistent Volume
:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-for-rmq
labels:
type: local
spec:
capacity:
storage: 4Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /devkube/rabbitmq
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- 457344.cloud4box.ru
В matchExpressions
указываем название ноды, на которой будем монтировать диск. Посмотреть имя доступных узлов можно с помощью команды:
kubectl get nodes
Для удобства будем монтировать диск сразу на master-ноде, хотя это можно сделать на любой из доступных в списке. Создадим директорию, в которую RabbitMQ
будет складывать свои данные:
mkdir -p /devkube/rabbitmq
Создадим ресурс Persistent Volume
:
kubectl apply -f pv.yaml
И проверим состояние:
Осталось только создать Persistent Volume Claim
. Его нужно обязательно создавать в том namespace, в котором будете разворачивать будущую очередь. RabbitMQ развернётся в пространстве dev-rmq. Создадим его:
kubectl create ns dev-rmq
Запишем манифест в файл pvc.yaml:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: rmq-pvc
namespace: dev-rmq
spec:
storageClassName: "local-storage"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 4Gi
Применим:
kubectl apply -f pvc.yaml
И, наконец, развернём RabbitMQ. Добавляем к себе репозиторий Bitnami, если ещё этого не сделали (у меня уже добавлен):
helm repo add bitnami https://charts.bitnami.com/bitnami
Установим чарт Helm RabbitMQ:
helm install dev-rmq-chart bitnami/rabbitmq --namespace dev-rmq --set persistence.existingClaim=rmq-pvc,ingress.enabled=true,ingress.hostname=dashboard.dev.rmq.cryptopantry.tech,auth.username=rmq_admin,auth.password=devrmquser,ingress.ingressClassName=nginx
В этой команде я указываю следующие настройки:
existingClaim=rmq-pvc
— имя существующего ресурсаPVC
, который мы выше создали;ingress.enabled=true
— активируем Ingress, это нужно для разворачивания удобной борды;ingress.hostname=dashboard.dev.rmq.somedomain.com
— адрес борды;auth.username=rmq_admin
иauth.password=devrmquser
— тут всё и так понятно;ingress.ingressClassName=nginx
— обязательная настройка для Ingress-ресурса.
Чарт Helm установлен. Проверим, что ресурсы успешно развёрнуты:
Теперь перейдите в браузере по доменному имени, которое указали в ingress.hostname
:
Заходим с учётными данными login=rmq_admin
и password=devrmquser
, и переходим во вкладку Admin:
Создадим нового пользователя qa_user
с паролем qa_pass
:
Создадим virtual host:
И привяжем пользователя к virtual host:
Готово! RabbitMQ развёрнут и готов к использованию:
В приложении укажите такой адрес:
RabbitMQ=amqp://qa_user:qa_pass@dev-rmq-chart-rabbitmq.dev-rmq:5672/qa_host
На этом у меня всё, мы успешно развернули PostgreSQL, Redis и RabbitMQ в небольшом dev-кластере.
Комментарии (12)
gmini
10.03.2022 16:14раз уж Вы чартами пользуетесь, почему тома руками создаете?
Mopckou Автор
10.03.2022 17:04Не видел у чартов bitnami возможность автоматически создавать директории, и вообще есть сомнения, что они могут. Может я захочу монтировать директорию на другой виртуальной машине, где даже helm не стоит?
К тому же, такой ручной контроль не особо трудозатратный, но зато наглядный - сразу понятно куда складываются данные.
vasyakolobok77
10.03.2022 23:37+3я захочу монтировать директорию на другой виртуальной машине, где даже helm не стоит?
helm - это просто шаблонизатор и выкладчик кубер-артефактов, ему не надо быть на виртуальной машине. Вы запускаете htlm локально или в ci-pipeline, он анализирует шаблоны, готовит артефакты и, используя k8s сессию, выкладывает их, все.
Не видел у чартов bitnami возможность автоматически создавать директории
Коллега выше верно заметил, что битнами чарт имеет в себе PVC и может порождать PV. Для дев-стенда это самое оно, не надо руками ничего создавать, просто helm install и в путь.
Еще важный момент, StorageClass может создать только админ кластера. И в принципе, если в кластере уже есть какие-то сторадж-классы, например, cephfs, то нет большого смысла объявлять свой.
Mopckou Автор
11.03.2022 14:42Спасибо за развернутый ответ. Благодаря ему я понял, что не понял изначального вопроса :). Подумал, что речь идет о создании директорий helm'ом на VPS, которые потом монтируются.
Да, согласен чарт от bitnami позволяет создать автоматом PVC. И как раз в этой инструкции при установке Redis автоматически создается PVC для slave-реплик. И вы, конечно, правы инструкцию можно еще больше упросить.
Но новичкам я бы рекомендовал некоторые вещи делать вручную, чтобы они не казались магией. Например даже инструкции от bitnami умалчивают (либо украдкой говорят) о необходимости PV и PVC. А когда ставишь чарт по рекомендованной команде, видишь, что ничего не работает из коробки.
paulstrong
10.03.2022 22:30+1не вижу ничего плохого чтобы размещать базы в кубере, при условии что они гвоздями прибиваются к нодам. тут тебе из коробки днс и выделение IP-адресов. норм гайд.
Saladin
11.03.2022 10:04Стоит заметить, что создание дополнительного пользователя и нестандартного virtual host возможно в RabbitMq сразу при старте. Для этого достаточно определить definitions файл. Helm chart от bitnami это позволяет.
Mopckou Автор
11.03.2022 14:47Да, спасибо за примечание. Но лично для себя решил, что лучше сделать только admin юзера, и только потом создавать других если потребуется. А то в чартах bitnami куча параметров типа user/password, global.user/global.password, auth.user/auth.password и причем некоторые из них переопределяются в зависимости указан дочерний или нет.
Aggron
12.03.2022 01:14+1По поводу PV и PVC - я конспектировал ту самую лекцию, возможно кому-то будет полезно
spacediver
Спасибо за прикладной гайд!
Я в прошлом году слышал, что кубер пока еще не вполне готов к тому, чтобы в нём надёжно хостить stateful сервисы, особенно критичные к внезапным остановкам контейнеров — такие, как СУБД.
Как с этим сейчас?
Mopckou Автор
Сегодня также никто не советует разворачивать продовую базу в кубе. Но для dev контура, просто поиграться, сделать демку приложения, проверить теорию вполне себе удобно.
Вот доклад на эту тему. Автор говорит, что для тестов смело разворачивайте в кубе и ничего страшного. И я с ним в этом вопросе согласен.