Construire un pipeline CI/CD Docker-Jenkins pour une application Python (Partie 2)

Déployer une application Python à l'aide d'un pipeline CI/CD


12/2022 10 min read 1912 words

[!note] Ceci est la suite du tutoriel pour construire un pipeline Docker Jenkins pour déployer une application Python simple en utilisant Git et GitHub. La première partie du tutoriel se trouve ici.

Installation de Jenkins

Nous avons maintenant les bases pour déployer notre application. Installons les logiciels restants pour compléter notre pipeline.

Nous commençons par importer la clé GPG qui vérifiera l’intégrité du paquet.

curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo tee \
  /usr/share/keyrings/jenkins-keyring.asc > /dev/null

Ensuite, nous ajoutons le dépôt Jenkins softwarey à la liste des sources et fournissons la clé d’authentification.

echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
  https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
  /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt update

Jenkins Key and Source

Maintenant, nous installons Jenkins

sudo apt-get install -y jenkins

Attendez que le processus d’installation soit terminé et que vous repreniez le contrôle du terminal.

Installing Jenkins

Pour vérifier que Jenkins a été installé correctement, nous allons vérifier si le service Jenkins est en cours d’exécution.

sudo systemctl status jenkins.service

Verifying Jenkins Installation

Appuyez sur Q pour reprendre le contrôle.

Configuration de Jenkins

Nous avons vérifié que le service Jenkins est maintenant en cours d’exécution. Cela signifie que nous pouvons aller de l’avant et le configurer à l’aide de notre navigateur.

Ouvrez votre navigateur et tapez ceci dans la barre d’adresse :

localhost:8080

La page Débloquer Jenkins devrait s’afficher.

Unlocking Jenkins for First Use

Jenkins a généré un mot de passe par défaut lors de son installation. Pour localiser ce mot de passe, nous allons utiliser la commande :

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

Jenkins first unlock password

Copiez ce mot de passe et collez-le dans la case de la page d’accueil.

Sur la page suivante, sélectionnez « Installer les plugins suggérés ».

Jenkins Suggested Plugins

Vous devriez voir Jenkins installer les plugins.

Jenkins Plugins Installation

Une fois l’installation terminée, cliquez sur Continuer.

Sur la page Create Admin User (Créer un utilisateur administrateur), cliquez sur Skip and Continue as Admin (Ignorer et continuer en tant qu’administrateur). Vous pouvez également créer un utilisateur Admin distinct, mais veillez à l’ajouter au groupe Docker.

Cliquez sur « Save and Continue

Sur la page Instance Configuration, Jenkins indiquera l’URL à laquelle il est possible d’accéder. Laissez-la et cliquez sur « Save and Finish ».

Cliquez sur « Start Using Jenkins ». Vous arriverez sur une page de bienvenue comme celle-ci :

Jenkins Landing Page

Nous avons maintenant configuré Jenkins avec succès. Revenons au terminal pour installer Docker.

Installation de Docker

Tout d’abord, nous devons désinstaller tous les éléments Docker précédents, s’il y en a.

sudo apt-get remove docker docker-engine docker.io containerd runc

Il est probable que rien ne sera supprimé puisque nous travaillons avec une nouvelle installation d’Ubuntu.

Nous utiliserons la ligne de commande pour installer Docker.

sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

Docker Pre-requisites

Ensuite, nous allons ajouter la clé GPG de Docker, comme nous l’avons fait avec Jenkins.

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Nous allons maintenant configurer le repository.

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Ensuite, nous allons installer le Docker Engine.

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Docker Installation

Vérifiez maintenant l’installation en tapant

docker version

Docker version

Notez que vous obtiendrez une erreur de permission refusée lors de la connexion au daemon socket de Docker. C’est parce qu’il nécessite un utilisateur root. Cela signifie que vous devrez préfixer sudo à chaque fois que vous voudrez exécuter des commandes Docker. Ce n’est pas idéal. Nous pouvons y remédier en créant un groupe Docker.

sudo groupadd docker

Le groupe docker peut déjà exister. Ajoutons maintenant l’utilisateur à ce groupe.

sudo usermod -aG docker $USER

Appliquez les modifications aux groupes Unix en tapant ce qui suit :

newgrp docker

[!warning] Si vous suivez ce tutoriel sur une VM, il se peut que vous deviez redémarrer votre instance pour que les changements prennent effet.

Vérifions que nous pouvons maintenant nous connecter au moteur Docker.

docker version

Docker Engine Version

Comme nous pouvons le voir, Docker est maintenant pleinement fonctionnel avec une connexion au moteur Docker.

Nous allons maintenant créer le fichier Docker qui construira l’image Docker.

Création du fichier Docker

Dans votre terminal, dans votre dossier, créez le Dockerfile en utilisant l’éditeur nano.

sudo nano Dockerfile

Tapez ce texte dans l’éditeur :

FROM python:3.8
WORKDIR /src
COPY . /src
RUN pip install flask
RUN pip install flask_restful
EXPOSE 3333
ENTRYPOINT ["python"]
CMD ["./src/helloworld.py"]

Construire l’image Docker

A partir du fichier Docker, nous allons maintenant construire une image Docker.

docker build -t helloworldpython .

Building the Docker Image

Créons maintenant un conteneur de test et lançons-le dans un navigateur pour vérifier que notre application s’affiche correctement.

docker run -p 3333:3333 helloworldpython

Ouvrez votre navigateur et allez sur localhost:3333 pour voir notre application python en action.

Python Webapp Running

Voyons maintenant comment automatiser cette impression à chaque fois que nous apportons une modification à notre code python.

Création du fichier Jenkins

Nous allons créer un fichier Jenkins qui élaborera un processus étape par étape de construction de l’image à partir du fichier Docker, en la poussant vers le registre, en la récupérant du registre et en l’exécutant en tant que conteneur.

Chaque modification apportée au dépôt GitHub déclenchera cette chaîne d’événements.

sudo nano Jenkinsfile

Dans l’éditeur nano, nous utiliserons le code suivant comme fichier Jenkins.

node {
	def application = "pythonapp"
	def dockerhubaccountid = "nyukeit"
	stage('Clone repository') {
		checkout scm
	}

	stage('Build image') {
		app = docker.build("${dockerhubaccountid}/${application}:${BUILD_NUMBER}")
	}

	stage('Push image') {
		withDockerRegistry([ credentialsId: "dockerHub", url: "" ]) {
		app.push()
		app.push("latest")
	}
	}

	stage('Deploy') {
		sh ("docker run -d -p 3333:3333 ${dockerhubaccountid}/${application}:${BUILD_NUMBER}")
	}

	stage('Remove old images') {
		// remove old docker images
		sh("docker rmi ${dockerhubaccountid}/${application}:latest -f")
   }
}

Explication du fichier Jenkins

Notre pipeline Jenkins est divisé en 5 étapes comme vous pouvez le voir dans le code.

  • Etape 1 - Clone notre repo Github
  • Etape 2 - Construit notre image Docker à partir du fichier Docker
  • Etape 3 - Pousse l’image vers Docker Hub
  • Étape 4 - Déploie l’image en tant que conteneur en l’extrayant de Docker Hub
  • Étape 5 - Supprime l’ancienne image pour mettre fin à l’empilement d’images.

Maintenant que notre fichier Jenkins est prêt, poussons tout notre code source sur GitHub.

Pousser des fichiers sur GitHub

Tout d’abord, vérifions le statut de notre repo local.

git status

Git not tracking files

Comme nous pouvons le voir, il n’y a pas encore de commits et il y a des fichiers et des dossiers non suivis. Demandons à Git de les suivre afin que nous puissions les pousser vers notre dépôt distant.

git add *

Cela ajoutera tous les fichiers présents dans le scope git.

Git suit maintenant nos fichiers et ils sont prêts à être livrés. La fonction commit pousse les fichiers vers la zone de stockage où ils seront prêts à être poussés.

git commit -m "First push of the python app"

First commit to Git

Il est maintenant temps de pousser nos fichiers.

git push -u origin main

Accédons à notre repo sur GitHub pour vérifier que notre push s’est bien déroulé.

Verifying the first push to GitHub

Création des identifiants Jenkins

Dans le tableau de bord Jenkins, allez dans Manage Jenkins.

Manage Jenkins

Dans la section Sécurité, cliquez sur Gérer les informations d’identification.

Manage Credentials in Jenkins

Dans la section des informations d’identification, cliquez sur Système. Sur la page qui s’ouvre, cliquez sur Global Credentials Unrestricted (informations d’identification globales non restreintes)

System Credentials

Global Credentials

Cliquez maintenant sur Add Credentials.

Gardez ‘Kind’ comme ‘Username and Password’ (nom d’utilisateur et mot de passe)

Dans ‘username’ tapez votre nom d’utilisateur Docker Hub.

Dans ‘password’ tapez votre mot de passe Docker Hub.

Si vous avez activé 2FA dans votre compte Docker Hub, vous devez créer un jeton d’accès et l’utiliser comme mot de passe ici.

Dans ‘ID’, tapez ‘dockerHub’

Enfin, cliquez sur Create

Docker credentials in Jenkins

Création d’un job Jenkins

Pour fermer notre pipeline, nous allons créer un job Jenkins qui sera déclenché lorsqu’il y aura des changements sur notre repo GitHub.

Dans Jenkins, si ce n’est pas déjà fait, installez les plugins Docker et Docker Pipeline. Redémarrez votre instance Jenkins après l’installation.

Cliquez sur New Item dans votre tableau de bord Jenkins. Entrez le nom de votre choix. Sélectionnez Pipeline et cliquez sur OK.

Jenkins New Project Pipeline

Dans la page de configuration, saisissez la description que vous souhaitez.

Configuring a Jenkins Project

Dans ‘Build Triggers’, sélectionnez Poll SCM.

Jenkins Poll SCM & Schedule

Dans ‘Schedule’, tapez * * * * * * (avec des espaces entre les deux). Ceci va interroger notre repo GitHub toutes les minutes pour vérifier s’il y a des changements. C’est souvent trop rapide pour un projet, mais nous ne faisons que tester notre code.

Dans la section ‘Pipeline’, dans ‘definition’ sélectionnez Pipeline Script from SCM. Ceci recherchera le fichier Jenkins que nous avons téléchargé dans notre repo sur GitHub et l’appliquera.

Ensuite, dans SCM, dans la section ‘Repositories’, copiez et collez votre repo GitHub HTTPS URL.

Jenkins Poll SCM Config

Dans ‘Branches à construire’, par défaut, il y aura master. Changez-la en main, puisque notre branche s’appelle main.

Assurez-vous que le ‘Script Path’ contient déjà ‘Jenkinsfile’. Si ce n’est pas le cas, vous pouvez le taper.

Jenkins SCM Branch

Cliquez sur Save.

Notre job Jenkins est maintenant créé. Il est temps de voir l’ensemble du pipeline en action.

Cliquez sur ‘Build Now’. Cela va déclencher toutes les étapes et si toutes les configurations sont correctes, notre conteneur devrait fonctionner avec l’application python et notre image personnalisée téléchargée sur Docker Hub. Vérifions cela.

Jenkins Console Output

Verifying our image on Docker Hub

Comme nous pouvons le voir, notre image personnalisée est maintenant disponible dans notre compte Docker Hub.

Vérifions maintenant que le conteneur fonctionne.

docker ps

Transmettre les changements à l’application Python

Pour voir le flux automatisé complet en action, modifions un peu l’application Python et retournons dans notre navigateur pour voir les changements se refléter automatiquement.

Nous avons changé le texte de sortie de Bonjour le monde! à Bonjour le monde ! J’apprends le DevOps!

Sauvegardez le fichier et envoyez-le sur GitHub.

Comme nous pouvons le voir, cette action a déclenché la création d’un job automatique sur Jenkins, qui a abouti à la Build No. 2 de notre application.

Jenkins build auto-trigger

Nous pouvons maintenant voir que notre application a 2 builds. Dans le premier build, nous pouvons voir ‘no changes’ parce que nous avons déclenché manuellement le premier build après avoir créé notre dépôt. Toutes les modifications ultérieures donneront lieu à une nouvelle compilation.

Nous pouvons voir que la Build No 2 mentionne qu’il y a eu 1 commit.

Jenkins 2nd Build Successfull

En ce qui concerne notre application web, le message affiché a maintenant changé.

Python App updated

C’est ainsi que nous pouvons créer une automatisation Docker-Jenkins.

Resources

Installing Jenkins

Installing Docker on Ubuntu

Fix Docker Socket Permission Denied

Dockerize your Python Application

Containerize A Python Application

Contents