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.

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.

Pour marque-pages : Permaliens.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *