Привет, Хабр!
Сегодня у нас на повестке дня тема миграции данных в Kubernetes. Kubernetes — это как швейцарский нож в разработке: умеет всё и сразу. Он не только управляет контейнерами, но и отлично справляется с данными, благодаря таким объектам как PersistentVolume и StatefulSet. PersistentVolume — это механизм для подключения постоянного хранилища, чтобы данные не исчезли при перезапуске контейнера. StatefulSet — это контроллер, который позволяет управлять состоянием приложений и сохранять данные в стабильном виде даже при изменениях в кластере.
Подготовка к миграции
Перед тем как начать, убедимся, что всё под рукой:
Kubernetes‑кластер: локально с Minikube или в облаке.
Kubectl: главный помощник для управления кластером.
Helm: пакетный менеджер для Kubernetes, который упростит жизнь (опционально, но очень рекомендую). Ознакомиться можно здесь.
Инструменты для миграции данных:
pg_dump
для PostgreSQL,mysqldump
для MySQL и т. д.Хранилище данных: будь то облачное или локальное, поддерживающее PersistentVolumes.
Настройка хранилища в Kubernetes
Чтобы данные были доступны приложениям, необходимо настроить хранилище. В Kubernetes для этого используются PersistentVolume и PersistentVolumeClaim.
persistent‑volume.yaml:
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
# Указываем объем хранилища, который будет выделен для приложения
capacity:
storage: 20Gi
# Определяем режим доступа: только одно приложение может одновременно читать и писать данные
accessModes:
- ReadWriteOnce
# Задаем политику для PV: данные сохраняются даже после удаления PV
persistentVolumeReclaimPolicy: Retain
# Задаем путь, где физически будут храниться данные
hostPath:
path: "/mnt/data"
persistent-volume-claim.yaml:
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
# Указываем объем хранилища, который будет выделен для приложения
capacity:
storage: 20Gi
# Определяем режим доступа: только одно приложение может одновременно читать и писать данные
accessModes:
- ReadWriteOnce
# Задаем политику для PV: данные сохраняются даже после удаления PV
persistentVolumeReclaimPolicy: Retain
# Задаем путь, где физически будут храниться данные
hostPath:
path: "/mnt/data"
Запустим манифесты
kubectl apply -f persistent-volume.yaml
kubectl apply -f persistent-volume-claim.yaml
kubectl get pv
kubectl get pvc
Если всё прошло гладко, можно будет увидеть, что PVC привязан к PV.
Развертываем StatefulSet для базы данных
Теперь пора заняться базой данных. Для этого отлично подходит StatefulSet — специальный ресурс Kubernetes для управления состоянием приложений.
Пример манифеста StatefulSe
statefulset‑postgres.yaml:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
# Имя сервиса, через который будут обращаться к PostgreSQL
serviceName: "postgres"
replicas: 1 # Количество реплик базы данных (в данном случае одна)
selector:
matchLabels:
app: postgres # Метка, по которой будет найден под для этого StatefulSet
template:
metadata:
labels:
app: postgres # Метка, присвоенная каждому поду
spec:
containers:
- name: postgres
image: postgres:13 # Указываем образ PostgreSQL для использования
ports:
- containerPort: 5432 # Порт, на котором работает PostgreSQL
env:
# Переменные окружения для настройки PostgreSQL (логин, пароль, база данных)
- name: POSTGRES_USER
value: "admin"
- name: POSTGRES_PASSWORD
value: "password"
- name: POSTGRES_DB
value: "mydatabase"
volumeMounts:
# Указываем, куда будут монтироваться данные в контейнере
- name: postgres-data
mountPath: /var/lib/postgresql/data
# Определяем шаблон для динамического создания хранилищ для каждой реплики
volumeClaimTemplates:
- metadata:
name: postgres-data # Название PVC для базы данных
spec:
accessModes: ["ReadWriteOnce"] # Одновременный доступ для одного экземпляра
resources:
requests:
storage: 20Gi # Размер запрашиваемого хранилища
storageClassName: standard # Класс хранилища для PVC
Применяем:
kubectl apply -f statefulset-postgres.yaml
kubectl get statefulsets
kubectl get pods
kubectl get pvc
Если всё прошло успешно, ваш под PostgreSQL запущен, и PVC привязан. Отлично!
Миграция данных
Теперь самое интересное — переносим данные из старой базы в новую, развернутую в Kubernetes.
Пример на PostgreSQL
Сначала на локальной машине выполняем команду для создания дампа базы данных:
pg_dump -U postgres -h localhost -p 5432 mydatabase > dump.sql
Чтобы перенести дамп в кластер, создадим ConfigMap:
configmap-pg-dump.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: pg-dump
data:
dump.sql: |
-- содержимое dump.sql сюда
Лучше использовать kubectl create configmap
с файлом напрямую, но для примера показал вручную.
kubectl create configmap pg-dump --from-file=dump.sql
Теперь создаем Job для восстановления данных
job-pg-restore.yaml:
apiVersion: batch/v1
kind: Job
metadata:
name: pg-restore
spec:
template:
spec:
containers:
- name: pg-restore
image: postgres:13 # Используем тот же образ PostgreSQL
env:
# Пароль для доступа к базе данных
- name: PGPASSWORD
value: "password"
# Команда для восстановления базы данных из дампа
command: ["sh", "-c", "psql -U admin -d mydatabase < /data/dump.sql"]
volumeMounts:
# Монтируем ConfigMap с дампом базы данных
- name: dump-volume
mountPath: /data
restartPolicy: OnFailure # Повторить задачу только в случае ошибки
volumes:
- name: dump-volume
configMap:
name: pg-dump # Название ConfigMap, где хранится дамп
Применяем:
kubectl apply -f job-pg-restore.yaml
kubectl get jobs
kubectl logs job/pg-restore
Если всё прошло успешно, данные будут восстановлены в новой базе данных в Kubernetes.
Мониторинг и резервное копирование
Миграция — это только начало. Данные должны быть всегда под контролем. Для этого отлично подходят Prometheus, Grafana и Velero.
Установка Prometheus:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install prometheus prometheus-community/prometheus
Установка Grafana:
helm install grafana grafana/grafana
Настроим PersistentVolume для Grafana:
persistent-volume-grafana.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: grafana-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
Применяем PVC:
kubectl apply -f persistent-volume-grafana.yaml
Настроим бэкапы с Velero
Если ты не хочешь обнаружить себя в 2 часа ночи с осознанием, что все данные потеряны, настроить резервное копирование с помощью Velero — это обязательный шаг.
mongodump --db mydatabase --out /path/to/backup
Создаем бэкап:
kubectl create configmap mongo-dump --from-file=/path/to/backup
Восстановливаем:
velero restore create --from-backup my-backup
Можно создать CronJob для регулярного создания бэкапов.
cronjob-velero-backup.yaml:
apiVersion: batch/v1
kind: CronJob
metadata:
name: velero-backup
spec:
# Расписание: бэкап будет запускаться каждый день в 2 часа ночи
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: velero
image: velero/velero:v1.6.0 # Образ Velero для выполнения бэкапа
command:
# Команда для создания ежедневного бэкапа
- /velero
- backup
- create
- daily-backup
- --include-namespaces=default
restartPolicy: OnFailure # Перезапуск только при неудачах
kubectl apply -f job-mongo-restore.yaml
Теперь бэкапы будут создаваться автоматически.
Прежде чем мигрировать большие базы, попробуйте на маленьких. Это поможет выявить проблемы заранее.
Можно интегрировать процесс миграции в конвейеры CI/CD. Автоматизация приводит к снижению вероятности ошибок.
Ведите подробную документацию.
Больше актуальных навыков по IT-инфраструктуре вы можете получить в рамках практических онлайн-курсов от экспертов отрасли.
Также приглашаем на открытый урок 6 ноября. На уроке рассмотрим популярные инструменты для сбора логов, такие как Vector, Fluentbit и Promtail. Узнаем, в чём их преимущества, как они работают и где лучше применять. Подробно разберём, какой функционал предлагают эти решения для управления логами. Записаться на урок
BlindB
Очень странная инструкция.
Дамп в configmap? Возможно автор никогда не делал подобного или никогда не сталкивался с кубером.
Ограничение configmap по размеру в 1мб со стороны etcd, ибо объект будет создаваться в виде записи в этой бд. И сама идея хранить одну бд внутри другой - это что то с чем то.
job по восстановлению дампа без привязки к реальному месту хранения данных?
Оно восстановит, но себе под ноги и на время жизни пода.
Т.е. статья - образец как делать не надо.