GitLab CI: 6 características de los últimos lanzamientos que hemos estado esperando



En la era del CI / CD omnipresente, nos enfrentamos a una amplia gama de herramientas relacionadas, incluidos los sistemas de CI. Sin embargo, fue GitLab el que se convirtió en el más cercano para nosotros, verdaderamente "nativo". Ganó notable popularidad en la industria en general *. Los desarrolladores del producto no se quedaron atrás del creciente interés en su uso, deleitando regularmente a la comunidad de desarrolladores e ingenieros de DevOps con nuevas versiones.


Mes del repositorio de GitLab y agregación de etiquetas

GitLab es el caso cuando el desarrollo activo trae muchas características nuevas e interesantes. Si para los usuarios potenciales este es solo uno de los factores para elegir una herramienta, para los existentes, la situación es la siguiente: si no ha actualizado su instalación de GitLab en el último mes, entonces con una alta probabilidad de que haya perdido algo interesante. Incluyendo regularmente actualizaciones de seguridad emergentes.

Sobre lo más significativo, es decir exigido por nuestros ingenieros y clientes de DevOps: innovaciones en los últimos lanzamientos de la edición comunitaria de GitLab, y se discutirá este artículo.

* 5 , «GitLab», : «, GitHub?». — , Google Trends 5- «gitlab» . «» , . , , «» .

№1: needs


  • job'.
  • GitLab: 12.2.
  • .

Pensamiento dependencies: ¿esto es lo que necesitas? Probablemente, no fuimos los únicos que cometimos el error de asignar esta directiva ... Es necesario enumerar los trabajos anteriores, cuyos artefactos serán necesarios. Son artefactos, y no dependencia del desempeño de la tarea anterior.

Suponga que sucedió que en una etapa hay trabajos que no es necesario realizar, pero por alguna razón no existe la posibilidad o solo el deseo de llevarlos a una etapa separada (la pereza es el motor del progreso, pero no se deje llevar).

Situación:



como puede ver, Stage Deploy contiene botones para desplegar tanto la producción como la etapa, y las pruebas de trabajo Seleniumpor alguna razón no se ejecuta. Es simple: espera hasta que todos los trabajos de la etapa anterior se completen con éxito. Sin embargo, en el marco de la misma tubería, no necesitamos desplegar la etapa ahora para ejecutar las pruebas (se bombeó antes, no dentro de la etiqueta). ¿Qué hacer? Entonces ven a las necesidades de rescate !

Enumeramos solo los trabajos previos necesarios para ejecutar nuestras pruebas:

  needs:
    - To production (Cluster 1)
    - To production (Cluster 2)

... y obtenemos un trabajo, que se llama automáticamente después de que solo se ejecuten los trabajos enumerados:



Convenientemente, ¿verdad? Pero una vez que esperaba que la directiva funcionara algo así dependencies...

No. 2: se extiende



¿Cansado de leer rollos .gitlab-ci.yaml? ¿Falta el principio de reutilización del código? Entonces ya lo has intentado y probablemente has llevado el tuyo .gitlab-ci.yamla un estado como este:

.base_deploy: &base_deploy
  stage: deploy
  script:
    - my_deploy_command.sh
  variables:
    CLUSTER: "default-cluster"
    MY_VAR: "10"

Deploy Test:
  <<: *base_deploy
  environment:
    url: test.example.com
    name: test

Deploy Production:
  <<: *base_deploy
  environment:
    url: production.example.com
    name: production
  variables:
    CLUSTER: "prod-cluster"
    MY_VAR: "10"

¿Suena genial? Sin embargo, si miras de cerca, algo te llama la atención ... ¿Por qué cambiamos en la producción no solo variables.CLUSTER, sino también prescrita por segunda vez variables.MY_VAR=10? ¿Debería tomarse esta variable base_deploy? Resulta que no debería: YAML funciona de modo que, al redefinir lo que se recibe del ancla, no expande el contenido de los campos coincidentes, sino que lo reemplaza . Por lo tanto, nos vemos obligados a enumerar las variables que ya conocemos en el párrafo correspondiente.

Sí, "expande" es la palabra correcta: esto es exactamente como se llama la característica en cuestión. ExtendsNos permiten no solo reescribir el campo, como sucede con el ancla, sino llevar a cabo una fusión inteligente:

.base_deploy: 
  stage: deploy
  script:
    - my_deploy_command.sh
  variables:
    CLUSTER: "default-cluster"
    MY_VAR: "10"

Deploy Production:
  extends: .base_deploy
  environment:
    url: production.example.com
    name: production
  variables:
    CLUSTER: "prod-cluster"

Aquí, en el trabajo final Implementar producción , habrá una variable MY_VARcon un valor predeterminado y una anulada CLUSTER.

Parece que esto es un poco insignificante, pero imagina: tienes uno base_deployy 20 circuitos desplegados de manera similar. Deben transmitirse a otros cluster, al environment.nametiempo que conservan un cierto conjunto de variables u otros campos coincidentes ... Este pequeño placer nos permitió reducir la descripción del despliegue de muchos circuitos de desarrollo en 2-3 veces.

No. 3: incluir



.gitlab-ci.yamltodavía parece una instrucción de plegado para una aspiradora en 20 idiomas (de los cuales solo entiende el nativo), ¿es difícil cuando necesita lidiar con una de sus secciones sin cambiar frente a los trabajos desconocidos que se encuentran en el camino?

Un amigo de programación desde hace mucho tiempo ayudará a include:

stages:
  - test
  - build
  - deploy

variables:
  VAR_FOR_ALL: 42

include:
  - local: .gitlab/ci/test.yml
  - local: .gitlab/ci/build.yml
  - local: .gitlab/ci/deploy-base.yml
  - local: .gitlab/ci/deploy-production.yml

Aquellos. Ahora estamos editando audazmente la implementación en producción, mientras que los probadores están ocupados modificando su archivo, lo que ni siquiera podemos mirar. Además, esto ayuda a evitar conflictos de fusión: no siempre es divertido entender el código de otra persona.

Pero, ¿qué sucede si conocemos el flujo de nuestros 20 proyectos a lo largo y ancho, podemos explicar la lógica de cada trabajo a partir de él? ¿Cómo nos ayudará esto? Para aquellos que han logrado la iluminación en la reutilización de código y para todos los que tienen muchos proyectos similares, puede:


Una docena del mismo tipo de proyectos con código diferente, pero implementados de la misma manera, ¡fácilmente y sin mantener un CI actualizado en todos los repositorios!

También se dio un ejemplo de uso práctico includeen este artículo .

No. 4: solo / excepto referencias


  • Condiciones integrales, incluidas variables y cambios de archivos.
  • Dado que esta es una familia completa de funciones, algunas partes comenzaron a aparecer en GitLab 10.0, mientras que otras (por ejemplo changes) comenzaron a aparecer en 11.4.
  • docs.gitlab.com/ce/ci/yaml/#onlyexcept-advanced

A veces me parece que esto no es una tubería que nos escucha, sino nosotros. Una excelente herramienta de gestión está only/ except- ahora integrada. ¿Qué significa esto?

En el caso más simple (y quizás el más agradable), saltear etapas:

Tests:
  only:
    - master
  except:
    refs:
    - schedules
    - triggers
    variables:
    - $CI_COMMIT_MESSAGE =~ /skip tests/

En el trabajo de ejemplo, solo se ejecuta en la rama maestra, pero no puede activarse mediante una programación o un activador (GitLab comparte llamadas y activadores de API, aunque esta es esencialmente la misma API). El trabajo no se ejecutará si hay una frase de contraseña de prueba de omisión en el mensaje de confirmación . Por ejemplo, README.mdse ha corregido un error tipográfico en el proyecto o la documentación: ¿por qué esperar los resultados de la prueba?

"¡Oye, 2020 está afuera!" ¿Por qué debería cada vez explicarle a la caja de hierro que no es necesario ejecutar pruebas al cambiar la documentación? Y realmente: only:changesle permite ejecutar pruebas al cambiar archivos solo en ciertos directorios. Por ejemplo:

  only:
    refs:
      - master
      - merge_requests
    changes:
      - "front/**/*"
      - "jest.config.js"
      - "package.json"

Y para la acción inversa, es decir No corras, sí except:changes.

No. 5: reglas



Esta directiva es muy similar a las anteriores only:*, pero con una diferencia importante: le permite controlar el parámetro when. Por ejemplo, si no desea eliminar por completo la posibilidad de comenzar un trabajo. Simplemente puede dejar el botón, que, si lo desea, se llamará de forma independiente, sin iniciar una nueva tubería o sin realizar una confirmación.

# 6: entorno: auto_stop_in



Aprendimos sobre esta oportunidad justo antes de la publicación del artículo y aún no hemos tenido tiempo suficiente para probarla en la práctica, pero esto es definitivamente "lo mismo" que se esperaba en varios proyectos.

Puede especificar un parámetro en entornos GitLab on_stop; es muy útil cuando desea crear y eliminar entornos dinámicamente, por ejemplo, para cada rama. El trabajo marcado con k on_stopse ejecuta, por ejemplo, cuando la fusión de MR está en la rama maestra o cuando se cierra MR (o incluso haciendo clic en el botón), por lo que el entorno innecesario se elimina automáticamente.

Todo es conveniente, lógico, funciona ... si no fuera por el factor humano. Muchos desarrolladores fusionan MR no haciendo clic en un botón en GitLab, sino localmente a través de git merge. Puedes entenderlos: ¡es conveniente! Pero en este caso, la lógicaon_stopno funciona, hemos acumulado un entorno olvidado ... Aquí es donde los tan esperados son útiles auto_stop_in.

Bonificación: cabañas temporales cuando no hay suficientes oportunidades


A pesar de todas estas (y muchas otras) funciones nuevas y demandadas de GitLab, desafortunadamente, a veces las condiciones para realizar un trabajo son simplemente imposibles de describir en el marco de las capacidades disponibles actualmente.

GitLab no es perfecto, pero proporciona las herramientas básicas para construir una tubería de ensueño ... si está listo para ir más allá del modesto DSL al sumergirse en el mundo de las secuencias de comandos. Aquí hay algunas soluciones de nuestra experiencia, que de ninguna manera pretenden ser ideológicamente correctas o recomendadas, sino que se presentan más para demostrar diferentes posibilidades con una falta de funcionalidad API incorporada.

Solución n. ° 1: inicie dos trabajos con un botón


script:
  - > 
    export CI_PROD_CL1_JOB_ID=`curl -s -H "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \ 
      "https://gitlab.domain/api/v4/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs" | \
      jq '[.[] | select(.name == "Deploy (Cluster 1)")][0] | .id'`
  - > 
    export CI_PROD_CL2_JOB_ID=`curl -s -H "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \ 
      "https://gitlab.domain/api/v4/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs" | \
      jq '[.[] | select(.name == "Deploy (Cluster 2)")][0] | .id'`
  - > 
    curl -s --request POST -H "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \ 
      "https://gitlab.domain/api/v4/projects/${CI_PROJECT_ID}/jobs/$CI_PROD_CL1_JOB_ID/play"
  - > 
    curl -s --request POST -H "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \ 
      "https://gitlab.domain/api/v4/projects/${CI_PROJECT_ID}/jobs/$CI_PROD_CL2_JOB_ID/play"

¿Y por qué no, si realmente quieres?

Solución n. ° 2: transferencia modificada en archivos MR rb para rubocop dentro de la imagen


Rubocop:
  stage: test
  allow_failure: false
  script:
    ...
    - export VARFILE=$(mktemp)
    - export MASTERCOMMIT=$(git merge-base origin/master HEAD)
    - echo -ne 'CHANGED_FILES=' > ${VARFILE}
    - if [ $(git --no-pager diff --name-only ${MASTERCOMMIT} | grep '.rb$' | wc -w |awk '{print $1}') -gt 0 ]; then
        git --no-pager diff --name-only ${MASTERCOMMIT} | grep '.rb$' |tr '\n' ' ' >> ${VARFILE} ;
      fi
    - if [ $(wc -w ${VARFILE} | awk '{print $1}') -gt 1 ]; then
        werf --stages-storage :local run rails-dev --docker-options="--rm --user app --env-file=${VARFILE}" -- bash -c /scripts/rubocop.sh ;
      fi
    - rm ${VARFILE}

No hay imagen adentro .git, así que tuve que salir para verificar solo los archivos modificados.

Nota: Esta no es una situación muy estándar y un intento desesperado de cumplir con muchas condiciones del problema, cuya descripción no está incluida en el alcance de este artículo.

Solución # 3: activador para iniciar trabajos desde otros repositorios cuando se implementa


  before_script:
    - |
      echo '### Trigger review: infra'
      curl -s -X POST \
        -F "token=$REVIEW_TOKEN_INFRA" \
        -F "ref=master" \
        -F "variables[REVIEW_NS]=$CI_ENVIRONMENT_SLUG" \
        -F "variables[ACTION]=auto_review_start" \
        https://gitlab.example.com/api/v4/projects/${INFRA_PROJECT_ID}/trigger/pipeline

Parece que una cosa tan simple y necesaria (en el mundo de los microservicios) está implementando otro microservicio en un circuito recién creado como una dependencia. Pero no es, por lo tanto, una llamada API y una característica ya familiar (descrita anteriormente) son necesarias:

  only:
    refs:
    - triggers
    variables:
    - $ACTION == "auto_review_start"

Notas:

  • Job on trigger está diseñado para estar vinculado a pasar una variable a la API, de manera similar al ejemplo No. 1. Es más lógico implementar esto en la API con el nombre del trabajo pasado.
  • Sí, la función está en la versión comercial (EE) de GitLab, pero no la consideramos.

Conclusión


GitLab intenta mantenerse al día con las tendencias, implementando gradualmente características que son agradables y demandadas por la comunidad DevOps. Son bastante fáciles de usar, y cuando las capacidades básicas no son suficientes, siempre se pueden ampliar con scripts. Y si vemos que resulta no tan elegante y convenientemente como soporte ... queda esperar los nuevos lanzamientos de GitLab, o ayudar al proyecto con nuestra contribución .

PD


Lea también en nuestro blog:


All Articles