Docker : petit résumé sur les commandes

Attention ceci est mon brouillon avant de faire une belle documentation sur Docker (il y a à boire et à manger).

Quelques commandes :

Quelques serveurs :

Quelques outils :

Quelques commandes linux :

  • crontab : Pour modifier la crontab qui permet de faire des taches planifiées. ( Article n°15, )
  • ss : statistique réseau ( Article n°3, )
  • ln -s : création d’un lien symbolique ( Article n°2, )
  • df -h : connaitre l’espace disque ( Article n°2Article n°1 )
  • mkdir : création d’un répertoire ( Article n°2, )
  • uname -a : permet de connaitre le nom de l’hôte et la version de l’OS de l’hôte ( Article n°1 )

Rappel :

Tableau de résumé des articles :

Post n° Intérêt Résumé
1 20% Mauvaise installation à cause de la partition Docker. Mais début des commandes sous Docker : docker run , docker rmi, docker run, docker ps,
2 70% On voit l’intérêt de l’ajout de la partition Btrfs, on découvre le fichier Dockerfile qui est utilisé pour faire les docker build.
3 70% On a vu la redirection de port avec l’option -p . Et aussi docker search qui permet de voir tous les containers existant. On a aussi l’installation du container PostgreSQL.
4 50% Installation du container PostgreSQL mais pas comme je l’aurai voulu car je n’arrive pas à initialiser les utilisateurs dans le Dockerfile. Et les sources de server.c .
5 30% Découverte de la commande docker run swarn. J’ai pas vraiment approfondi la notion.
6 60% Un nouveau serveur : server2.c , on découvre la commande docker exec env. On a aussi la création d’un server3.c qui exploite les liens entre containers (–link)
7 10% Un échec complet sur l’installation de HAproxy.
8 80% Bonne configuration de NGINX et de HAproxy.
9 10% Un échec complet sur la redirection des logs syslog vers un autre serveur.
10 90% La création d’un server5.c qui permet de faire des insertions dans la base, d’envoyer des logs à syslog et de tester les configuration de HAproxy et Nginx.
11  40%  Résumé, impasse sur syslog.
12  10%  Un échec complet sur etcd & confd.
13  40%  Notion de partage de fichier avec le OS hôte.
14 30%  Création dynamique de container via des scripts BASH. Et notion de partage de fichier.
15 50%  Lancement automatique de container via des scripts BASH.
16 80%  Notion de base sur GitHub & le Hub de Docker.
17 80%  Notion de base sur la Remote API de Docker.

Je savais bien qu’un petit résumé était nécessaire, après 17 jours sur Docker on commence à mieux comprendre le fonctionnement et les avantages.

Les livres sur Docker :

Docker : Le Dix-Septième pas.

Attention ceci est mon brouillon avant de faire une belle documentation sur Docker (il y a à boire et à manger).

Pour commencer, je vous rappelle ce très bon article sur Docker : http://www.journaldunet.com/solutions/cloud-computing/1146290-cloud-pourquoi-docker-peut-tout-changer/

  • Ces VM intègrent elles-mêmes un OS sur lequel les applications qu’elles contiennent sont exécutées. Ce n’est pas le cas du container.
  • Grâce à leur légèreté, les containers Docker sont portables de cloud en cloud
  • Les basculer d’un environnement de développement ou de test à un environnement de production peut donc se faire presque en un clic, ce qui n’est pas le cas pour la VM, plus lourde.
  • IBM notamment a réalisé un comparatif de performance entre Docker et KVM. Sa conclusion est sans appel : Docker égale ou excède les performances de cette technologie de virtualisation open source – et ce dans tous les cas testés dans le cadre du comparatif.

Maintenant je vais faire un clone de mon Docker actuel afin de faire un second Docker identique. Pour cela je fais une copie avec VirtualBox. Attention il faut avoir 21 Go de disponible sur le disque dur.

Capture d’écran 2016-05-03 à 15.52.28 Capture d’écran 2016-05-03 à 15.52.51 Capture d’écran 2016-05-03 à 15.53.00 Capture d’écran 2016-05-03 à 15.53.06

Et j’ajoute une nouvelle machine qui va utiliser cette copie.

Capture d’écran 2016-05-03 à 16.02.40 Capture d’écran 2016-05-03 à 16.03.42

Maintenant je vais lancer un serveur et voir si par défaut on peut faire appel au démon via la Remote API :

[root@localhost ~]# docker -H tcp://0.0.0.0:8000 ps
Cannot connect to the Docker daemon. Is the docker daemon running on this host?
[root@localhost ~]# docker -H tcp://127.0.0.1:8000 ps
Cannot connect to the Docker daemon. Is the docker daemon running on this host?
[root@localhost ~]# cat /etc/systemd/system/multi-user.target.wants/docker.service 
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target docker.socket
Requires=docker.socket

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/docker daemon -H fd://
MountFlags=slave
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes

[Install]
WantedBy=multi-user.target

Je vais donc faire des modifications afin de pouvoir modifier via la Remote API.

[root@localhost ~]# cat /etc/systemd/system/multi-user.target.wants/docker.service 
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target docker.socket
Requires=docker.socket

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
#ExecStart=/usr/bin/docker daemon -H fd://
ExecStart=/usr/bin/docker daemon -H tcp://0.0.0.0:8000 -H unix:///var/run/docker.sock
MountFlags=slave
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes

[Install]
WantedBy=multi-user.target
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker.service
[root@localhost ~]# docker -H tcp://127.0.0.1:8000 ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
[root@localhost ~]# docker -H tcp://0.0.0.0:8000 ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Pour l’instant je n’ai rien comme conteneur car pour faire la copie j’ai du arrêter le serveur et je ne relance pas les containers après un reboot. Je vais lancer deux containers :

[root@localhost ~]# docker start postgres2
postgres2
[root@localhost ~]# docker start my-server7-1
my-server7-1

Et voici ce qui est fort (au passage on peut faire cela en SSL pour plus de sécurité, c’est même FORTEMENT recommandé ! ) c’est d’avoir une API propre et accessible via curl (requête HTTP ou HTTPS) qui permette le pilotage de notre Docker et donc d’un Docker distant. Ceci ouvre une multitudes de possibilités !

Voici le « Docker ps » en JSON :

[root@localhost ~]# curl -X GET http://localhost:8000/containers/json
[{"Id":"1f84fca3adf1b16f380cae116c03b13a30fab5fceb2895196c202d7022b93122","Names":["/my-server7-1"],"Image":"my-server7","ImageID":"sha256:2dbb7ecbdaa1510f3609d119b72db9182f005f310300fa8f581d22902a42f39a","Command":"/sbin/server8","Created":1460820049,"Ports":[{"IP":"0.0.0.0","PrivatePort":80,"PublicPort":8086,"Type":"tcp"}],"Labels":{},"State":"running","Status":"Up 9 seconds","HostConfig":{"NetworkMode":"default"},"NetworkSettings":{"Networks":{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"","EndpointID":"f1cb4c52a9bbfaf4b7f60ea27f18053c3de80050e7eb2488263ae3c217de7bc0","Gateway":"172.17.0.1","IPAddress":"172.17.0.3","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:03"}}},"Mounts":[{"Source":"/docker/app/server/1","Destination":"/app/server","Mode":"","RW":true,"Propagation":"rprivate"}]},{"Id":"2fc533c557259f65236a97e1e4eb7123867d4c0e0cae784a620cc9c96e55c168","Names":["/postgres2","/my-server6-1/postgres2","/my-server7-2/postgres2","/my-server4-1/postgres2","/my-server4.b/postgres2","/my-server4.1/postgres2","/my-server7-1/postgres2","/my-server7-4/postgres2","/my-server4-5/postgres2","/my-server4-4/postgres2","/my-server2.3/postgres2","/my-server4-2/postgres2","/my-server3.1/postgres2","/my-server4.a/postgres2","/my-server4-3/postgres2","/my-server7-3/postgres2","/my-server2.2/postgres2"],"Image":"postgres","ImageID":"sha256:0f3af79d8673d184c84d013218d43ad4eb051b71ecb4d4f7fb550c50e68c7ee7","Command":"/docker-entrypoint.sh postgres","Created":1460661691,"Ports":[{"IP":"0.0.0.0","PrivatePort":5432,"PublicPort":5432,"Type":"tcp"}],"Labels":{},"State":"running","Status":"Up 11 seconds","HostConfig":{"NetworkMode":"default"},"NetworkSettings":{"Networks":{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"","EndpointID":"6f41260f42080f869ae6278f7615fa52d86cddc094a52acbddd18f4b6799a396","Gateway":"172.17.0.1","IPAddress":"172.17.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02"}}},"Mounts":[{"Name":"f73794569bbb8d387f4a2b2562679d30b664363ab6444251c61f0c86f494ee30","Source":"/docker/volumes/f73794569bbb8d387f4a2b2562679d30b664363ab6444251c61f0c86f494ee30/_data","Destination":"/var/lib/postgresql/data","Driver":"local","Mode":"","RW":true,"Propagation":""}]}]
[root@localhost ~]# curl -X POST http://127.0.0.1:8000/containers/1f84fca3adf1b16f380cae116c03b13a30fab5fceb2895196c202d7022b93122/stop
[root@localhost ~]# curl -X GET http://localhost:8000/containers/json
[{"Id":"2fc533c557259f65236a97e1e4eb7123867d4c0e0cae784a620cc9c96e55c168","Names":["/postgres2","/my-server6-1/postgres2","/my-server7-2/postgres2","/my-server4-1/postgres2","/my-server4.b/postgres2","/my-server4.1/postgres2","/my-server7-1/postgres2","/my-server7-4/postgres2","/my-server4-5/postgres2","/my-server4-4/postgres2","/my-server2.3/postgres2","/my-server4-2/postgres2","/my-server3.1/postgres2","/my-server4.a/postgres2","/my-server4-3/postgres2","/my-server7-3/postgres2","/my-server2.2/postgres2"],"Image":"postgres","ImageID":"sha256:0f3af79d8673d184c84d013218d43ad4eb051b71ecb4d4f7fb550c50e68c7ee7","Command":"/docker-entrypoint.sh postgres","Created":1460661691,"Ports":[{"IP":"0.0.0.0","PrivatePort":5432,"PublicPort":5432,"Type":"tcp"}],"Labels":{},"State":"running","Status":"Up 5 minutes","HostConfig":{"NetworkMode":"default"},"NetworkSettings":{"Networks":{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"","EndpointID":"6f41260f42080f869ae6278f7615fa52d86cddc094a52acbddd18f4b6799a396","Gateway":"172.17.0.1","IPAddress":"172.17.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02"}}},"Mounts":[{"Name":"f73794569bbb8d387f4a2b2562679d30b664363ab6444251c61f0c86f494ee30","Source":"/docker/volumes/f73794569bbb8d387f4a2b2562679d30b664363ab6444251c61f0c86f494ee30/_data","Destination":"/var/lib/postgresql/data","Driver":"local","Mode":"","RW":true,"Propagation":""}]}]
[root@localhost ~]# curl -X POST http://127.0.0.1:8000/containers/1f84fca3adf1b16f380cae116c03b13a30fab5fceb2895196c202d7022b93122/start
[root@localhost ~]# curl -X GET http://localhost:8000/containers/json
[{"Id":"1f84fca3adf1b16f380cae116c03b13a30fab5fceb2895196c202d7022b93122","Names":["/my-server7-1"],"Image":"my-server7","ImageID":"sha256:2dbb7ecbdaa1510f3609d119b72db9182f005f310300fa8f581d22902a42f39a","Command":"/sbin/server8","Created":1460820049,"Ports":[{"IP":"0.0.0.0","PrivatePort":80,"PublicPort":8086,"Type":"tcp"}],"Labels":{},"State":"running","Status":"Up 2 seconds","HostConfig":{"NetworkMode":"default"},"NetworkSettings":{"Networks":{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"","EndpointID":"404862f963268fd44d576960077146fc5baf834ca3d72a8818ec72a6bfb3789e","Gateway":"172.17.0.1","IPAddress":"172.17.0.3","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:03"}}},"Mounts":[{"Source":"/docker/app/server/1","Destination":"/app/server","Mode":"","RW":true,"Propagation":"rprivate"}]},{"Id":"2fc533c557259f65236a97e1e4eb7123867d4c0e0cae784a620cc9c96e55c168","Names":["/postgres2","/my-server6-1/postgres2","/my-server7-2/postgres2","/my-server4-1/postgres2","/my-server4.b/postgres2","/my-server4.1/postgres2","/my-server7-1/postgres2","/my-server7-4/postgres2","/my-server4-5/postgres2","/my-server4-4/postgres2","/my-server2.3/postgres2","/my-server4-2/postgres2","/my-server3.1/postgres2","/my-server4.a/postgres2","/my-server4-3/postgres2","/my-server7-3/postgres2","/my-server2.2/postgres2"],"Image":"postgres","ImageID":"sha256:0f3af79d8673d184c84d013218d43ad4eb051b71ecb4d4f7fb550c50e68c7ee7","Command":"/docker-entrypoint.sh postgres","Created":1460661691,"Ports":[{"IP":"0.0.0.0","PrivatePort":5432,"PublicPort":5432,"Type":"tcp"}],"Labels":{},"State":"running","Status":"Up 6 minutes","HostConfig":{"NetworkMode":"default"},"NetworkSettings":{"Networks":{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"","EndpointID":"6f41260f42080f869ae6278f7615fa52d86cddc094a52acbddd18f4b6799a396","Gateway":"172.17.0.1","IPAddress":"172.17.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02"}}},"Mounts":[{"Name":"f73794569bbb8d387f4a2b2562679d30b664363ab6444251c61f0c86f494ee30","Source":"/docker/volumes/f73794569bbb8d387f4a2b2562679d30b664363ab6444251c61f0c86f494ee30/_data","Destination":"/var/lib/postgresql/data","Driver":"local","Mode":"","RW":true,"Propagation":""}]}]

Docker : le seizième pas.

Attention ceci est mon brouillon avant de faire une belle documentation sur Docker (il y a à boire et à manger).

Maintenant je vais faire un test avec GitHub : https://github.com . D’abord il faut créer un compte farias06 :

Capture d’écran 2016-05-02 à 15.58.48

Ensuite on fait un projet, pour la part c’est hello_world :

Capture d’écran 2016-05-02 à 16.01.07

Et maintenant il va falloir mettre les sources :

Capture d’écran 2016-05-02 à 16.01.34

Sur le serveur on installe git :

[root@localhost ~]# yum install git
Modules complémentaires chargés : ulninfo
dockerrepo                                                                                                                      | 2.9 kB  00:00:00     
ol7_UEKR3                                                                                                                       | 1.2 kB  00:00:00     
ol7_UEKR4                                                                                                                       | 1.2 kB  00:00:00     
ol7_latest                                                                                                                      | 1.4 kB  00:00:00     
(1/4): ol7_UEKR4/x86_64/updateinfo                                                                                              |  14 kB  00:00:00     
(2/4): ol7_UEKR4/x86_64/primary                                                                                                 | 2.5 MB  00:00:04     
(3/4): ol7_latest/x86_64/updateinfo                                                                                             | 816 kB  00:00:05     
(4/4): ol7_latest/x86_64/primary                                                                                                |  16 MB  00:00:24     
ol7_UEKR4                                                                                                                                        77/77
ol7_latest                                                                                                                                 14274/14274
Résolution des dépendances
--> Lancement de la transaction de test
---> Le paquet git.x86_64 0:1.8.3.1-6.el7_2.1 sera installé
...
Installé :
  git.x86_64 0:1.8.3.1-6.el7_2.1                                                                                                                       

Dépendances installées :
  libgnome-keyring.x86_64 0:3.8.0-3.el7            perl.x86_64 4:5.16.3-286.el7                   perl-Carp.noarch 0:1.26-244.el7                     
  perl-Encode.x86_64 0:2.51-7.el7                  perl-Error.noarch 1:0.17020-2.el7              perl-Exporter.noarch 0:5.68-3.el7                   
  perl-File-Path.noarch 0:2.09-2.el7               perl-File-Temp.noarch 0:0.23.01-3.el7          perl-Filter.x86_64 0:1.49-3.el7                     
  perl-Getopt-Long.noarch 0:2.40-2.el7             perl-Git.noarch 0:1.8.3.1-6.el7_2.1            perl-HTTP-Tiny.noarch 0:0.033-3.el7                 
  perl-PathTools.x86_64 0:3.40-5.el7               perl-Pod-Escapes.noarch 1:1.04-286.el7         perl-Pod-Perldoc.noarch 0:3.20-4.el7                
  perl-Pod-Simple.noarch 1:3.28-4.el7              perl-Pod-Usage.noarch 0:1.63-3.el7             perl-Scalar-List-Utils.x86_64 0:1.27-248.el7        
  perl-Socket.x86_64 0:2.010-3.el7                 perl-Storable.x86_64 0:2.45-3.el7              perl-TermReadKey.x86_64 0:2.30-20.el7               
  perl-Text-ParseWords.noarch 0:3.29-4.el7         perl-Time-HiRes.x86_64 4:1.9725-3.el7          perl-Time-Local.noarch 0:1.2300-2.el7               
  perl-constant.noarch 0:1.27-2.el7                perl-libs.x86_64 4:5.16.3-286.el7              perl-macros.x86_64 4:5.16.3-286.el7                 
  perl-parent.noarch 1:0.225-244.el7               perl-podlators.noarch 0:2.5.1-3.el7            perl-threads.x86_64 0:1.87-4.el7                    
  perl-threads-shared.x86_64 0:1.43-6.el7          rsync.x86_64 0:3.0.9-17.el7                   

Terminé !
[root@localhost ~]# mkdir git
[root@localhost ~]# cd git/
[root@localhost git]# git init
Initialized empty Git repository in /root/git/.git/
[root@localhost git]# echo "# hello_world" >> README.md
[root@localhost git]# git add README.md
[root@localhost git]# git commit -m "first commit"
[master (root-commit) 666b78d] first commit
 Committer: root <root@localhost.localdomain>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 1 file changed, 1 insertion(+)
 create mode 100644 README.md
[root@localhost git]# git remote add origin https://github.com/farias06/hello_world.git
[root@localhost git]# git push -u origin master
Username for 'https://github.com': farias06
Password for 'https://farias06@github.com': 
Counting objects: 3, done.
Writing objects: 100% (3/3), 221 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/farias06/hello_world.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.
[root@localhost git]# git config --global user.name "ARIAS Frederic"
[root@localhost git]# git add server8.c 
[root@localhost git]# git commit -m "My Server"
[root@localhost git]# git push -u origin master
Username for 'https://github.com': farias06
Password for 'https://farias06@github.com': 
Counting objects: 4, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 4.08 KiB | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/farias06/hello_world.git
   666b78d..0ad8bd2  master -> master
Branch master set up to track remote branch master from origin.

Et maintenant on regarde sur l’interface si le source est disponible :

Capture d’écran 2016-05-02 à 16.24.43

Mon source est maintenant accessible du monde entier : hello_world/server8.c (https://github.com/farias06/hello_world/blob/master/server8.c). Le début de la célébrité 😉 .

Sinon on peut rester avec son SVN, voir même son CVS. Quel est le rapport entre GITHUB et Docker ? Le rapport c’est « Automated Build » (construction automatique) !

La seconde étape est donc la création d’un compte sur https://hub.docker.com/register/ .

Capture d’écran 2016-05-02 à 16.50.42 Capture d’écran 2016-05-02 à 16.51.07 Capture d’écran 2016-05-02 à 16.52.55

La prochaine étape c’est le push de l’image, et ensuite c’est la construction automatique.

[root@localhost git]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: farias06
Password: 
Login Succeeded
[root@localhost git]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
dc75f255cd90        my-server7          "/sbin/server8"          2 hours ago         Up 2 hours          0.0.0.0:8087->80/tcp     my-server7-2
1f84fca3adf1        my-server7          "/sbin/server8"          2 hours ago         Up 2 hours          0.0.0.0:8086->80/tcp     my-server7-1
51b94f30c07e        my-haproxy-v15      "/docker-entrypoint.s"   7 hours ago         Up 2 hours          0.0.0.0:80->80/tcp       mon-haproxy-v15c
2fc533c55725        postgres            "/docker-entrypoint.s"   46 hours ago        Up 46 hours         0.0.0.0:5432->5432/tcp   postgres2
[root@localhost git]# docker commit -m "Added server8" -a "ARIAS Frederic" dc75f255cd90 farias06/hello_docker 
sha256:ac157ca4e8b0e475960a4e07c8711a850a9fd69ffc5e209dcd096a51d4e0d809
[root@localhost git]# docker images
REPOSITORY                   TAG                 IMAGE ID            CREATED                  SIZE
ubuntu                       latest              44776f55294a        Less than a second ago   120.1 MB
farias06/hello_docker        latest              ac157ca4e8b0        2 minutes ago            367.4 MB
my-server7                   latest              2dbb7ecbdaa1        4 hours ago              367.4 MB
                                     b3b4e7faef2f        11 hours ago             367.4 MB

Oups j’ai du oublier de mettre la version ..

[root@localhost git]# docker commit -m "Added server8" -a "ARIAS Frederic" dc75f255cd90 farias06/hello_docker:v1
sha256:84198751afa71e272d561ea6a812bc7dec697f5663f0fa5047d7589118e6d6ab
[root@localhost git]# docker search farias06
NAME      DESCRIPTION   STARS     OFFICIAL   AUTOMATED
[root@localhost git]# docker images
REPOSITORY                   TAG                 IMAGE ID            CREATED                  SIZE
ubuntu                       latest              44776f55294a        Less than a second ago   120.1 MB
farias06/hello_docker        v1                  84198751afa7        About a minute ago       367.4 MB
...
[root@localhost git]# docker push farias06/hello_docker
The push refers to a repository [docker.io/farias06/hello_docker]
678521444a2e: Pushed 
a6cb83a08571: Pushed 
3bf1eecb904c: Pushed 
4f9e31a2233f: Pushed 
5f70bf18a086: Mounted from library/haproxy 
latest: digest: sha256:aaa7bf86b55ebd72b44f9d4b8141c18dc1f38fcb7c5b9748d165a3981cff083b size: 4834
678521444a2e: Layer already exists 
a6cb83a08571: Layer already exists 
3bf1eecb904c: Layer already exists 
4f9e31a2233f: Layer already exists 
5f70bf18a086: Layer already exists 
v1: digest: sha256:d91b2bfa33c6579b2a38a6504b836829edd753466da497f425be6e6af9e15a1f size: 4830
[root@localhost git]# docker search farias06
NAME                    DESCRIPTION    STARS     OFFICIAL   AUTOMATED
farias06/hello_docker   Hello Docker   1   

Si je regarde l’interface de Docker, j’ai bien la version v1 et la dernière version .

Capture d’écran 2016-05-02 à 17.24.01

Maintenant le monde entier peut avoir accès à mon image via : docker pull farias06/hello_docker

A noter que l’interface Docker permet de faire de PUSH, et donc de déclencher des actions sur d’autres sites.

Docker : le quinzième pas.

Attention ceci est mon brouillon avant de faire une belle documentation sur Docker (il y a à boire et à manger).

Maintenant il me faut faire un script d’arrêt des containers, on va donc arrêter un container qui a le status à OK et qui a une charge de 0.

Voici le script que je propose, ce script permet en plus de fixer notre bug sur la précédente version 😉 .

#!/bin/bash
cd /docker/app/server/
i=0
flag="KO"
inodemax=0
inodestop=0
for inode in $(ls -R)
do
if
    [ -d $inode ]
then
    cd $inode 
    inodeval=$(echo $inode);
    status="KO"
    for filename in $(ls -R)
    do
	  if
	     [ -f $filename ]
	  then
	    if [ $filename = "status" ]
	      then
	      status=$(cat /docker/app/server/$inode/$filename)
	      load=$(cat /docker/app/server/$inode/load)
            fi	
          fi
    done	
    if [ $status = "OK" ]
      then
      echo "Status is OK for $inode"
      if [ $load = 0 ]	
	then 
	echo "Il n'y a pas de charge $load"
        flag="OK"	
        inodestop=$inodeval
      fi
    fi    
    cd /docker/app/server/
fi
done
if [ $flag = "OK" ]
  then
  echo "On va arreter ce containter : $inodestop";
  docker stop my-server7-$inodestop
  #Pour fixer notre bug ;)
  echo "KO" > /docker/app/server/$inodestop/status
fi
echo "Fin du script";

Et un petit test :

[root@localhost ~]# ./stop_container.bash 
Status is OK for 1
Il n'y a pas de charge 0
Status is OK for 2
Il n'y a pas de charge 0
Status is OK for 3
Il n'y a pas de charge 0
Status is OK for 4
Il n'y a pas de charge 0
Status is OK for 5
Il n'y a pas de charge 0
Status is OK for 6
Il n'y a pas de charge 0
On va arreter ce containter : 6
my-server7-6
Fin du script
[root@localhost ~]# ./stop_container.bash 
Status is OK for 1
Il n'y a pas de charge 0
Status is OK for 2
Il n'y a pas de charge 0
Status is OK for 3
Il n'y a pas de charge 0
Status is OK for 4
Il n'y a pas de charge 0
Status is OK for 5
Il n'y a pas de charge 0
On va arreter ce containter : 5
my-server7-5
Fin du script

Maintenant je place tous les scripts dans /docker/scripts/ (c’est plus propre que sous /root/)

[root@localhost ~]# mkdir /docker/scripts
[root@localhost ~]# cp *.bash /docker/scripts/.
[root@localhost ~]# ls /docker/scripts/
build_haproxy.bash  create_container.bash  stop_container.bash  test_load.bash  view_load.bash

Et je finalise mon script test_load.bash :

[root@localhost ~]# cat test_load.bash 
#!/bin/bash
cd /docker/app/server/
i=0
load=0
max=0
for inode in $(ls -R)
do
if
    [ -d $inode ]
then
    cd $inode 
    status="KO"
    for filename in $(ls -R)
    do
	  if
	     [ -f $filename ]
	  then
	    if [ $filename = "status" ]
	      then
	      status=$(cat /docker/app/server/$inode/$filename)
	      cload=$(cat /docker/app/server/$inode/load)	
	      cmax=$(cat /docker/app/server/$inode/max) 
            fi	
          fi
    done	
    if [ $status = "OK" ]
      then
      echo "Status is OK for $inode: max $cmax load $cload"
      load=`expr $load + $cload`
      max=`expr $max + $cmax`
    fi
    cd /docker/app/server/
fi
done
echo "La charge actuelle est de $load/$max";
pourc=$(( $load * 100 / $max))
 echo "$load/$max" >> /docker/scripts/log.txt
#On fixe le seuil à 0% ce qui est extrême on devrait surement mettre 25%
if [ $pourc -eq 0 ]
  then
  # On fixe le minimum à 10 ressources.
  if [ $max -gt 10 ]
     then
     logger -t CheckLoad "On n'a plus de charge on stoppe un container"
     echo "On peut arreter des containers";
     /docker/scripts/stop_container.bash
     echo "On refait la configuration de haproxy"
     /docker/scripts/build_haproxy.bash
     echo "On recharge haproxy"
     docker restart mon-haproxy-v15c
  fi
fi
#On fixe le seuil a 70% avant de lancer de nouveaux containers
if [ $pourc -gt 70 ]
  then
  logger -t CheckLoad "On a de la charge on lance un container"
  echo "On doit faire un nouveau container"
  /docker/scripts/create_container.bash
  echo "On refait la configuration de haproxy"
  /docker/scripts/build_haproxy.bash
  echo "On recharge haproxy"
  docker restart mon-haproxy-v15c  
fi
echo "Fin du script";

Et notre phase de test :

[root@localhost ~]# ./test_load.bash 
Status is OK for 1: max 5 load 0
Status is OK for 2: max 5 load 0
Status is OK for 3: max 5 load 0
La charge actuelle est de 0/15
On peut arreter des containers
Status is OK for 1
Il n'y a pas de charge 0
Status is OK for 2
Il n'y a pas de charge 0
Status is OK for 3
Il n'y a pas de charge 0
On va arreter ce containter : 3
my-server7-3
Fin du script
Fin du script
[root@localhost ~]# grep "CheckLoad" /var/log/messages 
Apr 16 15:20:44 localhost CheckLoad: On n'a plus de charge on stoppe un container

On passe donc ce script dans la crontab.

[root@localhost ~]# crontab -l
* * * * * /docker/scripts/test_load.bash

On lance notre logiciel de charge :

[root@localhost ~]# ./client_stress localhost 80
Start 
Nombre 500 le temps 2 
Nombre 1000 le temps 4 
Nombre 1500 le temps 6 
Nombre 2000 le temps 8 
Nombre 2500 le temps 13 
Nombre 3000 le temps 17 
Nombre 3500 le temps 22 
Nombre 4000 le temps 26 
Nombre 4500 le temps 30 
Nombre 5000 le temps 35 
Nombre 5500 le temps 39 
Nombre 6000 le temps 41 
Nombre 6500 le temps 46 
Nombre 7000 le temps 50 
Nombre 7500 le temps 54 
Nombre 8000 le temps 57 
Nombre 8500 le temps 64 
Nombre 9000 le temps 70 
^C
Vous avez du nouveau courrier dans /var/spool/mail/root
[root@localhost ~]# tail -f /docker/scripts/log.txt 
0/10
0/10
0/10
1/10
1/10
4/10
4/10

On ne peut pas dire que cela soit le gros stress, ce qui est normal car on n’a qu’une tâche qui fait le stress. On va donc faire un petit script pour un plus gros stress 😉 Voici le script que je vous propose, j’arrête après 120 secondes le test :

[root@localhost ~]# cat gros_stress.bash 
#!/bin/bash

timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 &
timeout 120 ./client_stress localhost 80 

echo "Fin de la charge"

Le résultat :

[root@localhost ~]# ./gros_stress.bash 
Start 
Start 
Start 
Start 
Start 
...
Nombre 1500 le temps 99 
Nombre 1500 le temps 119 
Fin de la charge
Vous avez du nouveau courrier dans /var/spool/mail/root

Les logs :

[root@localhost ~]# tail -f /docker/scripts/log.txt 
3/10
4/10
0/10
0/10
4/10
4/10
0/10
4/10
4/10
2/10

Visiblement j’ai un bugs 🙁 La charge ne monte jamais au dessus de 4 alors que j’ai 16 process en parallèle. Je vais donc passer sur la dernière version de serveur (server8) pour avoir plus d’information. Au passage je vais faire un script pour mettre le debug et le syslog à 0 sur tous les serveurs.

[root@localhost ~]# ./gros_stress.bash 
Start 
Start 
Start 
Start 
Start 
Start 
Start 
Start 
Start 
Start 
Start 
Start 
Start 
Start 
Start 
Start 
Nombre 500 le temps 6 
Nombre 500 le temps 6 
Nombre 500 le temps 7 
Nombre 500 le temps 8 
Nombre 500 le temps 8 
Nombre 500 le temps 8 
Nombre 500 le temps 8 
Nombre 500 le temps 8 
Nombre 500 le temps 8 
Nombre 500 le temps 8 
Nombre 500 le temps 8 
Nombre 500 le temps 8 
Nombre 500 le temps 8 
Nombre 1000 le temps 9 
Nombre 500 le temps 9 
Nombre 1000 le temps 9 
Nombre 1000 le temps 14 
Nombre 1000 le temps 15 
Nombre 1000 le temps 17 
Nombre 1000 le temps 18 
connect: Connection refused
connect: Connection refused
connect: Connection refused
connect: Connection refused
Nombre 1000 le temps 19 
Fin de la charge
Vous avez du nouveau courrier dans /var/spool/mail/root
Nombre 500 le temps 24 
Nombre 1000 le temps 27 
Nombre 1500 le temps 30 
Nombre 1000 le temps 32 
Nombre 2000 le temps 32 
Nombre 1500 le temps 33 
Nombre 1500 le temps 35 
Nombre 2500 le temps 35 
Nombre 2000 le temps 36 
Nombre 2000 le temps 37 
Nombre 3000 le temps 37 
Nombre 2500 le temps 40 
Nombre 1000 le temps 41 
Nombre 1000 le temps 42 
Nombre 2500 le temps 43 
Nombre 1500 le temps 51 
Nombre 3500 le temps 51 
Nombre 3000 le temps 59 
Nombre 1500 le temps 61 
Nombre 3000 le temps 72 
Nombre 1500 le temps 88 
Nombre 4000 le temps 88 
Nombre 2000 le temps 97 
Vous avez du nouveau courrier dans /var/spool/mail/root
Nombre 2000 le temps 110 
Nombre 4500 le temps 111

On observe une coupure du haxproxy ce qui est normal car on le relance, ensuite si on regarde les logs :

[root@localhost ~]# tail -f /docker/scripts/log.txt 
0/0
0/0
0/0
0/20
11/15
8/20
8/20
0/20
0/15
0/10

[root@localhost ~]# grep "CheckLoad" /var/log/messages | tail -n3
Apr 16 16:22:01 localhost CheckLoad: On a de la charge on lance un container
Apr 16 16:25:01 localhost CheckLoad: On n'a plus de charge on stoppe un container
Apr 16 16:26:01 localhost CheckLoad: On n'a plus de charge on stoppe un container


[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
dc75f255cd90        my-server7          "/sbin/server8"          8 minutes ago       Up 8 minutes        0.0.0.0:8087->80/tcp     my-server7-2
1f84fca3adf1        my-server7          "/sbin/server8"          8 minutes ago       Up 8 minutes        0.0.0.0:8086->80/tcp     my-server7-1
51b94f30c07e        my-haproxy-v15      "/docker-entrypoint.s"   5 hours ago         Up 7 minutes        0.0.0.0:80->80/tcp       mon-haproxy-v15c
2fc533c55725        postgres            "/docker-entrypoint.s"   44 hours ago        Up 44 hours         0.0.0.0:5432->5432/tcp   postgres2

Le point a régler c’est l’arrêt du haxproxy. Mais le but c’était de démontrer la facilité de monter et démonter un container. L’utilisation de script simplifie grandement la vie !

Un dernier script pour arrêter le mode débug et syslog sur tous les containers :

[root@localhost ~]# cat stop_debug.bash 
#!/bin/bash
cd /docker/app/server/
i=0
load=0
max=0
for inode in $(ls -R)
do
if
    [ -d $inode ]
then
    cd $inode 
    status="KO"
    for filename in $(ls -R)
    do
	  if
	     [ -f $filename ]
	  then
	    if [ $filename = "status" ]
	      then
	      status=$(cat /docker/app/server/$inode/$filename)
	      debug=$(cat /docker/app/server/$inode/debug)
	      syslog=$(cat /docker/app/server/$inode/syslog)	
            fi	
          fi
    done	
    if [ $status = "OK" ]
      then
      echo "Stop syslog ($syslog) et debug ($debug) sur $inode"
      echo 0 > /docker/app/server/$inode/debug	
      echo 0 > /docker/app/server/$inode/syslog 
    fi
    cd /docker/app/server/
fi
done
echo "Fin du script";

Le test comme toujours :

[root@localhost ~]# ./stop_debug.bash 
Stop syslog (1) et debug (1) sur 1
Stop syslog (1) et debug (1) sur 2
Fin du script
[root@localhost ~]# ./stop_debug.bash 
Stop syslog (0) et debug (0) sur 1
Stop syslog (0) et debug (0) sur 2
Fin du script

Normalement sur ses 15 jours de test de docker, j’ai pu vous faire partager de l’administration de docker, VirtualBox, Oracle Linux, HAproxy, PostgreSQL, …. Mais aussi de développement de script et de programme en C. Maintenant si j’ai le courage il va falloir faire un article propre. Je pense qu’un bon exemple simple est plus parlant pour justifier le bien fondé de nouvelle technologie.
Il me reste à voir le « docker commit », « docker push », « docker pull », ceci devrait permettre de voir l’avantage du déploiement sur docker. Mais aussi la répartition de charge entre deux serveurs Dockers.

Un petit schéma pour expliquer ce que l’on a mis en place :

  • une crontab (via un script) qui lance/arrête des containers en fonction de la charge. Cette crontab fait aussi la création du fichier de configuration de haxproxy et relance celui-ci.
  • un container haxproxy qui réparti la charge sur tous les containers server8.
  • des containers server8 qui utilisent le superbe protocole « Hello World » dont je devrais avoir des royalties ;). Et les serveurs utilisent un partage de fichier afin de remonter les informations de leur status à l’OS (Oracle Linux).

Capture d’écran 2016-04-29 à 11.46.02

Si vous êtes encore bloqué avec le problème du HAproxy qui ne répond pas, vous avez une première solution qui est de mettre trois HAproxy. Un premier HAproxy qui n’est jamais arrêté qui pointe sur deux autres HAproxy qui lisent la configuration et qui sont relancés à chacun son tour :). Mais la meilleure solution cela semble être la version HAproxy-LUA. La syntaxe doit être :

global
   lua-load mes-conteneurs.lua

listen proxy
   bind 127.0.0.1:80
   tcp-request inspect-delay 1s
   tcp-request content use-service lua.mes-conteneurs

Je suis pas encore un expert de HAproxy mais il doit exister plusieurs solutions à ce problème de coupure.