Перевели статью о том, как создать PostgreSQL, работающий в контейнере с несколькими подсистемами на Kubernetes. Вы узнаете, как написать файлы ресурсов Kubernetes, как проверить развёрнутые ресурсы из Minikube и kubectl и как убедиться в существовании данных.

Развёртывание покажем на примере Minikube, поскольку его довольно просто установить и запустить через локальное окружение. Вы вряд ли столкнетесь с большой разницей, если будете использовать облачные платформы Amazon Web Service (AWS), Microsoft Azure, GCP или даже какую-то специальную вариацию Kubernetes, например Red Hat Openshift, поскольку работа идет с файлами ресурсов Kubernetes в формате YAML.

0.0. Перед началом

Чтобы статья была вам полезна, вам нужно:

  • Иметь представление о Kubernetes и контейнерах, чтобы понимать, что происходит.

  • Иметь CLI Kubernetes под названием kubectl.

  • Иметь Minikube для запуска Kubernetes. Технически можно использовать и другие Kubernetes, но для этого, вероятно, потребуется выполнить некоторые дополнительные действия, например, подключиться к платформе и т.д. Вероятно, у вас должен быть установлен и запущен Docker, если вы не используете QEMU или другой гипервизор.

  • Иметь Visual Studio Code или другой редактор, в котором можно создавать и изменять файлы.

  • Уметь пользоваться терминалом и выполнять некоторые команды unix.

1.0. Настройка

После установки kubectl и Minikube попробуем запустить Minikube, выполнив следующую команду в терминальном CLI.

minikube start
Успешный старт. Источник
Успешный старт. Источник

Если вы видите ошибку, убедитесь, что гипервизор или Docker запущен, или выделено достаточно ресурсов. Возможны и другие ошибки, например, поддерживаемой версии или пакета ПО, но это выходит за рамки данной статьи.

После запуска Minikube можно вызвать визуальный интерфейс, набрав следующую команду.

minikube dashboard
Дашборд Миникуба. Источник
Дашборд Миникуба. Источник

Мы будем работать в основном с помощью команд kubectl, хотя дашборд Minikube — тоже хороший способ мониторить, что происходит с вашим развертыванием.

Обратите внимание, что наше текущее пространство имен — default (показано в виде выпадающего списка). Для теста можно использовать его, но лучше сделать безопасное, выделенное пространство имен, чтобы не затрагивать другие ресурсы. Поэтому мы начнем с создания нашего пространства имен.

Когда вы запустите дашборд Minikube, он будет занимать ваш текущий терминал, поэтому запустите другой терминал, чтобы не прерывать работу с дашбордом.

2.0. Создание нового пространства имен

Давайте создадим новое пространство имен. Вы можете назвать его как угодно, но я буду называть его database-demo.

kubectl create namespace database-demo

Проверить созданное пространство имен можно с помощью команды kubectl get namespaces или kubectl get ns

Создаём новое пространство имён и проверяем. Источник
Создаём новое пространство имён и проверяем. Источник

Теперь перейдем к развертыванию ресурсов. Вот что нам необходимо создать:

  • Постоянный том

  • Утверждение постоянного тома

  • Карта конфигурации

  • Секрет

  • Развертывание

  • Сервис

Я буду пошагово объяснять, в чём суть каждого из них.

3.0. Persistent Volume

Хотя некоторые ресурсы Kubernetes не зависят от времени их создания, мы начнем с создания Persistent Volume.

Зачем нам нужен Persistent Volume (PV)? Kubernetes — это платформа для оркестрации контейнеров, но контейнеры должны быть эфемерными. То есть поды быстро поднимаются и затем отмирают. Таким образом, по умолчанию сохранить данные (или персистировать их) с помощью контейнеров невозможно.

Именно здесь на помощь приходит Persistent Volume. Persistent Volume позволяет создать в среде Kubernetes хранилище, в котором данные могут сохраняться даже в случае отмирания контейнеров.

Вот определение ресурса Persistent Volume. Я сохранил этот файл под именем pv-db.yml.


apiVersion: v1
# Kind for volume chain
kind: PersistentVolume
metadata:
  name: persistent-volume-pv
  labels:
    type: local
    app: my-database
spec:
  storageClassName: manual
  capacity:
    storage: 8Gi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: "/data/db"

Давайте посмотрим, что у нас здесь есть. Тип — PersistentVolume, и я присваиваю ему пользовательскую метку my-database. На эту метку я буду ссылаться в дальнейшем в своем ресурсе Deployment.

В разделе spec можно узнать, сколько места для хранения данных я выделяю, какая модель доступа используется и где хранить эти данные через hostPath.path. Как только поды будут запущены, вы сможете найти информацию о PostgreSQL по пути /data/db.

Хочу обратить внимание на то, что storageClassName, accessModes могут сильно меняться в зависимости от типа хранилища. Это становится очень важным при последующей работе с публичным облаком или локальным сервером, поскольку каждый тип хранилища будет обладать различными свойствами. Например, некоторые хранилища в Azure могут позволять ReadOnly, а не ReadWriteMany.

Мы создадим этот PV с помощью следующей команды. Обратите внимание, что параметром -n я указываю, что это для моего пространства имен.

kubectl apply -f pv-db.yml -n database-demo

Затем можно проверить, что созданный PV доступен, с помощью следующей команды.

kubectl get pv -n database-demo
Запускаем команду kubectl get pv. Источник
Запускаем команду kubectl get pv. Источник

4.0. Persistent Volume Claim

Следующий пункт — Persistent Volume Claim, коротко известный как PVC. Не имеет значения, используете ли вы сначала PV, а затем PVC, или наоборот. Порядок имеет значение, когда они используются подами в процессе развертывания.

Что такое PVC? PVC — это способ, с помощью которого под может потребовать доступный постоянный том. Это своего рода механизм запроса от пользователя, позволяющий эффективно распределять ресурсы.

Вот определение PVC. Я назвал свой файл pvc-db.yml, но вы можете назвать его как угодно.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-db
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 8Gi

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

kubectl apply -f pvc-db.yml -n database-demo

Я могу убедиться в том, что PVC создан, выполнив следующую команду:

Проверяем PVC. Источник
Проверяем PVC. Источник

Теперь мы можем перейти к развертыванию, чтобы получить наши поды, но в PostgreSQL не будет существующих данных, с которыми мы могли бы поиграть после развертывания. Поэтому при первом развертывании я бы создал таблицу базы данных с некоторыми примерными данными. Здесь на помощь приходит Config Map.

5.0. Config Map

Config Map (CM) можно рассматривать как способ хранения некоторых ключей в открытом виде или содержимого файлов, на которые могут ссылаться различные подсистемы.

В нашем случае мы создадим ConfigMap, содержащий файл create-database-table.sql, который создаст таблицу базы данных с именем gifts и заполнит ее некоторыми данными из примера. Я назвал свой файл cm-db.yml, но вы можете назвать его как угодно.

kind: ConfigMap
apiVersion: v1
metadata:
  name: database-cm
data:
  create-database-table.sql: |
    CREATE TABLE gifts (
      id SERIAL PRIMARY KEY,
      name VARCHAR,
      sold INT
    );

    INSERT INTO gifts (name,sold) VALUES ('Pumpkin', 3000);
    INSERT INTO gifts (name,sold) VALUES ('Christmas Tree', 1000);
    INSERT INTO gifts (name,sold) VALUES ('Socks', 10000);

Затем я могу создать свою Config Map с помощью следующей команды. Обратите внимание, что необходимо указать пространство имен.

kubectl apply -f cm-db.yml -n database-demo

Убедитесь в том, что CM успешно создан, с помощью команды kubectl get cm -n database-demo. Разумеется, вы можете проверить это и из дашборда Minikube. В качестве дополнительного совета можно проверить любой текущий ресурс с помощью команды kubectl describe. Только не забудьте указать правильное пространство имен.

Проверяем, что ресурсы созданы. Источник
Проверяем, что ресурсы созданы. Источник

Теперь нам необходимо предоставить учётные данные для входа в нашу базу данных PostgreSQL. Для этого мы воспользуемся командой Secret.

6.0. Secrets

Secret очень похож на Config Map по своей структуре и способу обращения к нему. Однако есть два явных отличия:

  • Secret должен храниться в виде закодированного значения в формате base64.

  • Secret должен хранить безопасные значения.

Существует множество примеров, когда эти учётные данные хранят в файле развертывания или в Config Map. Я не думаю, что это правильно, поскольку закодированное значение нуждается в дополнительной защите.

Для этого необходимо сначала закодировать значение в base64. Если вы используете MacOs, вы можете легко сделать это следующей командой:

echo -n "VALUE_YOU_WANT_ENCRYPT" | base64

Попробуйте сделать это для имени пользователя базы данных, имени таблицы базы данных и пароля базы данных. Я привел свой пример в файле с именем secret-db.yml

apiVersion: v1
kind: Secret

metadata:
  name: db-secret-credentials
  labels:
    app: my-database
data:
  POSTGRES_DB: Z2lmdHMtdGFibGU= # gifts-table
  POSTGRES_USER: YWRtaW4= # admin
  POSTGRES_PASSWORD: UEBzc3cwcmQ= # P@ssw0rd

Как и раньше, вы можете создать свой секрет с помощью следующей команды.

kubectl apply -f secret-db.yl -n database-demo

Еще раз проверьте свой Secret с помощью команды kubectl get secret. Теперь мы переходим к развёртыванию.

7.0. Deployments

Что такое развертывание? Проще говоря, это способ развёртывания приложения в Kubernetes, чтобы подсистемы могли запускаться. Я сказал, что это способ? Это способ, потому что существуют и другие способы, такие как Pod, StatefulSet и Daemonset. Хотя StatefulSet довольно популярен для сохранения ресурсов, таких как база данных, я выбрал Deployment, поскольку он обеспечивает некоторую гибкость.

Вот мой файл Deployment под названием deployment-db.yml, хотя имя файла может быть любым. Здесь много всего, но обратите внимание на несколько моментов:

  • Я выбираю ранее созданные ресурсы с помощью селектора.

  • Я использую образ под названием postgres:latest. Он берется непосредственно с DockerHub, но может храниться и в другом реестре образов, например, GitHub Packages, JFrog Artifactory. В последнем случае потребуется pull secret образа.

  • Он ссылается на учетные данные базы данных и имя базы данных из Secret, как показано в поле valueFrom.

  • Есть два монтируемых тома. db-data — это том, который сохраняет данные нашей базы данных. postgresdb-loadsql — это том, который загружает SQL-файл нашей базы данных.

  • Есть два тома. Обратите внимание, что они ссылаются на Persistent Volume и ConfigMap.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-db
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-database
  template:
    metadata:
      labels:
        app: my-database
    spec:
      containers:
        - name: my-database
          image: postgres:latest
          ports:
            - containerPort: 5432
          env:
            - name: POSTGRES_DB
              valueFrom:
                secretKeyRef:
                  name: db-secret-credentials
                  key: POSTGRES_DB

            - name: POSTGRES_USER
              valueFrom:
                secretKeyRef:
                  name: db-secret-credentials
                  key: POSTGRES_USER

            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret-credentials
                  key: POSTGRES_PASSWORD

          volumeMounts:
            - mountPath: /var/lib/postgres/data
              name: db-data

            - mountPath: /docker-entrypoint-initdb.d
              name: postgresdb-loadsql
      volumes:
        - name: postgresdb-loadsql
          configMap:
            name: database-cm

        - name: db-data
          persistentVolumeClaim:
            claimName: pvc-db

Создайте развертывание с помощью следующей команды.

kubectl apply -f deployment-db -n database-demo

Затем можно проверить развертывание командой kubectl get deployment, а подсистемы — командой kubectl get pods. Обязательно передайте пространство имен.

Как проверить deployment. Источник
Как проверить deployment. Источник

Вполне возможно, что на этом шаге вы столкнетесь с ошибкой. Хотя существует множество сценариев, по которым это может произойти, вот несколько способов отладки:

  • Если контейнер не запускается: Попробуйте выполнить команду kubectl logs POD_NAME. Это покажет, где произошел сбой. Вы также можете использовать команду kubectl describe pod POD_NAME, чтобы увидеть некоторые признаки ошибки.

  • Если поды работают, но видны ошибки, можно зайти внутрь контейнера с помощью следующей команды: kubectl exec -it POD_NAME -- sh

Теперь, в качестве последнего шага, давайте создадим наш сервис.

8.0. Сервис

Последнее, что мы создадим, — это сервис (SVC). Сервис — это способ, с помощью которого мы можем подключаться к нашим подам. Существует три (3) типа сервисов, поддерживаемых Kubernetes:

  • ClusterIP: предназначен для связи подов между собой

  • NodePort: Предоставляет внешний порт для подключения каждого узла.

  • LoadBalancer: Обычно это лучший способ подключения с какого-либо внешнего URL.

В нашем случае нам просто нужно проверить, что мы можем подключиться к нашей базе данных, поэтому мы будем использовать NodePort. Вот мое определение службы под названием svc-db.yml.

apiVersion: v1
kind: Service
metadata:
  name: svc-db
  labels:
    app: my-database
spec:
  type: NodePort
  ports:
    - port: 5432
  selector:
    app: my-database

Я могу создать службу следующей командой.

kubectl apply -f svc-db.yml -n database-demo

Я могу проверить, что мой сервис создан, с помощью команды kubectl get svc.

Но давайте проверим, что мы действительно можем подключиться к базе данных и получить результат. Я могу зайти внутрь пода и выполнить команду psql. Я выполню эту команду, чтобы напрямую получить данные.

kubectl exec -it POD_NAME -- psql -h localhost -U admin --password -p 5432 gifts-table

Замените соответствующие значения на заданные вами.

Вот мой результат.

Результат. Источник
Результат. Источник

Вы успешно развернули PostgreSQL внутри Kubernetes.


Если вы хотите научиться разбираться в архитектуре Kubernetes, создавать отказоустойчивые кластеры, запускать базы данных в Kubernetes, то приходите в Слёрм на курс Kubernetes: Мега. Это продвинутый курс для тех, кто уже имеет опыт работы с K8s, хочет заглянуть под капот, научиться тонкой настройке и кастомизации. Вот что будет на курсе:

  • Вручную создадим отказоустойчивый кластер.

  • Настроим аутентификацию и авторизацию пользователей.

  • Поработаем с Network Policy и сетевыми плагинами.

  • Познакомимся с инструментами безопасности.

  • Подробно разберём работу scheduler, API Server, Controller manager, научимся делать собственные операторы для Kubernetes.

  • Изучим особенности statful приложения в кластере.

  • Поработаем с секретами и интегрируем Hashicorp Vault.

  • Изучим механизм автоскейлинга и подключим к нему кастомные метрики.

  • Сделаем бекап кластера.

  • Настроим ротацию сертификатов.

  • Попробуем альтернативные методы деплоя.

  • Изучим Open Policy Agent (OPA).

  • На практике рассмотрим Service mesh на примере Istio.

В курсе 7 онлайн-встреч со спикерами, практика на стендах и сертификация. 

Ознакомиться с программой и оставить заявку можно на нашем сайте.

Если вы ещё только начинаете изучение Kubernetes, посмотрите бесплатные вебинары Вечерней школы Слёрма по Kubernetes. В них вы найдёте полезные теоретические и практические материалы для самообучения. Успехов!

Комментарии (2)


  1. svkreml
    09.10.2023 10:19
    +2

    Для этого необходимо сначала зашифровать значение в base64.

    Может не стоит путать "кодирование" и "шифрование" ? а то следующая статья будет о том, как в БД шифруются пароли пользователей в base64...


    1. Liloon21 Автор
      09.10.2023 10:19
      -1

      Спасибо! Поправили