Docker Apache Mysql PHP

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 :)

Ça peut vous intéresser aussi


Poste de développement PHP sous Fedora

Linux est un système parfait pour développer. Simple d’installation,...


Optimisations Copix PHP et Apache

Les temps de réponse… Dieu sait à quel point cela ...


Docker, Xvfb et links

Un conteneur = un service, c’est une règle qui ...


Et si on regardait nodejs

Quand j’entend beaucoup de développeurs (expérimentés qui plus est) cracher ...

Merci de m'aider à financer mes services

Si vous avez apprécié cet article, je vous serai reconnaissant de m'aider à me payer une petite bière :)

Si vous voulez en savoir plus sur l'utilisation de flattr sur mon blog, lisez cette page: Ayez pitié de moi

Commentaires

Ajouter un commentaire

Metal3d - 24/01/2017

Salut @Kev

Il faut vérifier si les droits sur le fichier sont OK (lecture pour tous). Tu peux aussi tenter d’entrer dans le conteneur pour voir si le fichier test.php existe, si la conf nginx est bien montée dans le répertoire etc…

Kev - 24/01/2017

Bonjour, lorsque j’essaie de visualiser sur mon navigateur mon adress local mon fichier test j’ai le message suivant qui s’affiche “not found The requested URL /test.php was not found on this server.”… Auriez vous une solution sachant que j’ai tout vérifié…

Metal3d - 16/11/2016

Merci ;)

Je mettrai à jour ce billet dans la semaine. Effectivement depuis le temps y’a pas mal de choses qui ont changé. La v2 permet d’ailleurs de ne plus déclarer les liens à chaque fois.

Mais comme je passe mon temps sur kubernetes et openshift depuis près de 6 mois… Je viens rarement modifier mon blog.

Laurent - 15/11/2016

la base ! merci pour ce petit tuto bien expliqué qui m’a permis en croisant avec d’autres sources de valider certains concepts Docker peu expliqués. suggestion : ajouter version: ‘2’ services: dans le fichier yml ?

metal3d - 14/10/2015

Merci @Nicolas, désolé pour le retard de validation de commentaire j’ai eut un peu de mal à m’en sortir ces derniers temps. Et en plus j’avais pas la notification.

Nicolas - 25/09/2015

Excellent article, simple et efficace !

Ajouter un commentaire

(*) Votre e-mail ne sera ni revendu, ni rendu public, ni utilisé pour vous proposer des mails commerciaux. Il n'est utilisé que pour vous contacter en cas de souci avec le contenu du commentaire, ou pour vous prévenir d'un nouveau commentaire si vous avez coché la case prévue à cet effet.