Voici les notes de l'atelier d'introduction à Gitlab CI que je donne le 23 septembre dans le cadre de la Semaine québécoise de l'informatique libres.
Pourquoi faire de l'intégration continue?
Il y a plusieurs bonnes raisons pour commencer à faire de l'intégration continue (CI). En voici quelques unes:
-
Tester son code. Souvent, l'intégration continue est une bonne manière de commencer à tester son code. Les tests automatisés permettent de trouver des erreurs d'inattention et forcent à vérifier si le code que l'on écrit fonctionne réellement.
-
Tester son code sur des environnements radicalement différents. Avoir des tests que l'on peut faire rouler localement sur sa machine est une bonne chose, mais utiliser un CI permet de tester son code sur des environnements sur lesquels on ne travaille pas.
-
Tester son code automatiquement. Utiliser un CI lié à une plateforme d'hébergement git permet de s'assurer que les nouveaux commits réussissent les tests avant d'être ajoutés à la branche
master
. -
Déployer son code automatiquement. Il est possible d'aller une étape plus loin et d'utiliser le CI pour publier du code sur une archive comme PyPi ou NPM automatiquement si tous les tests passent. On parle alors de déploiement continu (CD).
Introductions aux fonctionnalités de Gitlab CI
Aperçu
Pour utiliser Gitlab CI, il faut tout d'abord avoir un projet sur une instance
Gitlab. Quand on ajoute un commit git au dépôt, si un fichier .gitlab-ci.yml
est présent dans le dépôt, Gitlab suit ces instructions et roule un script dans
le runner, une machine externe qui sert à faire des tests.
Sur la plupart des instances Gitlab, il existe des runners partagés que tout le monde peut utiliser. Il est également possible de monter un runner privé pour son propre projet. Cela peut être intéressant si on a des tests qui demandent beaucoup de ressources.
Le fichier .gitlab-ci.yml
Pour commencer à utiliser Gitlab CI, il faut tout d'abord créer un fichier
.gitlab-ci.yml
.
Voici un exemple très simple de fichier:
--- image: debian:stable test12345: script: - echo 'deb http://deb.debian.org/debian buster main contrib non-free' >> /etc/apt/sources.list - apt-get update - apt-get install -y -t buster rolldice ...
La première partie du fichier est le paramètre image
. C'est l'image docker
qui va être utilisée par défaut dans les tests que l'on effectue. Cette image
est récupérée du Docker Hub. Pour utiliser une image, on spécifie le tag
complet de l'image. Ainsi, l'image pour la version stable de Debian est
debian:stable
.
La seconde partie du fichier est le test que l'on roule. Il est possible d'avoir
plusieurs tests l'un à la suite de l'autre. Le test dans notre exemple est
nommé test12345
, mais il aurait été possible de le nommer d'une autre manière.
apt:rolldice
aurait également été un nom valide.
Chaque test doit comporter un script. Ce script est un ensemble de commandes
shell de type bash
. L'ensemble des commandes que l'on souhaite effectuer s'y
retrouvent étapes par étapes.
Il est possible d'avoir plusieurs tests l'un à la suite de l'autre:
--- image: debian:stable apt:rolldice:stable: script: - apt-get install -y rolldice apt:rolldice:buster: script: - echo 'deb http://deb.debian.org/debian buster main contrib non-free' >> /etc/apt/sources.list - apt-get update - apt-get install -y -t buster rolldice ...
Il est également possible de changer l'image par défaut utilisée dans un test:
--- image: debian:stable apt:rolldice:stable: script: - apt-get install -y rolldice apt:rolldice:buster: image: debian:buster script: - apt-get install -y rolldice ...
Les fichiers présents dans votre dépôt git sont accessibles par vos scripts comme si vous travailliez directement dans ce dossier:
> foobar.txt
Hello World
> .gitlab-ci.yml
--- image: debian:stable test:hello: script: - cat foobar.txt - cat foobar.txt | grep "Hello World" ...
Le paramètre service
Pour certains tests plus complexes, il est parfois nécessaire d'avoir un service externe différent de notre image docker principale, par exemple une base de données.
Gitlab CI permet de rouler un service externe accessible par nos tests. Ces services sont également des images Docker. Par voici un exemple simple d'utilisation d'une base de données:
> mytest.sql
CREATE TABLE `table1` (randomvar VARCHAR(30) NOT NULL); CREATE TABLE `table2` (randomvar VARCHAR(30) NOT NULL); CREATE TABLE `table3` (randomvar VARCHAR(30) NOT NULL); CREATE TABLE `table4` (randomvar VARCHAR(30) NOT NULL);
> .gitlab-ci.yml
--- image: debian:stable services: - mariadb:10.1 variables: MYSQL_DATABASE: mytest MYSQL_ALLOW_EMPTY_PASSWORD: 1 test:mariadb: script: - apt-get update && apt-get -y install mariadb-client-10.1 - mariadb -u root -h mariadb -D mytest < mytest.sql - mariadb -u root -h mariadb -e "SELECT * FROM information_schema.columns WHERE table_schema = 'mytest'"; ...
N'importe quelle image Docker peut être utilisée comme service. Si vous avez des besoins particuliers, il est nécessaire de créer une image Docker par vous même.
Artifacts
Si vous souhaitez utiliser Gitlab CI pour compiler du code ou créer des fichiers
que vous souhaitez conserver par la suite, il est nécessaire d'utiliser le
paramètre artifacts
. Sa fonction est de spécifier un fichier ou un dossier qui
va être enregistré par Gitlab et que vous allez pouvoir récupérer par la suite.
> input.md
# Hello World This is a markdown test. It should be rendered to HTML properly using the great [pandoc](https://pandoc.org/MANUAL.html).
> .gitlab-ci.yml
--- image: debian:stable build:html: script: - apt-get update && apt-get -y install pandoc - pandoc -o output.html input.md artifacts: paths: - output.html ...
Tests à plusieurs étapes
Par défaut, les tests dans Gitlab CI fonctionnent tous simultanément. Cela est pratique pour des tests de type unit test. Pour des tests plus élaborés, on peut parfois vouloir fonctionner par étapes et créer des dépendances entre nos tests.
Le paramètre stage
permet de spécifier des groupes dans lesquels on peut
placer nos différentes tâches. Ces groupes peuvent par la suite être ordonnés,
pour que les tests roulent dans un ordre précis.
On peut également utiliser le paramètre dependencies
pour créer un lien de
dépendance entre différentes tâches. Les artifacts
créés dans une tâches sont
automatiquement passés à une seconde tâche si elle en dépend.
> hello.c
#includeint main (void) { printf ("Hello, world!\n"); return 0; }
> .gitlab-ci.yml
--- stages: - build - test compile:debian: image: debian:stable stage: build script: - apt-get update && apt install -y build-essential - gcc -Wall hello.c -o hello artifacts: paths: - hello compile:alpine: image: alpine stage: build script: - apk add --update build-base - gcc -Wall hello.c -o hello artifacts: paths: - hello test:debian: image: debian:stable stage: test dependencies: - compile:debian script: - ./hello test:alpine: image: alpine stage: test dependencies: - compile:alpine script: - ./hello ...
Variables secrètes
Si vous souhaitez utiliser Gitlab pour publier votre projet sur une plateforme comme PyPi ou NPM, il est nécessaire de stocker vos informations d'authentification quelque part.
Il n'est bien évidemment pas recommandé d'ajouter vos mots de passes directement
dans votre fichier .gitlab-ci.yml
ou dans un autre fichier dans votre dépôt
git pour des raisons de sécurité: n'importe qui pourrait lire ces fichiers et
compromettre vos comptes.
Gitlab permet de stocker des variables secrètes. Pour ce faire, il faut aller dans l'onglet Settings > CI/CD > Variables de votre projet.
Une fois que vous avez créé une variable secrète, il est possible d'y référer
comme une variable normale dans votre fichier .gitlab-ci.yml
.
--- image: debian:stable test:secret-var: script: - apt-get update && apt-get -y install wget - wget https://agendadulibre.qc.ca/events/$SECRET ...
Compiler et héberger un site web statique à l'aide de Gitlab CI et Gitlab Pages
Un cas de figure intéressant pour Gitlab CI est la compilation d'un site web statique. Une fois compilé, ce site web peut par la suite être hébergé directement sur Gitlab grâce au projet Gitlab Pages. Cela peut être utile pour héberger la documentation d'un projet.
Voici un exemple de projet utilisant Gitlab CI et Gitlab Pages. Ce projet utilise Sphinx avec le thème Read the Docs. Le site web compilé est disponible en ligne ici.
Une fois que l'on a ajouté un fichier .gitlab-ci.yml
qui compile notre site
statique, il faut aller dans l'onglet Settings > Pages de notre projet git
pour mettre en ligne notre projet. Gitlab offre également la possibilité
d'utiliser un domaine externe.
Plus d'informations
La documentation complète du fichier .gitlab-ci.yml
est disponible en ligne.
Atelier collaboratif d'utilisation de Gitlab CI
Trouvez un projet qui vous intéresse et tentez de créer une série de tests ầ l'aide de Gitlab CI.
Instructions pour installer Gitlab CI + Docker sur une machine privée (avancé)
On souhaite installer Docker et Gitlab CI sur un serveur Debian Stretch. Ces étapes nécessitent une certaine connaissance de la ligne de commande.
Docker
L'executor Docker est le plus simple et le plus flexible. C'est également celui qui est mis en place sur gitlab.com.
On commence donc par installer Docker sur notre machine. En temps normal, on installerait Docker à partir du dépôt officiel Debian. Malheureusement, Docker n'est pas packagé dans Debian alors il est nécessaire de l'installer à partir du dépôt offert par Docker.
On commence par ajouter un fichier source à apt:
> /etc/apt/sources.list.d/docker.sources
Types: deb URIs: https://download.docker.com/linux/debian/ Suites: stretch Architectures: amd64 Components: main Signed-By: /usr/share/keyrings/docker-archive-keyring.gpg
On complète l'installation en téléchargeant la clef GPG et en installant les packets1:
$ apt install apt-transport-https
$ curl https://download.docker.com/linux/debian/gpg | gpg --dearmor > /usr/share/keyrings/docker-archive-keyring.gpg
$ apt update
$ apt install docker-ce
Docker a la fâcheuse habitude de démarrer avant que l'interface réseau ne soit en ligne. Cela fait en sorte que quand notre machine redémarre, notre CI n'a plus accès à internet, ce qui fait avorter nos tests.
Pour remédier à ce problème, on créé un fichier cron
qui redémarre Docker 30
secondes après que notre machine ait démarrée:
$ sudo echo '@reboot root /bin/sleep 30 && /bin/systemctl restart docker' > /etc/cron.d/docker-reboot
On souhaite également éviter que notre serveur se remplisse des instances de
test que l'on fait rouler. On ajoute donc un autre fichier cron
pour purger
Docker périodiquement:
$ sudo echo '0 3 * * * root /usr/bin/docker system prune -a -f > /dev/null 2>&1' > /etc/cron.d/docker-prune
Et voilà! Docker est prêt à être utilisé dans notre installation future de Gitlab CI!
Gitlab CI
Encore une fois, plutôt que d'utiliser le dépôt Gitlab offert par Debian pour installer Gitlab CI, on choisi plutôt le dépôt offert par Gitlab.
Gitlab est encore très jeune dans Debian et il y de nombreuses mises à jour de sécurité. Peut-être dans le futur les paquets Debian vont être plus fiables, mais ce n'est pas le cas pour l'instant.
On commence par ajouter un fichier source à apt:
> /etc/apt/sources.list.d/gitlab.sources
Types: deb URIs: https://packages.gitlab.com/runner/gitlab-runner/debian/ Suites: stretch Architectures: amd64 Components: main Signed-By: /usr/share/keyrings/gitlab-archive-keyring.gpg
On complète l'installation en téléchargeant la clef GPG et en installant les packets:
$ curl https://packages.gitlab.com/gpg.key | gpg --dearmor > /usr/share/keyrings/gitlab-archive-keyring.gpg
$ apt update
$ apt install gitlab-runner
Une fois gitlab-runner
installé, on peut utiliser l'outil en ligne de commande
pour créer un nouveau runner:
$ sudo gitlab-runner register
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
> https://url-de-l-instance-gitlab
Please enter the gitlab-ci token for this runner:
> le-token-de-votre-projet
Please enter the gitlab-ci description for this runner:
> La description du runner
Please enter the gitlab-ci tags for this runner (comma separated):
> nom-du-runner-gitlab-ci, docker
Pour obtenir le token nécessaire à la création du runner, il faut aller dans l'onglet Settings > CI/CD > Runners dans votre projet git. Le token est spécifié dans la section Setup a specific Runner manually.
Et voilà! Si tout fonctionne correctement, le runner devrait s'afficher dans la l'onglet Settings > CI/CD > Runners de votre projet.
Pro Tip
Si vous utilisez votre propre runner Gitlab CI dans un environnement en production, il est important de s'assurer que ce dernier fonctionne pour s'éviter de fâcheux ennuis.
Pour s'assurer que notre runner est fonctionnel, on peut créer un projet git
dont le seul but est de s'assurer que le CI fonctionne. Ce dernier n'a qu'à
contenir un fichier .gitlab-ci.yml
de base.
Par la suite, vous pouvez faire rouler le test à tous les jours ou à toutes les heures en créant un nouvel item dans dans l'onglet CI/CD > Schedules de votre projet.
Voici un exemple de fichier gitlab-ci.yml
que l'on peut utiliser:
--- image: debian test-ci: script: - apt-get update && apt-get -y install rolldice tags: - nom-du-runner-gitlab-ci ...
Il est bien important de spécifier le nom du runner sur lequel vous souhaitez
que le test roule dans la section tags
pour éviter de faire le test sur une
autre machine que la vôtre.