Docker fournit un moyen élégant de définir et de gérer des applications multi-conteneurs. Dans cet article, je vais vous expliquer la configuration de Docker Compose qui crée l'environnement de développement pour Willow CMS. Cette configuration comprend tout, du serveur d'applications aux outils de développement, ce qui facilite le démarrage immédiat du développement. Obtenez le code de Willow CMS ici .

Services principaux configurés via docker-compose.yml

Serveur d'applications WillowCMS

Le cœur de notre configuration est le service WillowCMS :

willowcms:
  build:
    context: .
    dockerfile: docker/willowcms/Dockerfile
    args:
      - UID=${UID:-1000}
      - GID=${GID:-1000}
  ports: 
    - "8080:80"
  volumes:
    - .:/var/www/html/
    - ./docker/willowcms/config/app/cms_app_local.php:/var/www/html/config/app_local.php
    - ./logs/nginx:/var/log/nginx/
  environment:
    - REDIS_USERNAME=root
    - REDIS_PASSWORD=root

Cette configuration:

  1. Définit un service appelé willowcms
  2. Configure le service en tant que conteneur personnalisé à partir de notre Dockerfile qui gérera l'installation et la configuration du logiciel du conteneur
  3. Transmet deux arguments nommés UID (ID utilisateur) et GID (ID de groupe) qui sont utilisés pour garantir des autorisations de fichiers appropriées entre l'hôte et le conteneur.
  4. Mappe le port 8080 sur l'hôte pour accéder à l'application sur le port 80 du conteneur
  5. Mappe l'intégralité du répertoire du projet (.) de la machine hôte à/var/www/html/ à l'intérieur du conteneur. Cela vous permet d'utiliser VS Code sur l'hôte pour modifier le code source et voir instantanément les modifications résultantes sur le serveur de développement qui héberge le code
  6. Mappe le fichier de configuration cms_app_local.php de l'hôte vers le conteneur (avec un nouveau nom à l'intérieur du conteneur. Cela nous permet de conserver des paramètres de configuration distincts pour le développement sans risquer que la configuration de l'application soit vérifiée dans le référentiel.
  7. Mappe le répertoire des journaux nginx entre l'hôte et le conteneur, afin que nous puissions afficher les journaux nginx directement depuis votre machine hôte sans avoir à entrer dans le conteneur.
  8. Définit 2 variables d'environnement utilisées pour configurer le service redis

Vous pouvez accéder à Willow CMS à l'adresse http://localhost:8080 sur votre machine hôte.

Je reviendrai plus tard sur les détails du Dockerfile . Pour l'instant, sachez qu'il est responsable de l'installation et de la configuration de Nginx et PHP-FPM et d'autres logiciels nécessaires à l'exécution de Willow CMS (et de toute autre application CakePHP).

Couche de base de données

Nous utilisons MySQL 8.4.3 comme base de données :

mysql:
  image: mysql:8.4.3
  environment:
    MYSQL_ROOT_PASSWORD: password
  ports:
    - "3310:3306"
  volumes:
    - mysql_data:/var/lib/mysql
    - ./docker/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql

Cette configuration:

  1. Définit un service appelé mysql. Ceci est important et les autres conteneurs peuvent l'utilisermysql comme nom d'hôte pour le service MySQL au lieu d'une adresse IP.
  2. Utilise l'image Docker officielle de MySQL Server Community Edition v8.4.3 et configure la variable d'environnement utilisée pour définir le mot de passe root.
  3. Mappe le port 3310 sur la machine hôte sur 3306 sur le conteneur.
  4. Monte unmysql_data dossier géré par Docker dans le conteneur où MySQL stocke tous ses fichiers de base de données. Cela nous permet de conserver les données dans différentes versions/instances de ce conteneur.
  5. Copie un script SQL d'initialisation dans ledocker-entrypoint-initdb.d/init.sql répertoire dans le conteneur. Ce répertoire est préconfiguré par l'image MySQL pour exécuter automatiquement tous les scripts qu'il contient lors de la première initialisation du conteneur et permet de créer les bases de données par défaut et de test et les comptes d'utilisateurs associés pour l'environnement de développement.

Vous pouvez accéder à MySQL à l'adresse http://localhost:3310 sur votre machine hôte en utilisant MySQL Workbench ou quelque chose de similaire tel que phpMyAdmin.

Outils de développement

phpMyAdmin

Pour la gestion de la base de données, j'inclus phpMyAdmin :

phpmyadmin:
  image: phpmyadmin
  ports:
    - 8082:80
  environment:
    - PMA_HOST=mysql
    - PMA_USER=root
    - PMA_PASSWORD=password

Vous devriez voir un modèle maintenant, cette configuration :

  1. Utilise l'image Docker officielle maintenue par la communauté pour phpMyAdmin
  2. Mappe le port 8082 de la machine hôte au port 80 du conteneur
  3. Configure les variables d'environnement utilisées dans l'image pour configurer l'hôte, l'utilisateur et le mot de passe par défaut. Notez que l'hôte estmysql le nom que nous avons défini pour le service de base de données ci-dessus.

Accédez à phpMyAdmin à http://localhost:8082 pour une interface d'administration de base de données facile à utiliser.

Jenkins CI/CD

Bien que je n'utilise pas beaucoup ce conteneur dans mon processus de développement pour le moment, un service d'intégration continue est géré par Jenkins :

jenkins:
  build:
    context: .
    dockerfile: docker/jenkins/Dockerfile
  privileged: true
  user: root
  ports:
    - "8081:8080"
    - "50000:50000"
  volumes:
    - jenkins_home:/var/jenkins_home
    - /var/run/docker.sock:/var/run/docker.sock
    - ./docker/jenkins/jenkins.yaml:/var/jenkins_home/jenkins.yaml
  environment:
    - JAVA_OPTS=-Djenkins.install.runSetupWizard=false

Cette configuration:

  1. Définit un service appelé jenkins construit à l'aide d'un DockerFile. Nous faisons cela parce que je souhaite utiliser la configuration en tant que code afin que Jenkins soit préconfiguré avec des tâches utiles et les logiciels requis.
  2. Exécute le conteneur avec des privilèges élevés (privileged : true) et en tant qu’utilisateur root pour un accès complet au système.
  3. Mappe le port 8081 de l'hôte sur le port 8080 de l'interface Web Jenkins du conteneur et mappe le port 50000 pour la communication de l'agent Jenkins.
  4. Utilise un volume nommé « jenkins_home » pour conserver toutes les données et configurations Jenkins.
  5. Monte le socket Docker sur l'hôte pour permettre à Jenkins de créer et de gérer des conteneurs Docker lors de l'exécution de tâches.
  6. Fournit une configuration initiale via jenkins.yaml en utilisant Jenkins Configuration as Code.
  7. Ignore l'assistant de configuration Jenkins en définissant la variable d'environnement JAVA_OPTS (Jenkins sera prêt à exécuter des tâches prêtes à l'emploi !).

Accédez à Jenkins à l'adresse http://localhost:8081 . À l'avenir, Jenkins sera utilisé pour exécuter des tests front-end automatisés dans un navigateur. Pour l'instant, il a pour tâche d'exécuter les tests PHPUnit sur la branche principale.

Test des e-mails avec Mailpit

Pour les tests de courrier électronique, comme nous ne voulons pas envoyer de vrais courriers électroniques dans l'environnement de développement, nous utilisons Mailpit pour capturer les courriers électroniques de Willow CMS :

  mailpit:
    image: axllent/mailpit:latest
    ports:
      - "1125:1025"
      - "8025:8025"
    volumes:
      - mailpit_data:/data
    environment:
      - MP_MAX_MESSAGES=5000
      - MP_DATABASE=/data/mailpit.db
      - MP_SMTP_AUTH_ACCEPT_ANY=1
      - MP_SMTP_AUTH_ALLOW_INSECURE=1

Cette configuration:

  1. Crée un service appelémailpit .
  2. Utilise la dernière image officielle Mailpit Docker (axllent/mailpit:latest).
  3. Mappe le port 1125 de l'hôte au port SMTP 1025 de Mailpit sur le conteneur pour la capture des e-mails. Cela permet au conteneur willowcms exécutant le code CakePHP d'envoyer des e-mails à mailpit:1025.
  4. Mappe le port 8025 sur l'hôte au port 8025 de l'interface Web de Mailpit sur le conteneur.

Mailpit capture tous les e-mails sortants et fournit une interface Web à l'adresse http://localhost:8025 pour les afficher.

Gestion de Redis

Redis Commander fournit une interface Web pour la gestion de Redis :

redis-commander:
  image: rediscommander/redis-commander:latest
  environment:
    - REDIS_HOST=willowcms
    - REDIS_PORT=6379
    - REDIS_PASSWORD=root
    - HTTP_USER=root
    - HTTP_PASSWORD=root
  ports:
    - "8084:8081"
  depends_on:
    - willowcms

Cette configuration:

  1. Utilise la dernière image d'interface Web Redis Commander.
  2. Configure les variables d'environnement utilisées dans l'image pour se connecter par défaut à l'instance Redis exécutée sur le service « willowcms » sur le port 6379 avec le mot de passe root.
  3. Configure l'interface Web avec l'authentification de base HTTP (nom d'utilisateur : root, mot de passe : root)
  4. Mappe le port 8084 sur l'hôte au port 8081 de l'interface Web de Redis Commander.
  5. Garantit que le service Redis (willowcms) démarre avant Redis Commander.

Accédez à Redis Commander à l'adresse http://localhost:8084 pour surveiller et gérer l'instance Redis de WillowCMS. Il est utilisé comme stockage pour le plugin CakePHP Queue.

Stockage persistant

Nous définissons trois volumes pour la persistance des données :

volumes:
  mysql_data:
  rabbitmq_data:
  jenkins_home:

Ces volumes garantissent que nos données survivent aux redémarrages et aux reconstructions des conteneurs, même si ce n'est pas obligatoire.

Accéder à chaque service

Voici où trouver chaque service une fois l'environnement exécuté :

Démarrer l'environnement

Généralement, pour démarrer un environnement Docker, vous exécutez :

docker-compose up -d

Cela créera et démarrera tous les services en mode détaché (ce qui signifie que vous pouvez continuer à utiliser le terminal dans lequel vous avez tapé la commande) en utilisant le fichier docker-compose.yml par défaut. Cependant, je fournis un script pratique qui vous donne quelques options pour démarrer/arrêter l'environnement de développement Docker.

Au lieu de ce qui précède, exécutez :

./setup_dev_env.sh

Ce script automatise la gestion de l'environnement de développement Docker et la configuration de Willow CMS. Voici ce qu'il fait :

Tout d’abord, il détecte le système d’exploitation pour déterminer sisudo est nécessaire pour les commandes Docker (généralement requises sous Linux mais pas sous macOS). Il vérifie ensuite si les conteneurs Docker du projet sont déjà en cours d'exécution et, si ce n'est pas le cas, les démarre à l'aide de Docker Compose .

Une fois les conteneurs en cours d'exécution, le script attend que le service MySQL soit prêt en utilisant le script utilitaire wait-for-it . Notez que le script est exécuté sur le conteneur hébergeant lewillowcms service et utilise lemysql nom d'hôte. Si j'utilisais l'hôte mahine et le port (127.0.0.1:3310), attendez qu'il suppose que MySQL est opérationnel car Docker écoutera sur ce port hôte avant que MySQL Server n'ait commencé à écouter sur son port de conteneur.

Une fois MySQL disponible, le script installe les dépendances du projet à l'aide de Composer dans le conteneur Docker.

Le script effectue ensuite une vérification pour voir si la base de données a été précédemment configurée en recherchant une table « paramètres ». Cette vérification est effectuée par une commande CakePHP personnalisée (plus d'informations à ce sujet dans un prochain article de blog). Si la table existe (indiquant une configuration précédente), elle présente à l'utilisateur des options pour :

  • Effacez toutes les données et recommencez à zéro
  • Reconstruire les conteneurs
  • Redémarrer l'environnement
  • Continuer avec la configuration actuelle

S'il s'agit d'une première configuration (ou après un effacement des données), le script exécute les tâches de configuration initiales, notamment :

  • Définition des autorisations appropriées sur les répertoires clés
  • Exécution de migrations de bases de données
  • Créer un utilisateur administrateur par défaut
  • Importer des données par défaut dans la base de données

Enfin, qu'il s'agisse d'une configuration initiale ou ultérieure, le script efface le cache de l'application avant de terminer. Cela garantit un état propre pour que le travail de développement puisse commencer.

Plongée en profondeur - Explication du Dockerfile de Willow CMS

Maintenant que vous êtes au courant, plongeons dans le Dockerfile utilisé pour créer le conteneur qui héberge la base de code Willow CMS.

Installation de l'image de base et du package

Le conteneur démarre avec Alpine Linux v3.20 , choisi pour son faible encombrement et sa sécurité. Il installe un ensemble de packages soigneusement sélectionnés, notamment :

  • Redis pour la mise en cache et la gestion des files d'attente
  • Nginx comme serveur Web
  • PHP 8.3 avec des extensions essentielles pour CakePHP et Willow CMS
  • Superviseur pour la gestion des processus
  • ImageMagick pour le traitement d'images
  • Outils de développement (curl, wget, unzip, bash)

Configuration du service

Le Dockerfile configure plusieurs services :

  1. Configuration Redis : configure Redis avec la protection par nom d'utilisateur/mot de passe et la liaison localhost. L'environnement configuré dans docker-compose.yml est utilisé ici.
RUN echo "requirepass ${REDIS_PASSWORD}" >> /etc/redis.conf && \
    echo "bind 127.0.0.1" >> /etc/redis.conf && \
    echo "user ${REDIS_USERNAME} on >${REDIS_PASSWORD} ~* +@all" >> /etc/redis.conf
  1. Configuration de Nginx : Copie deux fichiers de configuration :
# Configure nginx - http
COPY docker/willowcms/config/nginx/nginx.conf /etc/nginx/nginx.conf
# Configure nginx - default server
COPY docker/willowcms/config/nginx/nginx-cms.conf /etc/nginx/conf.d/default.conf
  1. Configuration PHP-FPM : Installe les configurations PHP personnalisées :
    • fpm-pool.conf pour la gestion des processus PHP-FPM
    • php.ini pour les paramètres PHP optimisés pour CakePHP

Pour une maintenance plus facile, nous définissons une variable directement dans le Dockerfile pour lePHP_INI_DIR où iront les fichiers de configuration.

ENV PHP_INI_DIR /etc/php83
COPY docker/willowcms/config/php/fpm-pool.conf ${PHP_INI_DIR}/php-fpm.d/www.conf
COPY docker/willowcms/config/php/php.ini ${PHP_INI_DIR}/conf.d/custom.ini
  1. Installation de Composer : installe Composer pour la gestion des dépendances PHP. Nous ne voulons pas exécuter Composer à partir de la machine hôte dans le dossier de code source qui est ensuite mappé dans le conteneur. Nous pourrions, mais nous rencontrerions des problèmes d'autorisations de fichiers/dossiers entre l'hôte et le conteneur qui compliquent la génération de cache. Croyez-moi, c'est une meilleure façon de procéder lorsqu'elle est associée à la configuration des autorisations des utilisateurs et des groupes en fonction de l'ID utilisateur et de l'ID de groupe de l'hôte qui sont définis lors de l'exécution de docker-compose.yml ou via setup_dev_env.sh .

Autorisations

Le Dockerfile configure un utilisateur et un groupe qui aident avec les autorisations de l'hôte/du conteneur :

  1. Crée un utilisateur non root (personne) avec un UID/GID configurable provenant de l'utilisateur de la machine hôte et de son groupe.
  2. Définit la propriété appropriée des répertoires Web.
  3. Passe à l'utilisateur non root pour l'exécution des processus.
  4. Configure les autorisations de répertoire appropriées pour Nginx et PHP-FPM.
RUN deluser nobody && \
    addgroup -g ${GID} -S nobody && \
    adduser -u ${UID} -S -G nobody nobody

Gestion des processus

Supervisord est utilisé pour gérer plusieurs processus au sein du conteneur :

  • Démarre et surveille Nginx
  • Gère PHP-FPM
  • Gère le serveur Redis
  • Garantit que tous les services démarrent dans le bon ordre

Nous le faisons en copiant la configuration de Supervisord et en définissant la commande pour le démarrage du conteneur .

Surveillance de la santé

Le Dockerfile inclut un contrôle de santé qui valide l'état du conteneur en vérifiant si PHP-FPM répond. C'est une fonctionnalité intéressante qui vient de la version de production de cet environnement Docker.

Conclusion

Cette configuration Docker Compose fournit un environnement de développement complet pour Willow CMS. En conteneurisant ces services, nous garantissons la cohérence entre les différentes machines hôtes et facilitons la prise en main des nouveaux développeurs avec une configuration connue et fonctionnelle. Que vous travailliez sur une nouvelle fonctionnalité, que vous testiez des modèles d'e-mails ou que vous modifiiez la base de données, tout est à portée de port.

Mots clés

DockerCompose Docker CI Développement GâteauPHP Infrastructure DevOps Fichier Docker