lindev.fr

Aller au contenu | Aller au menu | Aller à la recherche

Mot-clé - virtualhost

Fil des billets - Fil des commentaires

07 juin 2017

Environnement de développement complet avec Docker

Qu'allons nous voir

docker-logo.jpg Nous allons voir comment mettre sur pied avec Docker un environnement de développement Web complet ( LAMP ) en quelques minutes ( si l'on compte uniquement le temps de déploiement, et non la lecture de ce post. ).

Mais surtout , rendre cet environnement facilement configurable pour qu'il réponde à vos attentes.

Au programme, nous aurons donc 3 conteneurs


Petit plus, nous aurons à disposition, un fichier de configuration permettant l'utilisation de la fonction mail() de php.

Pour lancer facilement ces conteneurs Docker, nous utiliseront l'outil docker-compose, qui permet en un seul fichier de déclarer notre environnements et bien plus encore.

Pour les plus pressés : Si vous ne souhaitez pas créer les répertoires et fichiers de conf à la main en suivant tout le billet, vous pouvez directement cloner le projet puis lancer ( Après avoir installé Docker sur votre machine évidemment ). Rendez-vous tout en bas de cette page, dans la section Go go go.

Installation de Docker et docker-compose

Franchement, il n'y a rien de compliqué, je ne vais pas détailler spécialement la méthode , juste vous donner les liens pour les différents systèmes.
Après, il suffit de suivre.

Docker CE

Docker-Compose

Bonne nouvelle pour les utilisateurs de Mac & Windows, l'outil est automatiquement installé avec Docker.

Pour les utilisateurs Linux, je conseille la commande pip

sudo pip install docker-compose

Le projet LAMP

Parfait, nous avons tout les outils nécessaires pour atteindre notre objectif.
Commençons par créer un répertoire qui contiendra l’ensemble des fichiers de configuration et le code source de nos futurs projets Web .

mkdir -p dockerlamp/www dockerlamp/docker/apache/vhosts dockerlamp/docker/mysql dockerlamp/docker/php

Voici en résumé ce que ça donne :

dockerlamp
├── docker
│   ├── apache
│   │   └── vhosts
│   ├── mysql
│   ├── php
└── www

Nous aurons donc les fichiers de configuration dans le répertoire docker/ et le code source sera dans le répertoire www/

docker-compose.yml

Je vais pas tourner autour du pot, je vais tout de suite vous donner le contenu complet du fichier docker-compose.yml, nous verrons ensuite les différents points à compléter.

Créez donc le fichier docker-compose.yml à la racine du répertoire dockerlamp/

# Adopt version 2 syntax:
#   https://docs.docker.com/compose/compose-file/#/versioning
version: '2'

volumes:
    database_data2:
        driver: local

services:
###########################
# Setup the Apache container
###########################
    httpd:
        container_name: dockerapache_httpd_1
        restart: always
        image: httpd:2.4.25
        ports:
            - 80:80
        volumes:
            - ./docker/apache/httpd.conf:/usr/local/apache2/conf/httpd.conf
            - ./docker/apache/vhosts/:/usr/local/apache2/conf/vhosts
        volumes_from:
            - php

###########################
# Setup the PHP container
###########################
    php:
        container_name: dockerapache_php_1
        restart: always
        build: ./docker/php/
        expose:
            - 9000
        volumes:
            - ./www/:/usr/local/apache2/htdocs
            - ./docker/php/ssmtp.conf:/etc/ssmtp/ssmtp.conf:ro
            - ./docker/php/php-mail.conf:/usr/local/etc/php/conf.d/mail.ini:ro


###########################
# Setup the Database (MySQL) container
###########################
    mysql:
        container_name: dockerapache_mysql_1
        restart: always
        image: mysql:5.6.36
        expose:
            - 3306
        volumes:
            - database_data2:/var/lib/mysql
            - ./docker/mysql/conf-mysql.cnf:/etc/mysql/mysql.conf.d/conf-mysql.cnf:ro
        environment:
            MYSQL_ROOT_PASSWORD: secret
            MYSQL_DATABASE: project
            MYSQL_USER: project
            MYSQL_PASSWORD: project

Configuration Apache

Afin de configurer finement le service Apache, nous allons récupérer le fichier httpd.conf et le déposer dans le répertoire dockerlamp/docker/apache/

Voici le lien de téléchargement httpd.conf

La seule modification faite à ce fichier ( comparé à la version d'origine ) est la prise en charge des virtualhosts.

Nous allons par conséquent également récupérer le virtualhost par défaut et le placer dans le répertoire dockerlamp/docker/apache/vhosts/

Voici le lien de téléchargement 000-default.conf


Pour les curieux, si vous éditez le fichier 000-default.conf, vous verrez que l'on utilise le module proxy d'apache pour gérer les sources php . Nous passons ces sources au service nommé "php" sur le port 9000.

Nous en avons terminé avec le service apache . Passons au service php.

Configuration php-fpm

Contrairement au service apache, le conteneur php-fpm doit être modifié, pour ne serait-ce qu'installer les extensions.
Nous allons donc créer un fichier Dockerfile, qui contiendra toutes les instructions pour finaliser notre container .

La bonne pratique

J'aurais pu simplement créer une image du container sur dockerHub et la mettre à disposition, mais pour partager une image modifiée, la bonne pratique consiste à utiliser comme base l'image officielle ( php ), puis d'ajouter explicitement les changements à apporter dans un DockerFile.

Ce qui vous permet d'être certain que l'image finale n'est pas corrompue.

Dockerfile

créez le fichier Dockerfile dans le répertoire dockerlamp/docker/php/, comme précisé dans docker-compose.yml.

FROM php:5.6-fpm

# install the PHP extensions we need
RUN set -ex; \
	\
	apt-get update; \
	apt-get install -y \
		libjpeg-dev \
		libpng12-dev \
                libmcrypt-dev \
                ssmtp \
	; \
	rm -rf /var/lib/apt/lists/*; \
	\
	docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr; \
	docker-php-ext-install gd mysqli opcache pdo_mysql json mcrypt; \
        pecl install -o -f xdebug redis \
        && rm -rf /tmp/pear \
        && echo "extension=redis.so" > /usr/local/etc/php/conf.d/redis.ini \
        && echo "zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20131226/xdebug.so" > /usr/local/etc/php/conf.d/xdebug.ini; 
# TODO consider removing the *-dev deps and only keeping the necessary lib* packages

# set recommended PHP.ini settings
# see https://secure.php.net/manual/en/opcache.installation.php
RUN { \
		echo 'opcache.memory_consumption=128'; \
		echo 'opcache.interned_strings_buffer=8'; \
		echo 'opcache.max_accelerated_files=4000'; \
		echo 'opcache.revalidate_freq=2'; \
		echo 'opcache.fast_shutdown=1'; \
		echo 'opcache.enable_cli=1'; \
	} > /usr/local/etc/php/conf.d/opcache-recommended.ini

RUN { \
                echo '[xdebug]'; \
                echo 'xdebug.default_enable = 0'; \
        } >> /usr/local/etc/php/conf.d/xdebug.ini


RUN { \
        echo 'error_reporting  =  E_ALL'; \
        echo 'log_errors = On'; \
        echo 'display_errors = Off'; \
    } > /usr/local/etc/php/php.ini

CMD ["php-fpm"]
EXPOSE 9000

php7-fpm : Si vous préférez une autre version de php, il vous suffit de la changer sur la première ligne ( ex : FROM php:7.1.5-fpm ).
Toutes les versions sont listées ici.

fonction mail()

Puisque nous utilisons le service php à l'intérieur d'un container, seul ce service est disponible ( bien qu'il soit possible de lancer plusieurs services dans un même conteneur, cette méthode n'est pas conseillée ), le service sendmail n'est pas disponible.

Pour palier à ce problème, nous allons utiliser ssmtp. Cet utilitaire ne fait que rediriger les mails vers un serveur SMTP externe.
Pour le configurer ( l'activer au sein de php et définir quel serveur SMTP utiliser ), nous allons ajouter deux fichiers dans le répertoire dockerlamp/docker/php/

  • php-mail.conf
  • ssmtp.conf
php-mail.conf

Ce fichier de configuration ( chargé comme un php.ini supplémentaire ) ne fait que surcharger le chemin de l’exécutable sendmail afin d'utiliser ssmtp.

[mail function]
sendmail_path = "/usr/sbin/ssmtp -t"
ssmtp.conf

Ce fichier vous permet de définir quel serveur SMTP utiliser pour envoyer vos mails.
Par exemple, pour utiliser un compte Gmail:

mailhub=smtp.gmail.com:587
[email protected]
AuthPass=mypassword

FromLineOverride=YES
hostname=dockerdev.foo.net
UseSTARTTLS=YES

Seules les 3 premières lignes sont à adapter selon votre cas.

Nous en avons terminé avec la configuration de php-fpm. Passons à Mysql

Configuration Mysql

C'est presque le service le plus simple... dans le fichier docker-compose, nous avons défini des variables d'environnements, qui spécifient le mot de passe du compte root, une base de données à créer avec un utilisateur associé (login et mot de passe) .

Par la suite, si vous devez ajouter une nouvelle base de données, deux possibilités .

  1. Ajouter les informations dans le fichier docker-compose, et relancer le conteneur
  2. Se connecter en root sur le service mysql et créer manuellement la base de données et son utilisateur .

Nous allons créer le fichier conf-mysql.cnf, dans le répertoire dockerlamp/docker/mysql/ ce fichier est automatiquement monté dans le conteneur Mysql à son démarrage et permet donc de modifier simplement la configuration de mysql .

Par exemple, si l'on souhaite modifier la variable sql_mode

[mysqld]  
sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

Note : Vous pouvez laisser ce fichier vide si vous n'en avez pas l'utilité pour le moment. Mais il doit être présent dans le répertoire mysql !

Notre environnement LAMP est maintenant prêt !

Lancer l'environnement LAMP

Puisque nous avons configuré notre environnement via un fichier docker-compose.yml, nous allons évidemment utiliser la commande docker-compose pour le lancer.
Placez-vous à la racine du projet dockerlamp/

docker-compose up -d

Cette commande va construire les volumes, les interfaces réseaux, télécharger les images nécessaires, construire les conteneurs si besoin ( via le Dockerfile ) et enfin ... les exécuter en tache de fond . Oui oui .. tout ça en une seule commande .. le pied!

Le test

Nous allons tester notre stack, apache et php.

Créez deux fichiers dans le répertoire www/

  • info.php
  • index.html
info.php
<?php 
echo phpinfo();
index.html
<h1>Hello World</h1>

Enfin ouvrez un navigateur et entrez ces URLs :

Vous devriez normalement voir un magnifique Hello World, et la page d'infos de php ! Selection_999_057_.png

Un vrai projet

Je ne vais pas vous laisser avec un simple phpinfo() et un Hello World !!
Nous allons aller au bout des choses, en installant par exemple un petit Drupal.

L'objectif est d'installer Drupal et qu'il soit accessible ( sur votre machine ) depuis l'url http://drupal.local/


Le Vhost

Afin de pouvoir utiliser un nom de domaine locale, ( drupal.local ), il faut auparavant renseigner le fichier hosts, pour le déclarer .

Linux et Mac
sudo sh -c "echo '127.0.0.1   drupal.local' >> /etc/hosts"
Windows

Pour Windows vous devez ouvrir le fichier c:\Windows\System32\Drivers\etc\hosts en administrateur avec NotePad et y ajouter la ligne :

127.0.0.1   drupal.local

Maintenant, nous allons créer notre vhost afin qu'Apache sache quoi faire lorsqu'il reçoit les requêtes avec le nom de domaine drupal.local.

Editer le fichier dockerlamp/docker/apache/vhosts/drupal.conf

<VirtualHost *:80>
        ServerAdmin [email protected]
        ServerName drupal.local

        <Directory />
            AllowOverride All
            Require all granted
        </Directory>

        DocumentRoot "/usr/local/apache2/htdocs/drupal"
        <Directory "/usr/local/apache2/htdocs/drupal">
                Options Indexes FollowSymLinks
                AllowOverride All
                Require all granted
        </Directory>


    <FilesMatch \.php$>
        # 2.4.10+ can proxy to unix socket
        # SetHandler "proxy:unix:/var/run/php5-fpm.sock|fcgi://localhost/"

        # Else we can just use a tcp socket:
        SetHandler "proxy:fcgi://php:9000"
    </FilesMatch>

</VirtualHost>

On a donc déclaré le nom de domaine à Apache, en lui spécifiant de pointer sur le répertoire drupal/

Les sources

Puisque nous avons demandé à Apache de pointer sur le répertoire drupal/, nous allons télécharger les sources de Drupal dans ce répertoire qui lui-même se trouve dans le répertoire dockerlamp/www/

cd www
wget https://ftp.drupal.org/files/projects/https://ftp.drupal.org/files/projects/drupal-8.3.2.tar.gz
tar xzf drupal-8.3.2.tar.gz 
mv drupal-8.3.2 drupal
mkdir -p drupal/sites/default/files/translations && chmod -R 777 sites/default/files/translations
chmod -R 777 drupal/sites/default/files
touch drupal/sites/default/settings.php && chmod 777 drupal/sites/default/settings.php

Enfin, pour que le conteneur Apache prenne en considération notre nouveau vhost, nous allons redémarrer notre stack

docker-compose restart

L'installation

Pour l'installation, il suffit de pointer sur notre nom de domaine local et suivre les instructions

http://drupal.local/

Arrivé à l'installation de la base de données, remplissez le formulaire comme ceci ( Base de données déclarée dans le fichier docker-compose.yml ),

  • Nom de la base de données : project
  • Utilisateur : project
  • Mot de passe : project
  • Et dans options avancés > Hôte : mysql


Selection_999_058_.png

Après cette étape, Drupal s'installe tranquillement sur votre environnement
Selection_999_059_.png
Remplissez les formulaires durant l'installation, vous devriez rapidement arriver sur la page d'accueil de votre Drupal fraîchement installé .

Selection_999_060_.png Selection_999_061_.png

Conclusion

Vous avez à disposition un environnement de développement complet comme démontré avec Drupal.

Pour chaque projet vous devez donc

  1. Créer un domaine local dans votre fichier hosts
  2. Créer la configuration du virtualHost pour apache
  3. Récupérer les sources et les placer dans le répertoire www/
  4. Relancer la stack LAMP via docker-compose

Voici quelques outils / lignes de commandes pour vous aider à travailler, "debugger".

Vous trouverez ces petits scripts dans le répertoire tools/ du dépôt dockerlamp.

Ces scripts ne représentent qu'une base pour vous aider à travailler, je vous laisse maintenant parcourir la documentation de Docker pour comprendre les différentes commandes / configurations utilisées dans ce billet.

N’hésitez pas à poser des questions si besoin.

Créer un dump d'une base de données

dump_sql.sh

docker exec dockerapache_mysql_1 /usr/bin/mysqldump --databases -uroot -psecret $DATABASE > $DATABASE.sql

Restaurer/Importer une base de donnée depuis un dump sql

restore_sql.sh

cat $DUMP | docker exec -i dockerapache_mysql_1 /usr/bin/mysql -uroot -psecret

Afficher les logs Apache en temps réel ( Pour débugger )

logs.sh

docker logs --tail 100 -f dockerapache_httpd_1 

Afficher les ressources utilisées par les conteneurs sur votre machine

stats.sh

docker stats --format "table {{.Container}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDs}}"

Selection_999_062_.png

Go go go

On clone l'environnement

git clone https://[email protected]/cdesaintleger/dockerlamp.git && cd dockerlamp

On Configure le smtp

cp docker/php/ssmtp.conf.dist docker/php/ssmtp.conf && vim docker/php/ssmtp.conf

On lance la stack

docker-compose up -d

22 fév. 2015

Apache2 php5-fpm VirtualHost

Cela fait maintenant quelques mois que je n'ai pas édité de nouveau billet sur ce site, je vais donc couper cette période creuse en vous proposant un petit tutoriel sur la mise en place de php5-fpm avec apache2 et tout ça configurable au besoin dans des virtualhost .

Nous avons déjà vu comment faire avec Nginx ( qui est franchement plus clair qu'apache ) mais parfois on a pas le choix du serveur web sur lequel on travail .. alors voyons comment faire ça proprement avec apache2.

Etat des lieux

Le tutoriel se base sur la version stable de Débian du moment, Debian 7 "Wheezy" .
Nous allons également activer les dépôts contrib et non-free pour installer ce qui va suivre .

Pour cela commencez par éditer le fichier /etc/apt/sources.list

sudo vim /etc/apt/sources.list

Et ajoutez à la fin de chaque ligne contrib non-free
Ce qui donne quelque chose comme çà

deb http://cloudfront.debian.net/debian wheezy main contrib non-free
deb-src http://cloudfront.debian.net/debian wheezy main contrib non-free
deb http://security.debian.org/ wheezy/updates main contrib non-free
deb-src http://security.debian.org/ wheezy/updates main contrib non-free
deb http://cloudfront.debian.net/debian wheezy-updates main contrib non-free
deb-src http://cloudfront.debian.net/debian wheezy-updates main contrib non-free

PS: ne faite pas attention à l'url de mes dépôts ci-dessus "cloudfront.debian.net" , j'utilise une instance (VM) Amazon pour réaliser mes tests .

Installation des paquets nécessaires

Nous allons installer les paquets suivants :

sudo apt-get install php5-fpm libapache2-mod-fastcgi php5-cgi

Puis il nous faut activer le module fastcgi et actions via la commande a2enmod

sudo a2enmod actions fastcgi

Configuration du module fastcgi

Il nous faut lier le module fastcgi aux processus php5-fpm, pour celà nous allons éditer le fichier de configuration du module fastcgi

vim /etc/apache2/mods-available/fastcgi.conf

Pour arriver à ce résultat

<IfModule mod_fastcgi.c>
 AddType application/x-httpd-fastphp5 .php
 Action application/x-httpd-fastphp5 /php5-fcgi
 Alias /php5-fcgi /usr/bin/php5-fcgi
 FastCgiExternalServer /usr/bin/php5-fcgi -socket /var/run/php5-fpm.sock -pass-header Authorization
</IfModule>

NB : il vous faut vérifier le chemin du socket php5-fpm dans votre cas, normalement, /var/run/php5-fpm.sock et la valeur par défaut pour l’environnement Débian 7, pour vérifier exécuter cette commande

cat /etc/php5/fpm/pool.d/www.conf | grep "listen = "

Le test

Il ne vous reste plus qu'à tester cette nouvelle configuration, commençons par tester l'ensemble des paramètres d'apache via la commande très pratique

sudo apache2ctl configtest

Puis il ne reste plus qu'à relancer Apache si tout est ok

sudo service apache2 restart

Enfin, nous allons mettre un simple fichier php dans le DocumentRoot par défaut d'apache2

sudo echo "<?php echo phpinfo();" > /var/www/lindev.php && chown www-data:www-data /var/www/lindev.php

Il ne vous reste plus qu'à entrer l'url http://localhost/lindev.php pour voir le résultat .

Conf spécifique par virtualhost

Jusque là, les scripts php sont exécutés par l'utilisateur système www-data dans la plupart des cas, cela va être adéquat, mais si pour une raison quelconque vous devez utiliser un autre utilisateur pour exécuter un script/site en particulier, dans le virtualhost correspondant, il vous faudra surcharger la configuration du module fastcgi, ce qui donnera par exemple

<VirtualHost *:80>
    ServerAdmin [email protected]
    ServerName lindev.fr
    ServerAlias www.lindev.fr
    DocumentRoot /var/www/lindev/
    ErrorLog /var/www/lindev/error.log
    CustomLog /var/www/lindev/access.log combined

    <IfModule mod_fastcgi.c>
        AddType application/x-httpd-fastphp5 .php
        Action application/x-httpd-fastphp5 /php5-fcgi
        Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi_lindev
        FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi_lindev -socket /var/run/php5-fpm_lindev.sock -pass-header Authorization
    </IfModule>

</VirtualHost>

Ici , j'ai donc donné un autre socket à utiliser, que j'ai nommé php5-fpm_lindev.sock. Ce socket devra bien évidement être configuré coté php-fpm, en créant un nouveau pool ( dans un prochain article certainement ), en attendant, pour tester copiez juste la conf du pool par défaut, et changer le paramètre listen pour spécifier le socket à créer pour ce pool.
C'est également dans ce fichier de pool que vous pourrez spécifier l'utilisateur système à utiliser pour interpréter les fichiers php.

cp /etc/php5/fpm/pool.d/www.conf /etc/php5/fpm/pool.d/lindev.conf

Changer les paramètres listen, user et group , puis relancer php-fpm

sudo service php5-fpm reload

L'article touche maintenant à sa fin, vous savez maintenant installer apache, php5-fpm et configurer un pool spécifique de php pour un virtualhost.

Ch.