RabbitMQ é un corredor de mensaxes escrito en Erlang que che permite organizar un clúster de conmutación por fallo con replicación completa de datos en varios nodos, onde cada nodo pode atender solicitudes de lectura e escritura. Tendo moitos clústeres de Kubernetes en operación de produción, admitimos un gran número de instalacións de RabbitMQ e enfrontámonos á necesidade de migrar os datos dun clúster a outro sen tempo de inactividade.
Precisamos esta operación en polo menos dous casos:
Transferir datos dun clúster RabbitMQ que non se atopa en Kubernetes a un clúster novo, xa "kubernetizado" (é dicir, que funciona en pods K8s).
Migración de RabbitMQ dentro de Kubernetes dun espazo de nomes a outro (por exemplo, se os circuítos están delimitados por espazos de nomes, para transferir infraestrutura dun circuíto a outro).
A receita que se propón no artigo céntrase en situacións (pero non se limita en absoluto a elas) nas que existe un clúster RabbitMQ antigo (por exemplo, de 3 nodos), situado xa en K8 ou nalgúns servidores antigos. Unha aplicación aloxada en Kubernetes (xa alí ou no futuro) funciona con ela:
... e estamos ante a tarefa de migralo á nova produción en Kubernetes.
En primeiro lugar, describirase o enfoque xeral da propia migración, e despois describiranse os detalles técnicos da súa implementación.
Algoritmo de migración
A primeira etapa, preliminar, antes de calquera acción é comprobar que o modo de alta dispoñibilidade está activado na antiga instalación de RabbitMQ (HA). O motivo é obvio: non queremos perder ningún dato. Para realizar esta comprobación, pode ir ao panel de administración de RabbitMQ e na pestana Administrador → Políticas asegúrese de que o valor estea definido ha-mode: all:
O seguinte paso é crear un novo clúster RabbitMQ en pods de Kubernetes (no noso caso, por exemplo, composto por 3 nodos, pero o seu número pode ser diferente).
Despois disto, fusionamos os clústeres antigos e novos de RabbitMQ, obtendo un único clúster (de 6 nodos):
Iníciase o proceso de sincronización de datos entre os clústeres RabbitMQ antigos e novos. Unha vez que todos os datos estean sincronizados entre todos os nodos do clúster, podemos cambiar a aplicación para usar o novo clúster:
Despois destas operacións, abonda con eliminar os nodos antigos do clúster RabbitMQ e o movemento pódese considerar completo:
Utilizamos este esquema moitas veces na produción. Non obstante, para a nosa propia comodidade, implementámolo nun sistema especializado que distribúe configuracións estándar de RMQ en varios clústeres de Kubernetes. (para os que teñan curiosidade: estamos a falar de operador-complementosobre o que nós dito recentemente). A continuación presentaremos instrucións individuais que calquera pode aplicar nas súas instalacións para probar a solución proposta en acción.
Probémolo na práctica
Requisitos
Os detalles son moi sinxelos:
Clúster de Kubernetes (tamén funcionará minikube);
Clúster RabbitMQ (pódese despregar en bare metal e facerse como un clúster normal en Kubernetes a partir do gráfico oficial de Helm).
Para o exemplo seguinte, despreguei RMQ en Kubernetes e chamei rmq-old.
Preparación do stand
1. Descarga o gráfico Helm e edítao un pouco:
helm fetch --untar stable/rabbitmq-ha
Para comodidade, establecemos un contrasinal, ErlangCookie e facer política ha-allde xeito que, por defecto, as colas están sincronizadas entre todos os nodos do clúster RMQ:
3. Vaia ao panel de administración de RabbitMQ, cree unha nova cola e engada varias mensaxes. Serán necesarios para que despois da migración poidamos asegurarnos de que se conservan todos os datos e non perdemos nada:
O banco de probas está listo: temos o RabbitMQ "antigo" con datos que hai que transferir.
Migrando un clúster RabbitMQ
1. Primeiro, imos implementar o novo RabbitMQ en amigo espazo de nomes con mesmoErlangCookie e contrasinal para o usuario. Para iso, realizaremos as operacións descritas anteriormente, cambiando o comando final para instalar RMQ ao seguinte:
helm install . --name rmq-new --namespace rmq-new
2. Agora cómpre combinar o novo clúster co antigo. Para iso, vai a cada unha das vainas novo RabbitMQ e executa os comandos:
Nunha variable OLD_RMQ atópase o enderezo dun dos nodos vello clúster RMQ.
Estes comandos deterán o nodo actual novo Clúster RMQ, axúdao ao clúster antigo e lánzao de novo.
3. O clúster RMQ de 6 nodos está listo:
Debe agardar mentres se sincronicen as mensaxes entre todos os nodos. Non é difícil adiviñar que o tempo de sincronización das mensaxes depende da capacidade do hardware no que se desprega o clúster e do número de mensaxes. No escenario descrito, só hai 10 deles, polo que os datos sincronizáronse ao instante, pero cun número suficientemente grande de mensaxes, a sincronización pode durar horas.
Entón, o estado de sincronización:
Aquí +5 significa que as mensaxes xa están máis en 5 nodos (agás o que se indica no campo Node). Así, a sincronización foi exitosa.
4. Só queda cambiar o enderezo RMQ da aplicación ao novo clúster (as accións específicas aquí dependen da pila de tecnoloxía que estea a usar e doutras características específicas da aplicación), despois de que pode despedirse da antiga.
Para a última operación (é dicir, xa despois cambiando a aplicación a un novo clúster) vaia a cada nodo vello cluster e executa os comandos:
rabbitmqctl stop_app
rabbitmqctl reset
O clúster "esqueceuse" dos nodos antigos: podes eliminar o antigo RMQ, momento no que completarase o movemento.
Nota: Se usa RMQ con certificados, nada cambia fundamentalmente: o proceso de mudanza realizarase exactamente igual.
Descubrimentos
O esquema descrito é axeitado para case todos os casos nos que necesitamos migrar RabbitMQ ou simplemente pasar a un novo clúster.
No noso caso, as dificultades xurdiron só unha vez, cando se accedeu a RMQ desde moitos lugares, e non tivemos a oportunidade de cambiar o enderezo de RMQ por un novo en todas partes. A continuación, lanzamos un novo RMQ no mesmo espazo de nomes coas mesmas etiquetas para que entrase dentro dos servizos e entradas existentes, e ao lanzar o pod manipulamos as etiquetas a man, eliminándoas ao principio para que as solicitudes non recaesen no RMQ baleiro e engadíndoos de novo despois de sincronizar as mensaxes.
Usamos a mesma estratexia ao actualizar RabbitMQ a unha nova versión cunha configuración modificada: todo funcionaba como un reloxo.
PS
Como continuación lóxica deste material, estamos a preparar artigos sobre MongoDB (migración dun servidor de hardware a Kubernetes) e MySQL (como preparamos este DBMS dentro de Kubernetes). Publicaranse nos próximos meses.