Pourquoi et comment mettre en place une politique de CI/CD ?

Image de couverture du post

Pourquoi et comment mettre en place une politique de CI/CD ?

Share on twitter
Share on linkedin
Share on pinterest
Share on reddit
Share on pocket
Share on email

Avec l’arrivée des nouvelles méthodes de travail comme l’Agile, le DevOps et maintenant le DataOps, les mises en production sont devenues beaucoup plus fréquentes. Ces nouvelles pratiques amènent toutes un lot d’avantages : flexibilité, efficacité des équipes, qualité des livraisons ; mais également leur lot de problématiques auxquelles il faut répondre en optant pour des bonnes pratiques, et en utilisant les bons outils.

Les déploiements en production étant plus fréquents, il est devenu indispensable de réduire le temps nécessaire à ce déploiement. Les tests et la mise à jour du code sont de plus en plus automatisés via des outils qu’on détaillera plus tard dans l’article.

Nouvelles fonctionnalités, code déployé sur l’environnement de développement ou sur l’environnement de production, il faut être maître de ces différentes versions et appliquer des bonnes pratiques pour éviter les mauvaises surprises.

« Tout seul on va plus vite, ensemble, on va plus loin« , et pour aller plus loin ensemble il faut d’abord appliquer des bonnes pratiques dans son code. Et également organiser ses projets afin de permettre de fusionner le travail de chacun dans les meilleures conditions avant une mise en production par exemple.

Cet article a pour objectif d’expliquer pourquoi il est important d’opter pour une politique de CI/CD en expliquant le procédé que l’on a mis en place chez Saagie pour exemple.

Qu'est-ce que la CI/CD ?

Avant de rentrer dans le cœur du sujet, commençons par définir la CI/CD. C’est un acronyme qui se réfère à la combinaison des pratiques qui permettent de livrer les modifications du code plus fréquemment et de manière plus fiable lors d’un développement logiciel.

La partie CI correspond à l’intégration continue. Elle consiste à construire, assembler et tester les modifications dans le code des applications de manière automatisée. De ce fait, les équipes sont plus susceptibles d’apporter des modifications fréquentes. Cela conduit à une meilleure collaboration au sein de l’équipe et à une meilleure qualité des applications, notamment en facilitant la gestion des conflits via des merges plus réguliers. Le processus CI peut englober des tests unitaires, des tests d’intégration, des tests de sécurité, etc, qu’on ne détaillera pas dans cet article.

Le CD, quant à lui, désigne la distribution continue et/ou le déploiement continu. Il automatise la livraison des applications au sein d’environnements d’infrastructure sélectionnés. C’est à dire que le CD est là pour automatiser le déploiement des modifications qui sont faites lors du CI dans l’environnement choisi (que ce soit un environnement de test, de développement ou même celui de production).

Quelques bonnes pratiques sur Git

Lors de l’initialisation d’un repository git, une branche master est automatiquement créée. Il est très fortement recommandé de ne pas faire de modifications directement sur cette branche et de créer une branche dédiée pour chaque ajout de fonctionnalité, correction de bugs. Exemple:

Exemple de branches sur un projet
Exemple de branches sur un projet

Ensuite, de faire une demande de Merge Request pour que ces modifications soient prises en compte dans la branche master. A chaque modification, des tests sont réalisés pour qu’il n’y ait pas de régression du fonctionnement. Pusher les modifications régulièrement (de manière journalière) permet un meilleur partage au sein du projet. De plus, cela servira de backup en cas de perte de code en local. Si des bugs sont détectés, la création d’issues permet de logger l’historique des bugs et de leur résolution.

Gitflow, des commits avec des messages clairs et informatifs, des rebases réguliers sur la branche master sont aussi de bonnes pratiques à prendre et il en existe plein d’autres. Certaines sont présentées dans cet article.

CI/CD GitLab

Il existe de nombreux outils pour faciliter la mise en place du CI/CD. Chez Saagie, nous utilisons les outils de CI/CD de GitLab.

On a cité quelques bonnes pratiques d’utilisation de Git, nous allons maintenant nous intéresser à Gitlab. C’est une solutions basée sur Git qui propose de nombreuses fonctionnalités, dont celle qui nous intéresse aujourd’hui : Gitlab CI/CD. Cette fonctionnalité intégrée à GitLab nous permet d’appliquer de la CI/CD sans installer d’application tierce.

Pour appliquer cette CI/CD dans Gitlab, tout passe par un fichier YAML: « .gitlab-ci.yml« . Une fois créé à la racine du projet, Gitlab détecte sa présence et va exécuter à chaque commit un pipeline de CI/CD. En fonction de sa configuration, ce pipeline va exécuter différentes instructions de build, de test et / ou de déploiement.

Exemple de fichier .gitlab-ci.yml:

# Définit l'image docker à utiliser pour exécuter le pipeline
image: gradle:alpine

# Définit les jobs (ou "stages") qui vont être exécutés pendant le pipeline 
stages:
  - test
  - deploy

# Stage test
unit tests:
  # Run unit tests on a specific image with python Installed
	image: saagie/python:3.7-1.46.0
	# Défini le tag du runner à utiliser pour l'exécution du job
  tags:
    - docker
	# Défini le "stage"
  stage: test
	# Défini le script à exécuter pour effectuer les tests
  script:
    - python -m unitTests
	# Défini les branches sur lesquelles le "stage" doit êter exécuté
  only:
    - develop
    - master

# Stage deploy sur la branche develop
deploy job to dev:
  tags:
    - docker
  stage: deploy
  script:
    - gradle -b saagie/jobs/build.gradle projectsUpdateJob -PjobName=collect -Penv=dev
    - gradle -b saagie/jobs/build.gradle projectsUpdateJob -PjobName=process -Penv=dev
  only:
    - develop

# Stage deploy sur la branche master
deploy job to prod:
  tags:
    - docker
  stage: deploy
  script:
    - gradle -b saagie/jobs/build.gradle projectsUpdateJob -PjobName=collect -Penv=prod
    - gradle -b saagie/jobs/build.gradle projectsUpdateJob -PjobName=process -Penv=prod
  only:
    - master

De ce fichier de configuration va découler un pipeline :

pipeline

Dans l’exemple ci-dessus, pour les « stages » deploy, on utilise la technologie gradle pour le packaging du code, et le déploiement du code dans l’environnement de développement ou de production selon la branche sur laquelle est poussée le code.

Gradle est un système de gestion de build, et nous avons développé un Plugin Gradle spécifique pour faciliter l’interaction avec la plateforme Saagie. Ce plugin nous permet par exemple de mettre à jour un job (un script), de run (exécuter) un job, d’exporter et d’importer un projet (les jobs, les pipelines et les variables d’environnement associées) sous format zip. Pour voir plus de fonctionnalités, n’hésitez pas à faire un tour sur ce lien github. Pour l’utiliser, nous devons créer un fichier build.gradle et un fichier properties (qui contient des variables dont aura besoin le fichier build.gradle). Voici un exemple de fichier build.gradle :

Exemple de fichier: build.gradle

plugins {
    id "io.saagie.gradle-saagie-dataops-plugin" version "1.1.68"
    id 'net.saliman.properties' version '1.5.1'
}


ext.commit_message = System.getenv('CI_COMMIT_MESSAGE') + " - "+  System.getenv('CI_PROJECT_URL') + "/-/commit/" + System.getenv('CI_COMMIT_SHA')
ext.is_ci = System.getenv('CI')


def releaseMessage = (is_ci != null) ? commit_message : "WIP"
def saagieProjectId =  (env == 'prod') ? saagieProjectIdProd : saagieProjectIdDev
def saagieJobId =  (env == 'prod') ? saagieJobIdProd : saagieJobIdDev
// You can get Saagie Platform IDs from Saagie URL
// https://base_url/projects/platform/[ID_PLATFORM]/project/[ID_PROJECT]/job/[ID_JOB]
def saagiePlatform =  (env == 'prod') ? 2 : 1
def saagieJobIsScheduled = (saagieJobIsScheduled == 'true') ? true : false
def saagieJobCronScheduling = (saagieJobIsScheduled == true) ? saagieJobCronScheduling : null
def saagieExtraTechnologyLanguage = (saagieJobType == 'spark') ? saagieExtraTechnologyLanguage : null
def saagieExtraTechnologyVersion = (saagieJobType == 'spark') ? saagieExtraTechnologyVersion : null

task packageCode(type: Zip) {
    archiveFileName = "${jobPath}.zip"
    destinationDirectory = file("/tmp/saagie")
    from "../../code/${jobPath}", "../../code/dependencies"
}

// The "url" value to fill is the base URL from Saagie. Everything before 
// "/projects/platform" when you're on the 'projects' module (including "https://")
saagie {
    server {
        url = TODO
        login = System.getenv('SAAGIE_LOGIN')
        password = System.getenv('SAAGIE_PWD')
        environment = saagiePlatform
        jwt = true
    }
    project {
        id = saagieProjectId
    }
    job {
          id = saagieJobId
          name = saagieJobName
          description = saagieJobDescription
          isScheduled = saagieJobIsScheduled
          cronScheduling = saagieJobCronScheduling
        }
    jobVersion {
        commandLine = commandLine
        releaseNote = releaseMessage
        runtimeVersion = saagieJobRuntimeVersion
        extraTechnology {
            language = saagieExtraTechnologyLanguage
            version = saagieExtraTechnologyVersion
        }
        packageInfo {
            name = "/tmp/saagie/${jobPath}.zip"
        }
    }
}


projectsUpdateJob.dependsOn(packageCode)
projectsRunJob.dependsOn(projectsUpdateJob)

On considère souvent qu’on possède deux environnements de travail : un environnement de développement, et un environnement de production, c’est pour cela que dans le build.gradle, vous trouverez des variables dont la valeur est différente selon l’environnement (les variables saagieProjectId, saagieJobID, et saagiePlatform).

Dans ce fichier build.gradle, on retrouve des plugins, des variables locales, des tâches, et une configuration. On remarquera qu’il y a une variable releaseMessage qui correspond au message du commit avec l’url du projet et le SHA (Secure Hash Algorithm) du commit, si notre variable d’environnement CI est différente de nulle. Sinon, elle est égale à WIP (Working In Progress). C’est cette variable que nous passons en paramètre dans la configuration et qui nous permet de retrouver le commit à une version de job donnée dans la release note du job. Ainsi, chaque version de job sur Saagie sera reliée à un commit dans Gitlab.

De ce fait, dans le cadre du CI/CD, ce plugin facilite le déploiement en continu et nous permet d’avoir un lien entre un commit du projet et une version du job déployé sur Saagie.

On peut aussi utiliser ce plugin pour pousser du code sur une plateforme Saagie depuis une IDE en utilisant la même ligne de commande que dans le fichier .gitlab-ci.yml:

 gradle -b saagie/jobs/build.gradle projectsUpdateJob -PjobName=collect -Penv=prod

On a beaucoup parlé de Saagie, mais qu’est-ce que c’est, en quoi cela permet-il de faciliter la CI/CD ?

Saagie et la CI/CD

Saagie est une plateforme DataOps. Elle rassemble de nombreuses technologies du marché data pour permettre aux data engineers de faciliter, d’accélérer et de fiabiliser la mise en production de leurs projets. Concrètement, elle met à disposition un environnement conçu pour la production qui permet de construire, d’exécuter et de déployer des pipelines automatisés.

En terme de process, elle permet d’automatiser le cycle de vie de la donnée. On peut faire

  • le déploiement en continu en connectant nos outils CI/CD via des plugins et APIs
  • le versionning des traitements: on peut documenter chaque version du job, superviser leurs logs pour chaque instances de lancement et effectuer des rollbacks si nécessaire
  • industrialiser des cas d’usage (automatiser la promotion des jobs entre environnements)

Pour une version de job, on a une vue comme suit. Sur cette image, on voit bien apparaître la release note qui contient le lien vers le commit du projet

Il est important de mettre en place une politique de CI/CD le plus tôt possible afin de gagner du temps par la suite sur vos projets. Même si le déploiement d’une stack de CI/CD s’avère coûteux au début, cela permet par la suite de d’intégrer, tester et déployer plus fréquemment les modifications que vous développez. En plus de cela, les différents outils, comme Gradle et Gitlab CI/CD, facilitent la collaboration au sein d’un même environnement pour une équipe.

Ces bonnes pratiques permettent également d’améliorer le monitoring de vos projets en normalisant les processus d’intégration et de déploiement à travers des outils.

Notre article sur les bonnes pratiques de monitoring