Enemigos de la realidad por 12f-2A finales de abril, mientras los caminantes blancos asediaban Invernalia, algo más interesante nos sucedió, hicimos un lanzamiento inusual. En principio, constantemente presentamos nuevas funciones en el producto (como todos los demás). Pero este no era como todos los demás. Su escala era tal que cualquier error potencial que pudiéramos cometer afectaría a todos nuestros servicios y usuarios. Como resultado, implementamos todo según el plan, en el tiempo de inactividad previsto y anunciado, sin consecuencias para la venta. El artículo trata sobre cómo logramos esto y cómo aquellos que lo deseen pueden repetir esto en casa.
Ahora no describiré nuestras decisiones arquitectónicas y técnicas, ni diré cómo funciona todo. Estas son notas bastante marginales sobre cómo tuvo lugar uno de los despliegues más difíciles, que observé y en el que participé directamente. No pretendo ser detalles completos o técnicos, tal vez aparecerán en otro artículo.
Fondo + qué tipo de funcionalidad es esta
Estamos construyendo la plataforma en la nube
Mail.ru Cloud Solutions (MCS), donde trabajo como CTO. Y ahora, es hora de conectarse a nuestra plataforma IAM (Identity and Access Management), que proporciona una gestión unificada de todas las cuentas de usuario, usuarios, contraseñas, roles, servicios y más. Por qué es necesario en la nube es una pregunta obvia: toda la información del usuario se almacena en ella.
Por lo general, tales cosas comienzan a desarrollarse desde el comienzo de cualquier proyecto. Pero MCS ha sido históricamente un poco diferente. MCS fue construido en dos partes:
- OpenStack con su propio módulo de autorización Keystone,
- Hotbox (almacenamiento S3) basado en el proyecto Cloud Mail.ru,
alrededor del cual aparecieron nuevos servicios.
En esencia, estos eran dos tipos diferentes de autorización. Además, utilizamos algunos desarrollos separados de Mail.ru, por ejemplo, el almacenamiento general de contraseñas de Mail.ru, así como un conector openid autoescrito, que habilitó SSO (autorización de transferencia) en el panel Horizon de máquinas virtuales (OpenItack UI nativo).
Hacer IAM significaba para nosotros combinar todo esto en un solo sistema, completamente nuestro. Al mismo tiempo, no pierda ninguna funcionalidad en el camino, cree una acumulación de trabajo para el futuro, lo que nos permitirá refinarlo de forma transparente sin refactorizarlo y escalarlo según la funcionalidad. También al principio, los usuarios aparecieron un modelo a seguir del acceso a los servicios (RBAC central, control de acceso basado en roles) y algunas otras pequeñas cosas.
La tarea resultó no ser trivial: python y perl, varios backends, servicios escritos de forma independiente, varios equipos de desarrollo y administradores. Y lo más importante, miles de usuarios en vivo en el sistema de producción de combate. Todo esto tenía que ser escrito y, lo más importante, desplegado sin bajas.
¿Qué vamos a desplegar?
Si es muy grosero, en algún lugar en 4 meses preparamos esto:
- Hicieron varios demonios nuevos que agregaron funciones que anteriormente funcionaban en diferentes partes de la infraestructura. A otros servicios se les prescribió un nuevo backend en forma de estos demonios.
- Escribimos nuestro propio repositorio central de contraseñas y claves, disponible para todos nuestros servicios, que puede modificarse libremente según lo necesitemos.
- Desde cero, escribieron 4 backends nuevos para Keystone (usuarios, proyectos, roles, asignaciones de roles), que, de hecho, reemplazaron su base y ahora actúan como un único depósito de nuestras contraseñas de usuario.
- Enseñamos a todos nuestros servicios de Openstack a ir por sus políticas a un servicio de políticas de terceros en lugar de leer estas políticas localmente desde cada servidor (¡sí, por defecto Openstack funciona así!)
Una alteración tan grande requiere cambios grandes, complejos y, lo más importante, sincrónicos en varios sistemas escritos por diferentes equipos de desarrollo. Después del ensamblaje, todo el sistema debería funcionar.
¿Cómo implementar tales cambios y no arruinarlo? Primero, decidimos mirar un poco hacia el futuro.
Estrategia de despliegue
- Sería posible implementarlo en varias etapas, pero esto aumentaría el tiempo de desarrollo en tres veces. Además, durante algún tiempo tendríamos una desincronización completa de datos en las bases de datos. Tendría que escribir mis propias herramientas de sincronización y vivir con múltiples almacenes de datos durante mucho tiempo. Y esto crea una amplia variedad de riesgos.
- Todo lo que pudieron preparar de forma transparente para el usuario se hizo de antemano. Tomó 2 meses.
- Nos permitimos el tiempo de inactividad durante varias horas, solo para que las operaciones del usuario puedan crear y modificar recursos.
- Para el trabajo de todos los recursos ya creados, el tiempo de inactividad era inaceptable. Planeamos que al desplegar los recursos debería funcionar sin tiempo de inactividad y sin afectar a los clientes.
- Para reducir el impacto en nuestros clientes, si algo sale mal, decidimos implementarlo el domingo por la noche. Por la noche, menos clientes administran máquinas virtuales.
- Advertimos a todos nuestros clientes que durante el período elegido para el despliegue, la gestión del servicio no estará disponible.
Digresión: ¿qué es el despliegue?
<filosofía de precaución>Cada especialista de TI responderá fácilmente qué es la implementación. Pones CI / CD, y automáticamente todo se entrega al producto. :)
Por supuesto, esto es verdad. Pero la dificultad es que con las herramientas modernas para automatizar la entrega de código, se pierde la comprensión del rodaje. ¿Cómo te olvidas de la invención épica de la rueda, mirando los vehículos modernos? Todo está tan automatizado que el despliegue a menudo se realiza sin darse cuenta de la imagen completa.
Y toda la imagen es la siguiente. La implementación consiste en cuatro grandes aspectos:
- Entrega de código, incluida la modificación de datos. Por ejemplo, su migración.
- Reversión de código: la capacidad de regresar si algo sale mal. Por ejemplo, a través de la creación de copias de seguridad.
- La hora de cada operación de despliegue / reversión. Uno debe entender el momento de cualquier operación de los dos primeros puntos.
- Funcionalidad afectada. Es necesario evaluar tanto los efectos positivos esperados como los posibles efectos negativos.
Todos estos aspectos deben tenerse en cuenta para un despliegue exitoso. Por lo general, solo evalúan el primero, en el mejor de los casos, el segundo punto, y luego el lanzamiento se considera exitoso. Pero el tercero y el cuarto son aún más importantes. ¿A qué usuario le gustará si la implementación demora 3 horas en lugar de un minuto? ¿O si algo superfluo afecta el despliegue? ¿O el tiempo de inactividad de un servicio dará lugar a consecuencias impredecibles?
Acto 1..n, preparación para la liberación
Al principio pensé en describir brevemente nuestras reuniones: todo el equipo, sus partes, un montón de discusiones en puntos de café, disputas, pruebas, tormentas cerebrales. Entonces pensé que sería superfluo. Cuatro meses de desarrollo siempre consisten en esto, especialmente cuando escribe no algo que se puede entregar constantemente, sino una gran característica en un sistema vivo. Lo que afecta a todos los servicios, pero los usuarios no deberían cambiar nada excepto el "botón de la interfaz web".
Nuestra comprensión de cómo implementar, cambió de cada nueva reunión, y de manera muy significativa. Por ejemplo, íbamos a actualizar toda nuestra base de facturación. Pero calcularon el tiempo y se dieron cuenta de que era imposible hacer esto en un tiempo de implementación razonable. Nos tomamos casi una semana adicional para fragmentar y archivar la base de datos de facturación. Y cuando la velocidad de despliegue esperada no funcionó después de eso, ordenaron un hierro adicional y más potente, donde arrastraron toda la base. No es que no quisiéramos hacer esto antes, pero la necesidad actual de implementación no nos dejó ninguna opción.
Cuando uno de nosotros tenía dudas de que la implementación podría afectar la disponibilidad de nuestras máquinas virtuales, pasamos una semana para probar, experimentar, analizar el código y entendimos claramente que esto no sucedería en nuestra producción, e incluso las personas más dudosas estuvieron de acuerdo con esto.
Mientras tanto, los técnicos de soporte técnico realizaron sus experimentos independientes para escribir a los clientes instrucciones sobre cómo conectarse, que se suponía que cambiarían después de la implementación. Trabajaron en una experiencia de usuario fácil de usar, prepararon instrucciones y brindaron asesoramiento personal.
Hemos automatizado todas las operaciones de implementación posibles. Cualquier operación fue programada, incluso la más simple, constantemente condujo pruebas. Discutieron sobre la mejor manera de desactivar el servicio: reducir el daemon o bloquear el acceso al servicio con un firewall. Se creó una lista de verificación de equipos para cada etapa de despliegue, se actualizó constantemente. Dibujamos y actualizamos constantemente el diagrama de Gantt para todos los trabajos de implementación, con tiempos.
Y entonces ...
Acto final, antes de lanzar
... es hora de lanzarse.
Como dice el refrán, una obra de arte no se puede completar, solo para terminar de trabajar en ella. Es necesario hacer un esfuerzo voluntario, entendiendo que no encontrará todo, pero creyendo que hizo todas las suposiciones razonables, proporcionó todos los casos posibles, cerró todos los errores críticos y todos los participantes hicieron todo lo posible. Cuanto más código implemente, más difícil será convencerse de esto (además, cualquiera comprende que es imposible prever todo).
Tomamos la decisión de que estábamos listos para implementar cuando estábamos convencidos de que hicimos todo lo posible para cerrar todos los riesgos para nuestros usuarios asociados con efectos inesperados y tiempos de inactividad. Es decir, cualquier cosa puede salir mal excepto:
- El afecto (sagrado para nosotros, el más preciado) de la infraestructura del usuario,
- Funcionalidad: el uso de nuestro servicio después de la implementación debe ser el mismo que antes.
Desplegar
Dos están rodando, 8 no interfierenTomamos el tiempo de inactividad para todas las solicitudes de los usuarios dentro de las 7 horas. En este momento, tenemos un plan de implementación y un plan de reversión.
- El despliegue en sí toma aproximadamente 3 horas.
- 2 horas - para pruebas.
- 2 horas: una reserva para una posible reversión de cambios.
Se ha compilado un diagrama de Gantt para cada acción, cuánto tiempo lleva, qué pasa en secuencia, qué se hace en paralelo.
Una porción del diagrama de despliegue de Gantt, una de las versiones anteriores (sin ejecución paralela). La herramienta de sincronización más valiosaTodos los participantes tienen su papel en el despliegue, las tareas que realizan y de las que son responsables. Estamos intentando que cada etapa sea automática, retroceder, recopilar comentarios y volver a rodar.
Crónica de los acontecimientos
Entonces, 15 personas vinieron a trabajar el domingo 28 de abril a las 10 p.m. Además de los participantes clave, algunos vinieron solo para apoyar al equipo, por lo que les agradecemos especialmente.
Por separado, vale la pena mencionar que nuestro probador clave está de vacaciones. Es imposible implementar sin probar, estamos trabajando en opciones. Una colega acepta ponernos a prueba fuera de vacaciones, por lo que tiene una gratitud inconmensurable de todo el equipo.
00:00. ParaDetuvimos las solicitudes de los usuarios, colgamos la placa de identificación, dicen, trabajo técnico. El monitoreo grita, pero todo es normal. Verificamos que nada cayó, excepto que debería. Y comenzamos a trabajar en la migración.
Todos tienen un plan de despliegue impreso para los puntos, todos saben quién está haciendo qué y en qué momento. Después de cada acción, verificamos los tiempos que no los exceden, y todo sale según el plan. Aquellos que no estén involucrados en el lanzamiento directamente en la etapa actual, prepárense lanzando un juguete en línea (Xonotic, tipo 3 kwaki), para no interferir con sus colegas. :)
02:00 a.m. DesplegadoUna sorpresa agradable: terminamos de implementar una hora antes, debido a la optimización de nuestras bases de datos y secuencias de comandos de migración. El grito universal, "desplegado!" Todas las funciones nuevas en el producto, pero hasta ahora solo podemos ver la interfaz. Todos entran en modo de prueba, ordenados en montones y comienzan a mirar lo que sucedió al final.
No funcionó muy bien, entendemos esto después de 10 minutos, cuando nada está conectado y no funciona en los proyectos de los miembros del equipo. Sincronización rápida, expresar nuestros problemas, priorizar, dividir en equipos y depurar.
2:30 a.m. Dos grandes problemas contra cuatro ojosEncontramos dos grandes problemas. Nos dimos cuenta de que los clientes no verán algunos servicios conectados y habrá problemas con las cuentas de socios. Ambos están asociados con scripts de migración imperfectos para algunos casos extremos. Necesitamos arreglarlo ahora.
Escribimos consultas que arreglan esto, al menos 4 ojos. Rodamos en la puerta previa para asegurarnos de que funcionen y no rompan nada. Puedes seguir adelante. Paralelamente, comienza nuestra prueba de integración habitual, que detecta algunos problemas más. Todos ellos son pequeños, pero también necesitan ser reparados.
03:00 a.m. -2 problemas +2 problemasLos dos grandes problemas anteriores están solucionados, casi todos los menores también. Todos los arreglos desocupados trabajan activamente en sus cuentas e informan lo que encuentran. Priorizamos, distribuimos por comandos, dejamos sin críticas por la mañana.
Al ejecutar las pruebas nuevamente, revelan dos nuevos problemas importantes. No todas las políticas de servicio llegaron correctamente, por lo que algunas solicitudes de los usuarios no se autentican. Además de un nuevo problema con las cuentas de socios. Nos apresuramos a mirar.
03:20. Sincronización de emergenciaUn nuevo problema solucionado. Para el segundo, organizamos una sincronización de emergencia. Entendemos lo que está sucediendo: la solución anterior solucionó un problema, pero creó otro. Tomamos un descanso para descubrir cómo hacerlo bien y sin consecuencias.
03:30 a.m. Seis ojosSomos conscientes de cuál debería ser el estado final de la base para que todo sea bueno para todos los socios. Escribimos una solicitud en 6 ojos, rodamos en la varilla previa, probamos, rodamos en el producto.
04:00. Todo funcionaTodas las pruebas pasaron, no hay problemas críticos visibles. De vez en cuando, algo no funciona en un equipo, respondemos rápidamente. Muy a menudo, la alarma es falsa. Pero a veces algo no llegó, en algún lugar una página separada no funciona. Nos sentamos, arreglamos, arreglamos, arreglamos. Un equipo separado lanza la última gran característica: la facturación.
04:30. Punto de no retornoSe acerca el punto de no retorno, es decir, el momento en que, si comenzamos a retroceder, no cumpliremos con el tiempo de inactividad que se nos ha dado. Hay problemas con la facturación, que lo sabe todo y escribe, pero obstinadamente no quiere cancelar el dinero de los clientes. Hay varios errores en páginas individuales, acciones, estados. La funcionalidad principal funciona, todas las pruebas pasan con éxito. Decidimos que se realizó el lanzamiento, no volveremos.
06:00 a.m. Abrimos todo en UILos errores son corregidos. Algunos usuarios no afectados quedan para más adelante. Abrimos la interfaz para todos. Continuamos evocando la facturación, esperamos los comentarios de los usuarios y los resultados del monitoreo.
07:00 a.m. Problemas de carga de APIQueda claro que tenemos una pequeña carga planificada incorrectamente en nuestra API y que estamos probando esta carga, lo que no pudo identificar el problema. Como resultado, ≈5% de las solicitudes falla. Nos estamos movilizando, buscando una razón.
La facturación es terca, tampoco quiere trabajar. Decidimos posponerlo para más adelante para realizar cambios en un modo tranquilo. Es decir, todos los recursos en él se acumulan, pero las cancelaciones de los clientes no pasan. Por supuesto, esto es un problema, pero en comparación con el despliegue general, no parece fundamental.
08:00. Fix APILanzamos una solución para la carga, los fallos se fueron. Empezamos a irnos a casa.
10 a.m. TodosTodo esta arreglado. En el monitoreo y los clientes están callados, el equipo se va a la cama gradualmente. La facturación permanece, la restauraremos mañana.
Luego, durante el día, hubo implementaciones que arreglaron los registros, notificaciones, códigos de retorno y códigos personalizados de algunos de nuestros clientes.
Entonces, el lanzamiento fue exitoso. Por supuesto, podría ser mejor, pero llegamos a conclusiones sobre lo que no teníamos lo suficiente para lograr la perfección.
Total
Dentro de los 2 meses de la preparación activa para el tiempo de implementación, se completaron 43 tareas, que duraron desde un par de horas hasta varios días.
Durante el despliegue:
- demonios nuevos y cambiados - 5 piezas, reemplazando 2 monolitos;
- cambios dentro de las bases de datos: nuestras 6 bases de datos con datos de usuario se ven afectadas, se descargan las descargas de tres bases de datos antiguas a una nueva;
- interfaz completamente renovada;
- el número de código bombeado: 33 mil líneas de código nuevo, ≈ 3 mil líneas de código en las pruebas, ≈ 5 mil líneas de código de migración;
- Todos los datos están intactos, ni una sola máquina virtual del cliente ha sufrido. :)
Buenas prácticas para un buen despliegue
Nos guiaron por ellos en esta difícil situación. Pero, en general, es útil observarlos en cualquier despliegue. Pero cuanto más difícil es la implementación, mayor es el papel que desempeñan.
- Lo primero que debe hacer es comprender cómo la implementación puede afectar o afectar a los usuarios. ¿Habrá tiempo de inactividad? Si es así, ¿qué es el tiempo de inactividad? ¿Cómo afectará esto a los usuarios? ¿Cuáles son los mejores y peores escenarios? Y cierra los riesgos.
- Planifica todo. En cada etapa, debe comprender todos los aspectos del despliegue:
- entrega de código;
- reversión de código;
- tiempo de cada operación;
- funcionalidad afectada
- Juega escenarios hasta que todas las etapas de despliegue estén claras, así como los riesgos en cada una de ellas. Si tiene alguna duda, puede tomar un descanso y explorar la dudosa etapa por separado.
- Cada etapa puede y debe mejorarse si ayuda a nuestros usuarios. Por ejemplo, reducirá el tiempo de inactividad o eliminará algunos riesgos.
- Probar la reversión es mucho más importante que probar la entrega del código. Es necesario verificar que, como resultado de la reversión, el sistema volverá a su estado original, confirme esto con pruebas.
- Todo lo que se puede automatizar debe ser automatizado. Todo lo que no se puede automatizar debe estar preescrito en la hoja de trucos.
- Registre los criterios de éxito. ¿Qué funcionalidad debería estar disponible y a qué hora? Si esto no sucede, comience un plan de reversión.
- Y lo más importante, la gente. Todos deben estar conscientes de lo que está haciendo, de qué y qué depende de sus acciones en el proceso de implementación.
Y si en una frase, con una buena planificación y elaboración, puede implementar lo que quiera sin consecuencias para la venta. Incluso eso afecta a todos sus servicios en prod.