Mise en place d'une Pipeline CI/CD Laravel sur Gitlab avec Docker
Vincent

Mise en place d'une Pipeline CI/CD Laravel sur Gitlab avec Docker

Cette article présente un exemple de mise en place d'une Pipeline Gitlab pour la compilation, les tests et le déploiement de projets Laravel.

Prérequis 

Laravel 5.8 / 6

Maitrise de Docker

Savoir deployer une image docker custom sur dockerhub ou autres repos https://hub.docker.com (cf. Article todo... )

Maitrise de Gitlab

 

Définition de la Pipeline

Gitlab permet de découper la Pipeline en "stages". Ici nous utiliserons 3 stages :

Build : c'est l'état où seront compilées toutes les dépendances et les composants en exécutant composer install et npm install. Nous verrons également que ces actions peuvent être éxécutées en parallèles sur défférents runners. 

Test : ici nous exécuterons les tests de code et de qualité.

Deploy : c'est la dernière étape qui permettra le déploiement de l'application vers vos serveurs de preprod, staging et prod. Cette action peut etre automatique au manuelle, ce qui est fortement recommandé pour un déploiement en production par exemple.

Voici un exemple de Pipeline qui build en parallèle composer et npm, puis qui joue une serie de test et qui permet le déploiement (en prod) si tout à correctement fonctionné.

Amélioration : Cette pipeline peut être améliorée en ajoutant une dernière étape s'éxecutant en parallèle du déploiement manuel (en prod) et permettant le déploiement automatique sur un autre evironnement staging ou preprod. Il est également possible d'ajouter un second couche de test plus fonctionnels par exemple en utilisant Dusk.

 

Le partage de fichier entre stages

Gitlab permet 2 méthodes pour partager des fichiers entre les stages, l'utilisation du cache et les artefacts. Nous utiliserons ces 2 méthodes pour passer les fichiers dans nos différents stages. Cette action est évidement possible que pour les stages exécutés séquentiellement. Nous noterons également que cela améliorement grandement les temps d'éxécution et réduit la charge des runners.

Le Cache

Le cache est le premier mechanisme proposé par Giltlab pour le partage de fichier. Il est général à toute une branche et permet de conserver et partager ce cache entre plusieurs Pipelines. 

Nous pouvons par exemple mettre en cache les /vendor pour la branche master et reduire ainsi significativement le temps de traitement global.

Les Artefacts

C'est le second méchanisme proposé par Gitlab qui permet de générer des artefacts. Les artefacts sont exclusivement partagés entre les stages d'une même Pipeline. Ce sont les outputs des stages, il sont compressés, versionnés et transmis dans le sens d'exécution de la pipeline.

 

Gitlab-ci.yml 

Le fichier utilisé par Gitlab pour la définition des pipelines est le fichier gitlab-ci.yml directement ajouté à la racine du projet. Nous allons maintenant reprendre pas à pas la construction de ce fichier pour la mise en place de notre pipeline décrite ci-dessus.

Image Docker custom

Je recommande fortement d'utiliser votre propre image docker pour la conception de votre pipeline. Vous pourrez également trouver beaucoup d'images préconstruites mais qui ne répondrons certainement pas excatement à votre config serveur cible. Le but étant d'être le plus possible iso avec l'architecture serveur finale. 

Nous ne détaillerons pas dans cet article le contenu et la conception de cette image. Je vous joins le lien de mon image custom déposée sur le hub docker officiel laravel-docker ainsi que le code associé Dockerfile

L'intégration d'une image dans gitlab-ci.yml :

image: vincentcau/laravel-docker:latest

Vous remarquerez que j'utilise la même image pour tous mes stages, néanmoins il est possible d'utiliser des images différentes en fonction de besoin de vos stages. Voici l'implémentation d'un image spécifique à un stage :

npm:
  stage: build
  image: vincentcau/laravel-docker:latest

Vous pouvez également avoir besoin d'une image supplémentaire pour l'exécution d'un jobs comme MySQL. Il faudra alors utiliser l'argument service dans gitlab-ci.yml et définir si besoin de variables associés :

# Variables
variables:
  MYSQL_ROOT_PASSWORD: root
  MYSQL_USER: homestead
  MYSQL_PASSWORD: secret
  MYSQL_DATABASE: sapiendo_id
  DB_HOST: mysql


testing:
  stage: test
  services:
    - mysql:5.7
  image: vincentcau/laravel-docker:latest    

 

Le build stage

Dans ce stage nous pouvons parallèliser composer et npm sur 2 runners différents si vous avec configurez plusieurs runners dans votre Gitlab. Pour utiliser plusieurs runners en parallèles il faut utiliser le paramètre tag et leur attribuer le même nom de stage.

composer:
  stage: build
  image: vincentcau/laravel-docker:latest
  tags:
    - tag-runner1
  ....


npm:
  stage: build
  image: vincentcau/laravel-docker:latest
  tags:
    - tag-runner2
  ....

 

Voici le code complet avec l'utilisation de tag pour l'exécution des runners en parallèle, le cache, les artefacts et les scripts associés à composer et npm : 

composer:
  stage: build
  image: vincentcau/laravel-docker:latest
  tags:
    - tag-runner1
  cache:
    key: ${CI_COMMIT_REF_SLUG}-composer
    paths:
      - vendor/
  script:
    - composer install --prefer-dist --no-ansi --no-interaction --no-progress --no-scripts
    - cp .env.example .env
    - php artisan key:generate
  artifacts:
    expire_in: 1 month
    paths:
      - vendor/
      - .env

npm:
  stage: build
  image: vincentcau/laravel-docker:latest
  tags:
    - tag-runner1
  cache:
    key: ${CI_COMMIT_REF_SLUG}-npm
    paths:
      - node_modules/
      - Modules/mon-module/node_modules/ #si utilisation de modules supp.
  script:
    - npm install
    - npm run production
    - cd Modules/mon-module/ && npm install && npm run production
  artifacts:
    expire_in: 1 month
    paths:
      - public/css/
      - public/js/
      - public/modules/
      - public/mix-manifest.json

Le test stage

C'est dans ce stage que seront exécutés tous les tests mis en place dans votre projet. Dans notre exemple nous utilisons security-checker, phpcs, phpunit et artisan code:analyse. Le stage test récupère directement les artefacts et le cache des stages de build. Nous aurons également besoin d'utiliser une image de mysql pour executer nos tests.

testing:
  stage: test
  services:
    - mysql:5.7
  image: vincentcau/laravel-docker:latest    
  tags:
    - tag-runner1
  script:
    - ./vendor/bin/security-checker security:check
    - ./vendor/bin/phpcs --report=summary
    - php artisan migrate
    - php artisan migrate:refresh
    - ./vendor/phpunit/phpunit/phpunit --no-coverage
    - php artisan code:analyse

Ce stage est bloquant pour la suite du déploiement. Le developpeur qui a push sur sa branche et qui rencontre une erreur recevra une notification d'echec et pourra se reporter aux logs du pipeline pour retrouver les erreurs en cours.

Le deploy stage

Ce stage est executé uniquement sur les branches designées par le paramettre only : et destinées au deploiement comme master, dev, preprod, rc. Il ne tournera pas sur les autres branches qui ne sont pas encore mergées sur ces branches designées. 

Dans ce stage vous pouvez utiliser les outils de deploiement comme deployer ou envoyer qui vous permettrons de versionner et d'executer les commandes serveur necessaires au bon deploiement de votre app sur le serveur distant.

Il faudra également preparer une connexion SSH avec échange de clés pour vous connecter à votre serveur distant depuis le container docker de votre pipeline.

Configurer la connexion SSH

Pour communiquer de façon sécurisée entre votre pipeline et votre/vos serveur(s) distant(s) il est nécessaire de mettre en place un connexion SSH avec échange de clés privées/publiques.

Voici la démarche à suivre pour la mise en place de cette connexion :

  1. Créer une nouvelle paire de clés SSH sur votre machine
  2. Déposer la clé publique sur votre serveur
  3. Déposer la clé privée sur Gitlab en utilisant les variables secrètes
  4. Utiliser la clé privée dans vos pipelines
  5.  

1. Création de la clé SSH

Exécuter la commande ci-dessous dans votre terminal :

ssh-keygen -t rsa -C "gitlab@yourdomain.com" -b 4096

Ne pas mettre de passphrase.

Attention également à ne pas écraser votre clé locale si vous en utilisez déjà une.

2. Déposer la clé publique sur votre serveur

Connectez-vous sur votre serveur distant et coller la clé id_rsa.pub dans ~/.ssh/authorized_keys

3. Déposer la clé privée sur Gitlab en utilisant les variables secrètes

Dans Gitlab aller dans Settings > CI/CD et ouvrir l'onglet Variables 

Utiliser une clé que vous pourrez ensuite passer en paramètre de votre pipeline par exemple SSH_PRIVATE_KEY

4. Utiliser la clé privée dans vos pipelines

Vous devez ensuite écrire un script qui permettra de passer la clé privé dans votre pipeline.

Voici un exemple :

.init_ssh: &init_ssh |
  eval $(ssh-agent -s)
  echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
  mkdir -p ~/.ssh
  chmod 700 ~/.ssh
  [[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config

Vous noterez que le format yaml permet d'écrire des scripts. Vous pouvez utiliser "." pour masque l'execution de ces script set "&" pur le rendre réutilisable.

Vous pouvez rencontrer une erreur dans l'utilisation des fichiers dans Gitlab notament au moment du déploiement. Je vous conseille donc d'écrire également un script pour modifier les droits des repertoires et des fichiers vendor :

.change_file_permissions: &change_file_permissions |
  find . -type f -not -path "./vendor/*" -exec chmod 664 {} \;    
  find . -type d -not -path "./vendor/*" -exec chmod 775 {} \;

 

Au final voici le résultat de notre stage deploy :

.init_ssh: &init_ssh |
  eval $(ssh-agent -s)
  echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
  mkdir -p ~/.ssh
  chmod 700 ~/.ssh
  [[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config

.change_file_permissions: &change_file_permissions |
  find . -type f -not -path "./vendor/*" -exec chmod 664 {} \;    
  find . -type d -not -path "./vendor/*" -exec chmod 775 {} \;


deploying:
  stage: deploy
  image: vincentcau/laravel-docker:latest
  tags:
    - tag-runner1
  script:
    - *init_ssh
    - *change_file_permissions
    - php artisan deploy yourdomain.com -s upload
  when: manual
  only:
    - master

Un dernier point le deploiement est donc manuel et se déclenchera au click sur le bouton deploying. Cette action est possible en definissant le parametre when : manual dans votre pipeline.

également sur le blog

Blend Web Mix : On y était ! (Jour 1)

C’est l’évènement web sur Lyon : Le Blend Web Mix. Nos deux chefs de projets préférées, Valentine et Iris, s’y sont rendues pour 2  jours de conférences intensives sur le thème “Tech for good : un nouvel espoir”. Design, Tech et Business sont les 3 grandes thématiques du Blend Web Mix. On y retrouve des geeks, des créatifs, des marketeux, des CTO, des products owner .. Bref, tout ce qu’on aime ! 

 

Lire la suite

Notes sur le salon Tech.Rocks 2018

Retour d'expérience sur l'événement TechRocks qui a eu lieu à Paris au mois de décembre 2018.

 

Lire la suite

En poursuivant votre navigation sur ce site, vous acceptez l’utilisation de cookies pour améliorer votre expérience utilisateur réaliser des statistiques de visites. En savoir plus

ok