C'est quoi Docker et comment l'utiliser pour un projet symfony ?
Docker, l’une des meilleures façons de travailler… Et pourtant je ne l’utilisais pas encore.
Il faut dire que la dernière fois que j’ai tenté, ma machine n’en a pas voulu (j’en reparlerai plus tard). Mais la j’ai tenté l’aventure et oui c’est quand même magique comme solution.
Qu'est-ce que Docker ?
Celà fait quelques années que l’on entend parler de Docker et à moins d’avoir tenté l’expérience, le concept vous échappe peut-être.
Bien souvent les non-initiés associent Docker à des VM mais lorsque l’on y regarde de plus près, le fonctionnement diffère énormément de par sa gestion des ressources partagées.
Je vais faire simple, une vm est une installation complète OS + application et donc chaque vm augmente la consommation cpu et disque car vous avez chaque fois un nouvel OS de déployé. Si vous avez besoin d’une db sur chaque machine, vous duppliquerez l’application et les ressources nécessaires sur chaque machine.
Docker lui règle ce problème, vous avez une distribution linux, une série d'applications unique disponible et finalement des environnements indépendants et isolés (container) qui vont piocher dans les ressources (logiciel et physique) disponibles.
De ce fait, vous limitez grandement le besoin en ressource.
https://www.docker.com/resources/what-container/
En bref, une économie de ressource mais pas que. L’autre grand avantage est l’assurance d’un environnement fidèle peut importe l’emplacement d’installation. Votre container se base sur un fichier de config listant les “dépendances” dont il a besoin et lors d’un déploiement, Docker buildera une image correspondante à la configuration demandée.
Vous pouvez donc sur la même machine avoir un container avec un apache+PHP7.1+MySQL (oui c’est pas recommandé mais parfois il faut déterrer de vieux projets) et un autre container avec nginx+php8.2+PostgreSQL. Et comme vos versions sont fixées dans la config, chaque déploiement sera identique.
Prérequis
Historiquement, Docker ne pouvait tourner que sur Linux. Et encore aujourd’hui celà reste bien plus simple et moins contraignant. Mais j’en ai déjà parlé dans d’autres articles, je n’ai pas envie de jouer avec plusieurs machines ou plusieurs partitions. Et heureusement aujourd’hui Docker peut fonctionner sur windows à condition de bien le préparer mais de vraiment bien le préparer !
Je vais éviter de me répéter et simplement vous rediriger vers mon précédent article qui vous décrit en détail Comment fusionner Windows et Linux grâce à WSL. Étape obligatoire pour la suite !
Installer Docker Desktop
Pour utiliser Docker, il faut bien entendu installer Docker Desktop qui vous permettra de gérer vos containers et vos images. Pour ce faire, c'est par ici: https://www.docker.com/products/docker-desktop/
Rien de compliqué, un installateur en ligne droite.
Une fois l’installation terminée, vous devrez redémarrer votre machine.
En ligne de commande ?
Alors oui on a un utilitaire windows tout beau mais on va continuer à faire un peu de ligne de commande. Car en réalité le soft que l’on vient d’installer contient les ressources nécessaires mais ne permet pas grand chose de plus.
Si vous souhaitez connaître la liste des commandes Docker disponible
docker
Oui c’est simple à retenir.
Petit rappel, n’oubliez pas d’executer vos commandes dans le terminal unix pour plus de performance.
Pour y accéder depuis votre terminal windows:wsl
Des images à collectionner
Je ne vous en ai pas encore parlé, mais Docker se base sur des images.
Par image, vous pouvez comparer ça à des snapshots configurés et configurables.
Impossible de déployer un container sans image.
Notion importante à savoir, une image hérite généralement d’une autre image.
On peut donc imaginer une image php8.2 qui hérite d’une image MySQL qui hérite d’une image Debian. Et de ce fait, une image php7.6 qui héritera de cette même image MySQL et donc également de cette même image Debian.
Si vous souhaitez voir les images disponibles publiquement: https://hub.docker.com/
Un container?
Bon tu nous a parlé d’images et maintenant des containers…
Les images ne font pas déjà tout?
Et bien non, les images représentent une installation vierge et donc pré-configurée. Dans certains cas (exemple plus bas), celà pourrait vous suffire mais il est cependant possible de créer vos propres images réutilisables et préconfigurées par vos soins mais c’est une autre histoire.
Je vais vous proposer deux cas de figure:
- L’utilisation d’une image native pour mettre en place un serveur MySQL/mariadb/PostgreSQL
- La mise en place d’un container pour un projet Symfony sur base d’image php8.2-apache et pouvant utiliser composer
Réseaux virtuels
Autre notion à connaître, celle des réseaux. Par défaut, les containers sont isolés les uns des autres. Mais dans certains cas comme dans les exemples que nous allons voir, il est intéressant de pouvoir communiquer d’un à l’autre comme par exemple entre un container contenant une base de donnée et un container contenant le projet web.
Pour ce faire, rien de compliqué, une nouvelle commande fait le job.
docker network create myNetworkName
Vous pouvez créer autant de réseau que vos besoins le demandent.
Mais vous pouvez aussi simplement mettre tous les projets dans le même réseau…
Pour les exemples qui vont suivre, nous allons créer le réseau “dev”.
docker network create dev
Installer un container MySQL / MariaDB / PostgreSQL
Comme je vous le disais, on va commencer par un petit exercice simple: mettre en place une base de données et ce via via une simple ligne de commande.
MySQL
docker run -d --name db-mysql -e MYSQL_ROOT_PASSWORD=admin -p 3306:3306 --network dev mysql
MariaDB
docker run -d --name db-mariadb -e MARIADB_USER=kevin -e MARIADB_PASSWORD=admin -e MARIADB_ROOT_PASSWORD=admin -p 3306:3306 --network dev mariadb
PostgreSQL
docker run -d --name db-postgres -e POSTGRES_PASSWORD=admin -p 5432:5432 --network dev postgres
Mais elle fait quoi cette commande en fait?
- -d autorise Docker à lancer ce container en arrière plan
- --name est le nom de votre container. Il n'est connu que de vous et doit être unique. Il vous servira aussi dans le cas où vous voudriez communiquer vos containers entre eux. Si vous ne l'indiquez pas, un identifiant random sera généré… moins pratique.
- -e spécifie une variable d'environnement. Ici ces variables servent pour la configuration des users des dbs.
- -p indique le port que doit utiliser le container
- –network indique le réseau interne que doit utiliser le container
- La dernière valeur (mysql/mariadb/postgres) indique l'image à utiliser
Donc en exécutant cette simple commande, vous avez un serveur installé et lancé !
Ce container restera actif aussi longtemps que votre Docker.
Pour la prochaine utilisation, utilisez la commande suivante pour démarrer votre container:docker start db-mysql docker start db-mariadb docker start db-postgres
Pour y accéder:
MySQL Host: localhost Port: 3306 User: root Password: admin |
MariaDB Host: localhost Port: 3306 User: root Password: admin |
PostgreSQL Host: localhost Port: 5432 User: postgres Password: admin |
Bon ca c'était relativement simple! Nous avons créé un container basé sur une simple image et les quelques infos ont été passées en paramètre.
Installer un container Apache/php
Cette fois, nous allons créer un container lié à un projet précis et vous connaissez mes habitudes, ce sera un projet Symfony. Nous allons nous baser sur trois images:
- php8.2-apache
- composer
- node
Petite remarque pour composer. Si vous cherchez sur internet, vous trouverez généralement une tout autre méthode consistant à récupérer le fichier composer depuis le site officiel par une commande curl… Perso, je n’ai jamais réussi à l'utiliser. Je vous propose donc une alternative plus propre via le docker-compose
Nous allons commencer par créer un fichier docker-compose.yml à la racine de notre projet.
Ce fichier va contenir nos différents services:
version: '3'
services:
web:
container_name: demosf6_web
build: docker
volumes:
- ./:/var/www/html
ports:
- "8000:80"
networks:
- dev
node:
container_name: demosf6_node
image: node:16-alpine3.13
command: ["yarn", "encore", "dev"]
working_dir: /var/www/app
volumes:
- .:/var/www/app
composer:
container_name: demosf6_composer
image: composer
command: ["composer", "install", "--ignore-platform-reqs"]
volumes:
- ./:/app
depends_on:
- web
networks:
dev:
name: dev
external: true
- web, node et composer sont des alias pour les services
- build: Indique que nous n’allons pas nous baser sur une image existence mais bien sur une configuration personnalisée qui se trouvera dans le fichier /docker/Dockerfile
- container_name est le com du container qui sera utilisé pour le démarrer si nécessaire. Pensez à le préfixer avec le nom de votre projet car si vous avec plusieurs projets avec un container semblable (composer par exemple) cela va poser problème… il y a peut être moyen de le réutiliser ou de le partager mais je n’ai pas trouvé l’info.
- ports: indique le port externe et interne du container
- networks: Spécifie les réseaux auxquels est connecté le container
- volumes liste des liens symboliques entre le projet et l’emplacement réel
- image fait référence a une image du https://hub.docker.com/
- command: Indique la commande à exécuter au lancement
La façon d’écrire est… spéciale mais c’est la méthode recommandée.
Il vous est cependant possible de l’écrire différemmentcommand: bundle exec thin -p 3000 command: ["bundle", "exec", "thin", "-p", "3000"]
https://docs.docker.com/compose/compose-file/compose-file-v3/#command
A l’heure actuelle il nous est impossible de lancer notre Docker car nous n’avons pas encore configurer le fichier /docker/Dockerfile
FROM php:8.1-apache
Indique que nous nous basons sur l’image php:8.1-apache pour créer notre propre image
Nous avons ensuite besoin d'ajouter des extensions php. Pour ce faire on va se baser sur docker-php-extension-installer.
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
RUN chmod +x /usr/local/bin/install-php-extensions && \
install-php-extensions xdebug gd pdo_mysql intl
Nous devons ensuite modifier la config apache pour accéder directement au dossier /public
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
RUN a2enmod rewrite && service apache2 restart && \
sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf && \
sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
Si l’on se réfère aux bonnes pratiques, il est conseillé de n’utiliser qu’une seule fois la commande RUN car lors du processus de création de l’image, Docker va créer une nouvelle image à chaque RUN et se baser sur cette nouvelle image pour le prochain RUN… Pas certain que ce soit clair mais si vous devez retenir quelque chose: Évitez de multiplier les RUN tant que possible.
FROM php:8.1-apache ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/ ENV APACHE_DOCUMENT_ROOT=/var/www/html/public RUN chmod +x /usr/local/bin/install-php-extensions && \ install-php-extensions xdebug gd pdo_mysql intl && \ a2enmod rewrite && service apache2 restart && \ sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf && \ sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
Il ne vous reste plus qu’à lancer la commande suivante en étant dans le dossier de votre projet
docker-compose up -d --build
Essayer d'accéder à http://localhost:8000/
Victoire, votre projet Symfony est accessible !
Lier la base de donnée
Vous trouverez souvent des exemples sur le net de fichier docker-compose.yml qui intègre également la base de données.
Dans mon cas, en développement local, je préfère avoir ma db séparée de mon projet, question d’habitude.
Comment faire? Hé bien nous l’avons déjà fait plus tôt dans cet article lors de la création du network!
“Ha mais je n’ai qu’a configurer mon .env Symfony pour le lier?”
Alors oui mais petite spécificité, vous ne pouvez pas attaquer notre cher 127.0.0.1 pour la simple et bonne raison que vos containers reçoivent une adresse IP différente et qui risque d’être différente à chaque lancement !
Ne vous inquiétez pas, ça va encore être plus simple !
Indiquez simplement comme host de votre db, le nom de votre container Docker.
DATABASE_URL="mysql://root:admin@db-mariadb:3306/sf6demo?serverVersion=mariadb-10.11.2&charset=UTF8"
Votre projet communique désormais avec votre db !
Le mot de la fin
Quelques concepts à comprendre mais honnêtement un tel confort si comme moi vous travaillez sur plusieurs machines en même temps.
Il suffit d’installer Docker, de faire un git push, de lancer les docker-compose et votre environnement est prêt. Aucun souci de compatibilité de version php,node,... Tout se lance tout seul, ca compose, ca compile,...
Bref, je suis conquis !