Tuto integration application dans pipeline - Sskiizens/DevSecOps GitHub Wiki

Attention, cette partie à été sans aucun doute une des plus complexe du projet. De bonnes connaissances en réseau, docker, et script sont nécessaires, sans quoi vous allez rapidement être perdu. Si vous avez des questions ou des interrogation, n'hésitez pas à me contacter et je prendrais du temps pour discuter avec vous et vous expliquer plus en détails si nécessaire. Au moment ou j'écris ces lignes je ne décris pas la procédure pour créer un gitlab-runner, j'essayerai de le faire dans le futur mais pour l'instant je n'ai pas le temps et vous allez donc devoir vous débrouiller seul mais ce n'est pas compliqué rassurez vous. J'en profite pour répéter que ce travail est open-source et à été en très grande majorité réalisé sur mon temps libre. Il n'appartient donc à personne, il est libre d'utilisation tant que vous ne vous en servez pas a des fins lucratives.

Création d'un pipeline CI/CD sous gitlab-ci

Il est bien sur important que l'on crée un pipeline CI/CD pour notre application. La finalité sera simplement de faire un commit sur notre repository gitlab, suivre l'évolution des étapes du pipeline, et si tout se passe bien, avoir notre modification de code intégré automatiquement en production.

Migration du projet vers gitlab

Certains s'étonne sans doute de ce changement de technologie. La raison est simple, gitlab-ci est extrêmement puissant, de plus cela me permet de garder le code de base clean car vous allez voir que l'intégration de notre application va nécessiter quelques modifications de code source.

Choix personnel, je vais implémenter chaque microservice comme un projet indépendant, ainsi ils auront tous leur pipeline et pourront être modifiés indépendamment.

Commencez par vous créer un compte gitlab, je ne peux pas le faire pour vous et il faudra simplement adapter l'URL de votre projet gitlab. Vous allez ensuite créer 3 projets sur gitlab que l'on nommera:

  • appliPython_admin
  • appliPython_frontend
  • appliPython_main Maintenant que nous avons nos projets, il va falloir pusher le code correspondant, pour cela on va pull l'ensemble du projet github, puis initialiser un repository git dans chaque microservice avant de le push dans le projet correspondant:
mkdir app_web
cd app_web
git init
git pull https://github.com/Sskiizens/DevSecOps.git
cd admin
git init --initial-branch=main
git remote add origin https://gitlab.com/sskiizens/appliPython_admin.git //Mettez votre url de projet sinon vous pushez sur mon git
git add .
git commit -m "Initial Commit"
git push -u origin main
cd ../main
git init --initial-branch=main
git remote add origin https://gitlab.com/sskiizens/appliPython_main.git //Mettez votre url de projet sinon vous pushez sur mon git
git add .
git commit -m "Initial Commit"
git push -u origin main
cd ../react-crud
git init --initial-branch=main
git remote add origin https://gitlab.com/sskiizens/appliPython_frontend.git //Mettez votre url de projet sinon vous pushez sur mon git
git add .
git commit -m "Initial Commit"
git push -u origin main

Bravo, vous avez maintenant 3 projets contenant chacun un microservice qui constitue votre application.

Passons maintenant à l'intégration.

Création Pipeline Admin

Le fichier .gitlab-ci.yml

On va commencer par l'application admin. Commencez par créer un nouveau fichier dans le dossier racine du projet appliPython_admin et nommez le .gitlab-ci.yml. C'est dans ce fichier que l'on va déclarer notre pipeline CI/CD. On commence par déclarer l'image docker que l'on va utiliser, dans notre cas tmaier/docker-compose:

image: tmaier/docker-compose:18.09

On déclare ensuite un service docker:dind, qui permet de créer des conteneurs dans des conteneurs, le concept et complique mais vous comprendrez plus tard:

services:
     - docker:dind

On déclare ensuite des variables qui nous sont utiles:

variables:
     DOCKER-DRIVER: overlay2
     SPRING_PROFILES_ACTIVE: gitlab-ci

C'est la que commence vraiment notre pipeline, on va commencer par annoncer les différents stages qui composent notre pipeline:

    - build
    - package
    - deploy

Notre pipeline ne se composera que de 3 étapes. C'est suffisant pour notre code et en rajouter ne ferait qu'ajouter de la complexité.

On va maintenant pouvoir passer à la description de chaque étape. Commençons par le première, build. Ici on va simplement build notre code pour voir si ça fonctionne bien, on réalise cela avec le morceau de code suivant:

build image:
    stage: build
    script:
        - docker-compose build

Rien de bien compliqué jusque là, mais cela vous permettra de vérifier que le build s'effectue correctement et vous verrez que cette étape peut échouer très souvent si l'on fait beaucoup de modification.

Passons à l'étape de package. Ici ça devient plus compliqué, on va exécuter notre application, puis se servir des compilations déjà effectués pour créer des conteneurs qui seront prêt à être utilisé (docker commit), on ajoutera ensuite nos images à un répertoire de docker. Pour cela vous aurez besoin de créer un compte docker.io. Une fois dedans, créez 3 répertoire que vous nommerez:

  • mysql
  • queue
  • backend

Cela vous servira à push vos conteneurs et à les conserver pour ensuite les exploiter. L'étape package du fichier .gitlab-ci.yml se décompose comme suit:

docekr-build:
     stage: package
     script:
         - docker network prune -f
         - docker-compose up -d
         - docker ps -a
         - docker commit backend nomUserRepoDocker/backend
         - docker commit queue nomUserRepoDocker/queue
         - docker commit applypython_admin_db_1 nomUserRepoDocker/mysql
         - docker logout
         - docker login -u nomUserRepoDocker -p mdpRepoDocker docker.io
         - docker push nomUserRepoDocker/backend:latest
         - docker push nomUserRepoDocker/mysql:latest
         - docker push nomUserRepoDocker/queue:latest

N'hésitez pas à regarder les logs et a modifier les noms des conteneurs de base des lignes commit si ils sont différents, c'est à cela que sert la commande docker ps.

Il ne vous reste plus qu'une étape, le déploiement en production de vos conteneurs fraichement créés. C’est ici que l'on va utilisé le SSH mit en place précédemment, l'étape se décompose comme suit:

deploy:
  image: alpine:latest
  stage: deploy
  tags:
    - deployment
  script:
    - chmod og= $ID_RSA
    - apk update && apk add openssh-client
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker login -u nomUserRepoDocker -p mdpRepoDocker"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull nomUserRepoDocker/backend:latest"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull nomUserRepoDocker/queue:latest"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker pull nomUserRepoDocker/mysql:latest"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f mysql || true"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run -d -p 33066:3306 --ip 172.17.0.2 -e MYSQL_ROOT_PASSWORD=root --name mysql nomUserRepoDocker/mysql "
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f queue || true"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run -d --name queue nomUserRepoDocker/queue python consumer.py"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker container rm -f backend || true"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker run -d -p 8000:8000 --name backend nomUserRepoDocker/backend python manage.py runserver 0.0.0.0:8000"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "rm -r dbdata"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "mkdir dbdata"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker cp backend:/app/.dbdata/. dbdata/"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker cp dbdata/. mysql:/var/lib/mysql/"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker restart mysql"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker restart backend"
    - ssh -i $ID_RSA -o StrictHostKeyChecking=no $SERVER_USER@$SERVER_IP "docker restart queue"

  environment:
    name: production
    url: http://192.168.196.130
  only:
    - main

Cette étape peut sembler complexe (elle l'a été dans sa création sans aucun doute), mais en réalité elle est plutôt simple. On récupére sur notre serveur de production les conteneurs, on les lances avec les configurations adaptées puis on effectue des actions comme la mise en place des données de la database. Tous cela est effectué via SSH.

Et voila, le pipeline fonctionne. Il se lancera à chaque modification ayant lieu sur le code. Il reste encore des choses à faire donc il affichera des erreurs mais vous verrez, il finira par fonctionner. En attendant votre fichier .gitlab-ci.yml ressemble à cela:

//////////// Image

Modifications code source

Il y a deux fichiers qui sont à modifier.

Le premier est le /docker-compose.yml. Dans ce fichier on va notamment modifier les noms des dockers, et gérer les connexions et IP des conteneurs pour qu'ils puissent interagir correctement quand nous allons le détacher du compose.

Le second est le fichier /admin/settings.py. Dans ce fichier on va simplement modifier le HOST de la database pour qu'il corresponde à l'IP du conteneur.

Je laisse cette partie comme cela pour le moment. Copiez-collez les fichiers de gitlab.

Création gitlab runner

Il faut d'abord commencer par monter une VM ubuntu. J'utilise personnellement VMWare. Une fois cela fait lancez un shell en entrez les commandes suivantes pour installer gitlab-runner:

sudo apt-get update
sudo apt-get install curl 
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo -E apt-get install gitlab-runner

Et voila, gitlab-runner est installé et fonctionnel. Vous pouvez le vérifier grâce à la commande:

sudo systemctl status gitlab-runner

Il va maintenant falloir que vous alliez chercher des informations sur votre gitlab. Connectez vous sur le projet admin, et rendez-vous dans:

Settings -> CICD -> Runners (expand)

Ici vous pouvez récupérer votre URL et TOKEN. Ils vous seront nécessaires pour la suite. Revenez sur votre machine ubuntu et configurez maintenant votre runner:

sudo gitlab-runner register

Saisissez maintenant votre URL puis votre TOKEN. Choisissez ensuite l'option shell.

Votre gitlab-runner est fonctionnel, maintenant vous pouvez recharger la page de configuration des runners sur gitlab et vous le verrez apparaitre. Il est maintenant prêt à réaliser les tâches du pipeline.

Dernières configurations (SSH, variables, ...)

Il va falloir installer SSH pour pouvoir communiquer entre votre machine ubuntu et votre pipeline gitlab. Je ne vais pas détailler l'installation du SSH car il convient à chacun de gérer cela et une mauvaise configuration peut être dangereux pour votre ordinateur.

Récupérez votre clé privé, incluant les lignes begin et end. Allez maintenant sur votre projet admin sur gitlab, et allez dans:

Settings -> CICD -> Variables (expand)

Cliquez sur add variable avec les paramètres:

Key: ID_RSA Value: votreCléPrivéSSH

Cliquez à nouveau sur add variable avec cette fois les paramètres:

Key: SERVER_IP Value: IPServerUbuntu

Cliquez à nouveau sur add variable avec cette fois les paramètres:

Key: SERVER_USER Value: nomUserServer

Ce sont les variables que l'on utilisera dans le code.