Docker, Docker-Compose & Magento 2.4
Objectif
Installer Magento 2.4 en utilisant Docker et Docker-Compose.
Sources
Avant de commencer, cela fait un moment que j'utilise Docker pour développer sous Magento 2. Après avoir testé plusieurs solutions, je me suis basé sur la solution proposée par Mark Shust.
J'ai également visionné un paquet de vidéos de la chaîne Xavki.
Tutoriel
Changelog
23/11/2020 :
- Remplacement de MariaDb 10.4.13 par MySQL 8.0.22
04/08/2020 :
- Rédaction du tutoriel
Arborescence
Commencer par créer le répertoire de travail et au sein de ce dossier, créer les répertoires suivants :
mkdir -p src/app_data1 src/nginx_log1 src/phpfpm_log1 src/sock_data1 src/mysql_data1 src/mysql_log1 src/redis_data1 src/es_data1 src/es_log1 src/rabbitmq_data1 src/rabbitmq_log1
Tous ces dossiers vont servir pour la persistance des données au sein de chacun de nos conteneurs Docker.
Créer ensuite les dossiers pour stocker les fichiers Dockerfile de chaque conteneur :
mkdir -p docker-images/nginx/1.19 docker-images/php/7.4
Dockerfile
NGINX
Dans le dossier docker-images/nginx/1.19, créer un fichier Dockerfile contenant :
FROM nginx:1.19
RUN groupadd -g 1000 app \
&& useradd -g 1000 -u 1000 -d /var/www -s /bin/bash app
RUN touch /var/run/nginx.pid
RUN mkdir /sock
COPY ./nginx.conf /etc/nginx/
COPY ./default.conf /etc/nginx/conf.d/
RUN mkdir -p /var/www/html
RUN chown -R app:app /etc/nginx /var/www /var/cache/nginx /var/run/nginx.pid /sock
EXPOSE 8000
USER app:app
VOLUME /var/www
WORKDIR /var/www/html
Pour finaliser la partie NGINX, créer un fichier nginx.conf contenant :
# let's assume dual-core machine
worker_processes 2;
error_log /var/log/nginx/error.log debug;
pid /var/run/nginx.pid;
events {
# this should be equal to value of "ulimit -n"
# reference: https://www.digitalocean.com/community/tutorials/how-to-optimize-nginx-configuration
worker_connections 768;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_names_hash_bucket_size 64;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# Permet d'uploader des fichers de 20Mo
client_max_body_size 20M;
include /etc/nginx/conf.d/*.conf;
}
Pour terminer, créer un autre fichier default.conf contenant :
upstream fastcgi_backend {
server unix:/sock/docker.sock;
}
server {
listen 8000;
server_name localhost;
set $MAGE_ROOT /var/www/html;
include /var/www/html/nginx.conf.sample;
}
PHP
Dans le dossier docker-images/php/7.4, créer un fichier Dockerfile contenant :
FROM php:7.4-fpm-buster
RUN apt-get update && apt-get install -y \
cron \
git \
gzip \
libbz2-dev \
libfreetype6-dev \
libicu-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
libpng-dev \
libsodium-dev \
libssh2-1-dev \
libxslt1-dev \
libzip-dev \
lsof \
default-mysql-client \
vim \
zip
RUN docker-php-ext-configure gd --with-freetype --with-jpeg
RUN docker-php-ext-install \
bcmath \
bz2 \
calendar \
exif \
gd \
gettext \
intl
RUN apt-get install -y libonig-dev
RUN docker-php-ext-install \
mysqli \
opcache \
pcntl \
pdo_mysql \
soap \
sockets \
sodium \
sysvmsg \
sysvsem \
sysvshm \
xsl \
zip
RUN cd /tmp \
&& curl -O https://downloads.ioncube.com/loader_downloads/ioncube_loaders_lin_x86-64.tar.gz \
&& tar zxvf ioncube_loaders_lin_x86-64.tar.gz \
&& export PHP_VERSION=$(php -r "echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;") \
&& export PHP_EXT_DIR=$(php-config --extension-dir) \
&& cp "./ioncube/ioncube_loader_lin_${PHP_VERSION}.so" "${PHP_EXT_DIR}/ioncube.so" \
&& rm -rf ./ioncube \
&& rm ioncube_loaders_lin_x86-64.tar.gz \
&& docker-php-ext-enable ioncube
RUN pecl channel-update pecl.php.net \
&& pecl install xdebug
RUN docker-php-ext-enable xdebug \
&& sed -i -e 's/^zend_extension/\;zend_extension/g' /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN curl -o /tmp/ssh2-1.2.tgz https://pecl.php.net/get/ssh2 \
&& pear install /tmp/ssh2-1.2.tgz \
&& rm /tmp/ssh2-1.2.tgz \
&& docker-php-ext-enable ssh2
RUN groupadd -g 1000 app \
&& useradd -g 1000 -u 1000 -d /var/www -s /bin/bash app
RUN apt-get install -y gnupg
RUN curl -sS https://getcomposer.org/installer | \
php -- --version=1.9.0 --install-dir=/usr/local/bin --filename=composer
RUN curl -s https://packages.blackfire.io/gpg.key | apt-key add - \
&& echo "deb http://packages.blackfire.io/debian any main" | tee /etc/apt/sources.list.d/blackfire.list \
&& apt-get update \
&& apt-get install blackfire-agent blackfire-php
RUN printf '* *\t* * *\tapp\t%s/usr/local/bin/php /var/www/html/update/cron.php\n' >> /etc/crontab \
&& printf '* *\t* * *\tapp\t%s/usr/local/bin/php /var/www/html/bin/magento cron:run\n' >> /etc/crontab \
&& printf '* *\t* * *\tapp\t%s/usr/local/bin/php /var/www/html/bin/magento setup:cron:run\n#\n' >> /etc/crontab
COPY ./www.conf /usr/local/etc/php-fpm.d/
COPY ./php.ini /usr/local/etc/php/
COPY ./php-fpm.conf /usr/local/etc/
COPY bin/cronstart /usr/local/bin/
RUN mkdir -p /etc/nginx/html /var/www/html /sock \
&& chown -R app:app /etc/nginx /var/www /usr/local/etc/php/conf.d /sock
USER app:app
VOLUME /var/www
WORKDIR /var/www/html
EXPOSE 9001
Continuer en créant le fichier php-fpm.conf en y intégrant le contenu suivant :
[global]
error_log = /proc/self/fd/2
daemonize = no
[www]
; if we send this to /proc/self/fd/1, it never appears
access.log = /proc/self/fd/2
listen = /sock/docker.sock
listen.owner = app
listen.group = app
listen.mode = 0660
pm = dynamic
pm.max_children = 10
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
clear_env = no
; Ensure worker stdout and stderr are sent to the main error log.
catch_workers_output = yes
Puis créer le fichier php.ini avec le contenu :
; https://devdocs.magento.com/guides/v2.3/install-gde/prereq/php-settings.html
memory_limit = 4G
max_execution_time = 1800
zlib.output_compression = On
cgi.fix_pathinfo = 0
date.timezone = "Europe/Paris"
xdebug.remote_autostart = 1
xdebug.remote_enable = 1
xdebug.remote_host = host.docker.internal
xdebug.remote_port = 9001
xdebug.idekey = PHPSTORM
opcache.enable_cli = 1
opcache.memory_consumption = 512
opcache.max_accelerated_files = 100000
opcache.save_comments = 1
upload_max_filesize = 20M
post_max_size = 20M
; https://www.cloud-devops.fr/php-cacher-la-version-dans-les-headers/
expose_php = On
L'avant-dernier fichier www.conf doit contenir :
[www]
user = app
group = app
listen = 127.0.0.1:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
CRON
Le conteneur pour les crons est basé sur le conteneur PHP. Seulement pour fonctionner, il a besoin que le contenu ci-dessous soit intégré dans un fichier cronstart situé dans le dossier docker-images/php/7.4/bin. De plus, veiller à ce que ce fichier ait les droits d'éxécution.
#!/bin/bash
service cron start
touch /var/www/html/var/.setup_cronjob_status /var/www/html/var/.update_cronjob_status
chown app:app /var/www/html/var/.setup_cronjob_status /var/www/html/var/.update_cronjob_status
/usr/bin/crontab
auth.json
Afin que les conteneurs puissent se lancer sans erreur, il est nécessaire de stocker les clés d'authentification pour Magento dans le fichier auth.json du dossier docker-images/php/7.4/.composer. Voici le contenu :
{
"http-basic": {
"repo.magento.com": {
"username": "XXXX",
"password": "XXXX"
}
}
}
Bien sûr, il faut remplacer les XXX par vos clés.
Docker-Compose
Créer un premier fichier nommé .env avec le contenu suivant :
NGINX_VERSION=1.19
PHP_VERSION=7.4
MYSQL_VERSION=8.0.22
REDIS_VERSION=6.0.6
ELASTICSEARCH_VERSION=7.6.2
RABBITMQ_VERSION=3.8.5-management
MYSQL_ROOT_PASSWORD=magento
MYSQL_DATABASE=magento
MYSQL_USER=magento
MYSQL_PASSWORD=magento
RABBITMQ_DEFAULT_USER=magento
RABBITMQ_DEFAULT_PASS=magento
Ce fichier permet de définir des variables qui seront utilisée au sein du fichier docker-compose.yml.
Créer le fichier docker-compose.yml en y insérant le contenu ci-dessous :
version: '3'
services:
nginx:
build:
context: ./docker-images/nginx/${NGINX_VERSION}
ports:
- 80:8000
links:
- phpfpm
- redis:cache
volumes:
- ./src/app_data1:/var/www/html
- ./src/sock_data1:/sock
- ./src/nginx_log1:/var/log/nginx
networks:
- magento
phpfpm:
build:
context: ./docker-images/php/${PHP_VERSION}
links:
- db1
volumes:
- ./docker-images/php/${PHP_VERSION}/.composer:/var/www/.composer
- ./src/app_data1:/var/www/html
- ./src/phpfpm_log1:/var/log
- ./src/sock_data1:/sock
networks:
- magento
redis:
image: redis:${REDIS_VERSION}
restart: on-failure:5
volumes:
- ./src/redis_data1:/data
expose:
- 6379
networks:
- magento
cron:
build:
context: ./docker-images/php/${PHP_VERSION}
user: root
command: /usr/local/bin/cronstart
tty: true
links:
- db1
- elasticsearch1
- rabbitmq
volumes:
- ./src/app_data1:/var/www/html
- ./src/sock_data1:/sock
networks:
- magento
db1:
image: mysql:${MYSQL_VERSION}
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
- ./src/mysql_data1:/var/lib/mysql
- ./src/mysql_log1:/var/log/mysql
ports:
- 3306:3306
networks:
- magento
elasticsearch1:
image: elasticsearch:${ELASTICSEARCH_VERSION}
environment:
- cluster.name=es-cluster
- bootstrap.memory_lock=true
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms2048m -Xmx2048m"
- cluster.initial_master_nodes=elasticsearch1
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- ./src/es_data1:/usr/share/elasticsearch/data
- ./src/es_log1:/var/log/elasticsearch
networks:
- magento
rabbitmq:
image: rabbitmq:${RABBITMQ_VERSION}
environment:
- RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER}
- RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS}
ports:
- 15672:15672
- 5672:5672
networks:
- magento
networks:
magento:
driver: bridge
Build et Installation
Pour terminer, lancer la commande ci-dessous pour construire et lancer les conteneurs :
docker-compose build && docker-compose up -d
Une fois les conteneurs lancés, télécharger et créer le projet Magento 2.4 :
docker-compose exec phpfpm composer create-project --repository=https://repo.magento.com/ magento/project-community-edition:2.4 .
Dès que les fichiers ont été téléchargés, vous pouvez lancer l'installation :
docker-compose exec -T phpfpm bin/magento setup:install \
--db-host=db1 \
--db-name=magento \
--db-user=magento \
--db-password=magento \
--base-url=http://localhost/ \
--backend-frontname=system \
--admin-firstname=Administrateur \
--admin-lastname=Magento \
[email protected] \
--admin-user=administrateur \
--admin-password=mettreIciVotreMotDePasse \
--language=fr_FR \
--currency=EUR \
--timezone=Europe/Paris \
--use-rewrites=1 \
--search-engine=elasticsearch7 \
--elasticsearch-host=elasticsearch1 \
--elasticsearch-port=9200 \
--elasticsearch-index-prefix=magento
A cet instant, Magento est installé, avant de vous lancer, je vous invite à lancer les commandes ci-dessous :
Activation de RabbitMQ :
docker-compose exec -T phpfpm bin/magento setup:config:set --no-interaction --amqp-host=rabbitmq --amqp-port=5672 --amqp-user=magento --amqp-password=magento --amqp-virtualhost=/ --consumers-wait-for-messages=1
Activation de Redis :
docker-compose exec -T phpfpm bin/magento setup:config:set --no-interaction --cache-backend=redis --cache-backend-redis-server=redis --cache-backend-redis-db=0
Activation de Redis pour le Full Page Cache :
docker-compose exec -T phpfpm bin/magento setup:config:set --no-interaction --page-cache=redis --page-cache-redis-server=redis --page-cache-redis-db=1
Activation de Redis pour les sessions :
docker-compose exec -T phpfpm bin/magento setup:config:set --no-interaction --session-save=redis --session-save-redis-host=redis --session-save-redis-log-level=4 --session-save-redis-db=2
Redémarrer les conteneurs :
docker-compose stop && docker-compose up -d
Installation des modules dans la base de données :
docker-compose exec -T phpfpm bin/magento setup:upgrade && docker-compose exec -T phpfpm bin/magento setup:di:compile
Résultat
Vous pouvez visualiser le résultat en lançant votre navigateur à l'adresse : http://localhost/