C√≥mo tradujimos el sitio web de la Rep√ļblica a Kubernetes



Todos los d√≠as no se publican materiales escandalosos, importantes y simplemente muy geniales, y ning√ļn editor se comprometer√° a predecir el √©xito de un art√≠culo con una precisi√≥n del 100%. Lo m√°ximo que tiene el equipo es en el nivel de instinto para decir material "fuerte" u "ordinario". Eso es todo. Luego comienza la magia impredecible de los medios, gracias a la cual el art√≠culo puede llegar a la cima de los resultados de b√ļsqueda con docenas de enlaces de otras publicaciones o el material se hundir√° en el olvido. Y solo en el caso de la publicaci√≥n de art√≠culos geniales, los sitios de medios peri√≥dicamente caen bajo la monstruosa afluencia de usuarios, que modestamente llamamos el "efecto habrae".

Este verano, el sitio web de la publicaci√≥n de la Rep√ļblica se convirti√≥ en una v√≠ctima de la profesionalidad de sus propios autores: los art√≠culos sobre el tema de la reforma de las pensiones, la educaci√≥n escolar y la nutrici√≥n adecuada en total reunieron una audiencia de varios millones de lectores. La publicaci√≥n de cada uno de los materiales mencionados condujo a cargas tan altas que hasta la ca√≠da del sitio web de la Rep√ļblica, qued√≥ absolutamente un "poco espacio". La administraci√≥n se dio cuenta de que hab√≠a que cambiar algo: era necesario cambiar la estructura del proyecto de tal manera que pudiera reaccionar vigorosamente a los cambios en las condiciones de trabajo (principalmente carga externa), mientras permanec√≠a completamente funcional y accesible para los lectores incluso en momentos de saltos muy bruscos. Y una gran ventaja ser√≠a la m√≠nima intervenci√≥n manual del equipo t√©cnico de la Rep√ļblica en esos momentos.

Seg√ļn los resultados de una discusi√≥n conjunta con expertos de la Rep√ļblica sobre varias opciones para implementar la lista de deseos sonora, decidimos transferir el sitio web de la publicaci√≥n a Kubernetes *. Sobre lo que nos cost√≥ a todos, y ser√° nuestra historia de hoy.

* Durante la mudanza, ni un solo especialista técnico republicano resultó herido

Cómo se veía en términos generales


Todo comenz√≥, por supuesto, con negociaciones sobre c√≥mo suceder√° todo "ahora" y "m√°s tarde". Desafortunadamente, el paradigma moderno en el mercado de TI implica que tan pronto como cualquier compa√Ī√≠a se vaya a un lado por alg√ļn tipo de soluci√≥n de infraestructura, la coloquen en una lista de precios de servicios llave en mano. Parecer√≠a que el trabajo es "llave en mano": ¬Ņqu√© podr√≠a ser m√°s y mejor que un director condicional o due√Īo de un negocio? Pagu√© y no me duele la cabeza: planificaci√≥n, desarrollo, apoyo: todo est√° ah√≠, por parte del contratista, el negocio solo puede ganar dinero para pagar un servicio tan agradable.

Sin embargo, la transferencia completa de la infraestructura de TI no siempre es apropiada para el cliente a largo plazo. Es m√°s correcto desde todos los puntos de vista trabajar como un gran equipo, de modo que despu√©s de que se complete el proyecto, el cliente entienda c√≥mo vivir a√ļn m√°s con la nueva infraestructura, y los colegas en el taller no tengan la pregunta "oh, pero ¬Ņqu√© hicieron aqu√≠? despu√©s de firmar el certificado de finalizaci√≥n y la demostraci√≥n de los resultados. Los chicos de la Rep√ļblica eran de la misma opini√≥n. Como resultado, durante dos meses conseguimos un aterrizaje de cuatro personas para el cliente, que no solo se dieron cuenta de nuestra idea, sino tambi√©n especialistas t√©cnicamente capacitados en el lado de la Rep√ļblica para un mayor trabajo y existencia en las realidades de Kubernetes.

Y todas las partes se beneficiaron de esto: completamos rápidamente el trabajo, mantuvimos a nuestros especialistas listos para los nuevos logros y obtuvimos a Republic como cliente en soporte consultivo con nuestros propios ingenieros. La publicación, por otro lado, recibió una nueva infraestructura adaptada a los "efectos de habra", su propio personal retenido de especialistas técnicos y la capacidad de buscar ayuda si es necesario.

Estamos preparando una cabeza de puente


"Destruir, no construir". Este dicho se aplica a cualquier cosa. Por supuesto, la soluci√≥n m√°s simple parece ser la toma de rehenes mencionada anteriormente de la infraestructura del cliente y encadenarlo a √©l, al cliente para s√≠ mismo, o overclocking del personal existente y el requisito de contratar a un gur√ļ en nuevas tecnolog√≠as. Fuimos el tercero, no la forma m√°s popular hoy, y comenzamos con la capacitaci√≥n de ingenieros de la Rep√ļblica.

Al comienzo, vimos una solución de este tipo para garantizar el funcionamiento del sitio:


Es decir, Republic ten√≠a solo dos servidores de hierro: el principal y el de respaldo. Lo m√°s importante para nosotros fue lograr un cambio de paradigma en el pensamiento de los especialistas t√©cnicos del cliente, porque antes se ocupaban de un grupo muy simple de NGINX, PHP-fpm y PostgreSQL. Ahora se enfrentaron con la arquitectura escalable de contenedores de Kubernetes. Entonces, primero, cambiamos el desarrollo local de la Rep√ļblica al entorno docker-compose. Y este fue solo el primer paso.

Antes de nuestro aterrizaje, los desarrolladores de Republic mantuvieron su entorno de trabajo local en máquinas virtuales configuradas a través de Vagrant, o trabajaron directamente con el servidor de desarrollo a través de sftp. Basado en la imagen básica general de una máquina virtual, cada desarrollador "preconfiguró" su máquina "para sí mismo", lo que dio lugar a un conjunto completo de configuraciones diferentes. Como resultado de este enfoque, la inclusión de nuevas personas en el equipo aumentó exponencialmente el tiempo que ingresaron al proyecto.

En las nuevas realidades, ofrecimos al equipo una estructura más transparente del entorno de trabajo. Describió declarativamente qué software y qué versiones se necesitan para el proyecto, el orden de las conexiones e interacciones entre los servicios (aplicaciones). Esta descripción se cargó en un repositorio git separado para que pueda administrarse de manera conveniente y centralizada.

Todas las aplicaciones necesarias comenzaron a ejecutarse en contenedores Docker separados, y este es un sitio php regular con nginx, muchas estadísticas, servicios para trabajar con imágenes (redimensionar, optimizar, etc.) y ... un servicio separado para sockets web escritos en D Todos los archivos de configuración (nginx-conf, php-conf ...) también se convirtieron en parte de la base del código del proyecto.

En consecuencia, el entorno local fue completamente "recreado", completamente id√©ntico a la infraestructura del servidor actual. Por lo tanto, se redujo el tiempo requerido para mantener el mismo entorno tanto en las m√°quinas locales de los desarrolladores como en el producto. Lo que, a su vez, ayud√≥ enormemente a evitar problemas completamente innecesarios causados ‚Äč‚Äčpor las configuraciones locales autoescritas de cada desarrollador.

Como resultado, los siguientes servicios se generaron en el entorno docker-compose:

  • web para la aplicaci√≥n php-fpm;
  • nginx;
  • impproxy y cairosvg (servicios para trabajar con im√°genes);
  • postgres
  • redis
  • b√ļsqueda el√°stica;
  • trompeta (el mismo servicio para sockets web en D).

Desde el punto de vista de los desarrolladores, el trabajo con el c√≥digo base se mantuvo sin cambios: se mont√≥ en los servicios necesarios desde un directorio separado (el repositorio base con el c√≥digo del sitio) en los servicios necesarios: el directorio p√ļblico en el servicio nginx, todo el c√≥digo de la aplicaci√≥n php en el servicio php-fpm. Desde el directorio separado (que contiene todas las configuraciones del entorno de composici√≥n), los archivos de configuraci√≥n correspondientes se montan en los servicios nginx y php-fpm. Los directorios con postgres de datos, elasticsearch y redis tambi√©n se montan en la m√°quina local del desarrollador, de modo que si todos los contenedores tienen que ser reconstruidos / eliminados, los datos en estos servicios no se perder√°n.

Para trabajar con registros de aplicaciones, también en el entorno de compilación acoplable, se generaron los servicios de la pila ELK. Anteriormente, parte de los registros de la aplicación se escribían en estándar / var / log / ..., los registros de la aplicación php y las ejecuciones se escribían en Sentry, y esta opción de almacenamiento de registro "descentralizado" era extremadamente inconveniente para trabajar. Ahora, las aplicaciones y servicios se han configurado y refinado para interactuar con la pila ELK. El uso de registros se ha vuelto mucho más fácil; los desarrolladores ahora tienen una interfaz conveniente para buscar y filtrar registros. En el futuro (ya en el cubo), puede ver los registros de una versión específica de la aplicación (por ejemplo, un kronzhoba lanzado anteayer).

Adem√°s, el equipo de la Rep√ļblica comenz√≥ un corto per√≠odo de adaptaci√≥n. El equipo necesitaba comprender y aprender a trabajar en el nuevo paradigma de desarrollo, en el cual se debe considerar lo siguiente:

  1. Las aplicaciones se vuelven sin estado y pueden perder datos en cualquier momento, por lo que trabajar con bases de datos, sesiones y archivos estáticos se debe construir de manera diferente. Las sesiones PHP deben almacenarse centralmente y compartirse entre todas las instancias de la aplicación. Puede seguir siendo archivos, pero más a menudo se toma redis para estos fines debido a su mayor facilidad de administración. Los contenedores para bases de datos deberían "montar" un datadir o la base de datos debería ejecutarse fuera de la infraestructura del contenedor.
  2. Un almacenamiento de archivos de aproximadamente 50-60 GB de im√°genes no debe estar "dentro de la aplicaci√≥n web". Para tales fines, es necesario utilizar alg√ļn almacenamiento externo, sistemas cdn, etc.
  3. Todas las aplicaciones (bases de datos, servidores de aplicaciones ...) ahora son "servicios" separados, y la interacción entre ellos debe configurarse en relación con el nuevo espacio de nombres.

Después de que el equipo de desarrollo de Republic se acostumbró a las innovaciones, comenzamos a transferir la infraestructura de ventas de la publicación a Kubernetes.

Y aquí está Kubernetes.


Basado en el entorno construido para el desarrollo local docker-compose, comenzamos a traducir el proyecto en un "cubo". Todos los servicios en los que se construye el proyecto localmente, los "empaquetamos en contenedores": organizamos un procedimiento lineal y comprensible para construir aplicaciones, almacenar configuraciones, compilar estadísticas. Desde el punto de vista del desarrollo, eliminaron los parámetros de configuración que necesitábamos en variables de entorno, comenzaron a almacenar sesiones no en archivos, sino en rábanos. Elevamos el entorno de prueba, donde implementamos una versión viable del sitio.

Dado que este es un proyecto monolítico anterior, es obvio que había una relación dura entre las versiones frontend y backend, respectivamente, y estos dos componentes se implementaron al mismo tiempo. Por lo tanto, decidimos construir los pods de la aplicación web de tal manera que dos contenedores giraran en un pod: php-fpm y nginx.

También creamos el escalado automático para que las aplicaciones web escalen a un máximo de 12 en el pico de tráfico, establezcan ciertas pruebas de vida / preparación, porque la aplicación requiere al menos 2 minutos para ejecutarse (ya que necesita calentar el caché, generar configuraciones ...)

Inmediatamente, por supuesto, hubo todo tipo de card√ļmenes y matices. Por ejemplo: las estad√≠sticas compiladas eran necesarias tanto para el servidor web que lo distribuy√≥ como para el servidor de aplicaciones en fpm, que en alg√ļn lugar sobre la marcha gener√≥ alg√ļn tipo de im√°genes, en alg√ļn lugar que svg le dio directamente al c√≥digo. Nos dimos cuenta de que para no levantarnos dos veces, necesitamos crear un contenedor de construcci√≥n intermedio y contenerizar el ensamblaje final a trav√©s de m√ļltiples etapas. Para hacer esto, creamos varios contenedores intermedios, en cada uno de los cuales las dependencias se extraen por separado, luego las estad√≠sticas (css y js) se recopilan por separado y luego en dos contenedores, en nginx y en fpm, se copian del contenedor de compilaci√≥n intermedio.

Empezamos


Para trabajar con archivos en la primera iteraci√≥n, creamos un directorio com√ļn que se sincroniz√≥ con todas las m√°quinas en funcionamiento. Por la palabra "sincronizado" quiero decir aqu√≠ exactamente lo que se puede pensar con horror en primer lugar: rsync en un c√≠rculo. Obviamente una mala decisi√≥n. Como resultado, obtuvimos todo el espacio en disco en GlusterFS, configuramos el trabajo con im√°genes para que siempre estuvieran accesibles desde cualquier m√°quina y nada se ralentizara. Para la interacci√≥n de nuestras aplicaciones con los sistemas de almacenamiento (postgres, elasticsearch, redis), se crearon servicios externalName en k8s, de modo que, por ejemplo, en caso de un cambio urgente a la base de datos de respaldo, actualice los par√°metros de conexi√≥n en un solo lugar.

Todo el trabajo con crones fue llevado a las nuevas entidades k8s: cronjob, que puede ejecutarse de acuerdo con un cronograma específico.

Como resultado, obtuvimos esta arquitectura:


Clickable

Oh dificil


Este fue el lanzamiento de la primera versi√≥n, porque en paralelo con la reestructuraci√≥n completa de la infraestructura, el sitio todav√≠a estaba siendo redise√Īado. Parte del sitio fue construido con algunos par√°metros - para estad√≠sticas y todo lo dem√°s, y parte - con otros. All√≠ era necesario ... para decirlo suavemente ... pervertir con todos estos contenedores de varias etapas, copiar datos de ellos en un orden diferente, etc.

Tambi√©n tuvimos que bailar con panderetas alrededor del sistema CI \ CD para ense√Īar todo esto a implementar y controlar desde diferentes repositorios y desde diferentes entornos. Despu√©s de todo, se necesita un control constante sobre las versiones de la aplicaci√≥n para que pueda comprender cu√°ndo se implement√≥ un servicio u otro servicio y con qu√© versi√≥n de la aplicaci√≥n se inici√≥ uno u otro error. Para hacer esto, configuramos el sistema de registro correcto (as√≠ como la propia cultura de registro) e implementamos ELK. Los colegas aprendieron a establecer ciertos selectores, ver qu√© cron genera qu√© errores, c√≥mo se ejecuta generalmente, porque en el "cubo" despu√©s de que se ejecuta el contenedor cron, ya no entrar√° en √©l.

Pero lo más difícil para nosotros fue reelaborar y revisar todo el código base.

Perm√≠tame recordarle que Republic es un proyecto que ahora tiene 10 a√Īos. Comenz√≥ con un equipo, otro se est√° desarrollando ahora, y es realmente dif√≠cil extraer todos los c√≥digos fuente para detectar posibles errores y fallas. Por supuesto, en este momento, nuestro grupo de desembarco de cuatro hombres conect√≥ los recursos del resto del equipo: hicimos clic y probamos todo el sitio con pruebas, incluso en aquellas secciones que la gente en vivo no hab√≠a visitado desde 2016.

No falla en ninguna parte


El lunes, temprano en la ma√Īana, cuando la gente fue al correo masivo con un resumen, todos obtuvimos una apuesta. El culpable se encontr√≥ con bastante rapidez: cronjob comenz√≥ y fren√©ticamente comenz√≥ a enviar cartas a todos los que quer√≠an obtener una selecci√≥n de noticias durante la semana pasada, devorando los recursos de todo el grupo en el camino. No pudimos soportar ese comportamiento, por lo que r√°pidamente pusimos l√≠mites estrictos a todos los recursos: cu√°nto procesador y memoria puede consumir un contenedor, etc.

¬ŅC√≥mo hizo frente el equipo de desarrolladores de la Rep√ļblica?


Nuestras actividades trajeron muchos cambios, y lo entendimos. De hecho, no solo redise√Īamos la infraestructura de la publicaci√≥n, en lugar del paquete habitual de "servidor de respaldo principal", implementamos una soluci√≥n de contenedor que conecta recursos adicionales seg√ļn sea necesario, sino que cambiamos completamente el enfoque para un mayor desarrollo.

Despu√©s de un tiempo, los chicos comenzaron a comprender que esto no funciona directamente con el c√≥digo, sino que funciona con una aplicaci√≥n abstracta. Dados los procesos CI \ CD (basados ‚Äč‚Äčen Jenkins), comenzaron a escribir pruebas, obtuvieron entornos completos de desarrollo-etapa-producto donde pueden probar nuevas versiones de su aplicaci√≥n en tiempo real, ver d√≥nde se cae todo y aprender a vivir Nuevo mundo ideal.

¬ŅQu√© recibi√≥ el cliente?


En primer lugar, ¬°Republic finalmente obtuvo un proceso de implementaci√≥n controlado! Sol√≠a ‚Äč‚Äčser: en la Rep√ļblica hab√≠a una persona responsable que fue al servidor, comenz√≥ todo manualmente, luego recopil√≥ estad√≠sticas, comprob√≥ con sus manos que nada se hab√≠a ca√≠do ... Ahora el proceso de implementaci√≥n se construye para que los desarrolladores se involucren en el desarrollo y no pierdan el tiempo en nada m√°s . Y la persona responsable ahora tiene una tarea: monitorear c√≥mo fue el lanzamiento en general.

Después de que se produce un empuje a la rama maestra, ya sea de forma automática o mediante una implementación de "botón" (periódicamente, debido a ciertos requisitos comerciales, la implementación automática se desactiva), Jenkins entra en la refriega: comienza el ensamblaje del proyecto. Primero, todos los contenedores acoplables se ensamblan: las dependencias (compositor, hilo, npm) se instalan en los contenedores preparatorios, lo que le permite acelerar el proceso de compilación si la lista de bibliotecas requeridas no ha cambiado durante la implementación; luego se recopilan contenedores para php-fpm, nginx, otros servicios, en los que, por analogía con el entorno de compilación de acoplador, solo se copian las partes necesarias de la base de código. Después de eso, se inician las pruebas y, en caso de aprobarlas con éxito, hay un impulso de imágenes a la tienda privada y, de hecho, despliegan implementaciones en el cubo.

Gracias a la transferencia de Republic a k8s, obtuvimos una arquitectura usando un grupo de tres m√°quinas reales en las que hasta doce copias de la aplicaci√≥n web pueden "girar" al mismo tiempo. Al mismo tiempo, el sistema mismo, basado en las cargas actuales, decide cu√°ntas copias necesita en este momento. Tomamos Republic de la loter√≠a ‚Äúfunciona - no funciona‚ÄĚ con servidores primarios y de respaldo est√°ticos y construimos un sistema flexible para ellos, listo para un aumento similar a una avalancha en la carga en el sitio.

En este momento, puede surgir la pregunta "muchachos, cambiaron dos piezas de hierro por las mismas piezas de hierro, pero con la virtualizaci√≥n, ¬Ņcu√°l es la ganancia? ¬ŅEst√°n bien all√≠?" Y, por supuesto, ser√° l√≥gico. Pero solo en parte. Como resultado, no solo obtuvimos piezas de hardware con virtualizaci√≥n. Conseguimos un entorno de trabajo estable, igual en alimentos y virgo. Un entorno que se gestiona de forma centralizada para todos los participantes del proyecto. Tenemos un mecanismo para ensamblar todo el proyecto y lanzar lanzamientos, nuevamente, lo mismo para todos. Tenemos un conveniente sistema de orquestaci√≥n de proyectos. Tan pronto como el equipo de Republic se da cuenta de que generalmente dejan de tener suficientes recursos actuales y los riesgos de cargas ultra altas (o cuando ya ha sucedido y todo se ha calmado), simplemente toman otro servidor, en 10 minutos implementan la funci√≥n de un nodo de cl√ļster en √©l y op-op Todo es hermoso y bueno de nuevo. La estructura del proyecto anterior no suger√≠a tal enfoque en absoluto; no hab√≠a soluciones lentas ni r√°pidas para tales problemas.

En segundo lugar, ha aparecido una implementación perfecta: el visitante podrá acceder a la versión anterior de la aplicación o a una nueva. Y no como antes, cuando el contenido podría ser nuevo, pero los estilos son viejos.
Como resultado, el negocio est√° satisfecho: todo tipo de cosas nuevas ahora se pueden hacer m√°s r√°pido y con m√°s frecuencia.
En total, desde "pero intentemos" hasta "hecho", el trabajo en el proyecto tomó 2 meses. El equipo de nuestra parte es un aterrizaje heroico de cuatro personas + soporte para la "base" durante la verificación del código y las pruebas.

Lo que obtuvieron los usuarios


Y los visitantes, en principio, no vieron los cambios. El proceso de implementación de la estrategia de RollingUpdate se construye "a la perfección". El lanzamiento de una nueva versión del sitio de ninguna manera perjudica a los usuarios, la nueva versión del sitio, hasta que pasen las pruebas y las pruebas de vida / preparación, no estarán disponibles. Simplemente ven que el sitio funciona y que no se caerá después de publicar artículos geniales. Que, en general, es lo que cualquier proyecto necesita.

Source: https://habr.com/ru/post/439458/


All Articles