Привет, Хабр!

Сегодня у нас на повестке дня тема миграции данных в 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. Узнаем, в чём их преимущества, как они работают и где лучше применять. Подробно разберём, какой функционал предлагают эти решения для управления логами. Записаться на урок

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


  1. BlindB
    01.11.2024 13:26

    Очень странная инструкция.

    Дамп в configmap? Возможно автор никогда не делал подобного или никогда не сталкивался с кубером.

    Ограничение configmap по размеру в 1мб со стороны etcd, ибо объект будет создаваться в виде записи в этой бд. И сама идея хранить одну бд внутри другой - это что то с чем то.

    job по восстановлению дампа без привязки к реальному месту хранения данных?

    Оно восстановит, но себе под ноги и на время жизни пода.

    Т.е. статья - образец как делать не надо.