Оригинал: CloudNativePG Recipe 10 — Simulating Production PostgreSQL on Kubernetes with Kind — 14 августа 2024.
Как использовать Kind для создания многонодового Kubernetes-кластера на локальной машине, имитирующего продакшн-среду, — с выделением узлов под PostgreSQL, приложения и инфраструктуру.
Kind (Kubernetes IN Docker) позволяет запускать полноценный Kubernetes-кластер, используя Docker-контейнеры в качестве узлов. Это портативная и воспроизводимая среда для тестирования приложений и интеграции в GitOps-пайплайны.
В Рецепте 1 рассматривались основы начала работы. Здесь — следующий шаг: многонодовый кластер с разделением ролей узлов.
Прежде чем начать
Убедитесь, что установлены:
Многонодовый кластер
По умолчанию Kind создаёт одноузловой кластер — этого достаточно для многих сценариев, но не для работы с node selectors, taints & tolerations, affinity и anti-affinity. Для этого нужен многонодовый кластер.
Kind позволяет настроить кластер через конфигурационный файл. Создадим кластер со следующей топологией:
- 1 узел — control plane;
- 1 worker с меткой
infra.node.kubernetes.io— инфраструктурные нагрузки (Prometheus, Grafana); - 1 worker с меткой
app.node.kubernetes.io— приложения (например, pgbench); - 3 worker’а с меткой
postgres.node.kubernetes.io— PostgreSQL-инстансы.
Соглашение по именам меток:
ROLE.node.kubernetes.io, гдеROLE—infra,appилиpostgres. Причины такого выбора описаны ниже.
Конфигурация Kind:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: multi-node-template
nodes:
- role: control-plane
- role: worker
labels:
infra.node.kubernetes.io:
- role: worker
labels:
app.node.kubernetes.io:
- role: worker
labels:
postgres.node.kubernetes.io:
- role: worker
labels:
postgres.node.kubernetes.io:
- role: worker
labels:
postgres.node.kubernetes.io:Создание кластера:
kind create cluster --config multi-node-template.yaml --name cnpgПроверяем узлы:
kubectl get nodesNAME STATUS ROLES AGE VERSION
cnpg-control-plane Ready control-plane 5m4s v1.35.0
cnpg-worker Ready <none> 4m44s v1.35.0
cnpg-worker2 Ready <none> 4m44s v1.35.0
cnpg-worker3 Ready <none> 4m45s v1.35.0
cnpg-worker4 Ready <none> 4m44s v1.35.0
cnpg-worker5 Ready <none> 4m45s v1.35.0Роль отображается только у cnpg-control-plane. У остальных — <none>. Почему?
Стандартные метки ролей узлов в Kubernetes
Kubernetes использует метку node-role.kubernetes.io/control-plane
для идентификации узлов control plane. Команда kubectl get nodes извлекает роль из строки после node-role.kubernetes.io/.
Чтобы отображались роли worker-узлов, нужно вручную назначить метки:
node-role.kubernetes.io/infranode-role.kubernetes.io/appnode-role.kubernetes.io/postgres
По умолчанию kubelet запрещает назначение меток в пространстве kubernetes.io, если у них нет префикса kubelet или node (мера безопасности). Обходной путь — назначить метки после создания через kubectl label node:
kubectl label node -l postgres.node.kubernetes.io node-role.kubernetes.io/postgres=
kubectl label node -l infra.node.kubernetes.io node-role.kubernetes.io/infra=
kubectl label node -l app.node.kubernetes.io node-role.kubernetes.io/app=Теперь kubectl get nodes покажет:
NAME STATUS ROLES AGE VERSION
cnpg-control-plane Ready control-plane 19m v1.35.0
cnpg-worker Ready infra 19m v1.35.0
cnpg-worker2 Ready app 19m v1.35.0
cnpg-worker3 Ready postgres 19m v1.35.0
cnpg-worker4 Ready postgres 19m v1.35.0
cnpg-worker5 Ready postgres 19m v1.35.0Шесть узлов с понятным распределением ролей: control plane, приложения, инфраструктура и Postgres.
Дополнительно
Выбранная конвенция ROLE.node.kubernetes.io удобна тем, что позволяет назначать метки через селекторы. Можно также маркировать узлы по одному:
kubectl label node cnpg-worker5 node-role.kubernetes.io/postgres=Планирование CNPG-кластеров на узлах postgres
Задача: декларативно создать PostgreSQL-кластер через CloudNativePG и обеспечить его запуск только на узлах с ролью postgres.
Это решается через node selectors
. В CloudNativePG — поле .spec.affinity.nodeSelector:
affinity:
nodeSelector:
node-role.kubernetes.io/postgres: ""Запуск
Установите оператор CloudNativePG (рекомендуется последняя стабильная версия):
curl -sSfL \
https://raw.githubusercontent.com/cloudnative-pg/artifacts/main/manifests/operator-manifest.yaml | \
kubectl apply --server-side -f -Дождитесь готовности оператора:
kubectl get pods -A -o wideСоздайте PostgreSQL-кластер:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-example
spec:
instances: 3
storage:
size: 1Gi
affinity:
nodeSelector:
node-role.kubernetes.io/postgres: ""Примените манифест:
kubectl apply -f cluster-example.yamlПроверка:
kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cluster-example-1 1/1 Running 0 96s 10.244.4.4 cnpg-worker4 <none> <none>
cluster-example-2 1/1 Running 0 54s 10.244.1.4 cnpg-worker3 <none> <none>
cluster-example-3 1/1 Running 0 13s 10.244.2.5 cnpg-worker5 <none> <none>Все три инстанса PostgreSQL запущены исключительно на узлах с ролью postgres.
Заключение
Kind — мощный инструмент, позволяющий моделировать реальные сценарии прямо на ноутбуке. В связке с Kubernetes, CloudNativePG и PostgreSQL (всё — open-source) можно проектировать, тестировать и автоматизировать инфраструктуру от разработки до продакшна, в том числе через GitOps-пайплайны.
Благодаря портативности Kubernetes эти рекомендации применимы к любому облачному окружению — частному, публичному, самоуправляемому или полностью управляемому.
Node labels — ключевой механизм контроля «физического» размещения PostgreSQL-нагрузок через декларативную конфигурацию. Можно выделять конкретные машины под один PostgreSQL-кластер или использовать bare-metal узлы с локальными дисками.
Однако одних меток недостаточно для полной изоляции. В примере выше оператор (cnpg-controller-manager) мог запуститься на одном из postgres-узлов. Если на этом узле возникнет проблема, это может замедлить failover. Решение — taints и tolerations — рассматривается в следующем рецепте.