table des matières
Ce document décrit la prise en main de la chaîne CI/CD avec Gitlab et les différents exécuteurs proposés
Une chaîne d’intégration et de déploiement continue automatise des actions sur le dépôt git d’un projet.
-
La partie “CI” pour Continious Integration concerne la compilation, les tests ou encore la génération de documentation. Elle va permettre de vérifier que le code poussé sur un dépot répond aux standards défini pour le projet.
-
La partie “CD” pour Continious Delivery concerne le déploiement de l’application ou du site web.
Le schéma ci-dessous résume les différentes étapes qui peuvent être concernées, en fonction du logiciel par la chaîne CI/CD
Il existe plusieurs logiciels CI/CD indépendant à Git comme Travis
ou Jenkins
. Gitlab
propose une chaîne CI/CD intégrée à sa solution et c’est cette chaîne que nous allons utiliser. L’avantage est que la chaîne CI/CD, ou pipeline est directement intégrée au projet.
Sitographie
Principe de fonctionnement
Les pipelines sont automatiquement déclenchés quand un fichier .gitlab-ci.yml
est présent à la racine du dépôt. Le fichier .gitlab-ci.yml
contient une suite d’actions déclenchées automatiquement lors d’un commit. Par exemple, le pipeline ci-après contient 4 actions :
- Compilation
- Tests unitaire
- Couverture du code
- Génération de la documentation doxygen
Les pipelines sont déclenchés par des executors disponible sur notre Gitlab. Actuellement, il y a 3 executors disponibles pour vos projets, en fonction des technologies que vous utilisez.
- Un executor pour les projets C et C++
- Un executor pour les projets mbed
- Un executor pour les projets Laravel
Remarque : Si aucun executor n’est disponible pour vos projets (Python, Android…), il est toujours possible d’utiliser des exécutors du DockerHub. Gitlab ira automatiquement chercher les images des containers pour votre pipeline. Il faudra surement ajouter des étapes supplémentaires (consistant à récupérer des logiciels supplémentaires) avant que votre pipeline soit fonctionnel.
Projets C et C++
Un projet modèle est disponible sur ce dépôt. Il contient tous les éléments nécessaires à la mise en place et l’exécution du pipeline décrit ci-après.
- Le fichier
.gitlab-ci.yml
est composé des éléments suivants
Executor à utiliser.
L’image cppimage2
contient l’ensemble des outils nécessaire à la compilation(CMake), aux tests unitaires (Catch2), à la couverture du code (Gcovr) et à la génération de la documentation (Doxygen).
image: cppimage2
Sous modules git
Si votre projet contient des sous modules git, ajouter cette ligne pour les inclure.
variables:
GIT_SUBMODULE_STRATEGY: recursive
Les différents étapes du pipeline
stages:
- build
- test
- coverage
- documentation
Job de build
On précise qu’on va exécuter le job:build
. Si nécessaire, il est possible d’ajouter des actions avant l’exécution du script (before_script
) Ensuite, le script exécute les étapes de compilation, puis génère un exécutable (artifacts
) à télécharger dans le dossier build
job:build:
stage: build
before_script:
script:
- mkdir build && cd build
- conan install -s build_type=Debug -if conan-dependencies ..
- cmake -GNinja ..
- ninja
artifacts:
paths:
- build
Tests unitaires
Une page du site est consacrée aux tests unitaires. Merci de s’y reporter pour le détail de la création des TU et l’importance de ceux-ci.
Les tests unitaires sont réalisés avec le framework Catch2
et sont dans le dossier test du modèle fourni.
L’intérêt est d’avoir une vue immédiate du rapport de test grâce au reporter junit
job:test:
stage: test
script:
- cd build/test/bin
- ./testProjet --reporter junit --out catch_results.xml
artifacts:
when: always
paths:
- build/test/bin/catch_results.xml
reports:
junit: build/test/bin/catch_results.xml
Couverture du code
La couverture du code est un indicateur important. Il permet de s’assurer que la majorité du code de l’application a été compilé par les tests unitaires.
L’artifact généré indique simplement le résumé du taux global de coverage. Si une exploration plus fine est nécessaire, il faut générer également le dossier build
pour avoir le rapport complet.
code coverage:
stage: coverage
before_script:
script:
- cd build
- conan install -s build_type=Debug -if conan-dependencies ..
- cmake -GNinja ..
- ninja
- ninja coverage
- gcovr --xml-pretty --exclude-unreachable-branches --exclude CMakeFiles --print-summary -o coverage.xml --root ${CI_PROJECT_DIR}
coverage: /^\s*lines:\s*\d+.\d+\%/
artifacts:
name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
expire_in: 2 days
reports:
cobertura: build/coverage.xml
paths:
- build/coverage
Job de documentation
Le job de documentation va générer automatiquement la documentation doxygen
en fonction des balises insérées dans votre code.
Remarque : doxygen s’appuie sur le fichier Doxyfile. Il faut que celui-ci soit présent à la racine de votre projet (et correctement configuré)
job:documentation:
only:
- master
- tags
stage: documentation
before_script:
script:
- doxygen Doxyfile
- mv html/ public/
artifacts:
paths:
- public
Remarques
- Le fichier
.gitlab-ci.yml
est sur le dépôt. - Attention à l’indentation des directives, le fichier est rapidement invalide. (Editez le en ligne pour le corriger)
- Certaines directives sont à adapter. Par exemple, il peut être intéressant de ne générer la documentation que sur la branche master
Projets Mbed
Un modèle de projet mbed6 est disponible à l’adresse suivante
Le fichier d’intégration continue pour Mbed ne contient que l’étape de compilation. En effet, les tests unitaires s’exécutent sur la carte physique et ne sont donc pas exécutables en ligne.
Attention : mbed-os
est déjà installé sur l’executor. Il ne faut donc pas que votre projet contienne de fichier mbed-os.lib
pour que le pipeline s’exécute correctement. La meilleure pratique consiste à avoir un répertoire avec mbed-os
externe à tout projet sur votre poste et à configurer correctement votre projet pour l’utiliser (Gérer plusieurs projets Mbed)
fichier .gitlab-ci.yml
image: mbedimage
variables:
GIT_SUBMODULE_STRATEGY: recursive
stages:
- build
job1:
only:
- master
- tags
stage: build
script:
- mbed new .
- mbed deploy
- mbed compile --source . --source /opt/mbed/mbed-os/ --profile=debug -t GCC_ARM -m NUCLEO_F746ZG
artifacts:
paths:
- BUILD
Projets Laravel
Le pipeline pour Laravel contient deux étapes, l’une pour les tests unitaires, l’autre pour le déploiement de l’application sur un serveur en production.
Sitographie
Configuration
L’executor laravelimage
contient les outils nécessaires pour le framework Laravel9
(php8
notamment) Il est possible d’utiliser un certain nombre de variables pour accéder à la base de données.
image: laravelimage
services:
- mysql:5.7
variables:
MYSQL_DATABASE: laravel
MYSQL_ROOT_PASSWORD: ""
DB_HOST: mysql
DB_USERNAME: root
stages:
- test
- deploy
Tests
Les test unitaires sont définis dans le dossier app\tests\Unit
de Laravel. Ici, ils sont exécutés avec phpunit
unit_test:
stage: test
script:
- cp .env.example .env
- composer install
- php artisan key:generate
# - php artisan migrate
- vendor/bin/phpunit
Déploiement
Le job va déployer le site sur le serveur en production. Il est donc nécessaire de configurer celui-ci au préalable pour la connexion d’un utilisateur au serveur ayant les droits sur le répertoire web de notre serveur.
Les étapes préalables consistent à :
- Créer un utilisateur
deployer
sur le serveur - Lui donner les droits sur le répertoire
/var/wwww
- Générer les clés publiques et privées SSH.
- Intégrer les clés au dépôt
gitlab
Remarque : Se référer à la documentation officielle pour la configuration du serveur et du dépôt.
Envoy
Dans la solution proposée, on utilise envoy pour cloner le dépôt. Le fichier Envoy.blade.php
doit être à la racine de votre projet.
- Se référer à la documentation officielle pour les explications détaillées sur
envoy
.
@servers(['web' => 'deployer@x.x.x.x'])
@setup
$repository = 'https://example.com/USER/laravel.git';
$releases_dir = '/var/www/app/releases';
$app_dir = '/var/www/app';
$release = date('YmdHis');
$new_release_dir = $releases_dir .'/'. $release;
@endsetup
@story('deploy')
clone_repository
run_composer
update_symlinks
@endstory
@task('clone_repository')
echo 'Cloning repository'
[ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
setfacl -R -m g:www-data:rwx {{ $new_release_dir }}
cd {{ $new_release_dir }}
git reset --hard {{ $commit }}
@endtask
@task('run_composer')
echo "Starting deployment ({{ $release }})"
cd {{ $new_release_dir }}
composer install --prefer-dist --no-scripts -q -o
@endtask
@task('update_symlinks')
echo "Linking storage directory"
rm -rf {{ $new_release_dir }}/storage
ln -nfs {{ $app_dir }}/storage {{ $new_release_dir }}/storage
echo 'Linking .env file'
ln -nfs {{ $app_dir }}/.env {{ $new_release_dir }}/.env
echo 'Linking current release'
ln -nfs {{ $new_release_dir }} {{ $app_dir }}/current
@endtask
Déploiement du site
Une fois gitlab et Laravel configuré, le job de déploiement va récupérer les clés ssh du projet, se connecter au serveur de production et exécuter le script Envoy.blade.php
Remarque : La directive manual
indique qu’il faut exécuter manuellement la tâche pour déployer la nouvelle version du site. Dans un fichier plus élaboré, il peut y avoir un serveur de préproduction avec une mise à jour automatique et un serveur en production avec une mise à jour manuelle.
deploy_production:
stage: deploy
script:
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- ssh-add <(echo "$SSH_PRIVATE_KEY")
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
- ~/.composer/vendor/bin/envoy run deploy --commit="$CI_COMMIT_SHA"
environment:
name: production
url: http://x.x.x.x
when: manual
only:
- master