Attention : la plupart des astuces indiquées parlent du partage de système d’authentification / sécurité entre l’hôte et un conteneur Docker. Ceci introduit un risque que ces systèmes soient utilisés pour voler votre identité. Il faut donc faire attention aux images que vous utilisez et mettre en œuvre les partages que s’ils sont nécessaires.

Entrypoint

Une des difficultés rencontrées avec Docker réside dans le fait que l’utilisateur de l’hôte et du conteneur sont différents. Par conséquent, cela pose des problèmes de création et d’édition des fichiers et répertoires en fonction de leur propriétaire. Dans un environnement Linux, les utilisateurs et leurs groupes sont identifiés par des ID stockés dans le fichier /etc/passwd.

Dans la plupart des cas, c’est en tant qu’utilisateur root que l’on se connecte dans un conteneur. C’est l’utilisateur par défaut qui fait fonctionner les logiciels tels qu’Apache. Or, le fonctionnement recherché est sensiblement différent. En effet, il convient de rester connecté en tant que root lorsqu’il s’agit seulement d’administrer le serveur Apache. En revanche, il est préférable de se connecter avec l’utilisateur www-data lorsqu’il s’agit d’exécuter des commandes du type composer install afin que celui-ci corresponde avec l’utilisateur de l’hôte, et ainsi éviter des problèmes de droits sur les fichiers.

Pour ce faire, Docker propose une mécanique à l’aide des commandes CMD et ENTRYPOINT. La première est lancée par défaut au démarrage du conteneur tandis que la seconde recevra CMD en argument.

Il s’agit donc de créer un script qui règlera les identifiants de l’utilisateur www-data en copiant ceux du répertoire /var/www/html qui proviennent de l’hôte, puis tester la commande CMD afin de savoir s’il faut changer ou non d’utilisateur.

Fichier entrypoint.sh :

#!/usr/bin/env sh
set -e

: ${WWW_DATA_UID:=`stat -c %u /var/www/html`}
: ${WWW_DATA_GUID:=`stat -c %g /var/www/html`}

# Change www-data's uid & guid to be the same as directory in host or the configured one
if [ "`id -u www-data`" != "$WWW_DATA_UID" ]; then
    usermod -u $WWW_DATA_UID www-data || true
fi

if [ "`id -u www-data`" != "$WWW_DATA_GUID" ]; then
    groupmod -g $WWW_DATA_GUID www-data || true
fi

# execute all commands with user www-data
if [ "$1" = "apache2-foreground" ]; then
    exec "$@"
else
    su www-data -s /bin/bash -c "$*"
fi

Puis dans le Dockerfile :

FROM php:7-apache

# ...

ADD entrypoint.sh /sbin/entrypoint
RUN chmod +x /sbin/entrypoint

ENTRYPOINT ["entrypoint"]
CMD ["apache2-foreground"]

Cache de Composer

Afin d’optimiser les installations via composer, il convient de prendre en compte la gestion de son cache afin d’éviter de télécharger systématiquement toutes les archives. Il est aussi conseillé de tenir compte des quotas tels que ceux imposés par l’API de GitHub qui autorise le téléchargement d’archives en nombre limité en mode anonyme.

Il existe deux solutions pour résoudre ces problèmes :

  1. créer un volume persistant dans Docker monté au niveau du dossier utilisateur qui lancera la commande composer. Puis générer une clé pour chaque projet qui sera ensuite ajoutée, via un fichier, dans le conteneur.
  2. partager votre dossier .composer avec le container.
version: '2'

services:
  api:
    build:
      context: docker/app
    volumes:
      - ~/.composer:/var/www/.composer
      - ./api:/var/www/html

Partager la socket SSH

Il est fréquent d’avoir un gestionnaire de paquets privé tels que Satis, Packagist privé, etc., et qui fonctionne avec une identification par clé. Le problème, c’est qu’il est délicat de partager le contenu du dossier ~/.ssh avec un conteneur car celui-ci pourrait contenir un script qui publie régulièrement les clés à un tiers.

Toutefois, il est possible de partager les sockets entre l’hôte et le conteneur. Par conséquent, ce sont les configurations de l’hôte qui seront employées lors d’une interaction entre le conteneur et les sockets. Le fichier known_hosts qui liste les machines autorisées est aussi partagé.

version: '2'

services:
  api:
    build:
      context: docker/app
    environment:
      - SSH_AUTH_SOCK=/tmp/ssh_auth_sock
    volumes:
      - ~/.composer:/var/www/.composer
      - ./api:/var/www/html
      - ~/.ssh/known_hosts:/var/www/.ssh/known_hosts:ro
      - $SSH_AUTH_SOCK:/tmp/ssh_auth_sock:ro