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

Laisser un commentaire

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

Time limit is exhausted. Please reload CAPTCHA.