Introduction

La Software Factory, est une suite logicielle modulaire et flexible pour répondre aux différents enjeux et besoins dans un contexte multi-clients, multi-sites, multi-prestataires, multi-technologies (Java, C/C++, PhP …), avec un processus et des outils à l’état de l’art :

  • Piloter l’usine logicielle, un site de production, un projet en particulier,
  • Maîtriser le processus de fabrication, la qualité du logiciel, les livrables venant de l’extérieur …
  • Standardiser le processus d’intégration continue, les tests systèmes, le suivi des exigences, le déploiement …
  • Améliorer la Productivité en automatisant les tâches non créatives et en incitant à la réutilisation.

C’est aussi une méthodologie d’audit puis d’accompagnement au changement et de formation pour :

  • Impliquer les différents acteurs et parties prenantes,
  • Industrialiser depuis une usine logicielle existante,
  • Accélérer le cycle de développement des produits.

Principales Fonctionnalités

Foundation : un socle de briques open source (OSS) enrichi par des use-cases :

  • Normalise les processus de développement pour plus de productivité,
  • Unifie l’usage des modules pour automatiser les tâches répétitives,
  • Rationalise le déploiement et le paramétrage de l’usine logicielle pour des montées de version maîtrisées.

Des modules additionnels indispensables :

  • Activity : pour suivre votre activité globale (timesheet, CIR/CII …),
  • Dashboard : pour des tableaux de bord de pilotage basé sur des KPI devons et la méthodologie Balanced-Score-Card (BSC),
  • Checking : pour une qualimétrie logicielle et une douane applicative.

Mise en oeuvre

Pour la mise en place d’une usine logicielle :

  • Suivi des versions : On utilise Git pour suivre les modifications sur le code source, permettre un retour en arrière, isoler des développements sur des branches, permettre la revue de code, etc. On utilise des versions en ligne (Github, Bitbucket), ou des logiciels libres (Gitlab)
  • Automatiser la Compilation : avec la mise en place de scripts de compilation (Bash, MakeFile, Gradle, Maven) déclenchés automatiquement par les outils d’intégration continue (Jenkins, Gitlab-ci, Travis)
  • Qualité de Code : Le service d’intégration continue peut déclencher les tests unitaires ou d’intégration (sur Docker), mais également lancer une analyse de code via SonarQube par exemple.
  • Déploiement : Déploiement Automatique vers les serveurs de tests ou d’intégration, et déploiement à la demande sur les serveurs de production. Livraison automatique des livrables sur les plateformes dédiées.

Installation Jenkins

Installation Docker

Installation Harbor

Interface Jenkins/Docker

Pour information, l'installation de Jenkins et docker a été réalisé sur CentOS 7

Après avoir effectué l'installation de Jenkins et Docker, il faut dans tout d'abord effectuer le paramétrage de Docker pour activer l'API REST ce qui est indispensable pour le rendre opérationnel l'interfaçage avec Jenkins.

Dans un premier temps, nous allons rendre SElinux permissif :

# setenforce permissive (pour la session en cours)
# sed -i s/enforcing/permissive/g /etc/selinux/config (pour que cela persiste au redémarrage)

Nous pouvons maintenant procéder à la configuration de Docker et activer l'API REST.

Pour activer le mode API il faut créer un fichier d'override systemd du service docker :

# systemctl edit docker

Puis y saisir le bloc suivant :

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:<port> --containerd=/run/containerd/containerd.sock

Nous constatons qu'il y a 2 fois la variable ExecStart pour la simple est bonne raison que systemd ne permet pas de surcharger directement des variable, il est nécessaire de abord “unset” la variable, puis de la “set” de nouveau suivi la commande que nous souhaitons passer.

Remplacez <port> par le port souhaité, dans notre exemple, nous allons utiliser le port 2376

ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 --containerd=/run/containerd/containerd.sock

Nous allons ensuite autoriser le port de l'API sur le firewall de l'OS

# firewall-cmd --add-port 2376/tcp --permanent
# firewall-cmd --reload

Il faut effectué ensuite un reload du daemon systemd afin que notre fichier d'override soit pris en compte au prochain démarrage de docker et nous allons le démarrer par la même occasion :

# systemctl daemon-reload && systemctl start docker

Maintenant que Docker est démarré nous allons vérifier que le port de l'API est bien en écoute :

# ss -lntp | grep 2376
LISTEN     0      128       [::]:2376                  [::]:*                   users:(("dockerd",pid=13004,fd=3))

Nous allons également s'assurer que l'API fonctionne correctement, nous allons faire le teste en lançant un container en mode détaché :

# docker run --name test-api -d -it ubuntu bash

Nous vérifions que le container est bien démarré :

# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
b61f0125afe9        ubuntu              "bash"              4 seconds ago       Up 4 seconds                            test-api

Nous pouvons désormais vérifier que l'API est bien opérationnelle en faisant une requête HTTP GET à l'aide de curl

# curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://localhost:2376/containers/json

Nous devrions obtenir le résultat suivant :

HTTP/1.1 200 OK
Api-Version: 1.40
Content-Type: application/json
Docker-Experimental: false
Ostype: linux
Server: Docker/19.03.8 (linux)
Date: Tue, 07 Apr 2020 17:31:05 GMT
Content-Length: 782

[{"Id":"b61f0125afe9c6e09295850f31c751422897ecb7bcb6a7522c4b2f88747434ce","Names":["/test-api"],"Image":"ubuntu","ImageID":"sha256:4e5021d210f65ebe915670c7089120120bc0a303b90208592851708c1b8c04bd","Command":"bash","Created":1586280369,"Ports":[],"Labels":{},"State":"running","Status":"Up 4 minutes","HostConfig":{"NetworkMode":"default"},"NetworkSettings":{"Networks":{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"ab2f857aeb3fb5e570cf014d9fe5fd6c8a3970acf3519d14d99c10754c5a2779","EndpointID":"4628c1ede46eb57f9d772ba57c197f7b8f4c14f0a5ccff20cb3f0f49f96a4c2a","Gateway":"172.17.0.1","IPAddress":"172.17.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02","DriverOpts":null}}},"Mounts":[]}]

A partir de cet instant nous pouvons confirmer que l'API Rest de docker est bien accessible, ce test peut être fait également depuis la machine Jenkins afin de s'assuré qu'il n'y a pas de blocage réseau entre ces 2 serveurs. Vous pouvez également stopper le container qui a été lancé, nous n'en aurons plus besoin.


Après avoir réalisé l'installation de Docker, nous pouvons désormais passer au paramétrage de Jenkins et la mise en place de son interconnexion avec Docker. Le but de cette configuration est de déployer des container docker qui auront pour rôle d'être des agents Jenkins.

Installation du plugin Docker

Se rendre dans le menu : Jenkins > Administrer Jenkins > Gestion des plugins

Lorsque vous êtes arrivé sur la page Gestion des plugins , cliquer sur l'onglet “Disponibles” , puis dans le champs Filtre saisir : Docker

Sélectionner ensuite le plugin Docker puis cliquer sur “Installer sans redémarrer”

Lorsque l'installation sera terminer, passer à l'étape suivante.


Paramétrage du plugin Docker

Pour notre exemple, l'IP du serveur Docker est 10.0.0.3

Se rendre dans le menu : Jenkins > Administrer Jenkins > Gerer les noeuds

Dans le menu de droite cliquer sur Configure Clouds

Puis cliquer sur “Ajouter un nouveau cloud” , sélectionner “Docker” , ensuite cliquer sur “Docker Cloud details” .

A partir de là, il faut renseigner les champs suivant :

  • Name
  • Docker Host URI
  • Cocher la case “Enabled”

Name : Correspond au nom que nous donnons à notre cloud, cela permettra par la suite de le repérer sur la page suivante https://<JENKINS_URL/docker-plugin/
Docker Host URI : Correspond à l'URI du serveur Docker vers lequel nous devons pointé, tcp://<IP_ou_FQDN_du_serveur_docker>:<port>
Enabled : Permet d'activer ou de désactiver le cloud

Une fois les 3 champs renseigné, cliquer sur “Test Connection” , cela effectuera un test de connexion vers le serveur Docker que nous avons paramétré

Voici un exemple de configuration :


Paramétrage d'un Agent

Il est important de noter que les images qui seront déployé comme agents doivent avoir JAVA (1.8 minimum) d'installé ansi que le .jar de l'agent Jenkins, l'image de base que nous utiliserons dans cet exemple est : https://hub.docker.com/r/jenkins/agent/ Vous pouvez consulter le dockerfile ici : https://www.github.com/jenkinsci/docker-agent

Toujours sur la page “Configure Clouds” , après avoir effectué le paramétrage du serveur Docker, nous pouvons désormais procéder au paramétrage d'un Agent Jenkins. Pour ce faire, cliquer sur “Docker Agent Template” .

A partir de là, il faut au minimum renseigner les champs suivant :

  • Labels
  • Cocher la case “Enabled”
  • Docker Image

Labels : Correspond au nom de l'agent, ce nom doit être pertinent, il sera utilisé dans les jobs.
Enabled : Permet d'activer ou de désactiver l'agent.
Name : Correspond au nom du container qui sera déployé, se nom sera suivi d'un ID aléatoire lorsque le container sera déployé pour un job. Docker Image : Corresponds au nom de l'image situé sur une registry Docker, par défaut, le plugin va récupérer les images sur hub.docker.io, mais nous pouvons préciser une autre registry au besoin, il faudra préciser le chemin complet sous la forme <fqdn_registry>/<projet>/<image>:<tag> par exemple registry.demo.com/monprojet/ssh-slave:latest

Voici un exemple de configuration exploitant une autre registry que hub.docker.io :

Pour cet exemple, nous avons tout simplement répliqué l'image officiel jenkins/agent sur notre registry personnelle. Par la suite nous mettrons en place une pipeline pour exploiter cet agent et ses fonctionnalités incluse (bash et GIT).

Et enfin cliquer sur “Save” .


Validation Jenkins / Docker

La pipeline que nous allons mettre en place, va permettre d'exploiter l'agent, ainsi que le contenu du container, l'image est basé sur une Debian Buster 10.3 avec openjdk11 et git.

Dans un premier temps, créer un nouvel item de type “pipeline”, pour ce test, nous allons utiliser le code suivant qui va effectuer un git sur un repos publique et exécuter un script bash “Hello world”

pipeline {
   agent none

   stages {
      stage('Hello') {
          agent { label 'docker-agent' }
          steps {
            git 'https://github.com/ruanyf/simple-bash-scripts.git'
            sh 'scripts/hello-world.sh'
          }
      }
   }
}

Lors de l’exécution du job, nous pouvons constaté qu'un agent Jenkins est généré sur notre host docker.

Maintenant que nous avons valider ce test nous allons maintenant travailler avec 2 container partageant le même volume, le premier container sera l'agent Jenkins qui nous avons précédemment paramétré, le second sera un container sous ansible 2.9.
Nous allons tout d'abord créer un nouveau volume sur le host docker :

# docker volume create jenkins_data


Nous pouvons maintenant effectué la configuration volumes sur les templates, retourner sur la page de configuration “Configure Clouds”, sur le template “docker-agent”, cliquer sur “container settings”, un formulaire va apparaître, dans le champs “Volumes” saisir :

jenkins_data:/home/jenkins

Maintenant il faut créer le “Docker Agent Template” pour le container ansible, cliquer sur “Add Docker Template” et saisir les paramètres suivants dans les champs adéquats :

  • Labels: ansible
  • Cocher la case “Enabled”
  • Name: ansible
  • Image: gdelachat/jenkins-ansible
  • Volumes : jenkins_data:/home/jenkins


L'image “gdelachat/jenkins-ansible” a été build par mes soins en se basant sur l'image docker-agent, dans celui-ci git n'est pas embarqué, mais uniquement ansible 2.9

On peut s'assurer que le container Ansible fonctionne correctement en utilisant la pipeline test suivante :

pipeline {
   agent none
   stages {
      stage('Ansible') {
          agent { label 'ansible' }
          steps {
            sh 'ansible localhost -m setup'
          }
      }
   }
}

Nous devons normalement obtenir l'output suivant :

Nous allons maintenant effectuer notre test qui utilisera les 2 containers partageant le même volume, la pipeline exécutera d'abord le premier le git sur notre container 'docker-agent' puis la commande ansible-playbook sera exécuter sur le second.

Pour notre exemple nous utiliser le playbook ping.yml sur le repo suivant : https://github.com/lukry59/ansible-playbook.git

Voici la pipeline utilisé pour notre test, elle est composé de 2 stages, un stage pour le git, puis un stage pour ansible :

pipeline {
   agent none
   stages {
      stage('git') {
          agent { label 'docker-agent' }
          steps {
              git 'https://github.com/lukry59/ansible-playbook.git'
          }
      }
      stage('ansible') {
          agent { label 'ansible' }
          steps {
              sh 'ansible-playbook ping.yml'
          }
      }
   }
}

Lors de l'exécution de cette pipeline nous devons obtenir le résultat suivant :
Nous constatons que 2 containers ont été généré et travaillent ensemble sur le même volume.

Le plugin jenkins “docker-plugin” dispose d'une fonction pouvant être appelé dans une pipeline déclarative, cette méthode nous permet d’exécuter notre container directement sans avoir au préalable défini de “Docker Agent Template

La documentation de la fonction dockerNode est disponible ici : https://www.jenkins.io/doc/pipeline/steps/docker-plugin/

Voici un exemple de pipeline exploitant l'image ansible précédemment utilisé :

pipeline {
   agent none
   stages {
      stage('ansible') {
        agent none
        steps {
            dockerNode(image: 'gdelachat/jenkins-ansible', dockerHost: 'tcp://10.0.0.3:2376') {
                sh 'ansible localhost -m ping'
            }
        }
      }
   }
}

Cependant cette méthode ne permet pas le mappage de volume.

Annexe

Ce site web utilise des cookies. En utilisant le site Web, vous acceptez le stockage de cookies sur votre ordinateur. Vous reconnaissez également que vous avez lu et compris notre politique de confidentialité. Si vous n'êtes pas d'accord, quittez le site.En savoir plus