.NET Core en Linux, DevOps a caballo

Desarrollamos DevOps lo mejor que pudimos. Éramos 8 y Vasya era el mejor en Windows. De repente Vasya se fue y yo tuve la tarea de lanzar un nuevo proyecto proporcionado por el desarrollo de Windows. Cuando dejé toda la pila de desarrollo de Windows sobre la mesa, me di cuenta de que la situación era un fastidio...

Así comienza la historia. Alexandra Sinchinova en DevOpsConf. Cuando el principal especialista en Windows dejó la empresa, Alexander se preguntó qué hacer ahora. ¡Cámbiate a Linux, por supuesto! Alexander le contará cómo logró sentar un precedente y transferir parte del desarrollo de Windows a Linux utilizando el ejemplo de un proyecto completado para 100 usuarios finales.

.NET Core en Linux, DevOps a caballo

¿Cómo entregar fácil y sin esfuerzo un proyecto a RPM usando TFS, Puppet, Linux .NET core? ¿Cómo admitir el control de versiones de la base de datos de un proyecto si el equipo de desarrollo escucha las palabras Postgres y Flyway por primera vez y la fecha límite es pasado mañana? ¿Cómo integrarse con Docker? ¿Cómo motivar a los desarrolladores .NET a abandonar Windows y los batidos en favor de Puppet y Linux? ¿Cómo resolver los conflictos ideológicos si no hay ni la fuerza, ni las ganas, ni los recursos para mantener Windows en producción? Sobre esto, así como sobre Web Deploy, pruebas, CI, sobre las prácticas de uso de TFS en proyectos existentes y, por supuesto, sobre muletas rotas y soluciones de trabajo, en la transcripción del informe de Alexander.


Entonces, Vasya se fue, la tarea recae en mí, los desarrolladores esperan impacientes con horcas. Cuando finalmente me di cuenta de que no podían devolver a Vasya, me puse manos a la obra. Para empezar, evalué el porcentaje de máquinas virtuales Win en nuestra flota. El marcador no estuvo a favor de Windows.

.NET Core en Linux, DevOps a caballo

Dado que estamos desarrollando activamente DevOps, me di cuenta de que es necesario cambiar algo en el enfoque para entregar una nueva aplicación. Sólo había una solución: si era posible, transferir todo a Linux. Google me ayudó: en ese momento .Net ya había sido portado a Linux y me di cuenta de que esta era la solución.

¿Por qué .NET Core junto con Linux?

Hubieron varias razones para esto. Entre “pagar dinero” y “no pagar”, la mayoría elegirá la segunda opción, como yo. Una licencia para MSDB cuesta alrededor de 1 dólares; mantener una flota de máquinas virtuales Windows cuesta cientos de dólares. Para una gran empresa esto supone un gran gasto. Es por eso ahorros - primera razón. No el más importante, pero sí uno de los más significativos.

Las máquinas virtuales de Windows consumen más recursos que sus hermanos de Linux. son pesadas. Dada la escala de la gran empresa, elegimos Linux.

El sistema se integra simplemente en la CI existente. Nos consideramos DevOps progresivos, utilizamos Bamboo, Jenkins y GitLab CI, por lo que la mayor parte de nuestro trabajo se ejecuta en Linux.

La última razón es acompañamiento conveniente. Necesitábamos reducir la barrera de entrada para los “acompañantes”, los muchachos que entienden la parte técnica, garantizan un servicio ininterrumpido y mantienen los servicios desde la segunda línea. Ya estaban familiarizados con la pila de Linux, por lo que les resulta mucho más fácil comprender, respaldar y mantener un nuevo producto que gastar recursos adicionales para comprender la misma funcionalidad del software para la plataforma Windows.

Requisitos

Primero y ante todo - conveniencia de la nueva solución para desarrolladores. No todos estaban preparados para el cambio, especialmente después de que se pronunció la palabra Linux. Los desarrolladores quieren su Visual Studio favorito, TFS con pruebas automáticas para ensamblajes y batidos. Para ellos no es importante cómo se produce la entrega a producción. Por lo tanto, decidimos no cambiar el proceso habitual y dejar todo sin cambios para el desarrollo de Windows.

Se necesita un nuevo proyecto integrarse en la CI existente. Los raíles ya estaban allí y todo el trabajo debía realizarse teniendo en cuenta los parámetros del sistema de gestión de configuración, los estándares de entrega aceptados y los sistemas de seguimiento.

Facilidad de soporte y operación., como condición para el umbral mínimo de entrada para todos los nuevos participantes de diferentes divisiones y el departamento de soporte.

Fecha límite - ayer.

Ganar grupo de desarrollo

¿Con qué estaba trabajando el equipo de Windows entonces?

.NET Core en Linux, DevOps a caballo

Ahora puedo decir con seguridad que Servidor de identidad4 es una excelente alternativa gratuita a ADFS con capacidades similares, o qué Núcleo del marco de la entidad - un paraíso para un desarrollador, donde no tiene que molestarse en escribir scripts SQL, sino describir consultas en la base de datos en términos de programación orientada a objetos. Pero luego, durante la discusión del plan de acción, miré esta pila como si fuera escritura cuneiforme sumeria, reconociendo solo PostgreSQL y Git.

En ese momento estábamos usando activamente Marioneta como sistema de gestión de configuración. En la mayoría de nuestros proyectos utilizamos CI de GitLab, ElásticoServicios equilibrados de alta carga utilizando HAProxy supervisó todo con Zabbix, ligamentos Grafana и Prometeo, Jaeger, y todo esto giraba sobre pedazos de hierro HPESXi en VMware. Todo el mundo lo sabe: un clásico del género.

.NET Core en Linux, DevOps a caballo

Miremos y tratemos de entender qué pasó antes de comenzar todas estas intervenciones.

Que era

TFS es un sistema bastante potente que no sólo entrega código desde el desarrollador a la máquina de producción final, sino que también tiene un conjunto para una integración muy flexible con varios servicios, para proporcionar CI a nivel multiplataforma.

.NET Core en Linux, DevOps a caballo
Anteriormente, eran ventanas macizas. TFS utilizó varios agentes de compilación, que se utilizaron para ensamblar muchos proyectos. Cada agente cuenta con 3-4 trabajadores para paralelizar tareas y optimizar el proceso. Luego, de acuerdo con los planes de lanzamiento, TFS entregó la compilación recién horneada al servidor de aplicaciones de Windows.

¿Qué queríamos lograr?

Usamos TFS para la entrega y el desarrollo, ejecutamos la aplicación en un servidor de aplicaciones Linux y existe una especie de magia entre ellos. Este caja Magica y ahí está la sal del trabajo por delante. Antes de desarmarlo, daré un paso a un lado y diré algunas palabras sobre la aplicación.

proyecto

La aplicación proporciona funcionalidad para el manejo de tarjetas prepago.

.NET Core en Linux, DevOps a caballo

Cliente

Había dos tipos de usuarios. primero obtuvo acceso iniciando sesión con un certificado SSL SHA-2. Ud. segundo se accedía mediante nombre de usuario y contraseña.

HAProxy

Luego la solicitud del cliente fue a HAProxy, que resolvió los siguientes problemas:

  • autorización primaria;
  • terminación SSL;
  • ajustar solicitudes HTTP;
  • solicitudes de transmisión.

El certificado del cliente fue verificado a lo largo de la cadena. Nosotros - autoridad Y podemos permitírnoslo, ya que nosotros mismos emitimos certificados a los clientes de servicios.

Presta atención al tercer punto, volveremos sobre él un poco más tarde.

Backend

Planeaban hacer el backend en Linux. El backend interactúa con la base de datos, carga la lista necesaria de privilegios y luego, dependiendo de los privilegios que tenga el usuario autorizado, proporciona acceso para firmar documentos financieros y enviarlos para su ejecución, o generar algún tipo de informe.

Ahorros con HAProxy

Además de los dos contextos por los que navegó cada cliente, también había un contexto de identidad. Servidor de identidad4 solo le permite iniciar sesión, este es un análogo gratuito y poderoso para ADFS - Servicios de federación de Active Directory.

La solicitud de identidad se procesó en varios pasos. Primer paso - cliente entró en el backend, que se comunicó con este servidor y verificó la presencia de un token para el cliente. Si no se encontraba, la solicitud se devolvía al contexto de donde procedía, pero con una redirección, y con la redirección se pasaba a identidad.

Segundo paso: se recibió la solicitud a la página de autorización en IdentityServer, donde se registró el cliente y ese token tan esperado apareció en la base de datos de IdentityServer.

Tercer paso - el cliente fue redirigido de regreso al contexto del que procede.

.NET Core en Linux, DevOps a caballo

IdentityServer4 tiene una característica: devuelve la respuesta a la solicitud de devolución a través de HTTP. No importa cuánto luchamos con la configuración del servidor, no importa cuánto nos ilustramos con la documentación, cada vez recibimos una solicitud inicial de un cliente con una URL que venía a través de HTTPS, y IdentityServer devolvía el mismo contexto, pero con HTTP. ¡Nos quedamos impactados! Y todo esto lo transferimos a través del contexto de identidad a HAProxy, y en los encabezados tuvimos que modificar el protocolo HTTP a HTTPS.

¿Cuál es la mejora y dónde ahorraste?

Ahorramos dinero al usar una solución gratuita para autorizar un grupo de usuarios y recursos, ya que no colocamos IdentityServer4 como un nodo separado en un segmento separado, sino que lo usamos junto con el backend en el mismo servidor donde se ejecuta el backend de la aplicación. .

¿Cómo debería funcionar?

Entonces, como prometí: Magic Box. Ya entendemos que tenemos la garantía de avanzar hacia Linux. Formulemos tareas específicas que requirieron soluciones.

.NET Core en Linux, DevOps a caballo

Manifestaciones de títeres. Para ofrecer y gestionar la configuración de servicios y aplicaciones, era necesario escribir recetas interesantes. Un rollo de lápiz muestra elocuentemente la rapidez y eficacia con la que se hizo.

Método de entrega. El estándar son RPM. Todo el mundo entiende que en Linux no se puede prescindir de él, pero el proyecto en sí, después del montaje, era un conjunto de archivos DLL ejecutables. Eran unos 150, el proyecto fue bastante difícil. La única solución armoniosa es empaquetar este binario en RPM e implementar la aplicación desde allí.

Versionado. Tuvimos que publicar muy a menudo y tuvimos que decidir cómo formar el nombre del paquete. Esta es una cuestión del nivel de integración con TFS. Teníamos un agente de compilación en Linux. Cuando TFS envía una tarea a un controlador (trabajador) al agente de compilación, también le pasa un montón de variables que terminan en el entorno del proceso del controlador. Estas variables de entorno contienen el nombre de la compilación, el nombre de la versión y otras variables. Lea más sobre esto en la sección "Creación de un paquete RPM".

Configurando TFS todo se redujo a configurar Pipeline. Anteriormente, recopilamos todos los proyectos de Windows en agentes de Windows, pero ahora aparece un agente de Linux: un agente de compilación, que debe incluirse en el grupo de compilación, enriquecerse con algunos artefactos e indicar qué tipo de proyectos se crearán en este agente de compilación. y modificar de alguna manera el Pipeline.

Servidor de identidad. ADFS no es nuestro camino, vamos por el Código Abierto.

Repasemos los componentes.

caja Magica

Consta de cuatro partes.

.NET Core en Linux, DevOps a caballo

Agente de compilación de Linux. Linux, porque construimos para él, es lógico. Esta parte se realizó en tres pasos.

  • Configurar trabajadores y no solo, ya que se esperaba un trabajo distribuido en el proyecto.
  • Instalar .NET Core 1.x. ¿Por qué 1.x cuando 2.0 ya está disponible en el repositorio estándar? Porque cuando empezamos el desarrollo, la versión estable era la 1.09 y se decidió hacer el proyecto en base a ella.
  • Git 2.x.

Repositorio RPM. Los paquetes RPM debían almacenarse en algún lugar. Se supuso que usaríamos el mismo repositorio RPM corporativo que está disponible para todos los hosts Linux. Eso es lo que hicieron. El servidor del repositorio está configurado. webhook que descargó el paquete RPM requerido desde la ubicación especificada. El agente de compilación informó la versión del paquete al webhook.

GitLab. ¡Atención! Aquí, GitLab no lo utilizan los desarrolladores, sino el departamento de operaciones para controlar las versiones de las aplicaciones, las versiones de los paquetes, monitorear el estado de todas las máquinas Linux y almacena la receta: todos los manifiestos de Puppet.

Marioneta — resuelve todos los problemas controvertidos y ofrece exactamente la configuración que queremos de Gitlab.

Empezamos a bucear. ¿Cómo funciona la entrega de DLL a RPM?

Entrega DDL a RPM

Digamos que tenemos una estrella del desarrollo .NET. Utiliza Visual Studio y crea una rama de lanzamiento. Después de eso, lo sube a Git, y aquí Git es una entidad TFS, es decir, es el repositorio de aplicaciones con el que trabaja el desarrollador.

.NET Core en Linux, DevOps a caballo

Después de lo cual TFS ve que ha llegado una nueva confirmación. ¿Qué aplicación? En la configuración de TFS hay una etiqueta que indica qué recursos tiene un agente de compilación en particular. En este caso, ve que estamos creando un proyecto .NET Core y selecciona un agente de compilación de Linux del grupo.

El agente de compilación recibe las fuentes y descarga los necesarios. dependencias desde el repositorio .NET, npm, etc. y después de construir la aplicación en sí y el posterior empaquetado, envía el paquete RPM al repositorio de RPM.

Por otro lado, sucede lo siguiente. El ingeniero del departamento de operaciones participa directamente en la implementación del proyecto: cambia las versiones de los paquetes en ayer en el repositorio donde se almacena la receta de la aplicación, después de lo cual Puppet activa Yum, recupera el nuevo paquete del repositorio y la nueva versión de la aplicación está lista para usarse.

.NET Core en Linux, DevOps a caballo

Todo es simple en palabras, pero ¿qué sucede dentro del propio agente Build?

Empaquetado DLL RPM

Recibí fuentes de proyecto y tarea de compilación de TFS. Agente de construcción comienza a construir el proyecto en sí a partir de fuentes. El proyecto ensamblado está disponible como un conjunto. archivos DLL, que están empaquetados en un archivo zip para reducir la carga en el sistema de archivos.

El archivo ZIP se desecha al directorio de compilación del paquete RPM. A continuación, el script Bash inicializa las variables de entorno, busca la versión de compilación, la versión del proyecto, la ruta al directorio de compilación y ejecuta RPM-build. Una vez que se completa la compilación, el paquete se publica en repositorio local, que se encuentra en el agente de compilación.

A continuación, desde el agente de compilación al servidor en el repositorio RPM. Se envía la solicitud JSON indicando el nombre de la versión y build. Webhook, del que hablé anteriormente, descarga este mismo paquete desde el repositorio local en el agente de compilación y hace que el nuevo ensamblado esté disponible para su instalación.

.NET Core en Linux, DevOps a caballo

¿Por qué este esquema particular de entrega de paquetes al repositorio RPM? ¿Por qué no puedo enviar inmediatamente el paquete ensamblado al repositorio? El hecho es que esta es una condición para garantizar la seguridad. Este escenario limita la posibilidad de que personas no autorizadas carguen paquetes RPM en un servidor al que pueden acceder todas las máquinas Linux.

Versionado de bases de datos

En una consulta con el equipo de desarrollo, resultó que los muchachos estaban más cerca de MS SQL, pero en la mayoría de los proyectos que no eran de Windows ya usábamos PostgreSQL con todas nuestras fuerzas. Como ya habíamos decidido abandonar todo lo pago, comenzamos a utilizar PostgreSQL aquí también.

.NET Core en Linux, DevOps a caballo

En esta parte quiero contarles cómo versionamos la base de datos y cómo elegimos entre Flyway y Entity Framework Core. Veamos sus pros y sus contras.

Contras

Flyway solo va en una dirección, nosotros no podemos retroceder - Esta es una desventaja significativa. Puede compararlo con Entity Framework Core de otras formas: en términos de comodidad para el desarrollador. Recuerde que pusimos esto en primer plano y el criterio principal era no cambiar nada para el desarrollo de Windows.

Para Flyway nosotros se necesitaba algún tipo de envoltoriopara que los chicos no escriban Consultas SQL. Están mucho más cerca de operar en términos de programación orientada a objetos. Escribimos instrucciones para trabajar con objetos de bases de datos, generamos una consulta SQL y la ejecutamos. La nueva versión de la base de datos está lista, probada: todo está bien, todo funciona.

Entity Framework Core tiene un inconveniente: bajo cargas pesadas construye consultas SQL subóptimas, y la reducción de la base de datos puede ser significativa. Pero como no tenemos un servicio de alta carga, no calculamos la carga en cientos de RPS, aceptamos estos riesgos y delegamos el problema en nosotros.

Pros

Núcleo del marco de la entidad funciona de inmediato y es fácil de desarrollary ruta migratoria Se integra fácilmente a la CI existente. Pero lo hacemos conveniente para los desarrolladores :)

Procedimiento de acumulación

Puppet ve que se avecina un cambio en la versión del paquete, incluida la que es responsable de la migración. Primero, instala un paquete que contiene scripts de migración y funciones relacionadas con la base de datos. Luego de esto se reinicia la aplicación que trabaja con la base de datos. Luego viene la instalación de los componentes restantes. El orden en el que se instalan los paquetes y se inician las aplicaciones se describe en el manifiesto de Puppet.

Las aplicaciones utilizan datos confidenciales, como tokens, contraseñas de bases de datos, todo esto se ingresa en la configuración de Puppet master, donde se almacenan en forma cifrada.

problemas de TFS

Después de que decidimos y nos dimos cuenta de que todo realmente funcionaba para nosotros, decidí observar lo que estaba sucediendo con los ensamblados en TFS en su conjunto para el departamento de desarrollo de Win en otros proyectos, ya sea que estuviéramos construyendo/lanzando rápidamente o no, y Descubrió problemas importantes con la velocidad.

Uno de los proyectos principales tarda entre 12 y 15 minutos en montarse; eso es mucho tiempo, no se puede vivir así. Un análisis rápido mostró una terrible reducción en la E/S, y esto se produjo en los arreglos.

Después de analizarlo componente por componente, identifiqué tres focos. Primero - "Antivirus Kaspersky", que escanea fuentes en todos los agentes de compilación de Windows. Segundo - Windows Indexador. No se deshabilitó y todo se indexó en tiempo real en los agentes de compilación durante el proceso de implementación.

Tercero - Instalación NPM. Resultó que en la mayoría de los Pipelines utilizamos este escenario exacto. ¿Por qué es malo? El procedimiento de instalación de Npm se ejecuta cuando se forma el árbol de dependencias en Paquete-lock.json, donde se registran las versiones de los paquetes que se utilizarán para construir el proyecto. La desventaja es que Npm install obtiene las últimas versiones de los paquetes de Internet cada vez, y esto lleva mucho tiempo en el caso de un proyecto grande.

A veces, los desarrolladores experimentan en una máquina local para probar cómo funciona una parte particular o un proyecto completo. A veces resultó que todo estaba bien localmente, pero lo ensamblaron, lo desplegaron y nada funcionó. Comenzamos a descubrir cuál es el problema: sí, diferentes versiones de paquetes con dependencias.

Solución

  • Fuentes en excepciones AV.
  • Deshabilitar la indexación.
  • Transición a npmci.

Las ventajas de npm ci son que Recopilamos el árbol de dependencia una vez., y tenemos la oportunidad de proporcionar al desarrollador lista actual de paquetes, con el que podrá experimentar localmente todo lo que quiera. Este ahorra tiempo desarrolladores que escriben código.

Configuración

Ahora un poco sobre la configuración del repositorio. Históricamente utilizamos Nexus para gestionar repositorios, incluyendo REPO interno. Este repositorio interno contiene todos los componentes que utilizamos para fines internos, por ejemplo, seguimiento escrito por nosotros mismos.

.NET Core en Linux, DevOps a caballo

También usamos NuGet, ya que tiene un mejor almacenamiento en caché en comparación con otros administradores de paquetes.

resultado

Después de optimizar los agentes de compilación, el tiempo promedio de compilación se redujo de 12 minutos a 7.

Si contamos todas las máquinas que podríamos haber usado para Windows, pero cambiamos a Linux en este proyecto, ahorramos alrededor de $10 000. Y eso es sólo en licencias, y más si tomamos en cuenta el contenido.

Planes

Para el próximo trimestre, planeamos trabajar para optimizar la entrega de código.

Cambiar a una imagen de Docker precompilada. TFS es algo interesante con muchos complementos que le permiten integrarse en Pipeline, incluido el ensamblaje basado en disparadores de, por ejemplo, una imagen de Docker. Queremos hacer este disparador para el mismo. Paquete-lock.json. Si la composición de los componentes utilizados para construir el proyecto cambia de alguna manera, creamos una nueva imagen de Docker. Posteriormente se utiliza para implementar el contenedor con la aplicación ensamblada. Este no es el caso ahora, pero estamos planeando cambiar a una arquitectura de microservicio en Kubernetes, que se está desarrollando activamente en nuestra empresa y ha estado sirviendo soluciones de producción durante mucho tiempo.

Resumen

Animo a todo el mundo a tirar Windows, pero no es porque no sepa cocinarlo. La razón es que la mayoría de las soluciones de código abierto son Pila de Linux. Estás bien ahorrar en recursos. En mi opinión, el futuro pertenece a las soluciones Open Source en Linux con una comunidad poderosa.

Perfil del orador de Alexander Sinchinov en GitHub.

Conferencia de DevOps es una conferencia sobre la integración de procesos de desarrollo, pruebas y operación para profesionales por profesionales. ¿Por eso el proyecto del que habló Alexander? implementado y funcionando, y el día de la actuación hubo dos lanzamientos exitosos. En Conferencia de DevOps en RIT++ Los días 27 y 28 de mayo habrá aún más casos similares por parte de practicantes. Aún puedes saltar al último vagón y Envíe un informe o tómate tu tiempo reservar boleto. ¡Encuéntranos en Skolkovo!

Fuente: habr.com

Añadir un comentario