Разворачиваем PostgreSQL, Redis и RabbitMQ в Kubernetes-кластере

e115d2558170195ee68c9d527834a5cf.png

В этой статье я не буду объяснять, зачем вот это всё нужно, или обсуждать достоинства и недостатки этого решения. Воспринимайте эту статью как инструкцию (заметку) для быстрого развертывания базы и очереди в dev-кластере Kubernetes.

Содержание

  1. Введение

  2. Установка PostgreSQL

  3. Установка Redis

  4. Установка RabbitMQ

Введение

Установки PostgresSQL, Redis и RabbitMQ очень похожи друг на друга. Можно выделить три основных этапа:

  • Создание Persistent Volume (PV) и Persistent Volume Claim (PVC).

  • Установка Helm-чарта целевого приложения.

  • Проверка работы.

Я не буду объяснять, что такое PV и PVC. Есть отличная лекция на эту тему, после которой можете смело возвращаться к моей инструкции. Перед началом работ нужно минимально настроить кластер Kubernetes. Вот небольшие требования:

  1. Версия Kubernetes 1.20+.

  2. Одна master-нода и одна worker-нода.

  3. Настроенный Ingress-controller.

  4. Если кластер развернут на bare-metal, то необходимо заменить внешний балансировщик. Например, поставить MetalLB или PorterLB.

  5. На виртуальной машине установлен Helm.

Как создать свой ламповый dev-кластер на голом железе подробно рассказано в предыдущей статье.

Установка PostgreSQL

Создадим ресурс StorageClass, для этого в файл storage.yaml вставьте следующую конфигурацию:

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

Применим манифест:

84c5eff304037fa52b0b2cc1af890d4c.png

Создадим ресурс 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

c57eeba752dbea21b0e13ea24cfea570.png

Для удобства будем монтировать диск сразу на мастер-ноде, хотя это можно сделать на любой из доступных в списке. Монтировать будем директорию /devkube/postgresql. Заходим на удалённую машину и создаём директорию такой командой:

mkdir -p /devkube/postgresql

Создадим ресурс Persistent Volume:

kubectl apply -f pv.yaml

a5d2ebb80a2308b8219e2cfbe35aaa72.png

Проверим состояние:

kubectl get pv

7c0f0ce9355ad010ceb1d1af48debbd1.png

Применим манифест с Persistent Volume Claim:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pg-pvc
spec:
  storageClassName: "local-storage"
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 4Gi

b025ca8f32df0b275cca8a1d867ce77d.png

Посмотрим состояние ресурса:

4783542e49668e0ecf8feac783ee758c.png

Ресурс PVC в ожидании привязки. Настало время развернуть Postgres в кластере. Подтягиваем к себе репозиторий Bitnami:

helm repo add bitnami https://charts.bitnami.com/bitnami

4450c4861535420de4b6e5c2dac656d3.png

Устанавливаем чарт Helm с Postgres:

helm install dev-pg bitnami/postgresql --set primary.persistence.existingClaim=pg-pvc,auth.postgresPassword=pgpass

Посмотрим на состояние PVC:

kubectl get pvc

49319629acd61a257b4f39a0f67505ed.png

Ресурс в статусе bound, теперь pod с Postgres будет писать данные в директорию /devkube/postgresql. Посмотрим на состояние pod, statefulset:

kubectl get pod,statefulset

d56c3a864eb3e96f404e6bd63bd255f9.png

База успешно развёрнута, теперь попробуем подключиться к ней: создать пользователя, таблицу и настроить доступы. После установки чарта в консоли будут показаны некоторые способы подключения к БД. Есть два способа:

1. Пробросить порт на локальную машину

Для этого требуется установить на машину утилиту psql. Проверим, что она установлена:

psql -V
b2782a86f3553b9849be33c1d0efaeb5.png

Экспортируем пароль от админ-пользователя в переменную окружения:

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
6820c1316864815aef18ae39d9d23b92.png

Консоль после выполнения команды будет заблокирована. В другом окне подключитесь к этой же машине и выполните подключение к БД:

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
d3c015933f660bcda4ea514d65d8e813.png

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
df21b13978a56c4d5f0efbdfc9124ef9.png

Создадим роль (пользователя) и пароль для неё:

CREATE ROLE qa_user WITH LOGIN ENCRYPTED PASSWORD 'qa-pg-pass';

1f2919ebd931424ea4d7fa220cbde337.png

Посмотреть список ролей:

\du

7e415469b9f118ae4c397ca7d7162332.png

Создадим базу, владельцем которой будет пользователь qa_user:

CREATE DATABASE qa_db OWNER qa_user;

da2adf3bef03c30c8e5dbdb57caed46b.png

Теперь отключимся:

\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

0fceffe49919c742f576388413c8432e.png

Создадим небольшую табличку:

CREATE TABLE qa_table (id int, name varchar(255));

b60c5bd595272681140e1733d5b5030f.png

Добавим запись:

INSERT INTO qa_table VALUES (1, 'first');

c5e47d750252e840c9a664e097f0d7d2.png

Теперь сделаем select, чтобы убедиться в работоспособности:

SELECT * FROM qa_table;

73801512288d6bf92e1f909bd52562a3.png

Посмотреть список таблиц в базе:

\dt+

9bd366f1c34b7e7edceefebb5553ab29.png

Готово, база успешно развёрнута! В приложении нужно указывать такой адрес БД:

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

У меня уже был установлен этот ресурс, поэтому манифест не применился.

95475308b53841a56fcb7dbaa8cafa41.png

Дальше настроим 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 .

49f0c6015e3aac3909e8268a336b3743.png

Проверим созданные ресурсы:

kubectl get pv

19bb5fba181a9797989559e3a3b07025.png

Созданные PV ещё свободны и ждут заявки на использование пространства. А Persistent Volumes Postgres уже связан со своим Persistent Volumes Сlaim (так осталось после поднятия Postgres-базы в Kubernetes).

Создадим PVC для мастер-реплики. Их нужно обязательно создавать в том namespace, в котором вы развернёте базу. Redis будет развёрнут в пространстве dev-redis. Создадим пространство:

kubectl create ns dev-redis

b613301fd9e2bda75a419016bb535cac.png

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

51bec30f5a70ae9739458cb45ef056fc.png

Для slave-реплик создавать PVC не будем, они будут автоматически созданы при установке чарта Helm.

Пришло время установить Redis. Подтягиваем к себе репозиторий Bitnami, если ещё этого не сделали (у меня уже добавлен):

helm repo add bitnami https://charts.bitnami.com/bitnami

ef3db1c2e469f607d1fe7aa1e83c05b0.png

Устанавливаем чарт 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

88bc652c3d93f932144f140b1b449cb9.png

Все ресурсы стали связаны с конкретным PVC. И посмотрим на созданные ресурсы:

kubectl get pod,svc,statefulset -n dev-redis

e9f115e491c7fc6c05dff9994c967e64.png

Всё успешно развернуто, пора подключиться и попинговать базу. Экспортируем пароль авторизации в переменную окружения:

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

228ab2c7ffa71ef6542d812e21d730dd.png

Проходим внутрь созданного пода:

kubectl exec --tty -i redis-client \
   --namespace dev-redis -- bash

d082cbebad44b7a459e1e37d5f204e5c.png

И теперь можно подключиться к 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-реплике:

1bd04b4eb5fb35e7ecab1203be8b9ad9.png

Пинганём базу:

11d483042ef152e21b629849e46f1f51.png

Записать данные можно в любую из 15 автоматически созданных баз (по умолчанию база под номером ноль). Выберем, например, вторую:

d0bb12822aafe2469ac3ac558f787bf3.png

Запишем некоторые данные:

c1cf011c595f412d8c3d0625efe92574.png

И запросим их же:

622b5c034d3bde9733ef11475344dd2d.png

Готово! 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

У меня уже был установлен этот ресурс, поэтому манифест не применился.

b29e504a43ae7104cae95faf382d09d9.png

Создадим 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

d1ba2d4f63b9fa4cb5e39582826d1cc6.png

Для удобства будем монтировать диск сразу на master-ноде, хотя это можно сделать на любой из доступных в списке. Создадим директорию, в которую RabbitMQ будет складывать свои данные:

mkdir -p /devkube/rabbitmq

Создадим ресурс Persistent Volume:

kubectl apply -f pv.yaml

ebd9d16e45d45ed2855adb1990605ba0.png

И проверим состояние:

93db462307574e89a6925d6fbdb61b8f.png

Осталось только создать Persistent Volume Claim. Его нужно обязательно создавать в том namespace, в котором будете разворачивать будущую очередь. RabbitMQ развернётся в пространстве dev-rmq. Создадим его:

kubectl create ns dev-rmq

0c7c41411a84c79d68a24b8c36f71374.png

Запишем манифест в файл 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

188ecf677280acffe08efae3bd08458d.png

И, наконец, развернём RabbitMQ. Добавляем к себе репозиторий Bitnami, если ещё этого не сделали (у меня уже добавлен):

helm repo add bitnami https://charts.bitnami.com/bitnami

fe3b74b265f5e6819eefff9b43bf4b05.png

Установим чарт 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 установлен. Проверим, что ресурсы успешно развёрнуты:

dfc5180576193d62a0df33a5713227df.png

Теперь перейдите в браузере по доменному имени, которое указали в ingress.hostname:

d2bc1bc3a7a4e367f0e4e38d424cf1a3.png

Заходим с учётными данными login=rmq_admin и password=devrmquser, и переходим во вкладку Admin:

3822fd2d3e32e1b60feaf33851f88ce5.png

Создадим нового пользователя qa_user с паролем qa_pass:

b6267c71a17c9569896a298f5e6e79fa.png

Создадим virtual host:

0ba7766e350b0ec909ccdc2dd662e30e.png

И привяжем пользователя к virtual host:

f6738308a42d78cb60252b9dbd7748af.png4b8788b7d306eeac5d1d3266f636c5b5.png

Готово! RabbitMQ развёрнут и готов к использованию:

3b3480fb30ce473f8ada3720ae20d5c3.png

В приложении укажите такой адрес:

RabbitMQ=amqp://qa_user:qa_pass@dev-rmq-chart-rabbitmq.dev-rmq:5672/qa_host

На этом у меня всё, мы успешно развернули PostgreSQL, Redis и RabbitMQ в небольшом dev-кластере.

© Habrahabr.ru