Nous pensons déplacer notre ci de jenkins à gitlab. Nous avons plusieurs projets qui ont le même workflow de build. À l'heure actuelle, nous utilisons une bibliothèque partagée dans laquelle les pipelines sont définis et le fichier jenkins dans le projet n'appelle qu'une méthode définie dans la bibliothèque partagée définissant le pipeline réel. Les modifications ne doivent donc être apportées qu'à un seul point affectant plusieurs projets.
Je me demande si la même chose est possible avec gitlab ci? Pour autant que je l'ai découvert, il n'est pas possible de définir le gitlab-ci.yml en dehors du référentiel. Existe-t-il une autre façon de définir un pipeline et de partager cette configuration avec plusieurs projets pour simplifier la maintenance?
Permettez-moi tout d'abord de dire: Merci d'avoir posé cette question! Cela m'a incité à chercher (encore) une solution après m'être souvent demandé si c'était moi-même possible. Nous avons également 20 à 30 projets qui sont assez identiques et qui ont .gitlab-ci.yml
Des fichiers d'environ 400 à 500 loc qui doivent être modifiés chacun si une chose change.
J'ai donc trouvé une solution de travail:
Inspiré par le modèle Auto DevOps .gitlab-ci.yml Gitlab lui-même créé, et où ils utilisent un travail de modèle pour définir toutes les fonctions utilisées et appeler = chaque before_script
pour les charger, j'ai trouvé la configuration suivante.
Fichiers
Donc, en utilisant un scipt partagé d'emplois ci :
#!/bin/bash
function list_files {
ls -lah
}
function current_job_info {
echo "Running job $CI_JOB_ID on runner $CI_RUNNER_ID ($CI_RUNNER_DESCRIPTION) for pipeline $CI_PIPELINE_ID"
}
Un .gitlab-ci.yml
Commun et générique:
image: ubuntu:latest
before_script:
# Install curl
- apt-get update -qqq && apt-get install -qqqy curl
# Get shared functions script
- curl -s -o functions.sh https://gitlab.com/giix/demo-shared-ci-functions/raw/master/functions.sh
# Set permissions
- chmod +x functions.sh
# Run script and load functions
- . ./functions.sh
job1:
script:
- current_job_info
- list_files
Vous pouvez copier-coller votre fichier de project-1 vers project-2 et il utiliserait les mêmes fonctions partagées de Gitlab CI.
Ces exemples sont assez verbeux à des fins d'exemple, optimisez-les comme vous le souhaitez.
Leçons apprises
Donc, après avoir appliqué la construction ci-dessus à grande échelle (plus de 40 projets), je veux partager quelques leçons apprises afin que vous n'ayez pas à découvrir à la dure:
sh
par défaut)GitLab 11.7
introduit de nouvelles méthodes include
, telles que include:file
: https://docs.gitlab.com/ee/ci/yaml/#includefile
include:
- project: 'my-group/my-project'
ref: master
file: '/templates/.gitlab-ci-template.yml'
Cela vous permettra de créer un nouveau projet sur la même instance GitLab qui contient un .gitlab-ci.yml
.
Utilisez la fonction include
, (disponible à partir de GitLab 10.6): https://docs.gitlab.com/ee/ci/yaml/#include
Depuis gitlab version 12.6 , il est possible de définir un fichier externe .gitlab-cy.yml
.
Pour personnaliser le chemin:
- Accédez aux paramètres du projet> CI/CD.
- Développez la section Pipelines généraux.
- Indiquez une valeur dans le champ Chemin de configuration du CI personnalisé.
- Cliquez sur Enregistrer les modifications. ...
Si la configuration CI sera hébergée sur un site externe, le lien URL doit se terminer par .yml:
http://example.com/generate/ci/config.yml
Si la configuration CI sera hébergée dans un autre projet dans GitLab, le chemin doit être relatif au répertoire racine de l'autre projet, avec le nom du groupe et du projet ajouté à la fin:
.gitlab-ci.yml @ mygroup/another-project
my/path/.my-custom-file.yml@mygroup/another-project
Donc, j'ai toujours voulu poster, avec ce que j'ai trouvé maintenant:
À l'heure actuelle, nous utilisons une approche mixte de l'idée de @ stefan-van-gastel d'une bibliothèque ci partagée et de la fonction include
relativement nouvelle de gitlab 11.7. Nous sommes très satisfaits de cette approche, car nous pouvons désormais gérer notre pipeline de build pour plus de 40 référentiels dans un seul référentiel.
J'ai créé un référentiel appelé ci_shared_library
Contenant
pipeline.yml
contenant toute la configuration du pipeline. Dans le script précédent, nous chargeons le ci_shared_library
Dans /tmp/shared
Pour pouvoir exécuter les scripts.stages:
- test
- build
- deploy
- validate
services:
- docker:dind
before_script:
# Clear existing shared library
- rm -rf /tmp/shared
# Get shared library
- git clone https://oauth2:${GITLAB_TOKEN}@${SHARED_LIBRARY} /tmp/shared
- cd /tmp/shared && git checkout master && cd $CI_PROJECT_DIR
# Set permissions
- chmod -R +x /tmp/shared
# open access to registry
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
test:
stage: test
script:
- /tmp/shared/test.sh
build:
stage: build
script:
- /tmp/shared/build.sh
artifacts:
paths:
- $CI_PROJECT_DIR/target/RPMS/x86_64/*.rpm
expire_in: 3h
only:
- develop
- /release/.*/
deploy:
stage: deploy
script:
- /tmp/shared/deploy.sh
artifacts:
paths:
- $CI_PROJECT_DIR/tmp/*
expire_in: 12h
only:
- develop
- /release/.*/
validate:
stage: validate
script:
- /tmp/shared/validate.sh
only:
- develop
- /release\/.*/
Chaque projet qui souhaite utiliser cette configuration de pipeline doit avoir un .gitlab-ci.yml
. Dans ce fichier, la seule chose à faire est d'importer le fichier partagé pipeline.yml
À partir du référentiel ci_shared_library
.
# .gitlab-ci.yml
include:
- project: 'ci_shared_library'
ref: master
file: 'pipeline.yml'
Avec cette approche, tout ce qui concerne le pipeline réside dans un seul référentiel et est réutilisable. Nous avons l'ensemble du modèle de pipeline dans un fichier, mais je pense qu'il serait même possible de le diviser pour avoir chaque tâche dans un fichier yml. De cette façon, il serait plus flexible et on pourrait créer des emplois par défaut qui peuvent être fusionnés différemment pour des projets qui ont des emplois similaires, mais pas tous les projets nécessitant tous les emplois ...