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 à confd & etc , 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 (¤tTime, 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