Docker et MacOS

Cet article débute sans doute une série dédiée à Docker. En effet aucun admin sys et développeur n’a pu ignorer l’existence de cette technologie en train de révolutionner notre métier. Je ne vais pas ressasser sur Docker ce que l’on trouve déjà partout sur Internet, pour résumer, il fourni les outils au codeur de développer dans un environnement qui sera identique à la production, et de mettre lui même en production. En se soustrayant des administrateurs systèmes, les livraisons sont plus rapide, et fonctionne dans un conteneur étanche. Pour un éditeur, la fourniture d’un conteneur garantira la bonne exécution du produit, l’image docker contenant toutes les bibliothèques et logiciels nécessaires, indépendamment de l’OS hôte. Pour l’administrateur système, plus besoin de jongler entre X versions de bibliothèques (PHP, java, … ) ce qui se finissait le plus souvent par déployer une VM par produit.
Docker fait parti de ces outils du mouvement devops, où le développeur est responsable et a la maitrise de son application du développement à la production.

Comme toujours sur MacOS le plus simple est d’utiliser homebrew. Un simple brew install docker suffit. Le client docker sera installé et permettra de piloter ses conteneurs Docker. Cependant pour les piloter sur sa machine de développement il faut y ajouter les paquets docker-machine et docker-machine-driver-xhyve (on reverra ce dernier à la fin).

docker-machine

il permet de gérer des environnements serveur de docker. En une ligne il peut installer un serveur Docker sur une machine distante ou locale, il faut pour cela déployer votre clé ssh publique dans l’environnement root cible :

ssh-copy-id -i .ssh/id_rsa.pub root@IP

puis on peut lancer docker-machine :

docker-machine create --driver generic --generic-ip-address=x.x.x.x server

server doit être indiqué dans le fichier .ssh/config :

cat .ssh/config
Host server
    User root
    Hostname IP

—driver est une option qui permet de déployer un serveur docker sur un cloud public en utilisant l’API du cloud, ou sur un serveur Linux type deb/yum en spécifiant generic. Voir la liste des drivers. Avec l’option generic, docker-machine ajoutera s’il est absent le dépôt docker dans le répertoire /etc/apt/sources.list.d sur un serveur Linux deb/yum (ubuntu,debian,centos..)

docker-machine create --driver generic --generic-ip-address=192.168.0.35 nuc
Running pre-create checks...
Creating machine...
(nuc) No SSH key specified. Assuming an existing key at the default location.
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with ubuntu(systemd)...
Installing Docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env nuc

on peut visualiser le serveur créé avec docker-machine ls :

docker-machine ls
NAME               ACTIVE   DRIVER           STATE     URL                        SWARM   DOCKER    ERRORS
nuc                -        generic          Running   tcp://192.168.0.35:2376            v1.12.1

et se connecter en ssh :

docker-machine ssh nuc
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-38-generic x86_64)

Documentation:  https://help.ubuntu.com
Management:     https://landscape.canonical.com
Support:        https://ubuntu.com/advantage

0 packages can be updated.
0 updates are security updates.

Last login: Sun Oct  2 11:55:15 2016 from 192.168.0.40
root@nuc:~#

il faut ensuite positionner les variables d’environnement associées à ce serveur

eval $(docker-machine env nuc)

le client docker du Mac peut ensuite gérer ce serveur :

docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 0
Server Version: 1.12.1
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 0
 Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: host null bridge overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Security Options: apparmor seccomp
Kernel Version: 4.4.0-38-generic
Operating System: Ubuntu 16.04.1 LTS
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 15.6 GiB
Name: nuc
ID: OJBG:ERG4:2QIF:2BPI:N5E3:ULNQ:NJC7:WCM6:MGV7:E3JG:M74I:52AT
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Username: fredix
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Labels:
 provider=generic
Insecure Registries:
 127.0.0.0/8

Comme on le voit le serveur nuc est une Ubuntu 16.04.1 LTS sur mon réseau local.
Le premier test est d’installer une image Alpine Linux qui va afficher une ligne Hello world :

docker run --rm alpine /bin/echo 'Hello world'
Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
c0cb142e4345: Pull complete
Digest: sha256:ca7b185775966003d38ccbd9bba822fb570766e4bb69292ac23490f36f8a742e
Status: Downloaded newer image for alpine:latest
Hello world

L’image de alpine n’était pas présente, docker l’a téléchargé du hub docker , puis exécuté la commande echo. Si on souhaite lancer un conteneur qui utilise Alpine, l’image ne sera pas téléchargée à nouveau. l’option -rm demande à docker de supprimer le conteneur dès qu’il a terminé sa tâche. Lorsque le conteneur a terminé sa tâche un docker ps n’affiche rien, si l’option -rm n’est pas positionnée il est visible avec un docker ps -a :

docker run alpine /bin/echo 'Hello world'
docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
7b9bc74dd21a        alpine              "/bin/echo 'Hello wor"   7 seconds ago       Exited (0) 6 seconds ago                       grave_ramanujan

un conteneur stoppé peut être relancé

docker start grave_ramanujan

puis voir la sortie dans le fichier de logs

docker logs grave_ramanujan
Hello world

Ce conteneur utilise une image Alpine linux :

docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              ee4603260daa        8 days ago          4.803 MB

On peut stopper un conteneur, le supprimer, et supprimer également une image si plus aucun conteneur ne l’utilise :

docker stop grave_ramanujan
docker rm grave_ramanujan
docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              ee4603260daa        8 days ago          4.803 MB
docker ami 

docker rmi ee4603260daa
Error response from daemon: conflict: unable to delete ee4603260daa (must be forced) - image is being used by stopped container 7b9bc74dd21a

On voit qu’on ne peut pas supprimer l’image car utilisée par notre conteneur.

docker rm grave_ramanujan
grave_ramanujan

docker rmi ee4603260daa
Untagged: alpine:latest
Untagged: alpine@sha256:ca7b185775966003d38ccbd9bba822fb570766e4bb69292ac23490f36f8a742e
Deleted: sha256:ee4603260daafe1a8c2f3b78fd760922918ab2441cbb2853ed5c439e59c52f96
Deleted: sha256:9007f5987db353ec398a223bc5a135c5a9601798ba20a1abba537ea2f8ac765f

Cet exemple Hello World est très basique, mais il existe des images docker très complète, comme le cloud opensource cozycloud qui contient tous les composants nécessaire (base de données, serveur web, …).

xhyve

Un autre driver docker-machine permet de s’abstenir de l’usage d’un serveur Linux. Auparavant il fallait installer virtualbox, mais depuis Yosemite, OSX embarque un hyperviseur en natif. Le projet xhyve un fork de bhyve exploite cet hyperviseur, il suffit d’installer avec brew le driver docker-machine-driver-xhyve pour l’utiliser :

brew install docker-machine-driver-xhyve
docker-machine create --driver xhyve xhyve1
…

docker-machine ls

NAME               ACTIVE   DRIVER           STATE     URL                        SWARM   DOCKER    ERRORS
xhyve1             -        xhyve            Running   tcp://192.168.64.9:2376            v1.12.1

eval $(docker-machine env xhyve1)
docker run alpine /bin/echo 'Hello world'

Si on se connecte en ssh avec docker-machine on constate que Linux est un Boot2Docker. Ce système est uniquement dédié à faire tourner des conteneurs Docker, vim n’étant même pas installé.

docker-machine ssh xhyve1
        .
## ##        ==
## ## ## ##    ===
   /"""""""""""""""""\___/ ===
~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
   \______ o           __/
 \    \         __/
  \____\_______/
 _                 _   ____     _            _
| |__   ___   ___ | |_|___ \ __| | ___   ___| | _____ _ __
| '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
| |_) | (_) | (_) | |_ / __/ (_| | (_) | (__|   <  __/ |
|_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
Boot2Docker version 1.12.1, build HEAD : ef7d0b4 - Thu Aug 18 21:18:06 UTC 2016
Docker version 1.12.1, build 23cf638
docker@boot2docker:~$ lsb_release -a
Boot2Docker 1.12.1 (TCL 7.2); HEAD : ef7d0b4 - Thu Aug 18 21:18:06 UTC 2016

Voilà pour débuter, n’hésitez pas à tester cozycloud ou mattermost pour voir comment s’installe et se lance en quelques minutes une application complexe en local dans votre machine ou votre propre serveur.

Dernière info et non des moindres, lorsqu’un conteneur est supprimé toutes les données qu’il contient le sont également ; il faudra donc utiliser des volumes docker pour mettre en place une persistence sur le serveur hôte.