Перевели статью о том, как создать PostgreSQL, работающий в контейнере с несколькими подсистемами на Kubernetes. Вы узнаете, как написать файлы ресурсов Kubernetes, как проверить развёрнутые ресурсы из Minikube и kubectl и как убедиться в существовании данных.
Развёртывание покажем на примере Minikube, поскольку его довольно просто установить и запустить через локальное окружение. Вы вряд ли столкнетесь с большой разницей, если будете использовать облачные платформы Amazon Web Service (AWS), Microsoft Azure, GCP или даже какую-то специальную вариацию Kubernetes, например Red Hat Openshift, поскольку работа идет с файлами ресурсов Kubernetes в формате YAML.
0.0. Перед началом
Чтобы статья была вам полезна, вам нужно:
Иметь представление о Kubernetes и контейнерах, чтобы понимать, что происходит.
Иметь 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
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 создан, выполнив следующую команду:
Теперь мы можем перейти к развертыванию, чтобы получить наши поды, но в 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
. Обязательно передайте пространство имен.
Вполне возможно, что на этом шаге вы столкнетесь с ошибкой. Хотя существует множество сценариев, по которым это может произойти, вот несколько способов отладки:
Если контейнер не запускается: Попробуйте выполнить команду
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. В них вы найдёте полезные теоретические и практические материалы для самообучения. Успехов!
svkreml
Может не стоит путать "кодирование" и "шифрование" ? а то следующая статья будет о том, как в БД шифруются пароли пользователей в base64...
Liloon21 Автор
Спасибо! Поправили