Outils pour utilisateurs

Outils du site


tutoriaux:docker-related:docker-apache-php-mysql-ide-proxy

Docker: Full Stack Developpement

Introduction

Pour divers projets, il m'arrive régulièrement de devoir mettre en place un serveur PHP/Apache + MySQL, et c'est souvent la galère pour développer (il faut se connecter en SSH sur le conteneur Apache ou SQL, il faut créer et gérer un sshfs pour développer ou synchroniser via un script ou encore un dépôt git), de plus l'image PHP-Apache de base ne dispose pas de toutes les librairies et/ou modules qui m’intéressent.

Image

J'ai donc créé une image “Apache2 + PHP” personalisée:

  • image manipulation (GD)
  • compression (zip)
  • mysqli/pdo_mysql
  • opcache
  • mod_rewrite

tutoriaux:docker-related:stack-v1.png

il est important de noter que cette image n'est pas directement exploitable en production,elle ne prends pad en charge le SSL/HTTPS; nous utiliserons un reverse proxy (voir ci-dessous) pour résoudre cette problématique.

Nous reviendrons plus tard sur le dossier/volume /var/www/html car c'est lui qui hébergera notre application, et permet donc de dissocié la partie “serveur APACHE/PHP” de l'application/web site.

Cette image même si elle est exploitable directement, demande un peu d'attention (notamment car elle ne supporte que le HTTP) et peut demander d'autres composants (MariaDB, PHPMyAdmin, reverse proxy, etc.).

Docker recommande d'utiliser un compose file pour créer des services et conteneurs, c'est exactement ce que je propose de faire plus bas.

DockerFile

Voici le DockerFile qui permet de “build” l'image, il attends un paramètre FROM_REF qui permet de choisir quelle image de référence l'on désire utiliser (PHP 8.3, PHP 8.4, bookworm ou autre…)

DockerFile
# Dockerfile for PHP Web app
#
# Specific PHP Version (bookworm & apache)
#
# Source & infos :
# https://hub.docker.com/_/php
# 
 
ARG FROM_REF
FROM ${FROM_REF}
 
# Update to latest package and install requierements
RUN apt-get update && apt-get dist-upgrade -y; \
    apt-get install -y --no-install-recommends \
        libgd-dev \
        libwebp-dev \
        libpng-dev \
        libjpeg-dev \
        libwebp-dev \
        libxpm-dev \
        libfreetype-dev \
        zlib1g-dev \
        libzip-dev; \
    apt-get autoremove; \
    apt-get autoclean; \
    rm -rf /var/lib/apt/lists/*;
 
# Add Apache Modules:
RUN a2enmod rewrite
 
# Use the default production configuration
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
 
# Add pdo & mysql extention
RUN docker-php-ext-configure gd --with-freetype --with-jpeg; \
    docker-php-ext-install pdo_mysql mysqli zip opcache gd

Il n'y a rien d'exotique:

  • un pull de l'image de référence,
  • un update de la distribution Linux et ajout des librairies nécessaires
  • inclusion des modules apache et des extension PHP.

build

On peut build l'image via la commande suivante:

frater@vulkan: ~$ docker build --rm --build-arg FROM_REF="php:8.3.23-apache-bookworm" -t saintfrater/php8-3-23-custom:$(date +%Y%m%d-%H%M) -t saintfrater/php8-3-23-custom:latest .
    
Sending build context to Docker daemon  56.83kB                                                                                                                                               
Step 1/6 : ARG FROM_REF                                                                                                                                                                       
Step 2/6 : FROM ${FROM_REF}                                                                                                                                                                   
 ---> fa6c27da5746                                                                                                                                                                            
Step 3/6 : RUN apt-get update && apt-get dist-upgrade -y; apt-get install -y --no-install-recommends libgd-dev libwebp-dev libpng-dev libjpeg-dev libwebp-dev libxpm-dev libfreetype-dev zlib1g-dev libzip-dev;     apt-get autoremove; apt-get autoclean;rm -rf /var/lib/apt/lists/*;
 ---> Using cache
 ---> 9096e3a0dfc4
Step 4/6 : RUN a2enmod rewrite
 ---> Using cache
 ---> eb2007e04345
Step 5/6 : RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
 ---> Using cache
 ---> 66c9fc9fc2f4
Step 6/6 : RUN docker-php-ext-configure gd --with-freetype --with-jpeg;     docker-php-ext-install pdo_mysql mysqli zip opcache gd
 ---> Using cache
 ---> 89c70d388760
Successfully built 89c70d388760
Successfully tagged saintfrater/php8-3-23-custom:20250630-0300
Successfully tagged saintfrater/php8-3-23-custom:latest    

Docker "services"

Comme annoncé précédemment, nous allons utiliser un compose.yaml file pour créer notre service.

Yaml

compose.yaml
services:
  # Web Server
  webserver:
    image: saintfrater/php8-3-23-custom:latest

    container_name: proj01-webserver
    restart: unless-stopped
    
    ports:
      - 80:80
    tty: true
    stdin_open: true
    volumes:
      - public:/var/www/html
      
    environment:
      - TZ=Europe/Brussels
    
    networks:
      - server

volumes:
  public:
  
networks:
  server:
    external: true

notes

Ce compose file crée un conteneur proj01-webserver et un volume public sur votre host docker, il permet de joindre le conteneur via l'url http://host/.

vous pouvez utiliser la commande suivante pour créer l'application:

frater@vulkan:~$ docker compose -f compose.yaml -p proj_vulkan up

Cette commande va créer:

  • un conteneur proj01-webserver (création du conteneur ou redémarrage si le conteneur existe déjà)
  • un volume proj_vulkan_public (si le volume existe déjà il ne sera pas modifié)

Veuillez noter que si un autre conteneur (ou même le host) utilise déjà le port HTTP/80, le compose ne fonctionnera pas, il faudra modifier le fichier “compose.yaml” pour utiliser un autre port libre

MariaDB

je l'ai dis avant, mais il est rare que nous n'ayons pas besoin de “composants” supplémentaires (database, etc.) dans une application.

Avec la phylosophie de Docker, c'est extremement facile.

Nous allons ajouter à notre compose.yaml ces services un par un; a commencer par un serveur MariaDB; afin que notre application puisse communiquer avec une base de données:

tutoriaux:docker-related:stack-apache-db.png

Modification du yaml

compose.yaml
services:
  # Web Server
  webserver:
    image: saintfrater/php8-3-23-custom:latest

    container_name: proj01-webserver
    restart: unless-stopped
    
    ports:
      - 80:80
    tty: true
    stdin_open: true
    volumes:
      - public:/var/www/html
      
    environment:
      - TZ=Europe/Brussels
      
    depends_on:
      - db
    
    networks:
      - server
      - backend
 
  # MariaDB Server
  db:
    image: mariadb:latest
    container_name: proj01-db
    restart: unless-stopped
    
    environment:
      # update with YOUR requiered db informations
      - MARIADB_DATABASE=__YOUR_DATABASE_NAME__
 
      # So you don't have to use root, but you can if you like
      - MARIADB_USER=__YOUR_APPLICATION_USER__
 
      # You can use whatever password you like
      - MARIADB_PASSWORD=__YOUR_APPLICATION_DB_PASSWORD__
 
      # Password for root access
      - MARIADB_ROOT_HOST=localhost
      - MARIADB_ROOT_PASSWORD=__YOUR_DB_ROOT_PASSWORD__
      
    volumes:
      - db:/var/lib/mysql
      
    networks:
      - backend

volumes:
  db:
  public:
  
networks:
  server:
    external: true
  backend:
    driver: bridge

notes

Ces paramètres sont utilisés par l'image MariaDB lors de l'initialisation des la base de données du conteneur (lorsque le volume db est vide) pour créer l'instance du SQL;

Une fois la base de données créée, vous pouvez supprimer l'information de votre compose file.

Le Host du root est localhost afin de restreindre la connexion “root” depuis un autre conteneur (il ne sera pas possible à PHPMyAdmin de se connecter en root), si vous désirez utiliser cette possibilité, il faudra remplacer localhost par %.

Veuillez noter que j'ai délibérement utiliser 2 réseaux :

  • un server (externe) qui est partagé par d'autres services sur le host, et permet la communication entre “front-end”.
  • un backend (interne) et est lié à mon environnement décrit dans le compose file.

ce choix permet de dissocié le front-end server et le back-end backend qui sera plutôt réservé à la communication entre conteneurs “internes” à mon application.

J'utilise ce design pour limiter les risques et contrôler plus facilement les interactions entre services.

Il faudra également adapter les paramètres d’environnement selon les besoins de votre application:

# MariaDB application's credentials
MARIADB_DATABASE=__YOUR_DATABASE_NAME__
MARIADB_USER=__YOUR_APPLICATION_USER__
MARIADB_PASSWORD=__YOUR_APPLICATION_DB_PASSWORD__

# MariaDB root informations
MARIADB_ROOT_HOST=localhost
MARIADB_ROOT_PASSWORD=__YOUR_DB_ROOT_PASSWORD__

PHPMyAdmin

Comme mentionné au début, le développement demande également un accès facile à la DB, j'ai donc ajouté à mon stack un phpmyadmin.

tutoriaux:docker-related:stack-v2.png

Comme il est impossible (sauf a utiliser un reverse proxy) de monter 2 serveurs différents sur le même port 80, nous devons connecter le port 80 du apache sur le port 80 du host docker, et le port 80 du PHPMyAdmin sur le port 8080 du host docker…

On peut donc accéder à l'application via l'url http://host/ et à l'interface phpMyAdmin via l'url http://host:8080/.

Modification du yaml

compose.yaml
services:

  # Web Server  
  webserver:
    image: saintfrater/php8-3-23-custom:latest

    container_name: proj01-webserver
    restart: unless-stopped
    
    ports:
      - 80:80
    tty: true
    stdin_open: true
    volumes:
      - public:/var/www/html
      
    environment:
      - TZ=Europe/Brussels
      
    depends_on:
      - db
    
    networks:
      - server
      - backend
 
  # MariaDB Server  
  db:
    image: mariadb:latest
    container_name: proj01-db
    restart: unless-stopped
    
    environment:
      # update with YOUR requiered db informations
      - MARIADB_DATABASE=__YOUR_DATABASE_NAME__
 
      # So you don't have to use root, but you can if you like
      - MARIADB_USER=__YOUR_APPLICATION_USER__
 
      # You can use whatever password you like
      - MARIADB_PASSWORD=__YOUR_APPLICATION_DB_PASSWORD__
 
      # Password for root access
      - MARIADB_ROOT_HOST=localhost
      - MARIADB_ROOT_PASSWORD=__YOUR_DB_ROOT_PASSWORD__
      
    volumes:
      - db:/var/lib/mysql
      
    networks:
      - backend
 
	# phpMyAdmin
	
  phpmyadmin:
    image: phpmyadmin
    container_name: proj01-phpmyadmin
    restart: unless-stopped
    ports:
      - 8080:80
    
    environment:
      - TZ=Europe/Brussels
      - 
      # define the SQL host name & connection port
      - PMA_HOST=proj01-db
      - PMA_PORT=3306
      # credentials for connection
      - PMA_USER=__YOUR_APPLICATION_USER__ or root
      - PMA_PASSWORD=__YOUR_APPLICATION_DB_PASSWORD__ or __YOUR_DB_ROOT_PASSWORD__

    depends_on:
      - db
      
    networks:
      - server
      - backend
      
volumes:
  db:
  public:
  
networks:
  server:
    external: true
  backend:
    driver: bridge

notes

Bien prendre en comptes les remarques exprimées pour le service MariaDB

Attention que si vous précisez les informations de login (PMA_USER et PMA_PASSWORD) dans votre environnement, PHPMyAdmin se connectera immédiatement à la DB sans demander d'authentification; exposant ainsi votre base de données (ou l'ensemble de votre serveur SQL si vous avez utiliser le compte root) a toute personne qui utilisera l'URL(http://host:8080/) pour se connecter.

IDE

Afin de ne pas s'enerver avec SSH, la syncho ou un git, j'ai décidé d'ajouter a mon stack, un IDE (Eclipse Theia IDE).

Theia est un environnement de développement intégré (IDE) open source développé principalement par Eclipse Foundation. Il est conçu pour être extensible, modulaire et utilisable en mode navigateur.

Et c'est là que la notion de volume /var/www/html prends tout son sens, en effet, il sera plus facile de “monter” le volume 2 fois, une fois pour le web serveur et une fois pour l'IDE et d'éditer les fichiers “en directe”.

tutoriaux:docker-related:stack-ide.png

Reverse Proxy

l'un des avantages du reverse proxy est qu'il permet de lier plusieurs services sur un meme port, c'est le role du Reverse Proxy de diriger les requetes externe vers le bon serveur (en général un différencie un service via son url), il peut également appliquer des parametres SSL de façon indépendante du web serveur, et donc le developpement peut se concentrer uniquement sur le code…

tutoriaux:docker-related:stack-v3.png

tutoriaux/docker-related/docker-apache-php-mysql-ide-proxy.txt · Dernière modification : de frater