Docker : le quatorzième pas.

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

On va utiliser le fichier dynamique fait par ./build_haproxy.bash qui se trouve dans /docker/app/haproxy.cfg (merci de regarder l’épisode précédent n°13 afin de mieux comprendre). Pour le lancement de haxproxy la dernière fois que l’on a vu cela c’était dans le n°10 , la commande était alors :

docker run -d --link my-server4-1 --link my-server4-2 --link my-server4-3 --link my-server4-4 -p 80:80 --name mon-haproxy-v15b my-haproxy-v15

Maintenant on n’a plus besoin de lien car les IP sont écrites par les serveurs eux-mêmes. On a seulement à faire un partage de fichier.

[root@localhost ~]# cat /docker/app/haproxy.cfg
global
    maxconn 400 
 
defaults
    log 127.0.0.1 local5 debug
    mode    tcp
    retries 4
    maxconn 200
    timeout connect  5000
    timeout client  50000
    timeout server  50000

frontend http-in
    bind *:80
    default_backend serveur

backend serveur
        mode tcp
        balance roundrobin
server server1 172.17.0.9:80
server server2 172.17.0.10:80
[root@localhost ~]# docker run -d -v /docker/app/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg -p 80:80 --name mon-haproxy-v15c my-haproxy-v15
51b94f30c07e4469cdb21039d67ad94e286baa184c195962dbfb1ad26d81ab5c
[root@localhost ~]# telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

HELLO
INTERFACE

172.17.0.10
QUIT
Connection closed by foreign host.
[root@localhost ~]# telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

HELLO
INTERFACE

172.17.0.9
QUIT
Connection closed by foreign host.

Conclusion : cela fonctionne ! Le fichier de configuration qui est généré par le script est bien pris en compte par le container haproxy. Pour demander la relecture du fichier de configuration, rien de plus simple :

[root@localhost ~]# docker restart mon-haproxy-v15c
mon-haproxy-v15c

Avec l’énorme inconvénient que toutes les sessions en cours sont perdus. Ensuite je travaillerai sur ce point, car on peut imaginer que ce système ne se lance qu’en cas d’urgence. Il faut faire le script qui va compter les sessions et prendre la decision de lancer un nouveau container et de lancer un container à l’arrêt.

Pour lancer un nouveau container rien de plus facile on cherche une inode disponible et un port disponible. Voici un script :

[root@localhost ~]# cat create_container.bash 
#!/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)
            fi	
          fi
    done	
    if [ $status = "KO" ]
      then
      echo "Status is KO for $inode"
      flag="OK"	
      inodestop=$inodeval
    fi    
    if [ $inodeval -gt $inodemax ]
      then
      inodemax=$inodeval
    fi
    cd /docker/app/server/
fi
done
if [ $flag = "KO" ]
  then
  echo "On na pas vu de container à l'arret on va donc un faire un nouveau le plus grand étant $inodemax";
  inodemax=`expr $inodemax + 1 `
  echo "Le nouveau sera donc le $inodemax ";
  mkdir /docker/app/server/$inodemax
  port=`expr 8085 + $inodemax `
  docker run -p $port:80 --link postgres2:postgres2 -v /docker/app/server/$inodemax:/app/server/ --name my-server7-$inodemax --log-driver=syslog --log-opt tag="my-server7-$inodemax"  -d my-server7
fi
if [ $flag = "OK" ]
  then
  echo "On a vu un container à l'arret on va donc le lancer : $inodestop";
  docker start my-server7-$inodemax
fi
echo "Fin du script";

Et maintenant le test :

[root@localhost ~]# ./create_container.bash 
On na pas vu de container à l'arret on va donc un faire un nouveau le plus grand étant 4
Le nouveau sera donc le 5 
50dc9fbd7890d24ca0453878134469627116181adc26e56a86661dc879fb7466
Fin du script
[root@localhost ~]# ./create_container.bash 
On na pas vu de container à l'arret on va donc un faire un nouveau le plus grand étant 5
Le nouveau sera donc le 6 
b7edb8b9405d5f6665505e36b5179172201260a1eecf06446abaf9cb6256bc05
Fin du script
[root@localhost ~]# ./create_container.bash 
On na pas vu de container à l'arret on va donc un faire un nouveau le plus grand étant 6
Le nouveau sera donc le 7 
f806c2ed062c0f1bc5a105923b3e2b410d3cfc656bbaa329c8f55c47e4ca736b
Fin du script
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                    NAMES
f806c2ed062c        my-server7          "/sbin/server7"          14 seconds ago       Up 14 seconds       0.0.0.0:8092->80/tcp     my-server7-7
b7edb8b9405d        my-server7          "/sbin/server7"          15 seconds ago       Up 15 seconds       0.0.0.0:8091->80/tcp     my-server7-6
50dc9fbd7890        my-server7          "/sbin/server7"          18 seconds ago       Up 18 seconds       0.0.0.0:8090->80/tcp     my-server7-5
4ec165c67c25        my-server7          "/sbin/server7"          40 seconds ago       Up 40 seconds       0.0.0.0:8089->80/tcp     my-server7-4
bdf7cd9d64a7        my-server7          "/sbin/server7"          About a minute ago   Up About a minute   0.0.0.0:8088->80/tcp     my-server7-3
51b94f30c07e        my-haproxy-v15      "/docker-entrypoint.s"   About an hour ago    Up About an hour    0.0.0.0:80->80/tcp       mon-haproxy-v15c
cf1110c0f435        my-server7          "/sbin/server7"          4 hours ago          Up 4 hours          0.0.0.0:8087->80/tcp     my-server7-2
c6181abdea21        my-server7          "/sbin/server7"          4 hours ago          Up 4 hours          0.0.0.0:8086->80/tcp     my-server7-1
2912a5b6f004        my-server6          "/sbin/server6"          13 hours ago         Up 13 hours         0.0.0.0:8085->80/tcp     my-server6-1
a814b5991a87        my-server5          "/sbin/server5"          14 hours ago         Up 14 hours         0.0.0.0:8084->80/tcp     my-server4-5
eb76431e86e0        my-server5          "/sbin/server5"          17 hours ago         Up 17 hours         0.0.0.0:8083->80/tcp     my-server4-4
1e87ae6b009b        my-server5          "/sbin/server5"          17 hours ago         Up 17 hours         0.0.0.0:8082->80/tcp     my-server4-3
5b9099ae80d0        my-server5          "/sbin/server5"          17 hours ago         Up 17 hours         0.0.0.0:8081->80/tcp     my-server4-2
4fb8f79456af        my-server5          "/sbin/server5"          17 hours ago         Up 17 hours         0.0.0.0:8080->80/tcp     my-server4-1
2fc533c55725        postgres            "/docker-entrypoint.s"   39 hours ago         Up 39 hours         0.0.0.0:5432->5432/tcp   postgres2
[root@localhost ~]# docker stop my-server7-6
my-server7-6
[root@localhost ~]# ./create_container.bash 
On na pas vu de container à l'arret on va donc un faire un nouveau le plus grand étant 7
Le nouveau sera donc le 8 
d85bf7ea1bf7497312a2c27c9438bc4d8c7e695f85984b7cf1f9880f9098cf69
Fin du script
1460804275
[root@localhost ~]# cat /docker/app/server/6/status
OK
[root@localhost ~]# cat /docker/app/server/6/time
1460804219
[root@localhost ~]# cat /docker/app/server/6/time
1460804219
[root@localhost ~]#

Visiblement le « status » n’est pas à KO quand il est arrêté via la commande docker propre (après le stop du my-server7-6 je n’aurais pas du avoir la création du n°8). Il va donc falloir utiliser le temps afin de voir que tout fonctionne bien.

Mais avant cela je vous propose un instant méditation : Pensez-vous qu’il soit aussi facile avec VM Ware de déployer 3 serveurs ? Et ceci via une ligne de commande ? Pensez-vous qu’il soit aussi facile de prendre en compte ses nouveaux serveurs via un script fait en quelques minutes ? En plus de faire un déploiement cette ligne de commande fait aussi un partage de fichier, pour avoir l’équivalent avec VM Ware il faudrait monter un serveur SAMBA. Il nous reste encore à voir les autres grands avantages à savoir la mise à jour automatique, la répartition de charge entre serveurs dockers. Et l’autre avantage c’est de pouvoir faire un script qui permet par exemple de mettre tous les serveurs en mode débug. Je pense que cela commence à vous plaire, moi aussi 🙂 . Mais aussi on pourrait parler de l’espace disque :

[root@localhost ~]# docker history my-server7
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
b3b4e7faef2f        6 hours ago         /bin/sh -c #(nop) CMD ["/sbin/server7"]         0 B                 
0ca55d5c158d        6 hours ago         /bin/sh -c #(nop) EXPOSE 80/tcp                 0 B                 
7c369e74da08        6 hours ago         /bin/sh -c dnf install postgresql -y            162.6 MB            
d111ddce9aa0        6 hours ago         /bin/sh -c #(nop) COPY file:bffd0481c43858dd3   23.47 kB            
bb6bc55cbbfc        41 hours ago        /bin/sh -c #(nop) MAINTAINER toto toto@cyber-   0 B                 
ddd5c9c1d0f2        6 weeks ago         /bin/sh -c #(nop) ADD file:bcb5e5cddd4c4d1cac   204.7 MB            
           6 weeks ago         /bin/sh -c #(nop) MAINTAINER Patrick Uiterwij   0 B    

On doit être dans les 400 Mo, la même chose avec VM Ware et on est dans les 2 Go…On arrête l’instant méditation ;).

Maintenant je vais proposer une version server8 (server8.c) qui écrit KO ! pour cela je vais utiliser la fonction atexit(). Par contre je vais appeler cette version server7 afin de montrer l’utilité de la version dans le fichier dynamique. J’en profite aussi pour ajouter un nouveau fichier dynamique qui indique le nombre de client traité et un fichier dynamique error permettant d’avoir le code de sortie.

server8 : le source du programme (j’arrête les copies directes dans WordPress car cela commence a être volumineux).

Compilation et test :

[root@localhost ~]# gcc -o server8 server8.c -lpq
[root@localhost ~]# ./server8 
Default interface is : enp0s3 
Local ip is : 192.168.10.159 
POSTGRES2_PORT_5432_TCP_ADDR : (null) 
Stdout is descriptor 1
Stderr is descriptor 2
Stdout is descriptor 1
Stderr is descriptor 2
OK : Table STATISTIQUE 
^CFin du programme
[ END : CTRL-C]

[root@localhost ~]# cat /app/server/status
KO[root@localhost ~]# cat /app/server/error
11

Parfait cela fonctionne ! Maintenant je vais déployer cette superbe version, on s’approche de la version « gold » 😉 . Attention cette fois je fais mettre la version 8 dans le my-server7 .

[root@localhost ~]# cat Dockerfile
FROM fedora
MAINTAINER toto toto@cyber-neurones.org 
COPY ./server8 /sbin/server8
RUN dnf install postgresql -y
# Le port en ecoute 
EXPOSE 80 
# Pour lancer postgres 
CMD ["/sbin/server8"]

[root@localhost ~]# docker build -t my-server7 .
Sending build context to Docker daemon 380.9 kB
Step 1 : FROM fedora
 ---> ddd5c9c1d0f2
Step 2 : MAINTAINER toto toto@cyber-neurones.org
 ---> Using cache
 ---> bb6bc55cbbfc
Step 3 : COPY ./server8 /sbin/server8
 ---> bce16fb36408
Removing intermediate container d7411590d297
Step 4 : RUN dnf install postgresql -y
 ---> Running in ca2051c554ae
....
Complete!
 ---> b4511089849d
Removing intermediate container 06ba37adc88b
Step 5 : EXPOSE 80
 ---> Running in 9a94125adc6b
 ---> a1834ef7e456
Removing intermediate container 9a94125adc6b
Step 6 : CMD /sbin/server8
 ---> Running in 9a1a3c3e7dbe
 ---> 2dbb7ecbdaa1
Removing intermediate container 9a1a3c3e7dbe
Successfully built 2dbb7ecbdaa1

La suite demain 😉
Pour finir le squelette du script qui va être dans la crontab :

[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))
if [ $pourc -eq 0 ]
  then
  if [ $max -gt 10 ]
     then
     echo "On peut arreter des serveurs";
     # script a écrire
     # on refait la conf de haproxy et on relance.
  fi
fi
if [ $pourc -gt 70 ]
  then
  echo "On doit faire un nouveau container"
  # create_container.bash
  echo "On refait la configuration de haproxy"
  # build_haproxy.bash
  echo "On recharge haproxy"
  # docker restart mon-haproxy-v15c
fi
echo "Fin du script";
[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
Status is OK for 4: max 5 load 0
Status is OK for 5: max 5 load 0
Status is OK for 6: max 5 load 0
Status is OK for 7: max 5 load 0
Status is OK for 8: max 5 load 0
La charge actuelle est de 0/40
On peut arreter des serveurs
Fin du script

Il nous faut donc écrire le script d’arrêt d’un container.

Docker : le treizième pas.

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

Je pense avoir trouvé une alternative à confdetc , c’est consul-haproxy .

[root@localhost ~]# yum install consul
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     
dockerrepo/primary_db                                                                                                                                      |  15 kB  00:00:00     
(1/2): ol7_latest/x86_64/updateinfo                                                                                                                        | 812 kB  00:00:01     
(2/2): ol7_latest/x86_64/primary                                                                                                                           |  16 MB  00:00:17     
ol7_latest                                                                                                                                                            14264/14264
Aucun paquet consul disponible.
Erreur : Rien à faire

Misère, cela commence fort … sinon j’ai aussi vu une configuration un peu complexe avec vagrant.

[root@localhost ~]# yum install vagrant
Modules complémentaires chargés : ulninfo
Aucun paquet vagrant disponible.
Erreur : Rien à faire

Google please help me : « HAProxy dynamic backend server list » 🙂

  • Consul : ( non pas standard )
  • Chef :
  • Thalassa :
  • LUA :
  • Etcd & Confd : ( non pas standard )
  • Keepalived : http://www.keepalived.org .
  • Serf :

Maintenant il me reste à voir lequel est le plus simple a mettre en oeuvre.

Un ange passe ….

Après étude, le premier point c’est que tout est fait pour du protocole HTT¨P or moi j’adore mon protocole « Hello » 🙂 Ensuite on mets des usines en place pour faire des choses qui me paraissent assez simple, certain se base sur un DNS, d’autre sur une base REDIS, d’autre sur du WordPress, d’autre sur un TinyWEB. Tout ceci me semble bien complexe …

Etant développeur je ne vais pas choisir entre la peste et le choléra  … je vais développer mon microbe à moi.

De quoi j’ai besoin ? D’un script qui peut tourner dans une crontab et qui parse un répertoire que l’on va appeler /docker/app/server/ . Dans ce répertoire chaque serveur va mettre ses informations à savoir chacun va écrire sa ligne :

server server1 my-server4-1:80

dans un fichier que l’on va appeler haproxy, et on va même faire des fichiers dynamiques pour modifier le niveau de logs (fichier debug) et pour savoir si on transmet ou pas dans syslog (fichier syslog). Et pour finir on va faire un fichier status qui va indiquer si on est OK ou KO. Soyons fou !, un fichier load qui indique la charge courante et un fichier version qui nous indique la version du logiciel. Et un fichier conf & db qui sont un dump de la configuration du serveur, qui seront utiles plus tard … je le sent. Et pourquoi pas un fichier max qui indique le maximum de connexion possible, un fichier time pour voir si notre server est bloqué. Je vais donc avoir 10 fichiers dynamiques.

Voici ce que cela donne, le server7.c (désolé mais WordPress n’a pas supporté l’indentation de cette dernière version, il suffit de faire indent -gnu server7.c pour remettre tout en ordre):

server7 : version sous fichier rtf car le copier/coller est fourbe 😉 .

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include "libpq-fe.h"
#include <syslog.h>

#define MYPORT 		80
#define BACKLOG 	5
#define MAXCLIENTS 	5
#define MAXDATASIZE 	100
#define MYPATH 			"/app/server/"
#define MYPATH_HAPROXY		"/app/server/haproxy"
#define MYPATH_CONF		"/app/server/conf"
#define MYPATH_DB               "/app/server/db"
#define MYPATH_STATUS		"/app/server/status"
#define MYPATH_DEBUG		"/app/server/debug"
#define MYPATH_LOAD		"/app/server/load"
#define MYPATH_SYSLOG           "/app/server/syslog"
#define MYPATH_MAX              "/app/server/max"
#define MYPATH_VERSION          "/app/server/version"
#define MYPATH_TIME		"/app/server/time"

long
getMicrotime ()
{
  struct timeval currentTime;
  gettimeofday (&currentTime, NULL);
  return currentTime.tv_sec * (int) 1e6 + currentTime.tv_usec;
}

int
putGeneric (char filename[], char status[], int vdebug, int vsyslog)
{
  FILE *file = NULL;
  if ((file = fopen (filename, "w")) == NULL)
    {
      if (vsyslog == 1)
	{
	  syslog (LOG_ERR, "Erreur dans l'ouverture de %s", filename);
	}
      return -1;
    }
  else
    {
      fprintf (file, "%s", status);
      fclose (file);
    }
  return 0;
}

int
putGeneric2 (char filename[], int status, int vdebug, int vsyslog)
{
  FILE *file = NULL;
  if ((file = fopen (filename, "w")) == NULL)
    {
      if (vsyslog == 1)
	{
	  syslog (LOG_ERR, "Erreur dans l'ouverture de %s", filename);
	}
      return -1;
    }
  else
    {
      fprintf (file, "%d", status);
      fclose (file);
    }
  return 0;
}

int
putGeneric3 (char filename[], unsigned long status, int vdebug, int vsyslog)
{
  FILE *file = NULL;
  if ((file = fopen (filename, "w")) == NULL)
    {
      if (vsyslog == 1)
	{
	  syslog (LOG_ERR, "Erreur dans l'ouverture de %s", filename);
	}
      return -1;
    }
  else
    {
      fprintf (file, "%ld", status);
      fclose (file);
    }
  return 0;
}

int
getGeneric2 (char filename[], int vdebug, int vsyslog)
{
  int status = -1;
  char string[20];
  FILE *file = NULL;
  if ((file = fopen (filename, "r")) == NULL)
    {
      if (vsyslog == 1)
	{
	  syslog (LOG_ERR, "Erreur dans l'ouverture de %s", filename);
	}
      return -1;
    }
  else
    {
      fgets (string, sizeof (string), file);
      status = atoi (string);
      fclose (file);
    }
  return status;
}


int
main (void)
{
  int sockfd = -1, new_fd, numbytes, highest = 0, i;
  int vdebug = 1;
  int vsyslog = 1;
  int clients[MAXCLIENTS];
  long clients_t[MAXCLIENTS];
  char clients_ip[MAXCLIENTS][MAXDATASIZE];
  char buffer[MAXDATASIZE];
  char localip[MAXDATASIZE];
  char haproxy[MAXDATASIZE];
  char conf[MAXDATASIZE];
  struct sockaddr_in my_addr, their_addr;
  socklen_t sin_size;
  struct timeval tv;
  fd_set readfds;
  char conninfo[MAXDATASIZE];
  PGconn *conn;
  PGresult *res;
  FILE *f;
  char line[100], *p, *c;
  const char *google_dns_server = "8.8.8.8";
  int dns_port = 53;
  struct sockaddr_in serv;
  int sock = socket (AF_INET, SOCK_DGRAM, 0);

  setlogmask (LOG_UPTO (LOG_NOTICE));
  openlog ("server5", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);

  putGeneric (MYPATH_STATUS, "OK", vdebug, vsyslog);
  putGeneric2 (MYPATH_SYSLOG, vsyslog, vdebug, vsyslog);
  putGeneric2 (MYPATH_DEBUG, vdebug, vdebug, vsyslog);
  putGeneric2 (MYPATH_LOAD, 0, vdebug, vsyslog);
  putGeneric2 (MYPATH_MAX, MAXCLIENTS, vdebug, vsyslog);
  putGeneric2 (MYPATH_VERSION, 7, vdebug, vsyslog);

  f = fopen ("/proc/net/route", "r");
  while (fgets (line, 100, f))
    {
      p = strtok (line, " \t");
      c = strtok (NULL, " \t");

      if (p != NULL && c != NULL)
	{
	  if (strcmp (c, "00000000") == 0)
	    {
	      if (vdebug == 1)
		{
		  fprintf (stdout, "Default interface is : %s \n", p);
		}
	      break;
	    }
	}
    }

  if (sock < 0) { 
    fprintf (stderr, "Socket error\n"); syslog (LOG_ERR, "Error on socket"); 
    closelog (); 
    putGeneric (MYPATH_STATUS, "KO", vdebug, vsyslog); 
    exit (-1); 
  } 
memset (&serv, 0, sizeof (serv)); 
serv.sin_family = AF_INET; 
serv.sin_addr.s_addr = inet_addr (google_dns_server); 
serv.sin_port = htons (dns_port); 
int err = connect (sock, (const struct sockaddr *) &serv, sizeof (serv)); 
struct sockaddr_in name; 
socklen_t namelen = sizeof (name); 
err = getsockname (sock, (struct sockaddr *) &name, &namelen); 
const char *p2 = inet_ntop (AF_INET, &name.sin_addr, localip, 100);
 if (p2 != NULL) { 
fprintf (stdout, "Local ip is : %s \n", localip); 
} else { 
fprintf (stdout, "Error number : %d . Error message : %s \n", errno, strerror (errno)); 
strcpy (localip, "Error"); 
} 
close (sock); 
sprintf (haproxy, "server %s %s:%d", p, localip, MYPORT); 
putGeneric (MYPATH_HAPROXY, haproxy, vdebug, vsyslog); 
sprintf (conf, "debug = %d \nsyslog = %d \ngoogle = %s \n", vdebug, vsyslog, google_dns_server); 
putGeneric (MYPATH_CONF, conf, vdebug, vsyslog); 
fprintf (stdout, "POSTGRES2_PORT_5432_TCP_ADDR : %s \n", getenv ("POSTGRES2_PORT_5432_TCP_ADDR")); 
if (getenv ("POSTGRES2_PORT_5432_TCP_ADDR") == NULL) { 
sprintf (conninfo, "hostaddr=%s port=%s user=postgres password=%s", "127.0.0.1", "5432", "password"); 
syslog (LOG_NOTICE, "Local mode"); 
} else { 
sprintf (conninfo, "hostaddr=%s port=%s user=postgres password=%s", getenv ("POSTGRES2_PORT_5432_TCP_ADDR"), getenv ("POSTGRES2_PORT_5432_TCP_PORT"), getenv ("POSTGRES2_ENV_POSTGRES_PASSWORD")); syslog (LOG_NOTICE, "Docker mode"); 
} 
putGeneric (MYPATH_DB, conninfo, vdebug, vsyslog); 
/* Ceinture et breteille */ 
fprintf (stdout, "Stdout is descriptor %d\n", fileno (stdout)); 
fprintf (stdout, "Stderr is descriptor %d\n", fileno (stderr)); 
freopen ("/dev/stdout", "w", stdout); 
freopen ("/dev/stderr", "w", stderr); 
fprintf (stdout, "Stdout is descriptor %d\n", fileno (stdout));
 fprintf (stdout, "Stderr is descriptor %d\n", fileno (stderr)); 
conn = PQconnectdb (conninfo); 
if (PQstatus (conn) != CONNECTION_OK) 
{ 
fprintf (stderr, "Connection to database failed: %s \n", PQerrorMessage (conn)); 
} else { 
res = PQexec (conn, "select count(*) from STATISTIQUE;"); 
if (PQresultStatus (res) != PGRES_TUPLES_OK) { 
fprintf (stdout, "KO : Table STATISTIQUE \n"); 
PQclear (res); 
res = PQexec (conn, "CREATE TABLE STATISTIQUE ( ID serial primary key, CLIENT CHAR(20) NOT NULL, SERVER CHAR(20) NOT NULL, TEMPS_MILLI INT NOT NULL, TEMPS_CUR INT);"); 
if (PQresultStatus (res) != PGRES_COMMAND_OK) { 
fprintf (stdout, "KO : Table STATISTIQUE (CREATE) \n"); 
PQclear (res); 
} else { 
fprintf (stdout, "OK : Table STATISTIQUE (CREATE) \n"); 
PQclear (res); 
} 
} else { 
fprintf (stdout, "OK : Table STATISTIQUE \n"); 
PQclear (res); 
} 
} 
PQfinish (conn); 
syslog (LOG_NOTICE, "End of check of table"); 
if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1) { 
fprintf (stderr, "socket error\n"); 
syslog (LOG_ERR, "Error on socket"); 
closelog (); 
putGeneric (MYPATH_STATUS, "KO", vdebug, vsyslog); exit (-1); 
} 
my_addr.sin_family = AF_INET; 
my_addr.sin_port = htons (MYPORT); 
my_addr.sin_addr.s_addr = INADDR_ANY; 
bzero (&(my_addr.sin_zero), 8); 
if (bind (sockfd, (struct sockaddr *) &my_addr, sizeof (struct sockaddr)) == -1) { 
fprintf (stderr, "bind error\n"); 
syslog (LOG_ERR, "Error on bind"); 
closelog (); 
putGeneric (MYPATH_STATUS, "KO", vdebug, vsyslog); 
exit (-1); 
} 
if (listen (sockfd, BACKLOG) == -1) { 
fprintf (stderr, "listen error\n"); syslog (LOG_ERR, "Error on listen"); 
closelog (); 
putGeneric (MYPATH_STATUS, "KO", vdebug, vsyslog); exit (-1); 
} 
bzero (clients, sizeof (clients)); 
highest = sockfd; 
while (1) 
   { 
    int nb = 0; 
    int new_debug = -1; 
    int new_syslog = -1; 
    putGeneric2 (MYPATH_TIME, time (0), vdebug, vsyslog); 
    new_debug = getGeneric2 (MYPATH_DEBUG, vdebug, vsyslog); 
    new_syslog = getGeneric2 (MYPATH_SYSLOG, vdebug, vsyslog); 
      if ((new_debug >= 0) && (new_debug != vdebug))
	{
	  vdebug = new_debug;
	  sprintf (conf, "debug = %d \nsyslog = %d \ngoogle = %s \n", vdebug,
		   vsyslog, google_dns_server);
	  putGeneric (MYPATH_CONF, conf, vdebug, vsyslog);
	}
      if ((new_syslog >= 0) && (new_syslog != vsyslog))
	{
	  vsyslog = new_syslog;
	  sprintf (conf, "debug = %d \nsyslog = %d \ngoogle = %s \n", vdebug,
		   vsyslog, google_dns_server);
	  putGeneric (MYPATH_CONF, conf, vdebug, vsyslog);
	}

      sin_size = sizeof (struct sockaddr_in);
      tv.tv_sec = 0;
      tv.tv_usec = 330000;
      FD_ZERO (&readfds);
      for (i = 0; i < MAXCLIENTS; i++) 
        { 
         if (clients[i] != 0) { 
           FD_SET (clients[i], &readfds); nb++; 
         } 
        } 
       putGeneric2 (MYPATH_LOAD, nb, vdebug, vsyslog); FD_SET (sockfd, &readfds); 
      if (select (highest + 1, &readfds, NULL, NULL, &tv) >= 0)
	{
	  if (FD_ISSET (sockfd, &readfds))
	    {
	      if ((new_fd =
		   accept (sockfd, (struct sockaddr *) &their_addr,
			   &sin_size)) == -1)
		{
		  if (vdebug == 1)
		    fprintf (stderr, "accept error\n");
		  if (vsyslog == 1)
		    syslog (LOG_ERR, "Error on accept");
		  continue;
		}
	      for (i = 0; i < MAXCLIENTS; i++) { 
                 if (clients[i] == 0) { 
                    clients[i] = new_fd; 
                    clients_t[i] = getMicrotime (); 
                    break; 
                    } 
                 } 
              if (i != MAXCLIENTS) { 
                  if (new_fd > highest)
		    {
		      highest = clients[i];
		    }
		  if (vdebug == 1)
		    fprintf (stdout, "Connexion received from %s (slot %i) ",
			     inet_ntoa (their_addr.sin_addr), i);
		  strcpy (clients_ip[i], inet_ntoa (their_addr.sin_addr));
		  if (vsyslog == 1)
		    syslog (LOG_NOTICE,
			    "Connexion received from %s (slot %i) ",
			    inet_ntoa (their_addr.sin_addr), i);
		  send (new_fd, "\nHELLO\n", 7, MSG_NOSIGNAL);
		}
	      else
		{
		  send (new_fd, "\nTOO MANY CLIENT\n", 17, MSG_NOSIGNAL);
		  close (new_fd);
		}
	    }
	  for (i = 0; i < MAXCLIENTS; i++)
	    {
	      if (FD_ISSET (clients[i], &readfds))
		{
		  if ((numbytes =
		       recv (clients[i], buffer, MAXDATASIZE, 0)) <= 0)
		    {
		      if (vdebug == 1)
			fprintf (stdout, "Connexion lost from slot %i", i);
		      if (vsyslog == 1)
			syslog (LOG_NOTICE, "Connexion lost from slot %i", i);
		      close (clients[i]);
		      clients[i] = 0;
		    }
		  else
		    {
		      buffer[numbytes] = '\0';
		      if (vdebug == 1)
			fprintf (stdout, "Received from slot %i : %s", i,
				 buffer);
		      if (vsyslog == 1)
			syslog (LOG_NOTICE, "Received from slot %i : %s",
				i, buffer);
		      if (strncmp (buffer, "POSTGRES", 6) == 0)
			{
			  conn = PQconnectdb (conninfo);
			  if (PQstatus (conn) != CONNECTION_OK)
			    {
			      if (vdebug == 1)
				fprintf (stderr,
					 "Connection to database failed: %s \n",
					 PQerrorMessage (conn));
			      send (new_fd, "\nDB KO\n", 7, MSG_NOSIGNAL);
			      if (vsyslog == 1)
				syslog (LOG_ALERT,
					"Connection to database failed: %s",
					PQerrorMessage (conn));
			    }
			  else
			    {
			      send (new_fd, "\nDB OK\n", 7, MSG_NOSIGNAL);
			    }
			  PQfinish (conn);
			}
		      if (strncmp (buffer, "DBINSERT", 6) == 0)
			{
			  conn = PQconnectdb (conninfo);
			  if (PQstatus (conn) != CONNECTION_OK)
			    {
			      fprintf (stderr,
				       "Connection to database failed: %s \n",
				       PQerrorMessage (conn));
			      send (new_fd, "\nDBINSERT KO (1)\n", 16,
				    MSG_NOSIGNAL);
			      syslog (LOG_ALERT,
				      "Connection to database failed: %s",
				      PQerrorMessage (conn));
			    }
			  else
			    {
			      char query_string[256];
			      send (new_fd, "\nDBINSERT OK\n", 7,
				    MSG_NOSIGNAL);
			      sprintf (query_string,
				       "INSERT INTO STATISTIQUE (CLIENT,SERVER,TEMPS_MILLI,TEMPS_CUR) VALUES ('%s','%s','%ld','%ld')",
				       clients_ip[i], localip,
				       getMicrotime () - clients_t[i],
				       time (0));
			      res = PQexec (conn, query_string);
			      if (PQresultStatus (res) != PGRES_COMMAND_OK)
				{
				  send (new_fd, "\nDBINSERT KO (2)\n", 16,
					MSG_NOSIGNAL);
				  send (new_fd, query_string,
					strlen (query_string), MSG_NOSIGNAL);
				  send (new_fd, "\n", 1, MSG_NOSIGNAL);
				  PQclear (res);
				}
			      else
				{
				  send (new_fd, "\nDBINSERT OK (1)\n", 16,
					MSG_NOSIGNAL);
				  PQclear (res);
				}
			    }
			  PQfinish (conn);
			}
		      if ((strncmp (buffer, "QUIT", 4) == 0))
			{
			  if (vdebug == 1)
			    fprintf (stdout,
				     "Connexion QUIT from slot %i \n", i);
			  syslog (LOG_NOTICE,
				  "End of cnx : QUIT (slot n°%i)", i);
			  close (clients[i]);
			  clients[i] = 0;
			}
		      if ((strncmp (buffer, "TIME", 4) == 0))
			{
			  if (vdebug == 1)
			    fprintf (stdout,
				     "TIME from slot %i : %ld ms \n", i,
				     getMicrotime () - clients_t[i]);
			}
		      if ((strncmp (buffer, "EXIT", 4) == 0))
			{
			  if (vdebug == 1)
			    fprintf (stdout,
				     "Connexion EXIT from slot %i \n", i);
			  syslog (LOG_NOTICE,
				  "End of cnx : EXIT (slot n°%i)", i);
			  close (clients[i]);
			  clients[i] = 0;
			}
		      if ((strncmp (buffer, "CLOSE", 5) == 0))
			{
			  if (vdebug == 1)
			    fprintf (stdout,
				     "Connexion CLOSE from slot %i \n", i);
			  syslog (LOG_NOTICE,
				  "End of cnx : CLOSE (slot n°%i)", i);
			  close (clients[i]);
			  clients[i] = 0;
			}
		      if ((strncmp (buffer, "INTERFACE", 9) == 0))
			{
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			  send (new_fd, localip, strlen (localip),
				MSG_NOSIGNAL);
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			}
		      if ((strncmp (buffer, "IP", 2) == 0))
			{
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			  send (new_fd, p, strlen (p), MSG_NOSIGNAL);
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			}
		      if ((strncmp (buffer, "CLIENT", 6) == 0))
			{
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			  send (new_fd, clients_ip[i],
				strlen (clients_ip[i]), MSG_NOSIGNAL);
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			}
		      if ((strncmp (buffer, "DBCNX", 2) == 0))
			{
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			  send (new_fd, conninfo, strlen (conninfo),
				MSG_NOSIGNAL);
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			}
		    }
		}
	    }
	}
      else
	{
	  fprintf (stderr, "select error\n");
	  syslog (LOG_ERR, "Error on select");
	  continue;
	}
    }
  putGeneric (MYPATH_STATUS, "KO", vdebug, vsyslog);
  return 0;
}

Pour l’utilisation de notre server7, il faut donc faire :

[root@localhost ~]# gcc -o server7 server7.c -lpq
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
2912a5b6f004        my-server6          "/sbin/server6"          7 hours ago         Up 7 hours          0.0.0.0:8085->80/tcp     my-server6-1
a814b5991a87        my-server5          "/sbin/server5"          8 hours ago         Up 8 hours          0.0.0.0:8084->80/tcp     my-server4-5
1f22de2c194b        my-haproxy-v15      "/docker-entrypoint.s"   11 hours ago        Up 5 hours          0.0.0.0:80->80/tcp       mon-haproxy-v15b
eb76431e86e0        my-server5          "/sbin/server5"          11 hours ago        Up 11 hours         0.0.0.0:8083->80/tcp     my-server4-4
1e87ae6b009b        my-server5          "/sbin/server5"          11 hours ago        Up 11 hours         0.0.0.0:8082->80/tcp     my-server4-3
5b9099ae80d0        my-server5          "/sbin/server5"          11 hours ago        Up 11 hours         0.0.0.0:8081->80/tcp     my-server4-2
4fb8f79456af        my-server5          "/sbin/server5"          11 hours ago        Up 11 hours         0.0.0.0:8080->80/tcp     my-server4-1
2fc533c55725        postgres            "/docker-entrypoint.s"   33 hours ago        Up 33 hours         0.0.0.0:5432->5432/tcp   postgres2
[root@localhost ~]# docker stop 1f22de2c194b
1f22de2c194b
[root@localhost ~]# mkdir /app
[root@localhost ~]# mkdir /app/server
[root@localhost ~]# ls -l /app/server
total 0
[root@localhost ~]# ./server7
Default interface is : enp0s3 
Local ip is : 192.168.10.159 
POSTGRES2_PORT_5432_TCP_ADDR : (null) 
Stdout is descriptor 1
Stderr is descriptor 2
Stdout is descriptor 1
Stderr is descriptor 2
OK : Table STATISTIQUE 

Et dans un autre terminal on fait la vérification :

[root@localhost ~]# ls -l /app/server/
conf  debug     load    status   version
db    haproxy   max     syslog   time
[root@localhost ~]# cat /app/server/conf
server enp0s3 192.168.10.159:80[root@localhost ~]#
[root@localhost ~]# cat /app/server/db
hostaddr=127.0.0.1 port=5432 user=postgres password=password[root@localhost ~]#
[root@localhost ~]# cat /app/server/debug
1[root@localhost ~]#
[root@localhost ~]# cat /app/server/syslog
1[root@localhost ~]#
[root@localhost ~]# cat /app/server/load
0[root@localhost ~]#
[root@localhost ~]# cat /app/server/max
5[root@localhost ~]#
[root@localhost ~]# cat /app/server/status
OK[root@localhost ~]#
[root@localhost ~]# cat /app/server/version
7[root@localhost ~]#
[root@localhost ~]# echo "0" > /app/server/syslog
[root@localhost ~]# echo "0" > /app/server/debug
[root@localhost ~]# cat /app/server/conf
debug = 0
syslog = 0
google = 8.8.8.8

Les fichiers dynamiques sont biens pris en compte dans la configuration. Maintenant on passe notre serveur sous Docker. Pour chaque server on va faire un répertoire dans /docker/app/server/ et on va essayer de faire un lien avec /app/server/.

[root@localhost ~]# mkdir /docker/app
[root@localhost ~]# mkdir /docker/app/server
[root@localhost ~]# mkdir /docker/app/server/1
[root@localhost ~]# mkdir /docker/app/server/2
[root@localhost ~]# mkdir /docker/app/server/3
[root@localhost ~]# mkdir /docker/app/server/4
[root@localhost ~]# cat Dockerfile
FROM fedora
MAINTAINER toto toto@cyber-neurones.org 
COPY ./server7 /sbin/server7
RUN dnf install postgresql -y
# Le port en ecoute 
EXPOSE 80 
# Pour lancer postgres 
CMD ["/sbin/server7"]

[root@localhost ~]# docker build -t my-server7 .
Sending build context to Docker daemon 314.4 kB
Step 1 : FROM fedora
 ---> ddd5c9c1d0f2
Step 2 : MAINTAINER toto toto@cyber-neurones.org
 ---> Using cache
 ---> bb6bc55cbbfc
Step 3 : COPY ./server7 /sbin/server7
 ---> d111ddce9aa0
Removing intermediate container 0931af942942
Step 4 : RUN dnf install postgresql -y
 ---> Running in 6f0d54a21f7b
 ---> Running in ab6e197abc3a
Last metadata expiration check performed 0:05:47 ago on Sat Apr 16 05:52:43 2016.
Dependencies resolved.
================================================================================
 Package                Arch          Version              Repository      Size
================================================================================
Installing:
 postgresql             x86_64        9.4.7-1.fc23         updates        1.1 M
 postgresql-libs        x86_64        9.4.7-1.fc23         updates        240 k

Transaction Summary
================================================================================
Install  2 Packages

Total download size: 1.3 M
Installed size: 4.4 M
Downloading Packages:
--------------------------------------------------------------------------------
Total                                            11 kB/s | 1.3 MB     02:03     
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Installing  : postgresql-libs-9.4.7-1.fc23.x86_64                         1/2 
  Installing  : postgresql-9.4.7-1.fc23.x86_64                              2/2 
  Verifying   : postgresql-9.4.7-1.fc23.x86_64                              1/2 
  Verifying   : postgresql-libs-9.4.7-1.fc23.x86_64                         2/2 

Installed:
  postgresql.x86_64 9.4.7-1.fc23       postgresql-libs.x86_64 9.4.7-1.fc23      

Complete!
 ---> 7c369e74da08
Removing intermediate container ab6e197abc3a
Step 5 : EXPOSE 80
 ---> Running in 2d30e96f6737
 ---> 0ca55d5c158d
Removing intermediate container 2d30e96f6737
Step 6 : CMD /sbin/server7
 ---> Running in af653d7460c9
 ---> b3b4e7faef2f
Removing intermediate container af653d7460c9
Successfully built b3b4e7faef2f

[root@localhost ~]# docker run -p 8086:80 --link postgres2:postgres2 -v /docker/app/server/1:/app/server/ --name my-server7-1 --log-driver=syslog --log-opt tag="my-server7-1"  -d my-server7 
c6181abdea219a4d656ea5d6e1735a2e2c579d8886d6da77518a5a7726fc6806
 
[root@localhost ~]# cat /docker/app/server/1/haproxy 
server eth0 172.17.0.9:80[root@localhost ~]# 

[root@localhost ~]# ls -ls /docker/app/server/1/*
4 -rw-r--r-- 1 root root 41 16 avril 07:07 /docker/app/server/1/conf
4 -rw-r--r-- 1 root root 61 16 avril 07:07 /docker/app/server/1/db
4 -rw-r--r-- 1 root root  1 16 avril 07:07 /docker/app/server/1/debug
4 -rw-r--r-- 1 root root 25 16 avril 07:07 /docker/app/server/1/haproxy
4 -rw-r--r-- 1 root root  1 16 avril 07:08 /docker/app/server/1/load
4 -rw-r--r-- 1 root root  1 16 avril 07:07 /docker/app/server/1/max
4 -rw-r--r-- 1 root root  2 16 avril 07:07 /docker/app/server/1/status
4 -rw-r--r-- 1 root root  1 16 avril 07:07 /docker/app/server/1/syslog
4 -rw-r--r-- 1 root root 10 16 avril 07:08 /docker/app/server/1/time
4 -rw-r--r-- 1 root root  1 16 avril 07:07 /docker/app/server/1/version

[root@localhost ~]# docker run -p 8087:80 --link postgres2:postgres2 -v /docker/app/server/2:/app/server/ --name my-server7-2 --log-driver=syslog --log-opt tag="my-server7-2"  -d my-server7 
cf1110c0f435226ab0fe96fe8eec805a42e36e3f243b7b06c8c2569269a5c34f
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
cf1110c0f435        my-server7          "/sbin/server7"          8 seconds ago       Up 7 seconds        0.0.0.0:8087->80/tcp     my-server7-2
c6181abdea21        my-server7          "/sbin/server7"          2 minutes ago       Up 2 minutes        0.0.0.0:8086->80/tcp     my-server7-1
2912a5b6f004        my-server6          "/sbin/server6"          8 hours ago         Up 8 hours          0.0.0.0:8085->80/tcp     my-server6-1
a814b5991a87        my-server5          "/sbin/server5"          9 hours ago         Up 9 hours          0.0.0.0:8084->80/tcp     my-server4-5
eb76431e86e0        my-server5          "/sbin/server5"          12 hours ago        Up 12 hours         0.0.0.0:8083->80/tcp     my-server4-4
1e87ae6b009b        my-server5          "/sbin/server5"          12 hours ago        Up 12 hours         0.0.0.0:8082->80/tcp     my-server4-3
5b9099ae80d0        my-server5          "/sbin/server5"          12 hours ago        Up 12 hours         0.0.0.0:8081->80/tcp     my-server4-2
4fb8f79456af        my-server5          "/sbin/server5"          12 hours ago        Up 12 hours         0.0.0.0:8080->80/tcp     my-server4-1
2fc533c55725        postgres            "/docker-entrypoint.s"   34 hours ago        Up 34 hours         0.0.0.0:5432->5432/tcp   postgres2

J’ai donc deux serveurs server7, maintenant il me faut faire des scripts qui font le check et qui font le fichier haproxy.cfg . Avant un petit rappel sur le lancement, l’option -p

-p 8087:80

le 8087 c’est le port de l’OS et le 80 c’est le port du container. Cette option permet d’avoir un lien entre ses deux ports. Ensuite il y a l’option -v

-v /docker/app/server/2:/app/server/

cela permet de faire un lien entre le répertoire de l’OS et le répertoire du container. L’option -d c’est pour le lancer en mode démon. L’option –name c’est pour lui donner un nom ce qui est plus pratique ensuite pour les stop/start…

Voici donc le script qui va générer le fichier de haxproxy :

[root@localhost ~]# cat build_haproxy.bash 
#!/bin/bash
echo "Debut du script"
echo "global" > /docker/app/haproxy.cfg
echo "    maxconn 400 " >> /docker/app/haproxy.cfg
echo " " >> /docker/app/haproxy.cfg
echo "defaults" >> /docker/app/haproxy.cfg
echo "    log 127.0.0.1 local5 debug" >> /docker/app/haproxy.cfg
echo "    mode    tcp" >> /docker/app/haproxy.cfg
echo "    retries 4" >> /docker/app/haproxy.cfg
echo "    maxconn 200" >> /docker/app/haproxy.cfg
echo "    timeout connect  5000" >> /docker/app/haproxy.cfg
echo "    timeout client  50000" >> /docker/app/haproxy.cfg
echo "    timeout server  50000" >> /docker/app/haproxy.cfg
echo "" >> /docker/app/haproxy.cfg
echo "frontend http-in" >> /docker/app/haproxy.cfg
echo "    bind *:80" >> /docker/app/haproxy.cfg
echo "    default_backend serveur" >> /docker/app/haproxy.cfg
echo "" >> /docker/app/haproxy.cfg
echo "backend serveur" >> /docker/app/haproxy.cfg
echo "        mode tcp" >> /docker/app/haproxy.cfg
echo "        balance roundrobin" >> /docker/app/haproxy.cfg
cd /docker/app/server/
i=0
for inode in $(ls -R)
do
if
    [ -d $inode ]
then
    status="KO"
    cd $inode 
    for filename in $(ls -R)
    do
	  if
	     [ -f $filename ]
	  then
	    if [ $filename = "status" ]
	      then
	      status=$(cat /docker/app/server/$inode/$filename)
	      haproxy=$(cat /docker/app/server/$inode/haproxy)	 
	      haproxy2=$(echo $haproxy | sed "s/eth0/server$inode/g")
            fi	
          fi
    done	
    if [ $status = "OK" ]
      then
      echo "Status is OK"
      echo $haproxy2 >> /docker/app/haproxy.cfg
    fi
    cd /docker/app/server/
fi
done
echo "Fin du script";
[root@localhost ~]# ./build_haproxy.bash 
Debut du script
Status is OK
Status is OK
Fin du script
[root@localhost ~]# cat /docker/app/haproxy.cfg 
global
    maxconn 400 
 
defaults
    log 127.0.0.1 local5 debug
    mode    tcp
    retries 4
    maxconn 200
    timeout connect  5000
    timeout client  50000
    timeout server  50000

frontend http-in
    bind *:80
    default_backend serveur

backend serveur
        mode tcp
        balance roundrobin
server server1 172.17.0.9:80
server server2 172.17.0.10:80

Maintenant il me faut faire un script qui regarde s’il y a un nouveau serveur server7 et un script qui fait un stop/start de mon haproxy. Et au passage il faut que mon nouveau haproxy pointe vers /docker/app/haproxy.cfg (option -v).

Avec cette architecture il est très simple de faire un script pour connaitre toutes les versions, ou alors un script pour connaitre la charge, ou encore un script pour passer tous les serveurs en mode debug. On pourrait alors imaginer que si on dépasse une certaine charge alors on se met à lancer de nouveau server7 et si on est en dessous d’une certaine charge alors on stoppe des server7. On va s’amuser 🙂 . Il y a déjà des solutions qui existent pour faire cela mais elle me semble complexe à mettre en oeuvre.

Un petit exemple :

[root@localhost ~]# cat view_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";
echo "Fin du script";
[root@localhost ~]# ./view_load.bash 
Status is OK for 1: max 5 load 0
Status is OK for 2: max 5 load 0
La charge actuelle est de 0/10
Fin du script

Docker : le douzième pas.

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

Maintenant je pense que je vais travailler avec confd et etcd pour faire de la reconfiguration dynamique du serveur HAproxy. L’idée c’est que les etcd informent le confd des changements, et si changement il y a le confd refait le fichier de configuration haproxy.cfg. Puis il relance HAproxy.

Capture d’écran 2016-04-27 à 08.10.40

Je n’ai pas trouvé de confd sous Oracle Linux 🙁 . C’est dommage car cela paraissait simple il fallait simplement faire des templates /etc/confd/conf.d/mon-server.toml :

[template]
src = "haproxy.cfg.tmpl"
dest = "/etc/haproxy/haproxy.cfg"
keys = [
"/app/servers",
]
reload_cmd = "docker restart mon-haproxy-v15b"

Et un autre fichier qui devait être le template /etc/confd/templates/haproxy.cfg.tmpl :

global
    maxconn 400

defaults
    log 127.0.0.1 local5 notice
    mode    tcp
    retries 5
    maxconn 200
    timeout connect  5000
    timeout client  50000
    timeout server  50000

frontend http-in
    bind *:80
    default_backend serveur

backend serveur
  mode tcp
  balance roundrobin
  {{range $server := .app_servers}}
  server {{Base $server.Key}} {{$server.Value}} check
  {{end}}

Mais visiblement il n’y a pas de confd 🙁 , je vais donc chercher un équivalent. Ou alors je refais l’installation à partir d’une débina ou mieux CoreOS.

Docker : le onzième pas.

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

Petit résumé rapide de mes précédents posts, à noter que grâce au tag Docker on peut retrouver tous les articles sur le sujet.

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.

Il y a eu des hauts des des bas dans cette découverte de Docker.

Maintenant je reviens sur les tests de hier, je me demande si c’est pas ma configuration du kernel qui faisait que le programme de stress ralentissait. Je fais donc les modifications suivantes :

[root@localhost ~]# cat /proc/sys/net/ipv4/tcp_fin_timeout
60
[root@localhost ~]# cat /proc/sys/net/ipv4/tcp_tw_recycle
0
[root@localhost ~]# cat /proc/sys/net/ipv4/tcp_tw_reuse
0
[root@localhost ~]# echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout
[root@localhost ~]# echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
[root@localhost ~]# echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

Maintenant je vais recycler plus vite les sockets. Par contre je vais me remettre sur HAproxy qui me semble plus fiable.

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                         NAMES
b37844241909        nginx               "nginx -g 'daemon off"   54 minutes ago      Up 54 minutes       0.0.0.0:80->80/tcp, 443/tcp   mon-nginx-v7
eb76431e86e0        my-server5          "/sbin/server5"          About an hour ago   Up About an hour    0.0.0.0:8083->80/tcp          my-server4-4
1e87ae6b009b        my-server5          "/sbin/server5"          About an hour ago   Up About an hour    0.0.0.0:8082->80/tcp          my-server4-3
5b9099ae80d0        my-server5          "/sbin/server5"          About an hour ago   Up About an hour    0.0.0.0:8081->80/tcp          my-server4-2
4fb8f79456af        my-server5          "/sbin/server5"          About an hour ago   Up About an hour    0.0.0.0:8080->80/tcp          my-server4-1
2fc533c55725        postgres            "/docker-entrypoint.s"   24 hours ago        Up 24 hours         0.0.0.0:5432->5432/tcp        postgres2
[root@localhost ~]# docker stop b37844241909
b37844241909
[root@localhost ~]# docker start 1f22de2c194b
1f22de2c194b
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
1f22de2c194b        my-haproxy-v15      "/docker-entrypoint.s"   About an hour ago   Up 3 seconds        0.0.0.0:80->80/tcp       mon-haproxy-v15b
eb76431e86e0        my-server5          "/sbin/server5"          About an hour ago   Up About an hour    0.0.0.0:8083->80/tcp     my-server4-4
1e87ae6b009b        my-server5          "/sbin/server5"          About an hour ago   Up About an hour    0.0.0.0:8082->80/tcp     my-server4-3
5b9099ae80d0        my-server5          "/sbin/server5"          About an hour ago   Up About an hour    0.0.0.0:8081->80/tcp     my-server4-2
4fb8f79456af        my-server5          "/sbin/server5"          About an hour ago   Up About an hour    0.0.0.0:8080->80/tcp     my-server4-1
2fc533c55725        postgres            "/docker-entrypoint.s"   24 hours ago        Up 24 hours         0.0.0.0:5432->5432/tcp   postgres2
[root@localhost ~]# ./client_stress localhost 80
Start 
Nombre 500 le temps 1 
Nombre 1000 le temps 3 
Nombre 1500 le temps 5 
Nombre 2000 le temps 9 
Nombre 2500 le temps 11 
Nombre 3000 le temps 13 
Nombre 3500 le temps 15 
Nombre 4000 le temps 17 
Nombre 4500 le temps 20 
Nombre 5000 le temps 23 
Nombre 5500 le temps 25 
Nombre 6000 le temps 28 
Nombre 6500 le temps 31 
Nombre 7000 le temps 34 
Nombre 7500 le temps 37 
Nombre 8000 le temps 39 
Nombre 8500 le temps 41 
Nombre 9000 le temps 45 
Nombre 9500 le temps 50 
Nombre 10000 le temps 65 
Nombre 10500 le temps 81 
Nombre 11000 le temps 83 
Nombre 11500 le temps 89 
Nombre 12000 le temps 104 

Perdu ce n’est pas linéaire, mais la piste était bonne 🙂 . Si je regarde à partir d’un autre terminal je n’ai pas énormément de sessions ouvertes :

[root@localhost ~]# netstat -nat | awk '{print $6}' | sort | uniq -c | sort -n
      1 Adresse
      1 établies)
      7 ESTABLISHED
     12 LISTEN
     23 CLOSE_WAIT
     23 FIN_WAIT2
     26 SYN_SENT
    109 TIME_WAIT

Je vais refaire une passe sur syslog, si je stoppe mon HAproxy et que je lance le server5.

[root@localhost ~]# docker stop 1f22de2c194b
1f22de2c194b
[root@localhost ~]# ./server5 
Default interface is : enp0s3 
Local ip is : 192.168.10.159 
POSTGRES2_PORT_5432_TCP_ADDR : (null) 
OK : Table STATISTIQUE 
^C
[root@localhost ~]# tail -f /var/log/messages -n2
Apr 15 20:31:28 localhost server5[12140]: Local mode
Apr 15 20:31:28 localhost server5[12140]: End of check of table

J’ai bien des logs dans le syslog.

Maintenant je vais rediriger mon syslog, pour cela je lance un nouveau server :

[root@localhost ~]# docker run -p 8084:80 --link postgres2:postgres2 --name my-server4-5 --log-driver=syslog --log-opt syslog-address=udp://127.0.0.1:514 --log-opt syslog-facility=daemon  -d my-server5 
6b6b20000ee28f2b5ef5d634537be21ef3a493c7f83c233ed57b08b14fecbc1a

Mais si je fais un tail dans le syslog local je n’ai rien 🙁 . Je vais donc employer les grands moyen et mettre tcpdump sur mon serveur.

[root@localhost ~]# yum install tcpdump
...
[root@localhost ~]# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "55fda48e57b67e66f6c0a55a123956056b9eb2c9dec518dbab92f946bc52a4c6",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16"
                }
            ]
        },
        "Internal": false,
        "Containers": {
            "1e87ae6b009be77a8795620aada0855b23f309d427f3d30ba9b822b09e98ae57": {
                "Name": "my-server4-3",
                "EndpointID": "2a4cd8aba5d7e3440b100e9056eba4e7b22eb9a0959785849839404306cd4cf0",
                "MacAddress": "02:42:ac:11:00:05",
                "IPv4Address": "172.17.0.5/16",
                "IPv6Address": ""
            },
            "2fc533c557259f65236a97e1e4eb7123867d4c0e0cae784a620cc9c96e55c168": {
                "Name": "postgres2",
                "EndpointID": "7b73488b725254d34f441cb5df7b621379ac762f8a3c3d49a8577a3f25959cdd",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "4fb8f79456af940d23ecd9913cb737326d2f9e9dc61ecb09e3ad99c669b57543": {
                "Name": "my-server4-1",
                "EndpointID": "8f6807afc74bcc0cae68960dc42736bf4556653164a2125570b4ebd049210b72",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "5b9099ae80d024518259d65c3519b05149164e4f0f8a1a7959ec17f032724a0c": {
                "Name": "my-server4-2",
                "EndpointID": "0a1844d89e32d8e8fe2b0dd741f3853657e6e44e85c3b54d060d0f1b7e446465",
                "MacAddress": "02:42:ac:11:00:04",
                "IPv4Address": "172.17.0.4/16",
                "IPv6Address": ""
            },
            "6b6b20000ee28f2b5ef5d634537be21ef3a493c7f83c233ed57b08b14fecbc1a": {
                "Name": "my-server4-5",
                "EndpointID": "43c1655064f132964f0d4b2c02a9061f74beaea77ee3b9005d39ac721b67006b",
                "MacAddress": "02:42:ac:11:00:07",
                "IPv4Address": "172.17.0.7/16",
                "IPv6Address": ""
            },
            "eb76431e86e0b7519e8314e93b5e8a48acfb2a26e60305564ccc1c35a69b2907": {
                "Name": "my-server4-4",
                "EndpointID": "77d41c7ac4d85291e586aaa07f21383eb3c64cb50650f18d6a2e2f93a77ce722",
                "MacAddress": "02:42:ac:11:00:06",
                "IPv4Address": "172.17.0.6/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
[root@localhost ~]# tcpdump udp port 514 -i docker0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size 65535 bytes

Dans une autre fenêtre :

[root@localhost ~]# docker stop 6b6b20000ee2
6b6b20000ee2
[root@localhost ~]# docker start 6b6b20000ee2
6b6b20000ee2

Idem si j’écoute sur local :

[root@localhost ~]# tcpdump udp port 514 -i lo
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size 65535 bytes

On va reprendre plus simple, normalement avec cette commande je devrais avoir un message dans /var/log/messages :

[root@localhost ~]# docker run -d --log-driver=syslog --log-opt tag="super" ubuntu echo "mon test syslog"
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
72b39c1d4615: Pull complete 
46a2d5ede4a6: Pull complete 
d7caf6e91ad4: Pull complete 
c7ac9f284354: Pull complete 
a3ed95caeb02: Pull complete 
Digest: sha256:c77ff4fba908a2d4a366d893e1a08b63271483fefd4d50b3d96909550ae3aae9
Status: Downloaded newer image for ubuntu:latest
729856be0fc4594aef9a6d77087b0a09f65dca9e180a5f42da2133aa3191551e

Normalement j’ai « mon test syslog »

[root@localhost ~]# grep "mon test" /var/log/messages 
Apr 15 21:29:23 localhost docker/super[856]: mon test syslog

Oups je viens de comprendre … j’avais modifié la configuration de mon rsyslog avec ceci :

# Save boot messages also to boot.log
local7.*                                                /var/log/boot.log
local0.*                                                /var/log/docker-0.log
local1.*                                                /var/log/docker-1.log
local5.*                                                /var/log/docker-5.log

Mais je n’ai rien via les containers …

Je reprends donc avec mon test précédent :

[root@localhost ~]# docker run -p 8084:80 --link postgres2:postgres2 --name my-server4-5 --log-driver=syslog --log-opt tag="my-server4-5"  -d my-server5 
a814b5991a873102d3d7d07a0786e44c5c3d6a701252a953bf7e6b6a7ce36321
[root@localhost ~]# grep "my-server4-5" /var/log/*

Je dois pas faire le printf sur le bon flux, je vais donc faire :

fprintf (stdout,"Default interface is : %s \n", p);

à la place de

printf ("Default interface is : %s \n", p);

Mais aussi :

fprintf (stderr,"Socket error");

à la place de

perror("Socket error");

Normalement de printf(«  ») c’est pareil que le fprintf(stdout, » ») mais comme je doute de tout…
Voici donc ce que donne le server6.c :

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include "libpq-fe.h"
#include <syslog.h>

#define MYPORT 80
#define BACKLOG 5
#define MAXCLIENTS 5
#define MAXDATASIZE 100

long
getMicrotime ()
{
  struct timeval currentTime;
  gettimeofday (&currentTime, NULL);
  return currentTime.tv_sec * (int) 1e6 + currentTime.tv_usec;
}

int
main (void)
{
  int sockfd = -1, new_fd, numbytes, highest = 0, i;
  int clients[MAXCLIENTS];
  long clients_t[MAXCLIENTS];
  char clients_ip[MAXCLIENTS][MAXDATASIZE];
  char buffer[MAXDATASIZE];
  char localip[MAXDATASIZE];
  struct sockaddr_in my_addr, their_addr;
  socklen_t sin_size;
  struct timeval tv;
  fd_set readfds;
  char conninfo[MAXDATASIZE];
  PGconn *conn;
  PGresult *res;
  FILE *f;
  char line[100], *p, *c;
  const char *google_dns_server = "8.8.8.8";
  int dns_port = 53;
  struct sockaddr_in serv;
  int sock = socket (AF_INET, SOCK_DGRAM, 0);

  setlogmask (LOG_UPTO (LOG_NOTICE));

  openlog ("server5", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);

  f = fopen ("/proc/net/route", "r");

  while (fgets (line, 100, f))
    {
      p = strtok (line, " \t");
      c = strtok (NULL, " \t");

      if (p != NULL && c != NULL)
	{
	  if (strcmp (c, "00000000") == 0)
	    {
	      fprintf (stdout,"Default interface is : %s \n", p);
	      break;
	    }
	}
    }

  if (sock < 0)
    {
      fprintf (stderr,"Socket error\n"); 
      syslog (LOG_ERR, "Error on socket");
      closelog ();
    }

  memset (&serv, 0, sizeof (serv));
  serv.sin_family = AF_INET;
  serv.sin_addr.s_addr = inet_addr (google_dns_server);
  serv.sin_port = htons (dns_port);

  int err = connect (sock, (const struct sockaddr *) &serv, sizeof (serv));

  struct sockaddr_in name;
  socklen_t namelen = sizeof (name);
  err = getsockname (sock, (struct sockaddr *) &name, &namelen);

  const char *p2 = inet_ntop (AF_INET, &name.sin_addr, localip, 100);

  if (p2 != NULL)
    {
      fprintf (stdout,"Local ip is : %s \n", localip);
    }
  else
    {
      fprintf (stdout,"Error number : %d . Error message : %s \n", errno,
	      strerror (errno));
      strcpy (localip, "Error");
    }

  close (sock);

  fprintf (stdout,"POSTGRES2_PORT_5432_TCP_ADDR : %s \n",
	  getenv ("POSTGRES2_PORT_5432_TCP_ADDR"));

  if (getenv ("POSTGRES2_PORT_5432_TCP_ADDR") == NULL)
    {
      sprintf (conninfo, "hostaddr=%s port=%s user=postgres password=%s",
	       "127.0.0.1", "5432", "password");
      syslog (LOG_NOTICE, "Local mode");
    }
  else
    {
      sprintf (conninfo, "hostaddr=%s port=%s user=postgres password=%s",
	       getenv ("POSTGRES2_PORT_5432_TCP_ADDR"),
	       getenv ("POSTGRES2_PORT_5432_TCP_PORT"),
	       getenv ("POSTGRES2_ENV_POSTGRES_PASSWORD"));
      syslog (LOG_NOTICE, "Docker mode");
    }

  /* Ceinture et breteille */
  fprintf(stdout,"Stdout is descriptor %d\n", fileno(stdout));
  fprintf(stdout,"Stderr is descriptor %d\n", fileno(stderr));
  freopen("/dev/stdout", "w", stdout);
  freopen("/dev/stderr", "w", stderr);
  fprintf(stdout,"Stdout is descriptor %d\n", fileno(stdout));
  fprintf(stdout,"Stderr is descriptor %d\n", fileno(stderr));

  conn = PQconnectdb (conninfo);
  if (PQstatus (conn) != CONNECTION_OK)
    {
      fprintf (stderr,
	       "Connection to database failed: %s \n", PQerrorMessage (conn));
    }
  else
    {
      res = PQexec (conn, "select count(*) from STATISTIQUE;");
      if (PQresultStatus (res) != PGRES_TUPLES_OK)
	{
	  fprintf (stdout, "KO : Table STATISTIQUE \n");
	  PQclear (res);
	  res =
	    PQexec (conn,
		    "CREATE TABLE STATISTIQUE ( ID serial primary key, CLIENT CHAR(20) NOT NULL, SERVER CHAR(20) NOT NULL, TEMPS_MILLI INT NOT NULL, TEMPS_CUR INT);");
	  if (PQresultStatus (res) != PGRES_COMMAND_OK)
	    {
	      fprintf (stdout, "KO : Table STATISTIQUE (CREATE) \n");
	      PQclear (res);
	    }
	  else
	    {
	      fprintf (stdout,"OK : Table STATISTIQUE (CREATE) \n");
	      PQclear (res);
	    }
	}
      else
	{
	  fprintf (stdout,"OK : Table STATISTIQUE \n");
	  PQclear (res);
	}
    }
  PQfinish (conn);

  syslog (LOG_NOTICE, "End of check of table");

  if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
    {
      fprintf (stderr, "socket error\n");
      syslog (LOG_ERR, "Error on socket");
      closelog ();
      exit (-1);
    }
  my_addr.sin_family = AF_INET;
  my_addr.sin_port = htons (MYPORT);
  my_addr.sin_addr.s_addr = INADDR_ANY;
  bzero (&(my_addr.sin_zero), 8);

  if (bind (sockfd, (struct sockaddr *) &my_addr, sizeof (struct sockaddr)) ==
      -1)
    {
      fprintf (stderr, "bind error\n");
      syslog (LOG_ERR, "Error on bind");
      closelog ();
      exit (-1);
    }
  if (listen (sockfd, BACKLOG) == -1)
    {
      fprintf (stderr, "listen error\n");
      syslog (LOG_ERR, "Error on listen");
      closelog ();
      exit (-1);
    }
  bzero (clients, sizeof (clients));
  highest = sockfd;
  while (1)
    {
      sin_size = sizeof (struct sockaddr_in);
      tv.tv_sec = 0;
      tv.tv_usec = 250000;
      FD_ZERO (&readfds);
      for (i = 0; i < MAXCLIENTS; i++) { if (clients[i] != 0) { FD_SET (clients[i], &readfds); } } FD_SET (sockfd, &readfds); if (select (highest + 1, &readfds, NULL, NULL, &tv) >= 0)
	{
	  if (FD_ISSET (sockfd, &readfds))
	    {
	      if ((new_fd =
		   accept (sockfd, (struct sockaddr *) &their_addr,
			   &sin_size)) == -1)
		{
		  fprintf (stderr, "accept error\n");
		  syslog (LOG_ERR, "Error on accept");
		  continue;
		}
	      for (i = 0; i < MAXCLIENTS; i++) { if (clients[i] == 0) { clients[i] = new_fd; clients_t[i] = getMicrotime (); break; } } if (i != MAXCLIENTS) { if (new_fd > highest)
		    {
		      highest = clients[i];
		    }
		  fprintf (stdout,"Connexion received from %s (slot %i) ",
			  inet_ntoa (their_addr.sin_addr), i);
		  strcpy (clients_ip[i], inet_ntoa (their_addr.sin_addr));
		  syslog (LOG_NOTICE, "Connexion received from %s (slot %i) ",
			  inet_ntoa (their_addr.sin_addr), i);
		  send (new_fd, "\nHELLO\n", 7, MSG_NOSIGNAL);
		}
	      else
		{
		  send (new_fd, "\nTOO MANY CLIENT\n", 17, MSG_NOSIGNAL);
		  close (new_fd);
		}
	    }
	  for (i = 0; i < MAXCLIENTS; i++)
	    {
	      if (FD_ISSET (clients[i], &readfds))
		{
		  if ((numbytes =
		       recv (clients[i], buffer, MAXDATASIZE, 0)) <= 0)
		    {
		      fprintf (stdout,"Connexion lost from slot %i", i);
		      syslog (LOG_NOTICE, "Connexion lost from slot %i", i);
		      close (clients[i]);
		      clients[i] = 0;
		    }
		  else
		    {
		      buffer[numbytes] = '\0';
		      fprintf (stdout,"Received from slot %i : %s", i, buffer);
		      syslog (LOG_NOTICE, "Received from slot %i : %s", i,
			      buffer);
		      if (strncmp (buffer, "POSTGRES", 6) == 0)
			{
			  conn = PQconnectdb (conninfo);
			  if (PQstatus (conn) != CONNECTION_OK)
			    {
			      fprintf (stderr,
				       "Connection to database failed: %s \n",
				       PQerrorMessage (conn));
			      send (new_fd, "\nDB KO\n", 7, MSG_NOSIGNAL);
			      syslog (LOG_ALERT,
				      "Connection to database failed: %s",
				      PQerrorMessage (conn));
			    }
			  else
			    {
			      send (new_fd, "\nDB OK\n", 7, MSG_NOSIGNAL);
			    }
			  PQfinish (conn);
			}
		      if (strncmp (buffer, "DBINSERT", 6) == 0)
			{
			  conn = PQconnectdb (conninfo);
			  if (PQstatus (conn) != CONNECTION_OK)
			    {
			      fprintf (stderr,
				       "Connection to database failed: %s \n",
				       PQerrorMessage (conn));
			      send (new_fd, "\nDBINSERT KO (1)\n", 16,
				    MSG_NOSIGNAL);
			      syslog (LOG_ALERT,
				      "Connection to database failed: %s",
				      PQerrorMessage (conn));
			    }
			  else
			    {
			      char query_string[256];
			      send (new_fd, "\nDBINSERT OK\n", 7,
				    MSG_NOSIGNAL);
			      sprintf (query_string,
				       "INSERT INTO STATISTIQUE (CLIENT,SERVER,TEMPS_MILLI,TEMPS_CUR) VALUES ('%s','%s','%ld','%ld')",
				       clients_ip[i], localip,
				       getMicrotime () - clients_t[i],
				       time (0));
			      res = PQexec (conn, query_string);
			      if (PQresultStatus (res) != PGRES_COMMAND_OK)
				{
				  send (new_fd, "\nDBINSERT KO (2)\n", 16,
					MSG_NOSIGNAL);
				  send (new_fd, query_string, strlen(query_string), MSG_NOSIGNAL);
				  send (new_fd, "\n", 1, MSG_NOSIGNAL);
				  PQclear (res);
				}
			      else
				{
				  send (new_fd, "\nDBINSERT OK (1)\n", 16,
					MSG_NOSIGNAL);
				  PQclear (res);
				}
			    }
			  PQfinish (conn);
			}
		      if ((strncmp (buffer, "QUIT", 4) == 0))
			{
			  fprintf (stdout,"Connexion QUIT from slot %i \n", i);
			  syslog (LOG_NOTICE,
				  "End of cnx : QUIT (slot n°%i)", i);
			  close (clients[i]);
			  clients[i] = 0;
			}
		      if ((strncmp (buffer, "TIME", 4) == 0))
			{
			  fprintf (stdout,"TIME from slot %i : %ld ms \n", i,
				  getMicrotime () - clients_t[i]);
			}
		      if ((strncmp (buffer, "EXIT", 4) == 0))
			{
			  fprintf (stdout,"Connexion EXIT from slot %i \n", i);
			  syslog (LOG_NOTICE,
				  "End of cnx : EXIT (slot n°%i)", i);
			  close (clients[i]);
			  clients[i] = 0;
			}
		      if ((strncmp (buffer, "CLOSE", 5) == 0))
			{
			  fprintf (stdout,"Connexion CLOSE from slot %i \n", i);
			  syslog (LOG_NOTICE,
				  "End of cnx : CLOSE (slot n°%i)", i);
			  close (clients[i]);
			  clients[i] = 0;
			}
		      if ((strncmp (buffer, "INTERFACE", 9) == 0))
			{
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			  send (new_fd, localip, strlen (localip),
				MSG_NOSIGNAL);
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			}
		      if ((strncmp (buffer, "IP", 2) == 0))
			{
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			  send (new_fd, p, strlen (p), MSG_NOSIGNAL);
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			}
		      if ((strncmp (buffer, "CLIENT", 6) == 0))
			{
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			  send (new_fd, clients_ip[i], strlen (clients_ip[i]),
				MSG_NOSIGNAL);
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			}
		      if ((strncmp (buffer, "DBCNX", 2) == 0))
			{
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			  send (new_fd, conninfo, strlen (conninfo),
				MSG_NOSIGNAL);
			  send (new_fd, "\n", 1, MSG_NOSIGNAL);
			}
		    }
		}
	    }
	}
      else
	{
	  fprintf (stderr, "select error\n");
	  syslog (LOG_ERR, "Error on select");
	  continue;
	}
    }
  return 0;
}

Quand on lance le programme on voit bien que « ceinture et bretelle » ne sert à rien :

[root@localhost ~]# ./server6
Default interface is : enp0s3 
Local ip is : 192.168.10.159 
POSTGRES2_PORT_5432_TCP_ADDR : (null) 
Stdout is descriptor 1
Stderr is descriptor 2
Stdout is descriptor 1
Stderr is descriptor 2
OK : Table STATISTIQUE 

Compilation, build, run …

[root@localhost ~]# gcc -o server6 server6.c -lpq
[root@localhost ~]# docker build -t my-server6 .
[root@localhost ~]# docker run -p 8085:80 --link postgres2:postgres2 --name my-server6-1 --log-driver=syslog --log-opt tag="my-server6-1"  -d my-server6 
2912a5b6f004d75e9c91e74e133a0934497269abb06d1036650adfbb9c9c9744
[root@localhost ~]# grep "my-server6" /var/log/*
grep: /var/log/anaconda: est un dossier
grep: /var/log/audit: est un dossier
/var/log/messages:Apr 15 22:37:00 localhost docker/my-server6-1[856]: Default interface is : eth0
/var/log/messages:Apr 15 22:37:00 localhost docker/my-server6-1[856]: Local ip is : 172.17.0.8
/var/log/messages:Apr 15 22:37:00 localhost docker/my-server6-1[856]: POSTGRES2_PORT_5432_TCP_ADDR : 172.17.0.2
/var/log/messages:Apr 15 22:37:00 localhost docker/my-server6-1[856]: Stdout is descriptor 1
/var/log/messages:Apr 15 22:37:00 localhost docker/my-server6-1[856]: Stderr is descriptor 2

Super cela fonctionne, j’ai bien les logs dans syslog maintenant. Mais j’ai du mal à comprendre pourquoi cela n’était pas le cas avant …
A noter que la commande logs ne fonctionne pas dans le cas d’une configuration syslog.

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
2912a5b6f004        my-server6          "/sbin/server6"          3 minutes ago       Up 3 minutes        0.0.0.0:8085->80/tcp     my-server6-1
a814b5991a87        my-server5          "/sbin/server5"          About an hour ago   Up About an hour    0.0.0.0:8084->80/tcp     my-server4-5
eb76431e86e0        my-server5          "/sbin/server5"          4 hours ago         Up 4 hours          0.0.0.0:8083->80/tcp     my-server4-4
1e87ae6b009b        my-server5          "/sbin/server5"          4 hours ago         Up 4 hours          0.0.0.0:8082->80/tcp     my-server4-3
5b9099ae80d0        my-server5          "/sbin/server5"          4 hours ago         Up 4 hours          0.0.0.0:8081->80/tcp     my-server4-2
4fb8f79456af        my-server5          "/sbin/server5"          4 hours ago         Up 4 hours          0.0.0.0:8080->80/tcp     my-server4-1
2fc533c55725        postgres            "/docker-entrypoint.s"   26 hours ago        Up 26 hours         0.0.0.0:5432->5432/tcp   postgres2
[root@localhost ~]# docker logs 2912a5b6f004
"logs" command is supported only for "json-file" and "journald" logging drivers (got: syslog)

C’est fini pour aujourd’hui.