Безпроста міграція RabbitMQ у Kubernetes

Безпроста міграція RabbitMQ у Kubernetes

RabbitMQ – написаний мовою Erlang брокер повідомлень, що дозволяє організувати стійкий до відмови кластер з повною реплікацією даних на кілька вузлів, де кожен вузол може обслуговувати запити на читання та запис. Маючи в production-експлуатації безліч кластерів Kubernetes, ми підтримуємо велику кількість інсталяцій RabbitMQ і зіткнулися з необхідністю міграції даних з одного кластера до іншого без простою.

Ця операція була необхідна нам як мінімум у двох випадках:

  1. Перенесення даних із кластера RabbitMQ, що знаходиться не в Kubernetes, у новий — вже «кубернетезований» (тобто функціонує в pod'ах K8s) — кластер.
  2. Міграція RabbitMQ в рамках Kubernetes з одного namespace до іншого (наприклад, якщо контури розмежовані просторами імен, то для перенесення інфраструктури з одного контуру до іншого).

Пропонований у статті рецепт орієнтований на ситуації (але зовсім не обмежений ними), в яких є старий кластер RabbitMQ (наприклад, з 3 вузлів), що знаходиться або вже в K8s, або на старих серверах. З ним працює додаток, розміщений у Kubernetes (вже там чи в перспективі):

Безпроста міграція RabbitMQ у Kubernetes

… і перед нами стоїть завдання його міграції у новий production у Kubernetes.

Спочатку буде описано загальний підхід до самої міграції, а вже після цього – технічні деталі щодо її реалізації.

Алгоритм міграції

Перший, попередній етап перед будь-якими діями - перевірка, що в старій інсталяції RabbitMQ включений режим високої доступності (HA). Причина очевидна — адже ми не хочемо втратити жодних даних. Щоб здійснити цю перевірку, можна зайти в адмінку RabbitMQ і у вкладці Admin → Policies переконатися, що встановлено значення ha-mode: all:

Безпроста міграція RabbitMQ у Kubernetes

Наступний крок - піднімаємо новий кластер RabbitMQ в pod'ах Kubernetes (у нашому випадку, наприклад, що складається з 3 вузлів, але їх число може бути й іншим).

Після цього ми об'єднуємо старий та новий кластери RabbitMQ, отримуючи єдиний кластер (з 6 вузлів):

Безпроста міграція RabbitMQ у Kubernetes

Ініціюється процес синхронізації даних між старим та новим кластерами RabbitMQ. Після того, як всі дані синхронізуються між усіма вузлами в кластері, ми можемо переключити програму на використання нового кластера:

Безпроста міграція RabbitMQ у Kubernetes

Після цих операцій достатньо вивести з кластера RabbitMQ старі вузли, і переїзд можна вважати завершеним:

Безпроста міграція RabbitMQ у Kubernetes

Цю схему ми неодноразово застосовували у нас у production. Однак для власної зручності реалізували її в рамках спеціалізованої системи, що розповсюджує типові конфігурації RMQ на множинах кластерів Kubernetes (Для тих, кому цікаво: мова йде про addon-operator, Про який ми зовсім недавно розповідали). Нижче будуть представлені окремі інструкції, які кожен може застосувати на своїх інсталяціях, щоб спробувати пропоноване рішення в дії.

Пробуємо на практиці

Вимоги

Реквізити дуже прості:

  1. кластер Kubernetes (підійде і minikube);
  2. Кластер RabbitMQ (можливо і розгорнутий на bare metal, та зроблений як звичайний кластер у Kubernetes з офіційного Helm-Чарту).

Для описаного нижче прикладу я розгорнув RMQ у Kubernetes і назвав його rmq-old.

Підготовка стенду

1. Скачаємо Helm-чарт і трохи відредагуємо його:

helm fetch --untar stable/rabbitmq-ha

Для зручності задаємо пароль, ErlangCookie і робимо політику ha-all, щоб за промовчанням черги синхронізувалися між усіма вузлами кластера RMQ:

rabbitmqPassword: guest
rabbitmqErlangCookie: mae9joopaol7aiVu3eechei2waiGa2we
definitions:
policies: |-
  {
    "name": "ha-all",
    "pattern": ".*",
    "vhost": "/",
    "definition": {
      "ha-mode": "all",
      "ha-sync-mode": "automatic",
      "ha-sync-batch-size": 81920
    }
  }

2. Встановлюємо чарт:

helm install . --name rmq-old --namespace rmq-old

3. Заходимо до адмінки RabbitMQ, створюємо нову чергу і додаємо кілька повідомлень. Вони знадобляться для того, щоб після міграції ми могли переконатися, що всі дані збереглися і нічого не втратили.

Безпроста міграція RabbitMQ у Kubernetes

Тестовий стенд готовий: у нас є «старий» RabbitMQ із даними, які потрібно перенести.

Міграція кластера RabbitMQ

1. Для початку розгорнемо новий RabbitMQ в другом просторі імен з такими ж ErlangCookie та паролем для користувача. Для цього проробимо описані вище операції, змінивши кінцеву команду встановлення RMQ на наступну:

helm install . --name rmq-new --namespace rmq-new

2. Тепер потрібно поєднати новий кластер зі старим. Для цього заходимо до кожного з pod'ів нового RabbitMQ і виконуємо команди:

export OLD_RMQ=rabbit@rmq-old-rabbitmq-ha-0.rmq-old-rabbitmq-ha-discovery.rmq-old.svc.cluster.local && 
  rabbitmqctl stop_app && 
  rabbitmqctl join_cluster $OLD_RMQ && 
  rabbitmqctl start_app

У змінній OLD_RMQ знаходиться адреса одного з вузлів старого кластеру RMQ.

Ці команди зупинять поточний вузол нового кластера RMQ, приєднають його до старого кластера і знову запустять.

3. Кластер RMQ із 6 вузлів готовий:

Безпроста міграція RabbitMQ у Kubernetes

Потрібно почекати, доки повідомлення синхронізуються між усіма вузлами. Неважко здогадатися, що час синхронізації повідомлень залежить від потужностей заліза, на якому розгорнуть кластер, та від кількості повідомлень. В описуваному сценарії їх всього 10, тому дані синхронізувалися миттєво, але при досить велику кількість повідомлень синхронізація може тривати годинами.

Отже, статус синхронізації:

Безпроста міграція RabbitMQ у Kubernetes

Тут +5 означає, що повідомлення вже знаходяться ще на 5 вузлах (крім того, що вказано у полі Node). Отже, синхронізація пройшла успішно.

4. Залишається лише переключити в додатку адресу RMQ на новий кластер (конкретні дії тут залежать від використовуваного вами технологічного стека та іншої специфіки програми), після чого можна попрощатися зі старим.

Для останньої операції (тобто вже після перемикання програми на новий кластер) заходимо на кожен вузол старого кластера та виконуємо команди:

rabbitmqctl stop_app
rabbitmqctl reset

Кластер "забув" про старі вузли: можна видаляти старий RMQ, на чому переїзд буде закінчено.

Примітка: Якщо ви використовуєте RMQ з сертифікатами, то принципово нічого не змінюється - процес переїзду буде здійснюватися так само.

Висновки

Описана схема підходить практично для всіх випадків коли нам потрібно перенести RabbitMQ або просто переїхати в новий кластер.

У нашому випадку складнощі виникали лише один раз, коли до RMQ зверталися з багатьох місць, а у нас не було можливості всюди поміняти адресу RMQ на нову. Тоді ми запускали новий RMQ у тому ж просторі імен з однаковими лейблами, щоб він потрапляв під вже існуючі сервіси та Ingress'и, а при запуску pod'а руками маніпулювали лейблами, видаляючи їх на початку, щоб на порожній RMQ не потрапляли запити, та додаючи їх назад після синхронізації повідомлень.

Таку ж стратегію ми застосовували при оновленні RabbitMQ на нову версію зі зміненою конфігурацією – все працювало як годинник.

PS

Як логічне продовження цього матеріалу ми готуємо статті про MongoDB (міграція із залізного сервера в Kubernetes) та MySQL (як ми готуємо цю СУБД усередині Kubernetes). Вони будуть опубліковані найближчими місяцями.

PPS

Читайте також у нашому блозі:

Джерело: habr.com

Додати коментар або відгук