
RabbitMQ – to napisany w języku Erlang broker wiadomości, który pozwala na zorganizowanie odpornego na awarie klastra z pełną replikacją danych na wielu węzłach, gdzie każdy węzeł może obsługiwać zapytania do odczytu i zapisu. Posiadając wiele klastrów Kubernetes w produkcji, wspieramy dużą liczbę instalacji RabbitMQ i stanęliśmy przed koniecznością migracji danych z jednego klastra do drugiego bez przestojów.
Operacja ta była nam konieczna przynajmniej w dwóch przypadkach:
- Przeniesienie danych z klastra RabbitMQ, który nie działa w Kubernetes, do nowego — już „skonfigurowanego pod K8s” (tj. funkcjonującego w podach K8s) — klastra.
- Migracja RabbitMQ w ramach Kubernetes z jednego namespace do drugiego (na przykład, jeśli obszary są rozgraniczone przez przestrzenie nazw, to w celu przeniesienia infrastruktury z jednego obszaru do innego).
Proponowany w artykule przepis jest skierowany na sytuacje (ale wcale ich nie ogranicza), w których istnieje stary klaster RabbitMQ (na przykład składający się z 3 węzłów), który znajduje się albo już w K8s, albo na jakichś starych serwerach. Z nim współpracuje aplikacja, umieszczona w Kubernetes (już tam lub w perspektywie):

… i przed nami stoi zadanie migracji do nowej produkcji w Kubernetes.
Na początku zostanie opisane ogólne podejście do samej migracji, a dopiero później — szczegóły techniczne dotyczące jej realizacji.
Algorytm migracji
Pierwszy, wstępny etap przed jakimikolwiek działaniami — sprawdzenie, czy w starej instalacji RabbitMQ włączony jest tryb wysokiej dostępności (). Powód jest oczywisty — nie chcemy przecież stracić żadnych danych. Aby to sprawdzić, można wejść do panelu administracyjnego RabbitMQ i w zakładce Admin → Policies upewnić się, że ustawiona jest wartość ha-mode: all:

Następny krok — uruchamiamy nowy klaster RabbitMQ w podach Kubernetes (w naszym przypadku, na przykład, składający się z 3 węzłów, ale ich liczba może być inna).
Po tym łączymy stary i nowy klaster RabbitMQ, uzyskując jeden wspólny klaster (z 6 węzłów):

Inicjowany jest proces synchronizacji danych między starym a nowym klastrem RabbitMQ. Po tym, jak wszystkie dane zostaną zsynchronizowane między wszystkimi węzłami w klastrze, możemy przełączyć aplikację na korzystanie z nowego klastra:

Po tych operacjach wystarczy wyłączyć stare węzły z klastra RabbitMQ, a migrację można uznać za zakończoną:

Ten schemat wielokrotnie stosowaliśmy w naszej produkcji. Jednak dla własnej wygody zaimplementowaliśmy go w ramach wyspecjalizowanego systemu, który rozprowadza typowe konfiguracje RMQ na wielu klastrach Kubernetes. (dla ciekawskich: mowa o , o którym niedawno opowiadaliśmy. )Sprawdzamy w praktyce
Rekwizyty są bardzo proste:
Wymagania
Klaster Kubernetes (może być także minikube);
- Klaster RabbitMQ (może być zainstalowany na bare metal lub stworzony jako zwykły klaster w Kubernetes za pomocą oficjalnego Helm-chart).
- Dla opisanego poniżej przykładu założyłem RMQ w Kubernetes i nazwałem go
rmq-old Przygotowanie stanowiska.
1. Pobieramy Helm-chart i nieco go edytujemy:
helm fetch --untar stable/rabbitmq-ha
Dla wygody ustawiamy hasło, ErlangCookie i tworzymy politykę ha-all , aby domyślnie kolejki synchronizowały się między wszystkimi węzłami klastra 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. Instalujemy chart:helm install . --name rmq-old --namespace rmq-old
3. Wchodzimy do panelu administracyjnego RabbitMQ, tworzymy nową kolejkę i dodajemy kilka wiadomości. Będą one potrzebne, aby po migracji upewnić się, że wszystkie dane zostały zachowane i nic nie zostało utracone:Testowe stanowisko gotowe: mamy „stary” RabbitMQ z danymi, które należy przenieść.
![]()
Migracja klastra RabbitMQ
1. Na początek uruchomimy nowy RabbitMQ w
innym przestrzeni nazw z takim samym i hasłem dla użytkownika. W tym celu wykonamy opisane powyżej operacje, zmieniając końcową komendę do instalacji RMQ na następującą: i tworzymy politykę helm install . --name rmq-new --namespace rmq-new
2. Teraz musimy połączyć nowy klaster ze starym. W tym celu wchodzimy do każdego z podównowego RabbitMQ i wykonujemy polecenia: 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 W zmiennej to adres jednego z węzłów starego klastra RMQ. Te polecenia zatrzymają bieżący węzeł
klastra RMQ, dołączą go do starego klastra i ponownie uruchomią. RabbitMQ i wykonujemy polecenia: 3. Klaster RMQ z 6 węzłami gotowy:
3. Klaster RMQ z 6 węzłami gotowy:

Musisz poczekać, aż wiadomości zsynchronizują się między wszystkimi węzłami. Nie trudno się domyślić, że czas synchronizacji wiadomości zależy od mocy sprzętu, na którym uruchomiony jest klaster, oraz od liczby wiadomości. W opisanym scenariuszu jest ich zaledwie 10, więc dane zsynchronizowały się natychmiast, ale przy wystarczająco dużej liczbie wiadomości synchronizacja może trwać godzinami.
Status synchronizacji:

Tutaj +5 oznacza, że wiadomości są już jeszcze na 5 węzłach (oprócz tego, który jest wskazany w polu Węzeł). W ten sposób synchronizacja przebiegła pomyślnie.
4. Pozostaje tylko przełączyć w aplikacji adres RMQ na nowy klaster (konkretne działania tutaj zależą od używanego przez Ciebie stosu technologicznego i innych specyfik aplikacji), po czym można pożegnać się ze starą wersją.
Aby wykonać ostatnią operację (tj. już po przełączenia aplikacji na nowy klaster), wchodzimy na każdy węzeł klastra RMQ. klastra i wykonujemy polecenia:
rabbitmqctl stop_app
rabbitmqctl resetKlaster „zapomniał” o starych węzłach: można usunąć stary RMQ, co zakończy migrację.
Uwaga: Jeśli używasz RMQ z certyfikatami, to zasadniczo nic się nie zmienia — proces migracji będzie przebiegał dokładnie tak samo.
Wnioski
Opisana schemat pasuje praktycznie do wszystkich przypadków, gdy musimy przenieść RabbitMQ lub po prostu przeprowadzić się do nowego klastra.
W naszym przypadku trudności wystąpiły tylko raz, gdy do RMQ zwracano się z wielu miejsc, a nie mieliśmy możliwości zmiany adresu RMQ wszędzie. Wtedy uruchomiliśmy nowy RMQ w tej samej przestrzeni nazw z identycznymi etykietami, aby pasował do już istniejących usług i Ingressów, a przy uruchamianiu pod'a ręcznie manipulowaliśmy etykietami, usuwając je na początku, aby żadne zapytania nie trafiały na pusty RMQ i dodając je z powrotem po synchronizacji wiadomości.
Tę samą strategię zastosowaliśmy podczas aktualizacji RabbitMQ do nowej wersji z zmienioną konfiguracją — wszystko działało jak w zegarku.
P.S.
Jako logiczne rozwinięcie tego materiału przygotowujemy artykuły na temat MongoDB (migracja z serwera fizycznego do Kubernetes) i MySQL (jak przygotowujemy tę bazę danych w Kubernetes). Zostaną one opublikowane w najbliższych miesiącach.
P.P.S.
Przeczytaj także na naszym blogu:
- «»;
- «».
Źródło: habr.com
