Consejos para crear flujos de trabajo personalizados en GitLab CI

Nota perev. : El artículo original fue escrito por Miłosz Smółka, uno de los fundadores de la pequeña empresa polaca Three Dots Labs , especializada en "soluciones avanzadas de backend". El autor se basa en su experiencia en el uso activo de GitLab CI y comparte los consejos acumulados para otros usuarios de este producto Open Source. Después de leerlos, nos dimos cuenta de lo cerca que están los problemas descritos por él, así que decidimos compartir las soluciones propuestas con un público más amplio.



Esta vez trataré temas más avanzados en GitLab CI. Una tarea común aquí es implementar características no estándar en la tubería. La mayoría de los consejos son específicos de GitLab, aunque algunos de ellos se pueden aplicar a otros sistemas de CI.

Ejecute pruebas de integración


Como regla general, la verificación de código mediante pruebas unitarias es fácil de conectar a cualquier sistema de CI. Por lo general, esto no es más complicado que ejecutar uno de los comandos integrados en el conjunto estándar de utilidades en un lenguaje de programación. En tales pruebas, es probable que use varios moki y stubs para ocultar los detalles de implementación y centrarse en probar la lógica específica. Por ejemplo, puede usar la base de datos en memoria como almacenamiento o apéndices de escritura para clientes HTTP que siempre devolverán respuestas ya preparadas.

Sin embargo, tarde o temprano necesitará pruebas de integración para cubrir situaciones más inusuales con pruebas. No entraré en discusión sobre todos los tipos posibles de pruebas y solo diré que por integración me refiero a las pruebas que usan algún tipo de recursos externos. Puede ser un servidor de base de datos real, servicio HTTP, almacenamiento conectado, etc.

En GitLab, es fácil ejecutar recursos conectables como contenedores Docker asociados con el contenedor donde se ejecutan los scripts. Estas dependencias se pueden definir utilizando services . Están disponibles por el nombre de la imagen o por el nombre que elija, si lo especifica en el campo de alias .

Aquí hay un ejemplo simple de uso de un contenedor conectable con MySQL:

 integration_tests: stage: tests services: - name: mysql:8 alias: db script: - ./run_tests.sh db:3306 

En este caso, en los scripts de prueba, deberá conectarse al host db . El uso de un alias suele ser una buena idea, ya que le permite reemplazar imágenes sin la necesidad de modificar el código de prueba. Por ejemplo, puede reemplazar la imagen mysql con mariadb , y el script seguirá funcionando correctamente.

Esperando contenedores


Como los contenedores de complementos tardan en cargarse, es posible que deba esperar antes de enviar cualquier solicitud. Una manera simple es esperar el script script for-it.sh con un tiempo de espera definido.

Usando Docker Compose


Para la mayoría de los casos, los services deberían ser suficientes. Sin embargo, a veces puede ser necesaria la interacción con servicios externos. Por ejemplo, en el caso de lanzar Kafka y ZooKeeper en dos contenedores separados (así es como se recopilan las imágenes oficiales). Otro ejemplo es ejecutar pruebas con un número dinámico de nodos, como Selenium. La mejor solución para ejecutar estos servicios sería Docker Compose :

 version: '3' services: zookeeper: image: confluentinc/cp-zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: image: confluentinc/cp-kafka environment: KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 ports: - 9092:9092 

Si usa su instalación con corredores GitLab en servidores confiables, puede ejecutar Docker Composer a través del ejecutor Shell . Otra opción posible es el dind Docker en Docker ( dind ). Pero en este caso, lea este artículo primero.

Una forma de usar Compose es configurar su entorno, ejecutar pruebas y luego destruir todo. Un script bash simple se vería así:

 docker-compose up -d ./run_tests.sh localhost:9092 docker-compose down 

Siempre que ejecute pruebas en un entorno mínimo, todo estará bien. Aunque puede surgir una situación en la que necesite instalar algunas dependencias ... Hay otra forma de ejecutar pruebas en Docker Compose: le permite crear su propia imagen de Docker con un entorno de prueba. En uno de los contenedores, ejecuta pruebas y sale con el código de retorno correspondiente:

 version: '3' services: zookeeper: image: confluentinc/cp-zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: image: confluentinc/cp-kafka environment: KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 tests: image: registry.example.com/some-image command: ./run_tests.sh kafka:9092 

Tenga en cuenta que hemos eliminado la necesidad de asignar puertos. En este ejemplo, las pruebas pueden interactuar con todos los servicios directamente.

Y su lanzamiento se lleva a cabo mediante un comando:

 docker-compose up --exit-code-from tests 

La --abort-on-container-exit --exit-code-from implica --abort-on-container-exit , lo que significa: todo el entorno iniciado por docker-compose up se detendrá una vez que se complete uno de los contenedores. El código de finalización para este comando será equivalente al código de salida del servicio seleccionado (es decir, estas son tests en el ejemplo anterior). Si el comando que inicia las pruebas se completa con un código distinto de cero, entonces todo docker-compose up saldrá con él.

Usar etiquetas como etiquetas CI


Advertencia : esta es una idea bastante inusual, pero me pareció muy útil y flexible.

Como ya sabrás, GitLab tiene una función de Etiquetas disponible a nivel de proyecto y grupo. Las etiquetas se pueden establecer en tickets y solicitudes de fusión. Sin embargo, no tienen relación con las tuberías.



Un pequeño refinamiento le permitirá acceder a las etiquetas de la solicitud de fusión en los scripts de trabajo. En GitLab 11.6, todo se ha vuelto aún más fácil, porque La variable de entorno CI_MERGE_REQUEST_IID ha aparecido (sí, es con el IID , no el ID ), si la canalización usa only: merge_requests .

Si only: merge_requests no se usa o si está trabajando con una versión anterior de GitLab, todavía se puede obtener MR, utilizando la llamada API:

 curl "$CI_API_V4_URL/projects/$CI_PROJECT_ID/repository/commits/$CI_COMMIT_SHA/merge_requests?private_token=$GITLAB_TOKEN" 

El campo que necesitamos es iid . Sin embargo, recuerde que muchos MR pueden regresar para un compromiso determinado.

Cuando se recibe el MR IID, solo queda recurrir a la API de solicitudes de combinación y usar el campo de labels de la respuesta:

 curl "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID?private_token=$GITLAB_TOKEN" 

Iniciar sesión


Desafortunadamente, por el momento no es posible usar $CI_JOB_TOKEN para acceder a la API del proyecto (al menos si el proyecto no es público). Si el proyecto tiene acceso limitado (interno o privado), para obtener autorización en la API de GitLab, deberá generar un token de API personal.



Sin embargo, esta no es la solución más segura, así que tenga cuidado. Si el token cae en malas manos, puede aparecer el acceso de escritura a todos sus proyectos. Una forma de reducir los riesgos es crear una cuenta separada con el derecho de leer el repositorio y generar un token personal para esta cuenta.

¿Qué tan seguras son sus variables?


Hace algunas versiones, la sección Variables se llamaba Variables secretas , que parece que fueron creadas para almacenar de forma confiable las credenciales y otra información crítica. De hecho, las variables simplemente están ocultas para los usuarios que no tienen privilegios de mantenedor. No están encriptados en el disco, y su fuga puede ocurrir fácilmente a través de variables de entorno en los scripts.

Tenga esto en cuenta al agregar cualquier variable y considere guardar secretos en soluciones más seguras (por ejemplo, Vault de HashiCorp ).

Casos de uso


Lo que debe hacer con las listas de etiquetas depende de usted. Aquí hay algunas ideas:

  • Úsalos para segmentar las pruebas.
  • Utilice la semántica de valores clave con dos puntos como separador (por ejemplo, etiquetas como tests:auth , tests:user )
  • Incluye ciertas características para trabajos.
  • Permita la depuración de trabajos específicos si existe la etiqueta.

Llamar a API externas


Aunque GitLab viene con una gama de características ya disponibles, es muy probable que desee utilizar otras utilidades que se puedan integrar con las canalizaciones. La forma más sencilla de implementarlo es, por supuesto, llamar al viejo curl .

Si crea sus propias herramientas, puede enseñarles a escuchar GitLab Webhooks (consulte la pestaña Integraciones en la configuración del proyecto). Sin embargo, si tiene la intención de usarlos con cualquier sistema crítico, asegúrese de que cumplan con los requisitos de alta disponibilidad.

Ejemplo: anotaciones de Grafana


Si trabaja con Grafana , las anotaciones son una excelente manera de marcar eventos que han ocurrido con el tiempo en los gráficos. Se pueden agregar no solo manualmente haciendo clic en la GUI, sino también llamando a la API REST de Grafana :



Para acceder a la API, deberá generar una clave de API. Considere crear un usuario separado con acceso limitado:



Defina dos variables en la configuración del proyecto:

  • GRAFANA_URL : URL de la instalación de Grafana (por ejemplo, https://grafana.example.com );
  • GRAFANA_APIKEY : clave generada para la API.

Para poder reutilizarlo, coloque el script en el repositorio con scripts comunes :

 #!/bin/bash set -e if [ $# -lt 2 ]; then echo "Usage: $0 <text> <tag>" exit 1 fi readonly text="$1" readonly tag="$2" readonly time="$(date +%s)000" cat >./payload.json <<EOF { "text": "$text", "tags": ["$tag"], "time": $time, "timeEnd": $time } EOF curl -X POST "$GRAFANA_URL/api/annotations" \ -H "Authorization: Bearer $GRAFANA_APIKEY" \ -H "content-type: application/json" \ -d @./payload.json 

Ahora puede agregar su llamada a la configuración de CI con los parámetros necesarios:

 deploy: stage: deploy script: - $SCRIPTS_DIR/deploy.sh production - $SCRIPTS_DIR/grafana-annotation.sh "$VERSION deployed to production" deploy-production 

Estas llamadas se pueden colocar en el script deploy.sh para simplificar la configuración de CI.

Bono: consejos rápidos


GitLab tiene una excelente documentación sobre todas las palabras clave posibles que se pueden usar para configurar CI. No quiero duplicar su contenido aquí, pero señalaré algunos casos útiles. Haga clic en los encabezados para ver la documentación relacionada.

Uso avanzado de solo / excepto


Al definir patrones para las variables de CI, puede definir ensamblados personalizados para algunas ramas. Esto puede ayudar, por ejemplo, a identificar soluciones push para soluciones urgentes, pero no abusar de ellas:

 only: refs: - branches variables: - $CI_COMMIT_REF_NAME =~ /^hotfix/ 

GitLab tiene muchas variables predefinidas en cada trabajo de CI: úselas.

Anclajes Yaml


Úsalos para evitar la duplicación.

Desde la versión 11.3, también puede usar la palabra clave extend :

 .common_before_script: &common_before_script before_script: - ... - ... deploy: <<: *common_before_script 

Exclusión de artefactos


De forma predeterminada, todos los artefactos recopilados en la tubería se transferirán a todos los trabajos posteriores. Si enumera explícitamente los artefactos de los que dependen los trabajos, puede ahorrar tiempo y espacio en disco:

 dependencies: - build 

O, por el contrario, omita todo por completo si no se requiere ninguno de ellos:

 dependencies: [] 

Estrategia Git


Omita la clonación del repositorio si el trabajo no usará estos archivos:

 variables: GIT_STRATEGY: none 

Eso es todo!

Gracias por leer! Para comentarios y preguntas, contácteme en Twitter o Reddit .

Se pueden encontrar más consejos de GitLab en publicaciones anteriores:


PD del traductor


Lea también en nuestro blog:

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


All Articles