
Тази статия продължава нашата за миграцията на RabbitMQ и е посветена на MongoDB. Тъй като обслужваме множество клъстери Kubernetes и MongoDB, се появява естествена необходимост да мигрираме данни от една инсталация в друга и да го правим без престой. Основните сценарии остават същите: прехвърляне на MongoDB от виртуален/железен сървър в Kubernetes или прехвърляне на MongoDB в рамките на един клъстер Kubernetes (от едно пространство на имена в друго).
Нашата рецепта е предназначена за случаи, в които функционира стар клъстер MongoDB (например, от 3 възела и който е вече в K8s или на стари сървъри), с който работи приложение, разположено в Kubernetes:

Как ще прехвърлим такъв клъстер в новия продукционен в Kubernetes?
Теория
Общият алгоритъм за миграция е подобен на описания в ситуацията с RabbitMQ.
Важно е да се отбележи, че за да се извърши прехвърлянето, е необходимо сървърите с MongoDB и Kubernetes да бъдат в една и съща мрежа. Възлите на клъстера MongoDB ще комуникират помежду си по IP адресите на старите сървъри (където се намират старите инсталации на MongoDB) и по DNS имената на pod-овете с MongoDB в K8s. Затова на железните сървъри (с старите инсталации) е необходимо да се пробият маршрути до pod-овете, а след това да се конфигурират да използват DNS сървъра, работещ в Kubernetes (или да се запишат нужните имена в /etc/hosts, въпреки че в общия случай е по-добре да се избягва такава възможност).
Следващата стъпка е да се стартира клъстера MongoDB в pod-овете на Kubernetes. В нашия случай клъстера БД се състои от 3 възела и всеки възел се намира в отделен pod на K8s — въпреки че тяхното число може да бъде различно. В ConfigMap-a трябва да се посочи адреса на мастера MongoDB от старата инсталация: тогава възлите MongoDB, разположени в pod-овете в K8s, веднага ще започнат синхронизация с него.
След като всички pod-ове стартират, ще се образува клъстер MongoDB от 6 възела:

Обърнете внимание, че pod-овете ще се стартират дълго, тъй като всеки pod започва последователно, а в момента на стартиране синхронизира данните с мастера.
След това може да се прехвърли приложението да използва новите сървъри MongoDB:

И остава само да се премахнат старите възли от клъстера MongoDB, след което прехвърлянето може да се счита за завършено:

Тази схема често я прилагаме в продукция и за удобство на използването й я реализирахме в рамките на модула на (този инструмент ние ), което позволява разпространение на типови конфигурации MongoDB през множество клъстери. Публикацията на нашите модули планираме да извършим в близко бъдеще, а засега представяме отделни инструкции, с които можете да опитате предложеното решение в действие и без използване на addon-operator.
Изпробваме на практика
Изисквания
Реквизити:
- Клъстер Kubernetes (подходящ е и minikube);
- Клъстер MongoDB (може да бъде разположен както на bare metal, така и като обикновен клъстер в Kubernetes от официалния Helm-чарт).
В описания по-долу пример старият клъстер с MongoDB ще бъде наречен mongo-old и ще бъде инсталиран в същия клъстер Kubernetes, където по-късно ще инсталираме и новия (mongo-new).
Подготвяме стария клъстер
1. За примера, демонстриращ описаната схема в действие, ще създадем „стар“ (т.е. подлежащ на миграция) клъстер MongoDB направо в Kubernetes (в действителност той може да се намира и на отделни сървъри извън K8s). За целта ще изтеглим Helm-чарта:
helm fetch --untar stable/mongodb-replicaset… и малко ще го редактираме, настройвайки авторизацията:
auth:
enabled: true
adminUser: mongo
adminPassword: pa33w0rd
# metricsUser: metrics
# metricsPassword: password
# key: keycontent
# existingKeySecret:
# existingAdminSecret:
# exisitingMetricsSecret: Също така в values.yaml може да се настроят сертификати и много друго.
2. Ще инсталираме чарт:
helm install . --name mongo-old --namespace mongo-oldСлед това ще бъде стартирана тестова „стара“ инсталация на MongoDB:
kubectl --namespace=mongo-old get pods 
Ще влезем в pod с нейния мастер и ще създадем тестова база:
kubectl --namespace=mongo-old exec -ti mongo-old-mongodb-replicaset-0 mongo
use admin
db.auth('mongo','password')
use music
db.artists.insert({ artistname: "The Tea Party" })
show dbs 
При влизане в различни pod'ове, установих, че мастерът е mongo-old-mongodb-replicaset-0. Въпреки това, за по-удобно решение на този въпрос след инсталиране на Helm-чарта се извежда команда, как да се определи MASTER_POD. В моя случай (за mongo-old от 3 възли) тя изглежда така:
for ((i = 0; i < 3; ++i)); do kubectl exec --namespace mongo-old mongo-old-mongodb-replicaset-$i -- sh -c 'mongo --eval="printjson(rs.isMaster())"'; doneС това подготовката на старата инсталация на MongoDB, чиито данни ще бъдат пренесени, е готова.
Миграция на клъстера MongoDB
Сега ще развием нова инсталация на MongoDB, която ще бъде в Kubernetes и ще се използва от приложението в production.
NB: Обърнете внимание, че трябва да се използва същата версия на MongoDB, каквато е била преди. В противен случай съществува риск от проблеми с несъвместимост.
По аналогия с предишния раздел (където симулирахме „старата“ инсталация на MongoDB), ще вземем вече споменатия Helm-чарт (с командата helm fetch) и ще настроим авторизация, както и други параметри, ако се използват. Освен това ще поправим файла init/on-start.sh, временно добавяйки на 165 ред адреса на майстора, получен на предишния етап (или познат ви от инсталацията на MongoDB на отделни сървъри):
peers='mongo-old-mongodb-replicaset-0.mongo-old-mongodb-replicaset.mongo-old.svc.cluster.local:27017'Подготвени сме за създаване на нова инсталация на MongoDB:
helm install . --name mongo-new --namespace mongo-newИзчакваме да стартират всички pod’ове (ако данните са много, стартирането им може да отнеме часове):

Сега правим exec в новия pod и гледаме списъка на базите:
kubectl --namespace=mongo-new exec -ti mongo-new-mongodb-replicaset-0 mongo 
Два клъстера MongoDB са обединени в един, състоящ се от 6 възела.
В момента вече можем да превключим приложението на новия клъстер, но за завършване на миграцията остават още няколко стъпки.
От файла init/on-start.sh в новата инсталация премахваме добавения от нас ред:
peers='mongo-old-mongodb-replicaset-0.mongo-old-mongodb-replicaset.mongo-old.svc.cluster.local:27017'Сега да отидем при стария майстор на клъстера и да го „свалим“ — тогава в клъстера ще бъде назначен нов майстор. Влизаме в pod с майстора на MongoDB:
kubectl --namespace=mongo-old exec -ti mongo-old-mongodb-replicaset-0 mongo
use admin
db.auth('mongo','password')След това променяме приоритетите на възлите и сменяме майстора:
cfg = rs.conf()
cfg.members[5].priority = 2
rs.reconfig(cfg)
rs.stepDown(120)Текущият възел спря да бъде майстор — ще се проведат избори за нов. Тъй като променихме приоритетите, майстор ще стане желаният от нас възел.
NB: По подразбиране на всички възли на MongoDB приоритетът е равен на 1. По-горе увеличаваме приоритета на желания от нас възел до 2. Така, общият майстор определено става член на новия клъстер. Повече за това как функционират тези механизми в MongoDB, можете да прочетете в .
Ще изключим старата инсталация на MongoDB, след което ще влезем в майстора на новия и ще изтрием старите възли:
rs.remove("mongo-old-mongodb-replicaset-0.mongo-old-mongodb-replicaset.mongo-old.svc.cluster.local:27017")
rs.remove("mongo-old-mongodb-replicaset-1.mongo-old-mongodb-replicaset.mongo-old.svc.cluster.local:27017")
rs.remove("mongo-old-mongodb-replicaset-2.mongo-old-mongodb-replicaset.mongo-old.svc.cluster.local:27017")След това миграцията може да се счита за завършена: успешно преминахме от стария клъстер MongoDB на новия!
Итог
Описаната схема е подходяща практически за всички случаи, когато трябва да преместите MongoDB или просто да се преместите в нов клъстер.
Може би, основният нюанс при преноса е необходимостта от пробиване на IP-адресите на новите pod’ове в сървърите на старата инсталация на MongoDB, ако тя е извън K8s, и правилната им именуване в DNS (или /etc/hosts). В примера тези стъпки не бяха необходими, тъй като миграцията протичаше между различни пространства на имената в един и същ Kubernetes клъстер.
P.S.
Прочетете също в нашия блог:
- «»;
- «»;
- «».
Източник: habr.com
