Aller au contenu

Introduction à Gitlab CI⚓︎

En cours de rédaction...

Gitlab CI permet d'automatiser des tâches et procédé au cours d'un projet. Pour cela, vous devez créer un fichier .gitlab-ci.yml à la source de votre projet Gitlab.

Par exemple, avec la configuration suivante, nous allons afficher un simple Hello World! sous un environnement alpine (par défaut sur l'instance gitlab.papierpain.fr).

.gitlab-ci.yml
1
2
3
job-name:
    script:
        - echo "Hello World!"

A vous de jouer !

Dans n'importe quel projet Gitlab, créez un fichier .gitlab-ci.yml à la source de votre projet, et ajoutez les lignes suivantes :

.gitlab-ci.yml
1
2
3
job-name:
    script:
        - echo "Hello World!"

Ensuite, allez dans le menu de gauche dans CI/CD > Pipelines.

Onglet Pipelines
Onglet Pipelines

Après avoir cliqué sur le button Run pipeline vous pourrez renseigner la branche sur laquelle vous pourrez exécuter votre configuration et ajouter des paramètres.

Parametrer un pipeline
Parametrer un pipeline

Une fois exécuté, vous vous trouvez sur une page listant tous les jobs (ici seulement un est présent).

Informations sur le pipeline exécuté
Informations sur le pipeline exécuté

Pour voir la console, il suffit de cliquer sur l'icon du job job-name et vous verrez plusieurs informations comme la préparation de l'environnement et l'exécution du script (ici echo "Hello World!").

Console d'un job
Console d'un job

01 - Pipeline et stages⚓︎

Pipeline stages jobs

Pipeline stages jobs

Un pipeline est un ensemble de tâche à réaliser lors d’un procédé (ex. : merge request, commit, etc.) et pouvant être en parallèle. Un pipeline est composé de stages que l'on peut comparer à des étapes. Chaque stage est composé de jobs qui sont les tâches à réaliser grâce à un script.

Structure d'un pipeline (.gitlab-ci.yml)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
build-site: # Nom du job
    stage: build # Définition du stage du job 'build-site'
    script: # Script contenant la liste des instructions bash
        - echo "Construction du site web..."

build-api:
    stage: build
    script:
        - echo "Construction des APIs..."

deploy:
    stage: deploy
    script:
        - echo "deploiement de l'application..."

Type de stage

Par défaut, il y a des stages prédifinis, ils sont les suivants (par ordre d'exécution) :

  1. .pre
  2. build
  3. test (par défaut si aucun stage n'est défini)
  4. deploy
  5. .post

Bien évidemment, vous pouvez définir les votre mais je vous conseille tout de même d'utiliser ceux par défaut pour respecter les conventions imposé par Gitlab CI.

Documentation officielle

02 - Job⚓︎

Documentation officielle

Comme vu plus haut, un job doit à minima contenir une clé script contenant comme valeur un tableau de ligne de commande.

.gitlab-ci.yml
1
2
3
4
5
job-name:
    script:
        - echo "Hello"
        - echo "World"
        - echo "!"

Les lignes de commande

L'environnement par défaut est une image Alpine mais vous verrez par la suite que vous pouvez choisir lequel vous souhaitez donc il faut adapter les scripts à l'environnement d'exécution.

02.1 - Before script & after script⚓︎

Documentation officielle

Ces deux clés permettent d'ajouter des pré-scripts et des post-scripts. Cela permet surtout d'améliorer la lisibilité. En plus de cela, la clé after_script s'exécute toujours même s'il y a une erreur dans le before_script ou dans le script.

.gitlab-ci.yml
1
2
3
4
5
6
7
test-before-after:
    before_script:
        - echo "Connecting..."
    script:
        - echo "Do something..."
    after_script:
        - echo "Clean workspace..."

02.2 - Artifacts⚓︎

Documentation officielle

Cela permet d'avoir une archive contenant des fichiers ou des dossiers, générée dans le job. Grâce à cela, on peut soit la télécharger à la main soit la transmettre à un autre job.

.gitlab-ci.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
generate-file:
    stage: build
    script:
        - echo "Hello World!" >> test.txt
    artifacts:
        paths:
            - test.txt
        expire_in: 1 week

print-file:
    stage: test
    script:
        - cat test.txt
    needs:
        - job: generate-file
          artifacts: true

02.3 - Dépendances (needs)⚓︎

Documentation officielle

Cela permet de modifier l’ordre d’exécution. Les dépendances sont liées aux jobs et non pas aux stages.

Schéma des dépendances

Schéma des dépendances
.gitlab-ci.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
build-site:
    stage: build
    script:
        - echo "Site..."
build-api:
    stage: build
    script:
        - echo "API..."
build-wiki:
    stage: build
    script:
        - echo "Wiki..."

deploy-app:
    stage: deploy
    script:
        - echo "Deploy app..."
    needs:
        - build-site
        - build-api
deploy-wiki:
    stage: deploy
    script:
        - echo "Publish wiki..."
    needs:
        - build-wiki

03 - Variables⚓︎

Documentation officielle

Je ne vais pas vous expliquer ce qu'est des variables (vous êtes normalement censés savoir ce que c'est...) mais voici les quatres types de variables dans Gitlab CI :

  • Variables prédéfini (CI_COMMIT_BRANCH, CI_PROJECT_NAME, etc.) : Variables proposées par défaut par Gitlab CI ;
  • Variables de groupes/projets : Définies par vous même soit globales aux projets d'un groupe ou spécifiques à un groupe (vous avez besoin d'être maintainer pour le faire) ;
  • Variables globales (de pipeline) : Définies dans le fichier .gitlab-ci.yml. C'est d'ailleurs elles qui permettent de configurer les paramètres ;
  • Variables de job : Définies sur chaque job.
Fonctionnement des variables (.gitlab-ci.yml)
1
2
3
4
job-name:
    script:
        - echo "$VAR_TEST"
        - 'echo "Nom du projet : $CI_PROJECT_NAME"'

Résultat du test des variables

Résultat du test des variables

04 - Conditions⚓︎

Il y a plein de type de conditions et de configurations mais nous allons voir celle qui sont souvent utilisés :

  • worflow : Configuration globale à tout le pipeline ;

    Dans l'exemple ci-dessous, on souhaite que la pipeline ne soit exécutable seulement lorsque l'on utilise l'interface web.

    .gitlab-ci.yml
    1
    2
    3
    4
    5
    workflow:
        rules:
          - if: $CI_PIPELINE_SOURCE == 'web'
            when: always
          - when: never
    
  • only & except : Configuration sur les jobs.

    Dans l'exemple ci-dessous, le job sera lancé seulement si on est sur la branche précisée.

    .gitlab-ci.yml
    1
    2
    3
    4
    5
    job-name:
        script:
          - echo "Hello World!"
        only:
          - my-branch
    

05 - Runners⚓︎

Documentation officielle

Les runners se sont des éléments clés pour pouvoir exécuter vos jobs car sans eux rien ne marche 😃 ! En fait, ce sont des agents exécutant les scripts des jobs de votre pipeline avec un environnement donné.

Sur PapierPain Corp. 🤡

Dans l'intance actuelle (gitlab.papierpain.fr), le runner par défaut c'est une image docker Alpine. Bien évidemment ce n'est pas du tout imposé, vous pouvez très bien généré votre image docker avec ce que vous voulez (⚠ faites attention à l'architecture du processeur pour la construction).

Ici on va voir deux types de runners, tels que :

  • Shell : Qui exécute les scripts directement sur le serveur où se trouve le runner.

    .gitlab-ci.yml
    1
    2
    3
    job-name:
        tag:
            - shell # tag permettant de choisir le runner shell
    
  • Docker : Qui crée un container docker où sera exécutées les commandes.

    .gitlab-ci.yml
    1
    2
    job-name:
        image: arm32v7/node:17.9-alpine # Comme le runner docker est par défaut, on a juste à préciser l'image que l'on souhaite
    

06 - Structure⚓︎

Pour ce qui est des fonctionnalités, globalement vous pouvez les retrouver sur la documentation officielle mais le problème est qu'il n'y a pas grand chose sur la structuration de vos pipeline. En effet, vous pouvez vous retrouver avec un seul fichier contenant les jobs pour les merge requests, les mises en production, etc. Donc ça devait très sale rapidemment.

Pour y remédier, voici quelques astuces à mettre en place.

06.1 - Configuration par défaut⚓︎

Ici on a un élément default qui servira de base pour tous les jobs.

.gitlab-ci.yml
1
2
3
4
5
6
7
default:
    tags:
        - shell

job-name:
    script:
        - echo "Hello!"

06.2 - Template de job⚓︎

L'inconvénient de l'élément default est qu'il s'exécute sur tous les jobs mais si vous souhaitez définir une configuration commune à certain jobs, il faudra utiliser les Templates.

.gitlab-ci.yml
1
2
3
4
5
6
7
8
.shell-template:
    tags:
        - shell

job-name:
    extends: .shell-template
    script:
        - echo "Hello!"

06.3 - Scripts⚓︎

Si vous avez un script assez important, je vous conseille FORTEMENT de faire une fonction dans un fichier à part. Voici un fichier type que vous pouvez créer (avec les commentaires c'est top !).

ci/scripts/my_function.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/bin/sh
set -x

#! USAGE:
#!   path/to/script.sh <param-01> <param-02>
#! MAIN:
#!   Description of the function

function_name()
{
    VAR_01=$1
    VAR_02=$2
    VAR_03="value"

    # Do something
}

function_name $1 $2
.gitlab-ci.yml
1
2
3
job-name:
    script:
        - ./ci/scripts/my_function.sh param01 param02

06.4 - Externalisation des fichiers Gitlab CI⚓︎

Enfin, vous pouvez aussi avoir des fichiers de configuration avec le pattern amazing-file.gitlab-ci.yml que vous appelez dans votre fichier principal .gitlab-ci.yml.

Par exemple :

ci/jobs/amazing-file.gitlab-ci.yml
1
2
3
job-name:
    script:
        - ./ci/scripts/my_function.sh param01 param02
.gitlab-ci.yml
1
2
include:
    - local: ci/jobs/amazing-file.gitlab-ci.yml

Arborescence du CI/CD

Comme vous avez pu le voir, je ne mets pas les fichiers à la racine car le but est d'avoir quelque chose de clair sachant que le CI/CD ne doit pas conplexifier l'arborescence de base du projet. C'est pour ça que l'on met toute la configuration dans un dossier ci.

Arborescence
1
2
3
4
5
6
ci
├── jobs
│   └── amazing-file.gitlab-ci.yml
└── scripts
    └── my_function.sh
.gitlab-ci.yml