RabbitMQ – напісаны на мове Erlang брокер паведамленняў, які дазваляе арганізаваць адмоваўстойлівасць кластар з поўнай рэплікацыяй дадзеных на некалькі вузлоў, дзе кожны вузел можа абслугоўваць запыты на чытанне і запіс. Маючы ў production-эксплуатацыі мноства кластараў Kubernetes, мы падтрымліваем вялікую колькасць усталёвак RabbitMQ і сутыкнуліся з неабходнасцю міграцыі дадзеных з аднаго кластара ў іншы без прастою.
Дадзеная аперацыя была неабходна нам як мінімум у двух выпадках:
Перанос дадзеных з кластара RabbitMQ, які знаходзіцца не ў Kubernetes, у новы – ужо «кубернетэзаваны» (г.зн. які функцыянуе ў pod'ах K8s) – кластар.
Міграцыя RabbitMQ у рамках Kubernetes з аднаго namespace ў іншы (напрыклад, калі контуры размежаваны прасторамі імёнаў, то для пераносу інфраструктуры з аднаго контуру ў іншы).
Прапанаваны ў артыкуле рэцэпт арыентаваны на сітуацыі (але зусім не абмежаваны імі), у якіх ёсць стары кластар RabbitMQ (напрыклад, з 3 вузлоў), які знаходзіцца альбо ўжо ў K8s, альбо на нейкіх старых серверах. З ім працуе дадатак, размешчанае ў Kubernetes (ужо там ці ў перспектыве):
… і перад намі стаіць задача яго міграцыі ў новы production у Kubernetes.
Спачатку будзе апісаны агульны падыход да самой міграцыі, а ўжо пасля гэтага - тэхнічныя дэталі па яе рэалізацыі.
Алгарытм міграцыі
Першы, папярэдні, этап перад якімі-небудзь дзеяннямі – праверка, што ў старой усталёўцы RabbitMQ уключаны рэжым высокай даступнасці (HA). Прычына відавочная - мы ж не хочам страціць якіх-небудзь дадзеных. Каб ажыццявіць гэтую праверку, можна зайсці ў адмінку RabbitMQ і ва ўкладцы Admin → Policies пераканацца, што ўсталявана значэнне ha-mode: all:
Наступны крок - паднімаем новы кластар RabbitMQ у pod'ах Kubernetes (у нашым выпадку, напрыклад, які складаецца з 3 вузлоў, але іх лік можа быць і іншым).
Пасля гэтага мы аб'ядноўваем стары і новы кластары RabbitMQ, атрымліваючы адзіны кластар (з 6 вузлоў):
Ініцыюецца працэс сінхранізацыі дадзеных паміж старым і новым кластарамі RabbitMQ. Пасля таго, як усе дадзеныя сінхранізуюцца паміж усімі вузламі ў кластары, мы можам пераключыць дадатак на выкарыстанне новага кластара:
Пасля гэтых аперацый дастаткова вывесці з кластара RabbitMQ старыя вузлы, і пераезд можна лічыць завершаным:
Гэтую схему мы неаднаразова ўжывалі ў нас у production. Аднак для ўласнай выгоды рэалізавалі яе ў рамках спецыялізаванай сістэмы, якая распаўсюджвае тыпавыя канфігурацыі RMQ на мноствах кластараў Kubernetes. (для тых, каму цікава: гаворка ідзе пра addon-operator, пра які мы зусім нядаўна расказвалі). Ніжэй будуць прадстаўлены асобна ўзятыя інструкцыі, якія кожны можа прымяніць на сваіх усталёўках, каб паспрабаваць прапанаванае рашэнне ў дзеянні.
Спрабуем на практыцы
Патрабаванні
Рэквізіты вельмі простыя:
кластар Kubernetes (падыдзе і minikube);
Кластар RabbitMQ (можа быць і разгорнуты на bare metal, і зроблены як звычайны кластар у Kubernetes з афіцыйнага Helm-чарта).
Для апісанага ніжэй прыкладу я разгарнуў RMQ у Kubernetes і назваў яго rmq-old.
Падрыхтоўка стэнда
1. Спампуем Helm-чарт і крыху адрэдагуем яго:
helm fetch --untar stable/rabbitmq-ha
Для зручнасці задаём пароль, ErlangCookie і робім палітыку ha-all, каб па змаўчанні чэргі сінхранізаваліся паміж усімі вузламі кластара RMQ:
3. Заходзім у адмінку RabbitMQ, ствараем новую чаргу і дадаем некалькі паведамленняў. Яны спатрэбяцца для таго, каб пасля міграцыі мы маглі пераканацца, што ўсе даныя захаваліся і мы нічога не страцілі:
Тэставы стэнд гатовы: у нас ёсць "стары" RabbitMQ з дадзенымі, якія трэба перанесці.
Міграцыя кластара RabbitMQ
1. Для пачатку разгорнем новы RabbitMQ у сябрам прасторы імён з такімі жErlangCookie і паролем для карыстальніка. Для гэтага праробім апісаныя вышэй аперацыі, змяніўшы канчатковую каманду па ўсталёўцы RMQ на наступную:
helm install . --name rmq-new --namespace rmq-new
2. Цяпер патрабуецца аб'яднаць новы кластар са старым. Для гэтага заходзім у кожны з pod'аў новага RabbitMQ і выконваем каманды:
У зменнай OLD_RMQ знаходзіцца адрас аднаго з вузлоў старога кластара RMQ.
Гэтыя каманды спыняць бягучы вузел. новага кластара RMQ, далучаць яго да старога кластара і зноў запусцяць.
3. Кластар RMQ з 6 вузлоў гатовы:
Неабходна пачакаць, пакуль паведамленні сінхранізуюцца паміж усімі вузламі. Няцяжка здагадацца, што час сінхранізацыі паведамленняў залежыць ад магутнасцяў жалеза, на якім разгорнуты кластар, і ад колькасці паведамленняў. У апісваным сцэнары іх усяго 10, таму дадзеныя сінхранізаваліся маментальна, але пры досыць вялікай колькасці паведамленняў сінхранізацыя можа доўжыцца гадзінамі.
Такім чынам, статут сінхранізацыі:
Тут +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). Яны будуць апублікаваны ў бліжэйшыя месяцы.