Prise en main de Docker
J’ai longtemps éludé le sujet Docker mais il est grand temps que je vous en parle.
Docker kesako… c’est une implémentation des vieux LXC (Linux Containers) mais qui, cette fois ci, a trouvée son public.
Dans les faits:
- c’est toujours de la virtualisation
- c’est toujours étanche par rapport à son host
- On gagne du temps dans la configuration et le déploiement
- On découvre plein de trucs
- On partage le kernel !
- On économise de la ram
Plutôt qu’un long discours, passons à l’installation. Je serais sur une CentOS en version 7 pour ce tutoriel, mais une Debian voir un Raspberry ça fera l’affaire.
[cyklodev_summary]
Installation
Mise à jour:
yum update && yum upgrade
Installation (root):
wget -qO- https://get.docker.com/ | sh
Ajout d’un user (non root) pour gérer tous nos conteneurs:
usermod -aG docker cyklo
Démarrage + au reboot
systemctl enable docker.service systemctl start docker.service
Utilisation
Quelques commandes de bases:
Le ps de docker
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Tout est en place pour déployer notre premier conteneur. Alors commençons simple avec un Hello world ;)
docker search hello-world NAME DESCRIPTION STARS OFFICIAL AUTOMATED hello-world Hello World! (an example of minimal Docker... 284 [OK] tutum/hello-world Image to test docker deployments. Has Apac... 33 [OK] ...
Vous l’avez sous les yeux, la recherche permet de trouver notre conteneur hello-world et commençons tout de suite par de la sensibilisation avec la colonne OFFICIAL.
Si vous voulez faire de la production, préférez partir d’une image officielle.
Mais d’où viennent toutes ces images ? Elles sont toutes issues de Docker Hub. Vous pouvez voir ça comme un gestionnaire de paquets conteneurs où tout le monde peut contribuer.
Alors commençons par l’installer.
cyklo@testmachina:~$ docker pull hello-world Using default tag: latest latest: Pulling from library/hello-world 78445dd45222: Pull complete Digest: sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7 Status: Downloaded newer image for hello-world:latest
Une vérification des images qu’on a localement :
cyklo@testmachina:~$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest 48b5124b2768 2 months ago 1.84 kB
Première exécution
cyklo@testmachina:~$ docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. ...
Mais par contre il n’y a rien qui tourne …
docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
C’est le fonctionnement standard, quand l’exécution du conteneur s’arrête, tout s’arrête.
Virtualiser un OS (ah quand même …)
On va s’arrêter un peu sur cette notion d’exécution avec un exemple de nano distribution : AlpineLinux.
cyklo@testmachina:~$ docker pull alpine Using default tag: latest latest: Pulling from library/alpine 627beaf3eaaf: Pull complete Digest: sha256:58e1a1bb75db1b5a24a462dd5e2915277ea06438c3f105138f97eb53149673c4 Status: Downloaded newer image for alpine:latest
Démarrons le comme notre précédent conteneur.
cyklo@testmachina:~$ docker run alpine docker: Error response from daemon: No command specified.
Il va falloir lui donner un peu plus d’arguments:
- -i pour le mode interactif
- -t pour avoir un pseudo TTY
- une commande (sh : un shell minimal)
cyklo@testmachina:~$ docker run -it alpine sh / # id uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) / # df -h Filesystem Size Used Available Use% Mounted on overlay 120.0G 16.3G 97.6G 14% / tmpfs 903.7M 0 903.7M 0% /dev tmpfs 903.7M 0 903.7M 0% /sys/fs/cgroup /dev/sda2 120.0G 16.3G 97.6G 14% /etc/resolv.conf /dev/sda2 120.0G 16.3G 97.6G 14% /etc/hostname /dev/sda2 120.0G 16.3G 97.6G 14% /etc/hosts shm 64.0M 0 64.0M 0% /dev/shm tmpfs 903.7M 0 903.7M 0% /proc/kcore tmpfs 903.7M 0 903.7M 0% /proc/timer_list tmpfs 903.7M 0 903.7M 0% /proc/timer_stats tmpfs 903.7M 0 903.7M 0% /proc/sched_debug tmpfs 903.7M 0 903.7M 0% /sys/firmware / #
Nous sommes à présent dans un OS à part entière. Mais gare au Ctrl+D car ça va tuer l’instance en cours.
Pour sortir en laissant le conteneur tourner il faut faire un Ctrl+P et ensuite Ctrl+Q.
cyklo@testmachina:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a1d8037920df alpine "sh" 8 seconds ago Up 6 seconds suspicious_ardinghelli
Gestion de l’instance
Pour retourner dedans, il faut fournir le ‘CONTAINER ID’ comme cela:
cyklo@testmachina:~$ docker exec -ti a1d8037920df sh / #
Et à partir de là, on peut quitter le conteneur avec un Ctrl+D sans tuer notre instance.
Si on veut tuer l’instance en cours :
cyklo@testmachina:~$ docker kill a1d8037920df a1d8037920df
Quelques astuces
A force d’utiliser Docker, vous allez vite vous rendre compte que c’est toujours les même commandes que vous tapez.
Voici quelques alias et fonctions (disponible sur mon GitHub):
#DOCKER alias dcs='docker ps' alias dcd='docker-compose down' alias dcu='docker-compose up -d' function dexec() { if [ ! $# -eq 1 ] then echo "missing CONTAINER ID" docker ps return else docker exec -ti $1 bash fi }
Les interactions entre hôte et conteneurs
Pour l’instant nous avons vu un conteneur tout seul qui certes peut communiquer avec le net, mais pas avec l’hôte.
Partage de répertoires
On va créer un répertoire local et l’attacher à notre conteneur Alpine.
cyklo@testmachina:~$ mkdir /home/cyklo/host-share cyklo@testmachina:~$ echo "From host" > /home/cyklo/host-share/test cyklo@testmachina:~$ docker run --rm -ti -v /home/cyklo/host-share:/host-share alpine sh / # cat /host-share/test From host
Attacher un volume est extrêmement simple, et surtout cela permet de mettre à jour facilement le conteneur tout en gardant les données bien au chaud sur l’hôte.
Pour aller un peu plus loin avec les volumes, je vous invite à aller sur l’article de Metal3d’s qui détaille le concept.
Gestion des ports
On va maintenant faire communiquer un conteneur avec le reste du monde, avec une instance de Nginx.
cyklo@testmachina:~$ docker search nginx NAME DESCRIPTION STARS OFFICIAL AUTOMATED nginx Official build of Nginx. 5737 [OK] jwilder/nginx-proxy Automated Nginx reverse proxy for docker c... 996 [OK]
On se base à nouveau sur l’image officielle.
cyklo@testmachina:~$ docker pull nginx Using default tag: latest latest: Pulling from library/nginx 6d827a3ef358: Already exists f8f2e0556751: Pull complete 5c9972dca3fd: Pull complete 451b9524cb06: Pull complete Digest: sha256:e6693c20186f837fc393390135d8a598a96a833917917789d63766cab6c59582 Status: Downloaded newer image for nginx:latest
On la démarre comme d’habitude avec en plus les paramètres du port à exposer.
cyklo@testmachina:~$ docker run -p 81:80 -ti nginx bash root@f2e936bd417e:/# root@f2e936bd417e:/# service nginx start root@f2e936bd417e:/# service nginx status [ ok ] nginx is running.
Ressortons avec Crtl+P et Ctrl+Q pour laisser l’instance tourner et regardons ce que ça donne.
Le serveur nginx est bien accessible via l’hôte.
cyklo@testmachina:~$ curl http://localhost:81 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> ...
Le conteneur expose bien son port 80, mais sur toutes les interfaces.
cyklo@testmachina:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5d30177253e5 nginx "bash" 21 seconds ago Up 19 seconds 443/tcp, 0.0.0.0:81->80/tcp gifted_edison
Corrigeons pour que le port n’écoute que sur le l’interface locale.
cyklo@testmachina:~$ docker run -p 127.0.0.1:81:80 -ti nginx bash root@cebd98176666:/# service nginx start root@cebd98176666:/# service nginx status [ ok ] nginx is running.
Et vérifions que tout est correct.
cyklo@testmachina:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES cebd98176666 nginx "bash" 12 seconds ago Up 11 seconds 443/tcp, 127.0.0.1:81->80/tcp gifted_edison
Si vous êtes curieux , vous avez sans doute déjà vu 2 choses:
- Plusieurs nouvelles interfaces (ifconfig)
- De nouvelles règles iptables (iptables -L)
Vous avez maintenant tout pour vous faire la main sur cette solution de virtualisation.