Docker Apache Mysql PHP

Publié le 24/09/2015

Ce matin un collègue me demande “comment tu ferais pour travailler en PHP avec Docker ?” - la question étant de pouvoir “développer localement en PHP + Apache + MySQL sans avoir à tout installer”. Ma réponse a été “docker-compose et des liens + des volumes”. Du coup, un petit billet pour expliquer la méthode s’imposait. Voici comment je procède.

Docker et Docker-Compose

En premier lieu, il vous faut Docker et docker-compose. En théorie, votre distribution propose des paquets tout prêts, il s’agit de les installer. Personnellement j’ai quand même installé “docker-compose” avec “pip”. La raison est simple, je peux mettre à jour l’outil rapidement sans avoir à attendre que le packageur propose un paquet.

Donc, en gros (sous Fedora 22):

sudo dnf install python-pip
pip install --user docker-compose
docker-compose --help

Voilà. Maintenant on s’atèle à mettre en place notre pile de conteneurs.

Les conteneurs

Rappel: il est fortement conseillé d’utiliser un conteur par service, comprennez bien “un conteneur pour mysql et un autre pous apache” dans notre cas. La raison est simple: je peux changer de version de php ou de mysql indépendament.

Bref, on se penche sur nos deux images Docker à utiliser:

Pour qu’on soit prêt:

docker pull php:apache
docker pull mysql:latest

Voilà, on a les images sur notre système. Sachez que si vous ne faites pas le “pull”, docker-compose le fera pour vous, mais je préfère préparer le terrain pour ne pas avoir à attendre le téléchargement quand je vais tester mon installation.

Docker-compose

Maintenant on va paramétrer notre composition de conteneur. En gros il faut que Apache démarre et qu’il sache lire mes sources PHP. Il faut que MySQL démarre, et il faut que PHP sache où trouver le serveur MySQL. Car je vous le rapelle, le conteneur MySQL peut changer d’IP à chaque redémarrage.

Le principe, pour partager un peu de configuration entre deux conteneurs, est d’utiliser un “lien”.

Bref, on prépare le terrain.

Créez un répertoire de travail, par exemple $HOME/workspace/monsite et allez dans ce répertoire.

Dans ce répertoire, on crée:

  • un répertoire de sources php
  • un fichier docker-compose.yml

Voyons le fichier YAML:

apache:
    image: php:apache
    volumes:
    - "src/:/var/www/html"
    links:
    - mysql
    ports:
    - "8080:80"
    privileged: true

mysql:
    image: mysql:latest
    environment:
        MYSQL_ROOT_PASSWORD: passroot

Explications:

La première entrée que j’ai nommé “apache” correspond à un conteneur. Il va utiliser une image “php:apache”. Dans ce conteneur, je “monte” le répertoire “src” local (qui contiendra mes sources php) sur le répertoire /var/www/html du conteneur.

Ainsi, quand apache va lire ce répertoire, il verra en fait ce que j’ai sur mon poste.

Je crée un lien dans la section “links” (qui est une liste), où je spécifie que mon conteneur “mysql” (défini plus bas) doit être démarré avant pour qu’il me fournisse des information (ip, nom, ports, etc…)

Je spécifie ensuite que je “bind” le port 8080 de ma machine sur le port 80 du conteneur. C’est le port 80 qu’écoutera apache sur le conteneur. Du coup, quand je vais requêter ma machine sur le port “8080” via http://localhost:8080, c’est le conteneur qui va répondre.

En dernier lieu, parce que je suis sur Fedora et que j’ai pas trouvé plus simple pour corriger un souci de droit que je déteste, je met “privileged: true”. Cela permet à mon conteneur d’avoir le droit de lire le volume monté. Le jour où je trouve une autre solution (qui ne me demande pas de labelliser avec SELinux) je donnerai des nouvelles.

Ensuite vient la section “mysql”, elle va utiliser l’image “mysql:latest”, et comme le spécifie la documentation je définir un mot de passe root pour la base.

Allons dans le répertoire “src” et créons un simple fichier “test.php”:

<?php
phpinfo()

Maintenant, on démarre le conteneur:

docker-compose up

Vous allez voir les logs des deux conteneurs, vous pouvez aller voir l’adresse http://localhost:8080/test.php

Variables d’environement

Descendez dans la page, et chercher la section “PHP Variables” où se trouve les entrées “_ENV”. Vous allez voir ce genre de chose:

_ENV["MYSQL_1_PORT_3306_TCP"] tcp://172.17.0.22:3306
_ENV["HOSTNAME"] 813ce8655fd2
_ENV["MYSQL_ENV_MYSQL_ROOT_PASSWORD"] passroot
_ENV["DOCKER_MYSQL_1_PORT_3306_TCP_ADDR"] 172.17.0.22
_ENV["DOCKER_MYSQL_1_PORT_3306_TCP_PROTO"] tcp
_ENV["MYSQL_1_PORT_3306_TCP_PROTO"] tcp
_ENV["MYSQL_1_PORT_3306_TCP_PORT"] 3306

Ces variables proviennent du lien que nous avons effectué dans docker-compose.yml. Cela va vous permettre de modifier la configuration de vos scripts ou du framework en utilisant la fonction php “getenv()” pour spécifier où se trouve le serveur mysql. Notez que docker permet aussi au conteneur qui reçoit le link d’utiliser le nom de conteneur en tant que nom de machine.

Or, docker-compose renomme les conteneurs en les suffixant avec un numéro (car docker-compose sait démarrer plusieurs conteneurs d’une même entrée). Il faudra alors tricher un peu et utiliser, par exemple, “mysql_1” au lieu de “mysql”. Je rappelle que “mysql” est le nom donné dans le fichier yaml, et non pas le nom de l’image.

En d’autres termes, vous utiliserez:

<?php
//via les variables d'environnement
$mysql_server = getenv("DOCKER_MYSQL_1_PORT_3306_TCP_ADDR");

//ou
// en admettant qu'on puisse utiliser un nom de machine
// ce qui est vrai pour le module php-mysql
$mysql_server = "mysql_1"; 


//

Ne pas perdre la base de donnée ?

Effectivement dans notre configuration on ne sauve pas la base localement. Si vous supprimez le conteneur mysql, vous perdez vos données. On règle le souci:

apache:
    image: php:apache
    volumes:
    - "src/:/var/www/html"
    links:
    - mysql
    ports:
    - "8080:80"
    privileged: true

mysql:
    image: mysql:latest
    volumes:
    - "data/:/var/lib/mysql"
    environment:
        MYSQL_ROOT_PASSWORD: passroot
    privileged: true

On a rajouté un volume à notre conteneur mysql, désormais le répertoire /var/lib/mysql où mysql stocke toutes ses bases sera sur notre répertoire local “data”. Pensez à le créer avant.

Et encore une fois, “privileged: true” si vous êtes sous Fedora ou une distribution qui utilise SELinux et qui refuse l’écriture depuis le conteneur.

Bilan:

En un seul fichier “docker-compose.yml” on peut aisément démarrer un développement PHP/MySQL sans trop d’effort, encore faut-il être sur Linux et avoir Docker d’installer. Mais vue la tendance du moment…

Intérêt certain, il est possible de prendre cette installation, de la déployer sur un serveur de production (même si Docker dit qu’ils sont pas encore prêt pour de la production…) et lancer docker-compose en tant que service. Restera alors à votre charge de faire un reverse-proxy (nginx, apache…) qui pointera sur localhost:8080

Vous n’aurez donc pas à installer php et mysql, et vous pourrez aisément mettre en production plusieurs sites avec différentes versions de PHP.

Voilà comment on passe de LAMP à DAMP :)

comments powered by Disqus