Hi!
Mi nombre es Sergey, trabajo como ingeniero de infraestructura en el equipo API de la plataforma tinkoff.ru.
En este artículo hablaré de los problemas que enfrentó nuestro equipo al preparar balanceadores basados en Nginx para diversos proyectos. También te hablaré de la herramienta que me permitió superar la mayoría de ellos.
Nginx es un servidor proxy multifuncional y en desarrollo activo. Cuenta con una gran cantidad de módulos, Esta no es una lista completa. Cada proyecto impone ciertos requisitos sobre la funcionalidad del balanceador y la versión de Nginx (por ejemplo, la presencia de proxy http/2 y grpc) y la composición de sus módulos.
Nos gustaría ver una versión nueva con el conjunto de módulos requerido, ejecutándose en una distribución de Linux específica. En nuestro caso, se trata de sistemas basados en deb y rpm. La opción con contenedores no se considera en este artículo.
Queremos cambiar rápidamente la funcionalidad de nuestros balanceadores. Y aquí surge inmediatamente la pregunta: ¿cómo lograrlo gastando la menor cantidad de recursos posible? Sería incluso mejor configurar el proceso para que podamos establecer un número finito de parámetros de entrada y, en la salida, recibir un artefacto en forma de un paquete deb/rpm para el sistema operativo deseado.
Como resultado, se pueden formular una serie de problemas:
No siempre hay paquetes con la última versión de Nginx.
No hay paquetes con los módulos requeridos.
Compilar y crear un paquete manualmente lleva mucho tiempo y es francamente tedioso.
No hay ninguna descripción de cómo se ensambla tal o cual instancia de Nginx.
Para resolver estos problemas, surge la necesidad de una herramienta que tome como entrada una especificación en un formato legible por humanos y ensamble un paquete Nginx con la funcionalidad necesaria basada en ella.
Al no encontrar una opción adecuada para nosotros en la inmensidad de Github, decidimos crear nuestra propia herramienta: constructor nginx.
Especificaciones
En nuestra herramienta, queríamos crear una descripción de la especificación en forma de código, que luego se pueda colocar en un repositorio de Git. Para hacer esto, elegimos el formato habitual para este tipo de cosas: yaml. Ejemplo de especificación:
Aquí indicamos que queremos ver un paquete deb con Nginx versión 1.14.2 con el conjunto de módulos requerido. La sección de módulos es opcional. Para cada uno de ellos puedes configurar:
Título.
Dirección donde conseguirlo:
Repositorio Git. También puede especificar una rama o etiqueta.
Enlace web de archivo.
Enlace local al archivo.
Algunos módulos requieren la instalación de dependencias adicionales, por ejemplo, nginx-auth-ldap requiere la instalación de libldap2-dev. Las dependencias necesarias también se pueden especificar al describir el módulo.
Medio ambiente
En nuestra herramienta puede obtener rápidamente un entorno con utilidades instaladas para compilación, ensamblaje de paquetes y otro software auxiliar. Un contenedor Docker con todo lo que necesitas es ideal aquí (el repositorio ya tiene un par de ejemplos de archivos Docker para ubuntu y centos).
Una vez redactada la especificación y preparado el entorno, lanzamos nuestro constructor, habiendo instalado previamente sus dependencias:
El número de revisión aquí es opcional y se utiliza para versiones de ensamblajes. Está escrito en la metainformación del paquete, lo que facilita su actualización en los servidores.
Desde los registros puedes monitorear lo que está sucediendo. A continuación se muestra un ejemplo de los puntos principales:
builder - INFO - Parse yaml file: example.config.yaml
builder - INFO - Download scripts for build deb package
builder - INFO - Downloading nginx src...
builder - INFO - --> http://nginx.org/download/nginx-1.14.1.tar.gz
builder - INFO - Downloading 3d-party modules...
builder - INFO - Module nginx-auth-ldap will download by branch
builder - INFO - -- Done: nginx-auth-ldap
builder - INFO - -- Done: ngx_http_substitutions_filter_module
builder - INFO - Module headers-more-nginx-module will downloading
builder - INFO - Module nginx-module-vts will download by tag
builder - INFO - -- Done: nginx-module-vts
builder - INFO - Module ngx_devel_kit will download by tag
builder - INFO - -- Done: ngx_devel_kit
builder - INFO - -- Done: ngx_cache_purge
builder - INFO - -- Done: ngx_http_dyups_module
builder - INFO - Downloading dependencies
builder - INFO - Building .deb package
builder - INFO - Running 'dh_make'...
builder - INFO - Running 'dpkg-buildpackage'...
dpkg-deb: building package 'nginx' in '../nginx_1.14.1-1_amd64.deb'.
Entonces, con solo un par de comandos, creamos el entorno y el ensamblado Nginx requerido, y el paquete aparece en el directorio desde donde se inicia el script.
incrustación
También podemos integrar nuestra herramienta en procesos de CI/CD. Cualquiera de los muchos sistemas de CI que existen hoy en día puede ayudar con esto, por ejemplo Ciudad del equipo o CI de Gitlab.
Como resultado, cada vez que cambia la especificación en el repositorio de Git, la compilación del artefacto se inicia automáticamente. El número de revisión está vinculado al contador de lanzamiento de compilación.
Con un poco más de tiempo, puede configurar el artefacto para que se envíe a su repositorio de paquetes local, Nexus, Artifactory, etc.
Una ventaja adicional es que el archivo de configuración yaml se puede conectar a Ansible u otro sistema de configuración automática, y de ahí podemos tomar el número de versión y el tipo de paquete que queremos implementar.
¿Qué sigue
El proyecto aún no está terminado. Esto es en lo que estamos trabajando ahora:
Ampliamos la posibilidad de configuración, pero al mismo tiempo la mantenemos lo más sencilla posible. No querrás definir mil parámetros si sólo necesitas dos y el resto encaja por defecto. Esto incluye indicadores de compilación (ahora puede cambiarlos en el archivo de configuración interno src/config.py), ruta de instalación y usuario de inicio.
Estamos agregando opciones para enviar automáticamente un paquete a varios repositorios de artefactos.