Docker
1 DOCKER
Docker est un logiciel libre (Licence Apache 2.0) à mi-chemin entre la virtualisation applicative et l’automatisation.

Docker permet de manipuler des conteneurs de logiciels.
Il complète le conteneur Linux LXC en isolant les processus les uns des autres pour créer une virtualisation de haut niveau.
Contrairement aux autres systèmes de (para) virtualisation, Docker n’embarque pas un système d’exploitation invité mais ne s’occupe que de la partie haut niveau.
Il utilise le noyau de l’hôte et ne fait fonctionner que le strict nécessaire sur les invités.
Docker c’est aussi un dépôt d’images à partir duquel vous pouvez télécharger et partager des applications sans avoir à réinventer la roue.
Le dépôt est consultable à l’adresse :
Il est alors simplissime de télécharger et d’utiliser :
- Ubuntu
- Nginx
- Mysql
- redis
- …
1.1 DIFFERENCE VM / CONTENEUR
Une VM a pour but de proposer une couche d’abstraction au-dessus d’un système physique, telle que peut proposer Virtualbox, Qemu, VMware…
Ces machines virtuelles permettent de simuler une machine physique et donc de faire tourner une application de très bas niveau à savoir un OS (système d’opération) de son choix.
Grâce à cela, une machine physique sous un OS peut faire tourner plusieurs VM avec chacun son propre OS et son ensemble applicatif.
Cette solution est relativement performante si elle repose sur des fonctions matérielles (architecture physique compatible et si possible avec instruction AMD-V, VT-d, VT-x…) car sinon il faut opérer par émulation (perte de près de 50% des performances CPU lors d’émulation de x86 sur PowerPC).
Les VM sont souvent considérées comme sécurisées car il n’y a pas de communication direct entre VM et la machine host.

Le container virtualise l’environnement d’exécution de l’OS de la machine host (Linux ou BSD, il n’existe pas à ce jour de container sous Windows).
Un container est un ensemble applicatif s’exécutant au sein de l’OS maître de manière virtuellement isolé et contraint (jails, chroot **).
Le container est très performant et léger car il partage de nombreuses ressources avec l’OS host (kernel, devices…).
En revanche bien que s’exécutant de manière isolée, le container ne peut être considéré comme très sécurisé puisque partageant la stack d’exécution avec l’OS maître.
Le container peut au choix démarrer un OS complet ou bien simplement des applications.
Docker a pour objectif de ne pas reproduire tout un OS dans un container mais simplement les applications/services souhaités.
D’autres outils utilisant des containers tel qu’OpenStack ou Proxmox gèrent des containers pour virtualiser tout l’OS.
1.2 FONCTIONNEMENT
Docker est un gestionnaire/administrateur de container basé sur un principe de template de container.
La gestion de template de container est un atout majeur de Docker qui propose une riche variété de containers pré-existants mais également grâce à la personnalisation de containers.
Docker utilise LXC qui est l’implémentation de référence de containers dans Linux :
- cgroup
- apparmor / selinux
- chroots
- kernel namespaces
Docker propose des services pour facilement créer, éditer, publier, exécuter des containers.

D’autres fonctions avancées pour la gestion des containers & inter-container sont également proposées pour limiter les ressources (RAM, CPU, disques), définir des supports partagés, des interfaces partagées…
2 INSTALLATION SUR DEBIAN 8+
Sur un Ubuntu 14.04, l’installation est simple :
# apt−get install −y −−no−install−recommends \
apt−transport−https \
ca−certificates \
curl \
software−properties−common
# curl −fsSL https://apt.dockerproject.org/gpg | sudo apt−key add −
# add−apt−repository \
« deb https://apt.dockerproject.org/repo/ \
debian−$(lsb_release −cs) \
main »
# apt−get update
# apt−get −y install docker−engine
# service docker start
On peut ensuite tester docker avec la commande :
# docker run hello−world
2.1 ET DERRIERE UN PROXY ?
De base, les commandes de téléchargement de paquets passent à travers le proxy (dans /etc/apt/apt.conf).
Pour la commande curl précédente, il faut ajouter le paramètre –proxy :
# curl −fsSL −−proxy https://192.168.0.1:3128 https://apt.dockerproject.org/gpg | sudo apt−key add −
Ensuite, pour autoriser docker à télécharger des images, on va indiquer à systemd de lancer docker avec des paramètres liés à l’utilisation du proxy.
# mkdir /etc/systemd/system/docker.service.d
On crée ensuite le fichier :
/etc/systemd/system/docker.service.d/http-proxy.conf :
[Service]
Environment= »HTTP_PROXY=http://192.168.0.1:3128/ »
Puis on redémarre docker pour pouvoir télécharger des images :
# systemctl daemon−reload
# systemctl show −−property Environment docker
Environment=HTTP_PROXY=http://192.168.0.1:3128/
# systemctl restart docker
# docker run hello−world
3 IMAGES
3.1 CREER UNE IMAGE
Nous allons créer un conteneur from scratch à partir de l’image minimale d’un OS Ubuntu LTS 14.04.
3.1.1 VIA DEBOOTSTRAP
Nous utilisons l’outil debootstrap pour générer cette imagesudo debootstrap −−include ubuntu−minimal −−arch amd64 trusty rootfs http://archive.ubuntu.com/ubuntu
On monte cette image dans un dossier spécifique (avec root) :
# tar −C rootfs −c . | docker import − nph/base
On vérifie ensuite que l’image est bien présente :
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
nph/base latest 91d2c1176b7c About a minute ago 228.4 MB
Pour démarrer l’image, il suffit de lancer :
# docker run −i −t 91d2c1176b7c /bin/bash
3.1.2 COMMIT
Le commit d’une image correpond à une copie “versionnée” de cette image.
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
nph/base latest 91d2c1176b7c 51 minutes ago 87.4 MB
# docker commit 91d2c1176b7c base:1.00
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
base 1.00 0a323ede50b4 6 seconds ago 98.34 MB
nph/base latest 91d2c1176b7c 51 minutes ago 87.4 MB
3.2 UTILISER UNE IMAGE DE BASE
3.2.1 CONTENEUR UBUNTU
Il faut commencer par rechercher les conteneurs disponibles :
# docker search ubuntu
Déployer une image du dépôt Docker est simple :
# docker pull ubuntu
Dans cet exemple, un système Ubuntu minimal est téléchargé.
Pour le lancer, il suffit de taper :
# docker run −i −t ubuntu /bin/bash
On se retrouve alors connecté à la machine Ubuntu en tant que root.
A ce stade on peut faire ce qu’on veut :
- mettre à jour
- installer des paquets
- configurer un serveur
- …
3.2.2 CONTENEUR TOMCAT
A présent, on va déployer un conteneur Tomcat déployable et utilisable sur le port 8080.
# docker search tomcat
…
# docker pull consol/tomcat−7.0
…
# docker images
La dernière commande permet de vérifier le conteneur est bien disponible.
Le lancement du conteneur tomcat se fait via la commande :
# docker run −p :8080 consol/tomcat7
3.3 PERSONNALISER UNE IMAGE
Une image peut être personnalisée suivant 2 méthodes :
- en se connectant via ssh ou bash dans le container pour installer et éditer les configurations.
Ce mode bien que plus facile ne permet pas de capitaliser sur la “recette” et ne permet donc pas facilement une édition en incrémentale. - édition d’un fichier DockerFile contenant l’ensemble des actions à faire pour constituer le container (Cf. chapitre suivant)
4 AUTOMATISATION AVEC UN DOCKERFILE
Le dockerfile est un fichier texte qui inclut une liste d’actions à exécuter pour construire une image.
Exemple de dockerfile Apache :
# Apache et PHP dans un container
#
# VERSION 0.0.1
#
# Image de base
FROM debian:wheezy
# Mainteneur du conteneur
MAINTAINER NosPHeratus »nospheratus@nosland.com »
ENV DEBIAN_FRONTEND noninteractive
# Depots, mises a jour et installs
RUN (apt−get update && apt−get upgrade −y −q && apt−get dist−upgrade −y −q && apt−get −y −q autoclean && apt−get −y −q autoremove)
RUN apt−get install −y −q apache2 libapache2−mod−php5 php5 supervisor
RUN rm /var/www/index.html
ADD index.php /var/www/index.php
# Config de Apache
ENV APACHE_RUN_USER www−data
ENV APACHE_RUN_GROUP www−data
ENV APACHE_LOG_DIR /var/log/apache2
# Port a ouvrir a l’exterieur
EXPOSE 80
# Demarrage des services
RUN mkdir −p /var/log/supervisor
# Copie du fichier dans le fs du conteneur
ADD apache.conf /etc/supervisor/conf.d/apache.conf
# Commande a executer lors du demarrage du conteneur
CMD source /etc/apache2/envvars && exec /usr/sbin/apache2 −DFOREGROUND
Construire un conteneur :
# docker build −t nom_du_conteneur .
5 COMMANDES DE BASE
Voir les conteneurs qui tournent :
# docker ps
# docker ps −a
Démarrer une image
# docker run −i −t ubuntu /bin/bash
Supprimer un conteneur / supprimer tous les conteneurs :
# docker rm id_du_conteneur
# docker rm ‘docker ps −a −q‘
Supprimer une images :
# docker rmi id_ou_nom_de_l_image
Exporter/Importer un container en tar.gz :
# docker export id_ou_nom_de_l_image > nginx.tgz
# cat nginx.tgz | docker import − nginx
Arrêter un ou plusieurs conteneurs :
# docker stop $(docker ps −a −q)
# docker stop id_ou_nom_de_l_image
Supprimer un conteneur :
# docker rm id_ou_nom_de_l_image
Enregistrer l’état d’un conteneur (commit) :
# docker commit <container_id> <some_name>
# docker images
Afficher les infos d’une image :
# docker inspect id_ou_nom_de_l_image
6 CONTENEURS PERSONNALISES
Dans le cadre des laboratoires, nous avons créé plusieurs conteneurs dédiés.
Nous présentons ici quelques images.
6.1 JDK7
Utilisateurs inconditionnels de Java ( :, nous créons une image Java à partir de la distribution 14.04 d’Ubuntu.
Dockerfile :
# Image de base
FROM ubuntu:14.04
# Mainteneur
MAINTAINER NosPheratus < nospheratus@nosland.com>
# On met la liste des a jour et on installe
RUN apt−get update && apt−get −y install python−software−properties \
software−properties−common
RUN add−apt−repository ppa:webupd8team/java
RUN apt−get update && apt−get −y upgrade
# On accepte automatiquement la licence oracle
RUN echo oracle−java7−installer shared/accepted−oracle−license−v1−1 \
select true | /usr/bin/debconf−set−selections
# Installation java 7 oracle jdk
RUN apt−get −y install oracle−java7−installer && apt−get clean
RUN update−alternatives −−display java
RUN echo « JAVA_HOME=/usr/lib/jvm/java−7−oracle » >> /etc/environment
# Nettoyage
RUN rm −rf /var/lib/apt/lists/∗ && apt−get clean
Ce fichier placé dans un dossier spécifique, la création du contenur se fait via la commande :
# docker build −t « nph/jdk7 » .
On peut ensuite exécuter le conteneur, le distribuer…
# docker run −i −t nph/jdk7 /bin/bash
# docker ps −a
# docker export 88514bc5947c > jdk7.tgz
Cette image fait 719 Mo
6.2 TOMCAT7
Nous nous basons sur l’image JDK7 pour ajouter un serveur Tomcat 7.
Nous ajoutons un serveur SSH pour accéder au conteneur qui sera lancé en background.
Le service supervisor lancera SSH et Tomcat automatiquement lors du démarrage.
Nous utilisons le fichier d’autorisation ci-dessous pour accéder au manager d’applications :
tomcat-users.xml :
<?xml version=’1.0’ encoding=’utf−8’?>
<tomcat−users>
<role rolename= »manager−gui »/>
<user username= »admin » password= »admin » roles= »manager−gui »/>
</tomcat−users>
On utilise le démon supervisor pour démarrer le serveur tomcat :
tomcat.conf :
[supervisord]
nodaemon=true
[program:tomcat]
command=/bin/bash −c « env > /tmp/tomcat.env && cat /etc/default/tomcat7 \
>> /tmp/tomcat.env && mv /tmp/tomcat.env /etc/default/tomcat7 \
&& service tomcat7 start »
redirect_stderr=true
… et le serveur SSH
ssh.conf :
[program:sshd]
command=/usr/sbin/sshd −D
Ces trois fichiers sont placés dans le même dossier que le dockerfile ci-dessous :
:Dockerfile
# Image de base
FROM nph/jdk7
# Mainteneur
MAINTAINER NosPHeratus < nospheratus@nosland.com>
# On cree l’utilisateur nph
RUN useradd nph −m −d /home/nph −s /bin/bash
RUN adduser nph sudo
RUN echo nph:nph | chpasswd
# On installe Tomcat 7
RUN apt−get −y install tomcat7 tomcat7−admin
RUN echo « JAVA_HOME=/usr/lib/jvm/java−7−oracle » >> /etc/default/tomcat7
RUN cp −Rf /usr/share/tomcat7−admin/manager /var/lib/tomcat7/webapps/
RUN cp −Rf /usr/share/tomcat7−admin/host−manager /var/lib/tomcat7/webapps/
COPY tomcat−users.xml /etc/tomcat7/tomcat−users.xml
COPY tomcat.conf /etc/supervisor/conf.d/tomcat.conf
# On installe SSH
RUN apt−get update && apt−get install −y openssh−server
RUN mkdir /var/run/sshd
RUN sed −i ’s/PermitRootLogin without−password/PermitRootLogin no/’ \
/etc/ssh/sshd_config
# On installe supervisor
RUN apt−get −y install supervisor
RUN mkdir −p /var/log/supervisor
COPY tomcat.conf /etc/supervisor/conf.d/tomcat.conf
COPY ssh.conf /etc/supervisor/conf.d/ssh.conf
# On ouvre les ports
EXPOSE 8080 22
# On corrige les dependances diverses (pb tomcat−java)
RUN apt−get update −−fix−missing
# Nettoyage
RUN rm −rf /var/lib/apt/lists/∗ && apt−get clean
# On demarre supervisor automatiquement
CMD [« supervisord », « −n »]
Ce fichier placé dans un dossier spécifique, la création du contenur se fait via la commande :
# docker build −t « nph/tomcat7 » .
On peut ensuite exécuter le conteneur et accéder aux ports 8090 (tomcat, utilisateur admin/admin) et 2022 (SSH) de sa machine via l’utilisateur nph/nph.
Par défaut, l’image doit se lancer en mode background (1ere ligne).
# docker run −d −p 8090:8080 −p 2022:22 nph/tomcat7
# docker run −i −t nph/tomcat7 /bin/bash
# docker ps
# docker export 88514bc5947c > tomcat7.tgz
Cette image fait 704 Mo.
On peut visualiser le manager d’applications là :
… ou se connecter en SSH avec l’utilisateur root/root.
6.3 MYSQL
Mysql dispose d’un repository officiel : https://hub.docker.com/_/mysql/ et il est tout à fait possible d’utiliser les images disponibles.
Néanmoins… nos habitudes de travail autour de la virtualisation nous font préférer créer notre propre image mysql, qui s’apparentra davantage à une machine virtuelle classique.
On prévoit donc de disposer d’un service ssh pour se connecter sur l’image, ainsi que le serveur mysql 🙂
6.3.1 CREATION DE L’IMAGE
Nous créons un mot de passe pour l’utilisateur root de mysql, ainsi qu’une base de travail (nph) et l’utilisateur adéquat.
On utilise le démon supervisor pour démarrer le serveur mysql :
mysql.conf :
[supervisord]
nodaemon=true
[program:mysql]
command=/bin/bash −c « /opt/startup_mysql.sh »
redirect_stderr=true
… et le serveur SSH
ssh.conf :
[program:sshd]
command=/usr/sbin/sshd −D
Comme d’habitude, nous utilisons la distribution Ubuntu.
Le kernel de la version 14.04 posant problème lors des tests, nous utilisons la version 14.04
: DockerfileFROM ubuntu:14.04
# Mainteneur
MAINTAINER NosPHeratus < nospheratus@nosland.com>
ENV DEBIAN_FRONTEND noninteractive
# On met a jour les paquets
RUN apt−get update && apt−get install −y sudo apt−utils
# On cree l’utilisateur nph
RUN useradd nph −m −d /home/nph −s /bin/bash
RUN adduser nph sudo
RUN echo nph:nph| chpasswd
# On installe SSH
RUN apt−get update && apt−get install −y openssh−server
RUN mkdir /var/run/sshd
RUN sed −i ’s/PermitRootLogin without−password/PermitRootLogin no/’ /etc/ssh/sshd_config
# Installation de mysql
RUN apt−get install −y mysql−server
RUN sed −i −e « s/^bind−address\s∗=\s∗127.0.0.1/bind−address = 0.0.0.0/ » /etc/mysql/my.cnf
RUN rm −Rf /var/lib/mysql/∗
ADD ./startup_mysql.sh /opt/startup_mysql.sh
RUN chmod 755 /opt/startup_mysql.sh
# On installe supervisor
RUN apt−get install −y supervisor
RUN mkdir −p /var/log/supervisor
COPY mysql.conf /etc/supervisor/conf.d/mysql.conf
COPY ssh.conf /etc/supervisor/conf.d/ssh.conf
# Nettoyage
RUN rm −rf /var/lib/apt/lists/∗ && apt−get clean
# On ouvre les ports
EXPOSE 3306 22
# On demarre supervisor automatiquement
CMD [« supervisord », « −n »]
On utilise le fichier startup.sh pour démarrer le service :
startup_mysql.sh :
#!/bin/bash
if [ ! −f /var/lib/mysql/ibdata1 ]; then
mysql_install_db
/usr/bin/mysqld_safe &
sleep 10s
# Base nph
echo « create database portail; » | mysql −u root mysql
# Utilisateur nph
MYSQL_USER=nph
PASS=nph
echo « CREATE USER ’${MYSQL_USER}’@’%’ IDENTIFIED BY ’$PASS’ » | mysql −u root mysql
echo « GRANT ALL PRIVILEGES ON portail.∗ TO ’${MYSQL_USER}’@’%’ WITH GRANT OPTION » | mysql −u root mysql
# Utilisateur root
echo « GRANT ALL ON ∗.∗ TO root@’%’ IDENTIFIED BY ’root’ WITH GRANT OPTION; FLUSH PRIVILEGES » | mysql −u root mysq
l
echo « UPDATE user SET password=PASSWORD(’root’) WHERE user=’root’; » | mysql −u root mysql
killall mysqld
sleep 10s
fi
/usr/bin/mysqld_safe
Ce fichier placé dans un dossier spécifique, la création du contenur se fait via la commande :
# docker build −t « nph/mysql » .
On peut ensuite exécuter le conteneur et accéder aux ports 3306 (mysql) et 2022 (SSH) de sa machine.
Par défaut, l’image doit se lancer en mode background (1ere ligne).
# docker run −d −p 3306:3306 −p 2022:22 nph/mysql
# docker run −i −t nph/mysql /bin/bash
# docker ps
# docker export 8376201b28f6 > nph−mysql.tgz
Cette image fait 391 Mo.
On peut ensuite exécutuer des requêtes SQL (via mysql-client) ou se connecter en SSH avec l’utilisateur nph/nph (l’utilisateur root étant désactivé).
6.3.2 HUB
Cette image est publiée sur le Hub Docker : https://hub.docker.com
ce qui permet de la déployer facilement via :
# docker pull nph/mysql
Disposant d’un compte sur le Hub, l’envoi d’une image est simple :
# docker push nph/mysql
6.4 LDAP
Pour cette image, nous souhaitons disposer d’une serveur LDAP directement fonctionnel.
On prévoit également un service ssh pour se connecter sur l’image.
6.4.1 CREATION DE L’IMAGE
Nous utilisons le service slapd (openldap) avec le suffix : dc=nosland,dc=com.
Pour cette image, la configuration est classique (via slapd.conf).
Nous utilisons toutes les classes d’objets du projet Etamine.
Nous déclarons l’administrateur :
- DN : cn=admin,dc=nosland,dc=com
- mot de passe : admin
Nous créons un utilisateur :
- DN : uid=nospheratus,ou=people,dc=nosland,dc=com
- mot de passe : NPH
On utilise le démon supervisor pour démarrer le serveur slapd :
ldap.conf :
[supervisord]
nodaemon=true
[program:ldap]
command=/bin/bash −c « /opt/startup_ldap.sh »
redirect_stderr=true
… et le serveur SSH
ssh.conf :
[program:sshd]
command=/usr/sbin/sshd −D
Comme d’habitude, nous utilisons la distribution Ubuntu.
Nous utilisons la version 14.04
DockerfileFROM ubuntu:14.04 :
# Mainteneur
MAINTAINER NosPHeratus < nospheratus@nosland.com>
ENV DEBIAN_FRONTEND noninteractive
# On cree l’utilisateur nph
RUN apt−get update && apt−get install −y sudo apt−utils
RUN useradd nph −m −d /home/nph −s /bin/bash
RUN adduser nph sudo
RUN echo nph:nph | chpasswd
# On installe SSH
RUN apt−get update && apt−get install −y openssh−server
RUN mkdir /var/run/sshd
RUN sed −i ’s/PermitRootLogin without−password/PermitRootLogin no/’ /etc/ssh/sshd_config
# Installation de slapd
RUN apt−get install −y slapd ldap−utils
RUN rm −Rf /var/lib/ldap /etc/ldap/slapd.d
COPY ./autofs.schema /etc/ldap/schema/autofs.schema
COPY ./core.schema /etc/ldap/schema/core.schema
COPY ./dhcp.schema /etc/ldap/schema/dhcp.schema
COPY ./dns.schema /etc/ldap/schema/dns.schema
COPY ./dyngroup.schema /etc/ldap/schema/dyngroup.schema
COPY ./qmail.schema /etc/ldap/schema/qmail.schema
COPY ./radius.schema /etc/ldap/schema/radius.schema
COPY ./samba.schema /etc/ldap/schema/samba.schema
COPY ./supann.schema /etc/ldap/schema/supann.schema
COPY ./nosland.schema /etc/ldap/schema/nosland.schema
COPY ./slapd.conf /etc/ldap/slapd.conf
COPY ./base.ldif /opt/base.ldif
COPY ./startup_slapd.sh /opt/startup_slapd.sh
RUN chmod 755 /opt/startup_slapd.sh
# On installe supervisor
RUN apt−get install −y supervisor
RUN mkdir −p /var/log/supervisor
COPY ldap.conf /etc/supervisor/conf.d/ldap.conf
COPY ssh.conf /etc/supervisor/conf.d/ssh.conf
# Nettoyage
RUN rm −rf /var/lib/apt/lists/∗ && apt−get clean
# On ouvre les ports
EXPOSE 389 636 22
# On demarre supervisor automatiquement
CMD [« supervisord », « −n »]
On utilise le fichier startup.sh pour démarrer le service :
startup_ldap.sh :
#!/bin/bash
if [ ! −f /var/lib/ldap ]; then
mkdir /var/lib/ldap
slapadd < /opt/base.ldif
chown −Rf openldap: /var/lib/ldap
fi
/etc/init.d/slapd start
Ce fichier placé dans un dossier spécifique, la création du contenur se fait via la commande :
# docker build −t « nph/ldap » .
On peut ensuite exécuter le conteneur et accéder aux ports 389 (ldap) et 2022 (SSH) de sa machine.
Par défaut, l’image doit se lancer en mode background (1ere ligne).
# docker run −d −p 389:389 −p 2022:22 nph/ldap
# docker run −i −t nph/ldap /bin/bash
# docker ps
# docker export ec7288a3f430 > nph−ldap.tgz
Cette image fait 301 Mo.
On peut ensuite exécutuer des requêtes LDAP sur localhost (via Directory Studio par exemple) ou se connecter en SSH avec l’utilisateur nph/nph (l’utilisateur root étant désactivé).
6.4.2 HUB
Cette image est publiée sur le Hub Docker : https://hub.docker.com
ce qui permet de la déployer facilement via :
# docker pull nph/ldap
Disposant d’un compte sur le Hub, l’envoi d’une image est simple :
# docker push nph/ldap