GitLab CI: 6 fonctionnalités des dernières versions que nous attendions



À l'ère du CI / CD omniprésent, nous sommes confrontés à une large gamme d'outils connexes, y compris les systèmes CI. Cependant, c'est GitLab qui est devenu le plus proche pour nous, vraiment «natif». Il a gagné une popularité notable dans l'industrie dans son ensemble *. Les développeurs du produit n'ont pas été à la traîne de l'intérêt croissant pour son utilisation, ravissant régulièrement la communauté des développeurs et des ingénieurs DevOps avec de nouvelles versions.


Mois du référentiel GitLab et agrégation de balises

GitLab est le cas lorsque le développement actif apporte de nombreuses fonctionnalités nouvelles et intéressantes. Si pour les utilisateurs potentiels, ce n'est qu'un des facteurs de choix d'un outil, pour les outils existants, la situation est la suivante: si vous n'avez pas mis à jour votre installation GitLab au cours du dernier mois, alors avec une forte probabilité vous avez manqué quelque chose d'intéressant. Y compris les mises à jour de sécurité émergentes régulièrement.

À propos des plus importants - c.-à-d. demandés par nos ingénieurs et clients DevOps - innovations dans les dernières versions de l'édition communautaire de GitLab, et cet article sera discuté.

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

№1: needs


  • job'.
  • GitLab: 12.2.
  • .

Pensée dependencies- c'est ce dont vous avez besoin? Probablement, nous n'avons pas été les seuls à avoir fait l'erreur d'assigner cette directive ... Il faut lister les jobs précédents, dont les artefacts seront nécessaires. Il s'agit d'artefacts et non de dépendance à l'égard des performances de la tâche précédente.

Supposons qu'il se soit produit qu'à un moment donné, il y a des tâches qui ne sont pas nécessaires à exécuter, mais pour une raison quelconque, il n'y a aucune possibilité ou simplement le désir de les faire passer à un stade distinct (la paresse est le moteur du progrès, mais ne vous laissez pas emporter).

Situation:



comme vous pouvez le voir, stage Deploy contient des boutons permettant de déployer à la fois la production et la phase, ainsi que les tests Selenium de travailpour une raison quelconque n'est pas exécuté. C'est simple: il attend que tous les travaux de l'étape précédente soient terminés avec succès. Cependant, dans le cadre du même pipeline, nous n'avons pas besoin de déployer l'étape maintenant pour exécuter les tests (il a été pompé plus tôt, pas dans la balise). Que faire? Viennent ensuite les secours besoins !

Nous listons uniquement les travaux précédents nécessaires pour exécuter nos tests:

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

... et nous obtenons un travail, qui est automatiquement appelé après que seuls les travaux répertoriés sont exécutés: de manière



pratique, non? Mais une fois que je m'attendais à ce que la directive fonctionne quelque chose comme ça dependencies...

N ° 2: étend



Fatigué des rouleaux de lecture .gitlab-ci.yaml? Vous manquez le principe de réutilisation du code? Ensuite, vous avez déjà essayé et probablement réussi à amener le vôtre .gitlab-ci.yamldans un état comme celui-ci:

.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"

Super? Cependant, si vous regardez attentivement, quelque chose attire votre attention ... Pourquoi avons-nous changé de production non seulement variables.CLUSTER, mais aussi prescrit une deuxième fois variables.MY_VAR=10? Faut-il prendre cette variable base_deploy? Il s'avère que cela ne devrait pas: YAML fonctionne de sorte que, en redéfinissant ce qui est reçu de l'ancre, il n'élargisse pas le contenu des champs correspondants, mais le remplace . Par conséquent, nous sommes obligés de lister les variables que nous connaissons déjà dans le paragraphe correspondant.

Oui, «se développe» est le bon mot: c'est exactement ce que la fonction en question est appelée. ExtendsIls nous permettent non seulement de réécrire le champ, comme cela se produit avec l'ancre, mais de procéder à une fusion intelligente pour cela:

.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"

Ici, dans le travail final Déployer la production, il y aura à la fois une variable MY_VARavec une valeur par défaut et une valeur remplacée CLUSTER.

Il semble que ce soit une bagatelle, mais imaginez: vous avez un base_deployet 20 circuits déployés de manière similaire. Ils doivent être transmis à d'autres cluster, environment.nametout en conservant un certain ensemble de variables ou d'autres champs correspondants ... Cette petite douceur nous a permis de réduire la description du déploiement de nombreux circuits de développement de 2-3 fois.

N ° 3: inclure



.gitlab-ci.yamlcela ressemble toujours à une instruction de pliage pour un aspirateur en 20 langues (dont vous ne comprenez que votre langue maternelle). Est- ce difficile quand vous avez besoin de traiter une de ses sections sans changer face à des travaux inconnus rencontrés sur le chemin?

Un ami de longue date de la programmation vous aidera à 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

Ceux. Maintenant, nous modifions hardiment le déploiement en production, tandis que les testeurs sont occupés à modifier leur fichier, que nous ne verrons peut-être même pas. De plus, cela permet d'éviter les conflits de fusion: ce n'est pas toujours amusant de comprendre le code de quelqu'un d'autre.

Mais que se passe-t-il si nous connaissons le pipeline de nos 20 projets de part et d'autre, pouvons-nous en expliquer la logique de chaque travail? Comment cela nous aidera-t-il? Pour ceux qui ont atteint l'illumination dans la réutilisation du code et pour tous ceux qui ont de nombreux projets similaires, vous pouvez:


Une douzaine de projets du même type avec du code différent, mais déployés de la même manière - facilement et sans maintenir à jour CI dans tous les référentiels!

Un exemple d'utilisation pratique includea également été donné dans cet article .

N ° 4: uniquement / sauf refs


  • Conditions complètes, y compris les variables et les modifications de fichiers.
  • Comme il s'agit de toute une famille de fonctions, certaines parties ont commencé à apparaître dans GitLab 10.0, tandis que d'autres (par exemple, changes) ont commencé à apparaître dans 11.4.
  • docs.gitlab.com/ce/ci/yaml/#onlyexcept-advanced

Parfois, il me semble que ce n'est pas un pipeline qui nous écoute, mais nous lui. Un excellent outil de gestion est only/ except- désormais intégré. Qu'est-ce que ça veut dire?

Dans le cas le plus simple (et peut-être le plus agréable), sauter les étapes:

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

Dans l'exemple de travail, il s'exécute uniquement sur la branche principale, mais ne peut pas être déclenché par une planification ou un déclencheur (GitLab partage les appels et les déclencheurs d'API, bien qu'il s'agisse essentiellement de la même API). Le travail ne sera pas exécuté s'il y a une phrase secrète de saut de tests dans le message de validation . Par exemple, une faute de frappe dans le README.mdprojet ou la documentation a été corrigée - pourquoi attendre les résultats du test?

"Hé, 2020 est dehors!" Pourquoi devrais-je expliquer à chaque fois à la boîte de fer qu'il n'est pas nécessaire d'exécuter des tests lors du changement de la documentation? » Et vraiment: only:changesil vous permet d'exécuter des tests lors de la modification de fichiers uniquement dans certains répertoires. Par exemple:

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

Et pour l'action inverse - i.e. ne courez pas - oui except:changes.

N ° 5: règles



Cette directive est très similaire aux précédentes only:*, mais avec une différence importante: elle vous permet de contrôler le paramètre when. Par exemple, si vous ne souhaitez pas supprimer complètement la possibilité de démarrer un travail. Vous pouvez simplement laisser le bouton qui, si vous le souhaitez, sera appelé indépendamment, sans lancer de nouveau pipeline ou sans faire de commit.

# 6: environnement: auto_stop_in



Nous avons eu connaissance de cette opportunité juste avant la publication de l'article et n'avons pas encore eu suffisamment de temps pour le tester dans la pratique, mais c'est certainement «la même chose» qui était si attendue dans plusieurs projets.

Vous pouvez spécifier un paramètre dans les environnements GitLab on_stop- il est très utile lorsque vous souhaitez créer et supprimer des environnements dynamiquement, par exemple, pour chaque branche. Le travail marqué par k on_stopest exécuté, par exemple, lorsque la fusion du MR est dans la branche principale ou lorsque le MR est fermé (ou même simplement en cliquant sur le bouton), grâce à quoi l'environnement inutile est automatiquement supprimé.

Tout est pratique, logique, fonctionne ... sinon pour le facteur humain. De nombreux développeurs fusionnent les MR non pas en cliquant sur un bouton dans GitLab, mais localement via git merge. Vous pouvez les comprendre: c'est pratique! Mais dans ce cas, la logiqueon_stopcela ne fonctionne pas, nous avons accumulé un environnement oublié ... C'est là que les tant attendus sont utiles auto_stop_in.

Bonus: cabanes temporaires quand il n'y a pas assez d'opportunités


Malgré toutes ces fonctions (et bien d'autres) nouvelles et demandées de GitLab, malheureusement, les conditions pour remplir un travail sont parfois impossibles à décrire en termes de capacités actuellement disponibles.

GitLab n'est pas parfait, mais il fournit les outils de base pour construire un pipeline de rêve ... si vous êtes prêt à aller au-delà de la modeste DSL en plongeant dans le monde des scripts. Voici quelques solutions de notre expérience, qui ne prétendent en aucun cas être idéologiquement correctes ou recommandées, mais sont présentées davantage pour démontrer différentes possibilités avec un manque de fonctionnalité API intégrée.

Solution de contournement n ° 1: lancez deux tâches avec un seul bouton


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"

Et pourquoi pas, si vous en avez vraiment envie?

Solution n ° 2: transfert modifié dans les fichiers MR MR pour rubocop à l'intérieur de l'image


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}

Il n'y a pas d'image à l'intérieur .git, j'ai donc dû sortir pour vérifier uniquement les fichiers modifiés.

Remarque: Ce n'est pas une situation très standard et une tentative désespérée de se conformer à de nombreuses conditions du problème, dont la description n'est pas incluse dans la portée de cet article.

Solution de contournement n ° 3: déclencheur pour démarrer des travaux à partir d'autres référentiels lors du déploiement


  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

Il semblerait qu'une chose aussi simple et nécessaire (dans le monde des microservices) déploie un autre microservice dans un circuit fraîchement créé en tant que dépendance. Mais ce n'est donc pas un appel d'API et une fonctionnalité déjà familière (décrite ci-dessus) est requise:

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

Remarques:

  • Job on trigger est conçu pour être lié à la transmission d'une variable à l'API, de manière similaire à l'exemple n ° 1. Il est plus logique de l'implémenter sur l'API avec le nom de travail transmis.
  • Oui, la fonction est dans la version commerciale (EE) de GitLab, mais nous ne la considérons pas.

Conclusion


GitLab essaie de suivre les tendances, implémentant progressivement des fonctionnalités agréables et demandées par la communauté DevOps. Ils sont assez faciles à utiliser et lorsque les capacités de base ne sont pas suffisantes, ils peuvent toujours être étendus avec des scripts. Et si nous voyons que cela ne s'avère pas si élégant et pratique à l'appui ... il reste à attendre les nouvelles versions de GitLab - ou à aider le projet avec notre contribution .

PS


Lisez aussi dans notre blog:


All Articles