Cómo implementar CI/CD para todos los desarrolladores del banco. CI/CD por App.Farm / Sudo Null Noticias de TI

¡Hola! Mi nombre es Konstantin Belkin, soy Teamlead SRE en RSHB-Intech. Hoy les contaré qué es CI/CD en la plataforma App.Farm, qué metodologías utilizamos en nuestro trabajo, cómo funciona la plataforma, qué herramientas brindamos a los desarrolladores y cómo organizamos CI/CD en RSHB para nuestro amado desarrolladores.

El artículo se basa en un informe que leí en el RSHB Meetup: Think like DevOps in a big company, celebrado el 29 de agosto dentro de los muros de RSHB-Intech.

Ver informe

Ahora todas las empresas están construyendo plataformas, pequeñas o grandes, que se llenan con sus productos. Las plataformas hacen la vida más fácil a los desarrolladores. El objetivo de nuestra App.Farm es similar: simplificar la vida y estimular el desarrollo interno. En el momento del inicio del proyecto, RSHB estaba atascado en proveedores, y esto tuvo que corregirse. Una de las formas más seguras de salir de esta situación es brindarle al desarrollador herramientas simples y comprensibles para que pueda escribir lógica de negocios e implementarla en algún lugar en forma de producto.

Los principios fundamentales sobre los que se construye CI/CD son GitOps, IaC y CI/CD.

GitOps Es una metodología que asume que todo es código. Si todo es código, entonces podemos describirlo todo en forma de código y cargarlo en un conjunto de herramientas que lo procesará todo y lo llevará al circuito productivo o zona de desarrollo.

Así es como se ve una ruta típica aproximada.

El desarrollador escribe código, lo sube a Git, algo se construye allí, se ensambla imagehay algunas infraconfiguraciones que también se recopilan y terminan en Git. También contamos con herramientas GitOps que, en última instancia, lo vierten todo en uno o más clústeres. Usamos un clúster para la aplicación de la aplicación.

Si hablamos del enfoque IaC, pide describir completamente su infraestructura como código, indicar las direcciones de los servidores, qué herramientas instalar, qué roles asignar, etc. En consecuencia, el código para gestionar la infraestructura se puede escribir en diferentes estilos: declarativo o imperativo.

Utilizamos un enfoque declarativo. También se puede utilizar al desarrollar una aplicación o implementar infraestructura.

El tercer enfoque que utilizamos es CI/CD Flow. No entregamos YAML gigantesco a los desarrolladores ni tenemos un equipo en cada departamento que describa su proceso de CI/CD. Pensamos que sería más fácil concentrar toda la competencia en la parte de CI/CD en todo el equipo de la plataforma y entregar 3 líneas. Si un desarrollador quiere escribir en Java o un proveedor quiere iniciar sesión en la plataforma, puede escribir tres líneas, todo iniciará sesión y funcionará.

Nuestra tubería típica se ve así.

Primero realizamos la verificación. Luego, en consecuencia, viene la construcción, las pruebas, las comprobaciones, las inspecciones, DevSecOps, la publicación y, al final, todo se implementa. Todo esto se debe a una gran cantidad de herramientas adicionales.

En la plataforma AppFarm entregamos las siguientes herramientas como código.

La documentación de la plataforma es una herramienta para compartir conocimientos. Esto es probablemente lo más importante de los enfoques de CI/CD en general. Debe informar a los desarrolladores u otros desarrolladores cómo utilizar sus herramientas en general. El flujo también se crea usando código.

Hay datos básicos que utilizamos en la plataforma. Este es el código fuente de la plataforma en sí y el código base, la configuración de inicio de esta aplicación, los archivos adicionales que se necesitan para que la aplicación se inicie. Y hay partes adicionales que también describimos como código: clusters kafka, enlaces, conexiones, interconexiones. Modelo a seguir y paneles de seguimiento del servicio, si es necesario, y una base de datos. Almacenamos el secreto por separado en Vault.

Aquí puedes ver una tabla que muestra qué flujos admitimos en este momento.

Para nosotros, Java es el lenguaje más popular del banco. Casi el 30% de las solicitudes están escritas en él. Es por eso que implementamos soporte para ello en primer lugar. Y, por supuesto, hicieron lo mismo con las aplicaciones frontend para JS+TS. La última característica que hemos implementado es la compatibilidad con la implementación directa de contenedores Docker de los proveedores. Muchas personas ahora envían sus aplicaciones en formato Docker y podemos aceptarlas y trabajar con ellas fácilmente. Hicimos una tubería especializada para esto.

Como ya dije, usamos un enfoque declarativo y lo usamos para describir el resultado final. Y nuestras herramientas más detalladas lo llevarán al resultado real, que recibiremos de alguna forma.

¿Cómo es una descripción declarativa de un servicio?

Se nos ocurrió nuestra propia manifestación, es decir, todo termina en Kubernetes. Pero hay un controlador especial que procesa manifiestos cortos. Es decir, el desarrollador no necesita conocer la especificación de Kubernetes, cómo escribir una implementación, una descripción de la entidad de servicio, cómo crear algún tipo de servicio virtual, escribir un NetworkSet y una NetworkPolicy, etc. Puede escribir 16 líneas de código según la documentación, parametrizar su servicio, pasar algunas variables necesarias para ejecutarlo y trabajar con él.

Además, generamos varias entidades adicionales. Anteriormente, para registrar, por ejemplo, un clúster de Kafka, era necesario ir al departamento de gestión de administración del sistema, solicitar un servidor, coordinar el acceso, obtener acceso al servidor e implementar Kafka allí. Con el enfoque declarativo todo se ha vuelto más sencillo. Simplemente escribe un par de líneas y dice que necesito un clúster Kafka para un sistema de información. Luego, el operador va al grupo de recursos, toma estos recursos de su grupo de recursos e implementa un clúster Kafka listo para usar para su trabajo. Eso es todo, luego conéctate y trabaja con los temas.

A continuación se muestra un ejemplo de cómo se ve la declaratividad dentro de nuestro sistema.

Logramos el enfoque declarativo utilizando un operador de plataforma personalizado que escribimos. Atiende entidades especiales K8S. Si crea una pequeña descripción que consta de ocho líneas, llévela al clúster de cuber usando la herramienta de implementación, luego el operador de la plataforma resta este valor del recurso personalizado y lo dispersa en dos entidades. Creará un espacio de nombres y creará una cuota de recursos utilizando los valores descritos aquí.

Hay otro ejemplo.

El desarrollador declara el enlace, dice que abandonaré el servicio. frontend_for_asp al servicio asp_net_serviceque también se encuentra aquí, derrama la tubería, las entidades de la plataforma caen, en consecuencia, aparece la entidad del servicio de plataforma, la entidad de implementación y la entidad del enlace personalizado.

El operador de la plataforma dice:

– Sí, hay un vínculo.
– ¿Qué hay que hacer?
— Necesitamos hacer un servicio virtual.

Fui, basándome en la breve esencia de estas seis líneas, creé un gran manifiesto y lo publiqué. Esto aseguró el acceso desde el frontend al backend.

No está disponible la creación dinámica de entidades en nuestra plataforma. Es decir, no puedes inventar algo con tus propias manos y crear algo en Kubernetes. Siempre debes describir todo de forma declarativa utilizando el modelo de lenguaje que te ofrecemos y en base a ello obtener acceso a la red, roles, permisos, etc. Hay que describir todo, esto nos da una sensación de seguridad. Siempre sabes dónde debe ir tu servicio y dónde no. No existe tal cosa que no comprenda en absoluto con qué interactúa el servicio.

Herramientas

Nuestro conjunto de herramientas incluye varios componentes: dónde almacenamos el código, cómo implementamos todas las herramientas, dónde almacenamos nuestros artefactos. Cuando iniciamos el proyecto, había cinco soluciones disponibles en el mercado: GitHub, GitLab, Gitea, Bitbucket, Gogs. Ahora la mayoría ya ha abandonado el mercado, pero el código abierto permanece. A continuación queríamos elegir algún tipo de sistema de CI. Teníamos muchas opciones aquí, algunas las conocíamos y otras no. Al final, nuestra elección recayó en GitLab, GitLab CI y Nexus como repositorio.

¿Por qué los elegimos? Porque ya hemos trabajado con ellos antes, y muchos de vosotros probablemente habéis trabajado con ellos. Existe una gran base establecida y, en general, se trata de productos de buena calidad que llevan muchos años en el mercado.

La composición final es la siguiente: GitLab, bajo su capó está Crunchy Postgres, Minio, que es un almacenamiento de objetos para GitLab, como herramienta de CI es GitLab CI y Nexus.

Los beneficios del Código Abierto son claros y comprensibles para todos. Podemos trabajar con él, podemos cambiarlo, sabemos que es seguro, es fácil de verificar y no estamos ubicados como proveedores de software. Siempre podemos cambiar a otros productos de código abierto. Es gratis, pero por supuesto es un tema controvertido. Siempre lo pagas con recursos humanos. Ahora la tendencia es utilizar software de código abierto en Rusia, lo cual es bueno.

Para recrear todo el sistema CI/CD, además de algunas herramientas globales que utilizamos, también necesitamos de alguna manera facilitar la vida a los desarrolladores y mejorar la seguridad de nuestras canalizaciones de CI/CD. Hemos escrito varias herramientas que son necesarias para el trabajo. Hablemos de cada uno de ellos.

Entonces, el verificador Verificador. Es necesario para guiar al desarrollador por el camino correcto. Puede ser que el desarrollador haya decidido recrear algo propio en el proyecto que no se ajuste a la documentación. El verificador comprobará estáticamente si completó todo correctamente para poder construir su proyecto. Es decir, en la primera etapa lanzamos el proyecto en el verificador, lo verificamos y podemos detenerlo con anticipación antes de que aparezcan errores, antes de que se ensamble allí.

Luego llega el turno DockerfileGen. Muchos desarrolladores pueden escribir archivos Docker, pero decidimos que no deberíamos permitirles hacerlo. Por lo tanto, elegimos para el desarrollador qué archivo Docker utilizar. Para ello contamos con DockerfileGen. Esto es muy útil, incluso desde el punto de vista de la seguridad. Simplemente puede tomarlo y, en caso de fallas en el proceso general, o más precisamente en las imágenes generales, reconstruir la imagen para eliminar algunas vulnerabilidades u otros problemas. No es necesario ejecutar todos los proyectos como DevSecOps.

También tenemos un producto como Firmante. Se dedica a transferir a producción, crea una llave en un lado, la mete en el nabo y al transferirla verifica que la imagen sea realmente la que va a producción.

Buildjit-Viaje es nuestro producto de ensamblaje. Reemplazó a Kaniko.

Kube-implementar-aplicaciones – este es nuestro conjunto de herramientas que nos permite implementar cualquier cosa en la plataforma, es decir, allí se describen los manifiestos YAML, se producen plantillas y también forma entidades, implementaciones, servicios y todo lo demás.

BASE, LADRILLOS, TRABAJOS

Hablemos de cómo armamos un proceso de CI/CD. Hemos elegido un enfoque bastante no trivial. Los manifiestos grandes y de varias páginas no son muy buenos, es difícil trabajar con ellos. Resultó que existe tal principio: LADRILLOS. Subyace a la división según características funcionales. Puedes dividir el manifiesto YAML en manifestaciones breves, cada una de las cuales tendrá su propio propósito específico. De esta manera podemos usar diferentes piezas, reutilizar las mismas piezas en diferentes pipelines, para ensamblar diferentes pipelines para diferentes idiomas. Si lo desea, puede leer sobre esto en GitLab y cómo puede optimizar en general sus manifiestos YAML. Enlace al documento de GitLab.

Entonces, ¿cómo se ve la estructura de nuestro proyecto, que se utiliza para hacer una pequeña inclusión en tres líneas?

Al principio hay ladrillos. Estas son exactamente las piezas que podemos reutilizar. Representan algún tipo de funciones de implementación, funciones de compilación, funciones de prueba, etc. Allí también se incluye la verificación. A continuación, la base es la base, algo sin lo cual la tubería definitivamente no funcionará. Ya incluye algunos componentes básicos, imágenes, sus versiones, estas son variables para que funcione la canalización, algunas funciones de implementación que definitivamente son necesarias para el trabajo, construir componentes, probar componentes y todo lo demás.

A partir de estas dos primeras piezas, ladrillos y base, creamos un flujo. Dentro del flujo hay varios tipos: CDL (flujo de entrega), CDP (flujo de publicación), y cuando solo necesitamos un CDP sin todo lo demás. Esto generalmente se usa para proveedores. Sólo necesitamos implementar un servicio desde algún jar, ejecutar el jar en un contenedor y listo. De hecho, este es un caso raro, pero se utiliza. Al final obtenemos el idioma compilado para los idiomas, es decir, para Java, Go, Dotnet, etc. Si solo desea realizar entregas en el sitio de producción, utilice CDL. Si desea publicar en la plataforma, utilice un CDP.

Cómo se ve el manifiesto YAML final conectado.

Detrás de tres líneas se esconde un conjunto de etapas e inclusiones que, en última instancia, se convierten en un muro de trabajos.

Aquí puede ver que algunas pruebas no pasaron, pero en general el proyecto salió bien e incluso entró en producción.

La conexión del manifiesto final, como mostré anteriormente, se ve exactamente así, en forma de tres líneas, donde simplemente indicamos flujo, que se trata de una publicación, que se trata de un servicio escrito en Java.

¿Cuáles son las ventajas aquí? Por supuesto, esto es una conveniencia para el usuario, es decir, en parte de la documentación lo describimos condicionalmente: conecte tres líneas y todo será genial. No es necesario que escribas un montón de canalizaciones, algunos manifiestos adicionales ni describas nada más. Esto es, en consecuencia, minimización de campos. Siempre sabemos que un proyecto debe tener tres líneas y nada más. Es decir, si alguien añade alguna otra lógica, y también tenemos esas cifras, esto es malo. Decimos, quítatelo, no lo necesitamos.

Y después de todo, no es código, es una referencia al código, por lo que hay un YAML gigante de 5000 líneas detrás.

Problemas

Hubo muchos problemas, pero destacaré dos fundamentales, por los cuales los oleoductos “comunales” fueron detenidos indefinidamente.

El primer problema que encontramos es problema de confusión de caché. ¿Recuerdas lo que dije sobre Kaniko? Ella nos dio este problema y así apareció Buildjit-Journey. Usamos Kaniko, que acelera la compilación porque almacena en caché las imágenes de la ventana acoplable, las coloca en Nexus y, en función de las cachés y otras etapas, toma, en términos generales, las cachés y las reutiliza durante compilaciones posteriores.

Al final, lo que empezó a pasar. Kaniko se volvió loco y comenzó a agregar piezas de Angular y más a proyectos JVM. Todo empezó a convertirse en un desastre. Podría entrar en producción un contenedor ensamblado, en el que había piezas de Java, piezas de Angular, y en general no estaba claro cómo funcionaba todo.

Pensamos, pensemos en algo sobre esto y pensemos en cómo seguir viviendo. Era 2021, analizamos las tendencias en general. Vimos una solución ya preparada como BuildKit de Moby, el creador de Docker. Miramos que, en principio, funciona bastante bien. Encontró muy buen articulo Explorador japonés, venerado. Resultó que BuildKit es mucho más rápido que Kaniko: entre un 15 y un 30%. Decidimos saltar a esta historia, pero tuvimos que desechar a Kaniko de manera flexible y traer BuildKit.

Kaniko tiene una lógica de punto de entrada para ejecutar. Pero BuildKit no tiene esto. En consecuencia, para ensamblar BuildKit y que comenzara a funcionar, fue necesario escribir un contenedor. Este es un contenedor de BuildKit y BuildKitD para que pueda aparecer como cliente y demonio al mismo tiempo. ¿Por qué es esto necesario? Usamos Istio, tenemos MTLS en todas partes y tuvimos que proporcionar certificados transversales para todos los ensamblajes.

En consecuencia, finalmente lo conectamos como reemplazo de Kaniko y obtuvimos tuberías bastante rápidas. En promedio, nuestra canalización, si es solo para un desarrollador, se ensambla en 3 a 4 minutos; si es la primera compilación, la siguiente demora 2 minutos; (No en horas pico, donde el montaje demora de 6 a 10 minutos).

Hubo un segundo problema. Afirmamos escribir código correctamente, por eso presentamos SonarQube. Incluso comprobamos este tema en la parte superior, cuántas comprobaciones se han realizado. Por eso utilizamos SonarQube y comprobaciones estáticas en él. El tiempo medio de verificación en SonarQube es de 7 segundos (en un microservicio estadístico medio). Estamos comprobando 25 tecnologías diferentes que se están implementando allí, estos son proyectos JSON, SQL, Java, etc.

En un momento, nuestras compilaciones comenzaron a ralentizarse terriblemente debido a SonarQube. El tiempo medio por control aumentó a tres minutos. Como usamos la versión Community LTS, solo teníamos un trabajador. Imagínese, un grupo de desarrolladores están desarrollando y todos hacen cola. En sólo 20 minutos se creó una cola de 16 horas de antelación.

En busca de un problema, revertimos la última versión de SonarQube y decidimos darle algunos recursos. Y esta parte también fue nuestro error fatal. Resulta que SonarQube tiene una característica muy interesante: cuanto más procesador le pongas, más lento funcionará. Parece engordar, grita que ya no puede moverse y pide ayuda. Al final, nuestros oleoductos comenzaron a ralentizarse debido a esto.

No hemos investigado más este problema. Puede que haya sido a nivel del kernel de Linux, ya que estábamos usando una versión antigua de Linux 3.12. Pero la moraleja de la historia es que todo debe implementarse de forma secuencial, traer recursos por separado, traer actualizaciones por separado. Y siempre preste atención a todos los factores y busque cambios en las diferencias.

Beneficio empresarial

El principal medio para lograr un resultado positivo en la construcción de oleoductos “comunales” es la documentación. Debemos darle muy claramente al desarrollador información sobre cómo debe llevar a cabo su proyecto, cómo funciona la plataforma, qué manifiestos se pueden utilizar para trabajar. Por eso presentamos un producto de documentación de calidad llamado Docsify.

Así es como se ve nuestra guía de plataforma. Esta es la página de título, en realidad hay un montón de texto allí. Puedes publicar un libro de 500 páginas.

¿Qué representa la documentación? Esta es una pila de tecnología basada en Docsify. Una buena tecnología que permite estructurar información con Markdown. Para escribir documentación en Docsify, la redacción técnica simplemente necesita aprender Markdown. También conectamos el motor Commento allí para que sea posible dejar comentarios para mejorar la documentación. Los usuarios pueden modificar este muelle a través de una solicitud de fusión. Aquí enlace al proyecto Docsify, puedes recogerlo.

¿Qué ventajas trajo la implementación de enfoques unificados de CI/CD?

Ahora No hay necesidad de especialistas en Devops en cada departamento.. Por lo general, siempre hay algún tipo de servicio devops que se vende a los departamentos. Contamos con un departamento de soporte para toda la plataforma. Todo el banco trabaja en la plataforma. En consecuencia, hemos unificado todo en un solo servicio, un desarrollo único y estándares uniformes. Lo sabemos todo, lo vemos todo, lo observamos todo.

La transición de un desarrollador de un proyecto a otro lleva un tiempo mínimo. Usó tecnología CI/CD en un departamento, se mudó a otro; aquí ocurre lo mismo, todo es bueno y familiar.

El zoológico tecnológico se ha reducido de tamaño. Tenemos bases de datos fijas que estamos listos para conectar, corredores que estamos listos para servir. Existe un servicio de mensajería fija en toda la plataforma. Por lo tanto, la participación de nuevos desarrolladores también requiere un mínimo de tiempo. Puedes trabajar muy rápidamente con la documentación y ver lo que necesitas, hay una búsqueda interesante.

Los desarrolladores se centran en la lógica empresarialno en infraestructura. No escriben archivos Docker ni piensan en cómo implementar Kafka, conectar Zookeeper, implementar IBM MQ o cualquier otra cosa. Todo esto se desarrolla a base de manifiestos, en los que simplemente escribes tres líneas y listo.

Finalmente, hablemos de números. Funciona en nuestra plataforma. 2300 desarrolladores, totales 3620 usuarios, si agrega administración, administradores del sistema, etc. Actualmente en desarrollo 5518 proyectos, 1,123 millones Los oleoductos se lanzaron durante todo el período de trabajo y se completaron. 23 689 solicitudes de soporte. estaba hecho 273 697 Señor y 1,598 millones se compromete.

Hay algunos gráficos aquí. Demuestran que estamos en constante crecimiento, literalmente todos los días.

Esto es en términos generales. Puede leer una descripción básica más detallada del componente técnico de App.Farm en el artículo anterior.

Publicaciones Similares

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *