Logo de Béjean Développement

Mettre en place une CI/CD avec Slim Framework (PHP)

Objectif

Mettre en place une CI/CD très simple pour une application PHP utilisant le framework SLIM.

Pré-requis

Pour mettre en place une CI/CD simple, nous devons posséder :

  • un dépôt GitLab,
  • un clone de votre dépôt en local sur votre poste,
  • un GitLab Runner, lien vers l'article,
  • un hébergement avec un accès SFTP.

Pour ma part, j'utilise un dépôt sur Froggit. Si vous souhaitez plus d'informations sur Froggit, je vous invite à consulter ce lien.

Votre dépôt doit contenir uniquement un fichier README.md.

Tutoriel

Le projet Git de cet article est disponible sur Froggit, lien vers le dépôt.

Création du runner SSH

Pour se connecter au serveur distant, le runner SSH utilise, soit le mot de passe, soit la clé SSH. Il est préférable d'utiliser la clé SSH car le mot de passe n'est pas crypté lorsqu'il est enregistré dans le fichier de configuration du GitLab Runner.

Voici la marche à suivre pour créer une clé SSH : ssh-keygen -t ed25519 -C "comment".

Une fois la clé générée, il faut l'envoyer sur le serveur distant en lançant : ssh-copy-id -i ~/.ssh/mykey user@host.

Procéder ensuite à la création d'un nouveau runner via la commande : gitlab-runner register. Mon GitLab Runner SSH n'est pas créé dans le groupe où se trouve le dépôt, il est créé dans le projet GitLab.

Pour utiliser votre runner SSH, il faut installer Git sur le serveur où se connectera le runner.

Création du fichier .gitlab-ci.yml

Notre pipeline sera composé de 2 jobs, un premier utilisant un runner Docker avec l'image php:8.0.1-fpm-buster pour tester notre code PHP. Nous indiquons le runner à utiliser en précisant le tag. Le second job utilisera le runner SSH pour déployer notre code sur notre serveur.

Commençons par tester que nos 2 runners fonctionne correctement, pour cela, créer le fichier .gitlab-ci.yml à la racine du projet, insérer le contenu ci-dessous dans le fichier et envoyer le sur le serveur via un git push.

stages:
- test
- deploy

docker:test:
  stage: test
  tags:
    - docker
  image: php:8.0.1-fpm-buster
  before_script:
    - echo "Before Script"
  script:
    - echo "Script"

ssh:deploy:
  stage: deploy
  needs:
    - docker:test
  tags:
    - ssh
  script:
    - echo "Script"

Il est possible que votre runner SSH vous renvoie l'erreur suivante : ERROR: Job failed (system failure): prepare environment: Process exited with status 1. Check https://docs.gitlab.com/runner/shells/index.html#shell-profile-loading for more information. Pour corriger cela, il faut, sur le serveur distant, commenter les lignes ci-dessous du fichier .bash_logout de l'utilisateur utilisé par le runner SSH.

if [ "$SHLVL" = 1 ]; then
    [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q
fi

Une fois le pipeline exécuté avec succès, nous allons créer l'environnement de développement Docker.

Création du projet Docker

L'environnement de développement est très simple. Tout d'abord, nous allons créer un fichier .env à la racine du projet. Ceci est nécessaire pour Docker Compose. Le contenu du fichier est le suivant :

COMPOSE_PROJECT_NAME=basecicddockerforslimframework

Je ne vais pas vous détailler la partie Docker dans cet article, je vous invite à télécharger le contenu du projet Base CI/CD & Docker for Slim Framework présent sur Froggit.

Une fois le projet cloné, vous trouverez 2 dossiers bin et docker. Le dossier bin contient quelques commandes utiles. Par exemple :

  • Pour construire les images Docker : ./bin/docker build
  • Pour lancer les conteneurs Docker : ./bin/docker up -d
  • Pour installer un paquet via Composer : ./bin/composer require ...

Ce dossier peut contenir autant de commandes que vous le souhaitez.

Dès que les conteneurs sont lancés, vous pouvez passer à la création du projet PHP.

Création du projet PHP

L'installation de Slim PHP est très simple, il suffit de suivre leur documentation. Voici les commandes à lancer depuis la racine du projet :

./bin/composer require slim/slim:"4.*"
./bin/composer require slim/psr7
./bin/composer require nyholm/psr7 nyholm/psr7-server
./bin/composer require guzzlehttp/psr7 http-interop/http-factory-guzzle
./bin/composer require laminas/laminas-diactoros

Terminer la création du projet en créant le dossier public et intégrant le contenu suivant dans le fichier public/index.php :

<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;

require __DIR__ . '/../vendor/autoload.php';

$app = AppFactory::create();

$app->get('/', function (Request $request, Response $response, $args) {
    $response->getBody()->write("Hello world!");
    return $response;
});

$app->run();

Je vous invite à vérifier que tout fonctionne en ouvrant la page http://localhost:8000 dans votre navigateur.

Installation & Paramétrage de PHPUnit 9

L'installation de PHPUnit est réalisée facilement en lançant la commande : ./bin/composer require --dev phpunit/phpunit. Le paramétrage nécessite quelques interventions.

Commençons par ajouter .phpunit.result.cache au fichier .gitignore. Puis créer le dossier app à la racine du projet et ajouter le contenu suivant dans le fichier composer.json au même niveau que require et require-dev. :

    "autoload": {
        "classmap": [
            "app/"
        ]
    },

Lancer ensuite la commande : ./bin/composer dump-autoload pour générer les fichiers d'autoload. Voici un lien vers Grafikart pour quelques précisions supplémentaires.

À la racine du projet, nous allons créer le fichier phpunit.xml avec le contenu suivant :

<phpunit bootstrap="vendor/autoload.php">
    <testsuites>
        <testsuite name="baseTests">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
</phpunit>

Ce fichier nous servira à mieux organiser les tests unitaires.

En lançant la commande ./bin/phpunit, le résultat affiché doit être :

PHPUnit 9.5.2 by Sebastian Bergmann and contributors.

No tests executed!

Terminons cette partie en mettant à jour notre Ci dans le fichier .gitlab-ci.yml. Remplacer toute la partie docker:test par :

docker:test:
  stage: test
  tags:
    - docker
  image: php:8.0.1-fpm-buster
  before_script:
    - apt-get update -yqq
    - apt-get install -yqq zip curl unzip libzip-dev libxml2-dev libonig-dev
    # Install PHP extensions
    - docker-php-ext-install dom mysqli xml zip
    # Install and run Composer
    - curl -sS https://getcomposer.org/installer | php
    - php composer.phar install --ignore-platform-reqs
  script:
    - php vendor/bin/phpunit --configuration phpunit.xml

Avant de passer à l'étape suivante, nous devons tester notre CI en réalisant un push dans le projet Git.

Mise en place de la CD

Pour le déploiement de l'application, je dispose d'un conteneur LXC sous Debian dans lequel j'ai installé Git, Nginx, PHP-FPM ainsi que les extensions PHP, sans oublier Composer, que nous avons utilisé dans notre application.

Au sein du serveur distant, créons un dossier app dans /var/www/html/app. Dans ce dernier, nous allons cloner le dépôt du projet. Dès que le projet a été cloné, nous pouvons modifier le fichier .gitlab-ci.yml pour remplacer le contenu du job ssh:deploy par celui-ci :

ssh:deploy:
  stage: deploy
  needs:
    - docker:test
  tags:
    - ssh
  only:
    refs:
      - master
  script:
    - cd /var/www/html/app
    - git fetch origin
    - git checkout master
    - git pull
    - composer install

Dans ce job, nous précisons que le runner ayant le tag ssh exécutera le script dès que le job docker:test est finalisé et uniquement si le git push a été réalisé sur la branche master.

Vous pouvez push vos modifications sur le dépôt du projet et contrôler que le déploiement fonctionne.