---
title: "Docker : le sixième pas."
url: https://www.cyber-neurones.org/2016/04/docker-le-sixieme-pas/
date: 2016-04-20
modified: 2017-09-06
author: "Frederic"
description: "Attention ceci est mon brouillon avant de faire une belle documentation sur Docker (il y a à boire et à manger).  On passe donc à l'étape de l'installation de HAProxy,..."
categories:
  - "Docker"
tags:
  - "Docker"
  - "haproxy"
  - "PostgreSQL"
word_count: 1861
---

# Docker : le sixième pas.

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

On passe donc à l'étape de l'installation de **HAProxy**, l'installation cible est la suivante (il va falloir que j'améliore mon **server.c** (que l'on va appeler **server2.c**) afin d'avoir une connexion avec la base de donnée):

[![Capture d’écran 2016-04-20 à 14.47.21](https://www.cyber-neurones.org/wp-content/uploads/2016/04/cyber-neurones_capture-d’ecran-2016-04-20-a-14.47.21.png)](https://www.cyber-neurones.org/wp-content/uploads/2016/04/cyber-neurones_capture-d’ecran-2016-04-20-a-14.47.21.png)Voici un nouveau **server2.c** , mais avant cela il faut installer le RPM qui permet de faire de dev :
[root@localhost ~]# **yum install postgresql-devel
**
Pour compiler il va falloir appeler la librairie pq (pour postgresql), cela donne donc :
[root@localhost ~]# **gcc -o server2 server2.c -lpq
**
J'ai donc ajouter dans le programme :
**-un bout de code afin de voir quel est l'interface locale**
**-un bout de code afin de voir quel est l'ip locale.**
**-un bout de code pour couper la communication via QUIT, EXIT, CLOSE.**
**-un bout de code pour se connecter à la base de donnée.**
**-un bout de code pour avoir des informations via le telnet.**

Le source :
#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"

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

int
main (void)
{
int sockfd = -1, new_fd, numbytes, highest = 0, i;
int clients[MAXCLIENTS];
char buffer[MAXDATASIZE];
char localip[MAXDATASIZE];
struct sockaddr_in my_addr, their_addr;
socklen_t sin_size;
struct timeval tv;
fd_set readfds;
const char *conninfo;
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);

** 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)
{
printf ("Default interface is : %s \n", p);
break;
}
}
}**

** if (sock < 0)
{
perror ("Socket error");
}**

** 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)
{
printf ("Local ip is : %s \n", localip);
}
else
{
//Some error
printf ("Error number : %d . Error message : %s \n", errno,
strerror (errno));
strcpy (localip, "Error");
}**

close (sock);

**conninfo =
"hostaddr=127.0.0.1 port=5432 dbname=postgres user=postgres password=password";**

if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("socket");
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)
{
perror ("bind");
exit (-1);
}
if (listen (sockfd, BACKLOG) == -1)
{
perror ("listen");
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)
{
perror ("ACCEPT");
continue;
}
for (i = 0; i < MAXCLIENTS; i++) { if (clients[i] == 0) { clients[i] = new_fd; break; } } if (i != MAXCLIENTS) { if (new_fd > highest)
{
highest = clients[i];
}
printf ("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)
{
printf ("Connexion lost from slot %i", i);
close (clients[i]);
clients[i] = 0;
}
else
{
buffer[numbytes] = '\0';
printf ("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",
PQerrorMessage (conn));
send (new_fd, "\nDB KO\n", 7, MSG_NOSIGNAL);
}
else
{
send (new_fd, "\nDB OK\n", 7, MSG_NOSIGNAL);
/* INSERT CLIENT IP and timestamp */
}
PQfinish (conn);**
}
** if ((strncmp (buffer, "QUIT", 4) == 0))
{
printf ("Connexion QUIT from slot %i", i);
close (clients[i]);
clients[i] = 0;
}
if ((strncmp (buffer, "EXIT", 4) == 0))
{
printf ("Connexion EXIT from slot %i", i);
close (clients[i]);
clients[i] = 0;
}
if ((strncmp (buffer, "CLOSE", 5) == 0))
{
printf ("Connexion CLOSE from slot %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, "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
{
perror ("SELECT");
continue;
}
}
return 0;
}

Un petit test, sur un terminal je lance mon ./server2 :
[root@localhost ~]# ./server2
Default interface is : enp0s3
Local ip is : 192.168.10.159
Connexion received from 127.0.0.1 (slot 0) Received from slot 0 : IP
Received from slot 0 : INTERFACE
Received from slot 0 : DB
Received from slot 0 : POSTGRES
Received from slot 0 : QUIT

Et sur l'autre terminal je fais mon telnet :

[![Capture d’écran 2016-04-20 à 15.37.53](https://www.cyber-neurones.org/wp-content/uploads/2016/04/cyber-neurones_capture-d’ecran-2016-04-20-a-15.37.53.png)](https://www.cyber-neurones.org/wp-content/uploads/2016/04/cyber-neurones_capture-d’ecran-2016-04-20-a-15.37.53.png)

Maintenant il faut faire le Dockerfile de notre nouvelle application de test.
[root@localhost ~]# **cat Dockerfile**
FROM fedora
MAINTAINER toto toto@cyber-neurones.org
COPY ./server2 /sbin/server2
RUN dnf install postgresql -y
# Le port en ecoute
EXPOSE 80
# Pour lancer postgres
CMD ["/sbin/server2"]

[root@localhost ~]# **docker build -t my-server2 .**
Sending build context to Docker daemon 81.41 kB
Step 1 : FROM fedora
---> ddd5c9c1d0f2
Step 2 : MAINTAINER toto toto@cyber-neurones.org
---> Using cache
---> bb6bc55cbbfc
Step 3 : COPY ./server2 /sbin/server2
---> Using cache
---> 9dc98bb8714f
Step 4 : RUN dnf install postgresql -y
---> Running in 6ecdbee5cb9d

Last metadata expiration check performed 0:00:40 ago on Fri Apr 15 02:43:33 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 5.7 kB/s | 1.3 MB 04:02
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!
---> db3219dbae87
Removing intermediate container 6ecdbee5cb9d
Step 5 : EXPOSE 80
---> Running in 46227ce25198
---> 0ed57fe27084
Removing intermediate container 46227ce25198
Step 6 : CMD /sbin/server2
---> Running in 1da4a2133df3
---> 2b02e0bc8c6e
Removing intermediate container 1da4a2133df3
Successfully built 2b02e0bc8c6e

Et maintenant le moment de vérité, on fait le test de notre server2 :
[root@localhost ~]# docker run -p 80:80 --name my-server2.1 -d my-server2
d7d4cb51000828388a09e5648e5b92094e5a17298d799b63b41d9511129b6211
[root@localhost ~]# telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

HELLO
IP

eth0
INTERFACE

172.17.0.3
POSTGRES

**DB KO**
DBCNX

hostaddr=127.0.0.1 port=5432 dbname=postgres user=postgres password=password
QUIT
Connection closed by foreign host.

C'est l'échec, et c'est normal :( ... on essaye de se connecter en local, alors que le local c'est le conteneur !. Il faut donc se connecter à distance c'est à dire d'un conteneur à l'autre.

Je vais donc essayer d'utiliser la commande **link** :
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2fc533c55725 postgres "/docker-entrypoint.s" 7 hours ago Up 7 hours 0.0.0.0:5432->5432/tcp **postgres2**
[root@localhost ~]# docker run -p 80:80 **--link** **postgres2**:**postgres2** --name my-server2.2 -d my-server2
1c35469315b9de3d720ee963cfffe010a8efc069ee027c4e6c7bff119ea8865e
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c35469315b9 my-server2 "/sbin/server2" 18 seconds ago Up 17 seconds 0.0.0.0:80->80/tcp my-server2.2
2fc533c55725 postgres "/docker-entrypoint.s" 7 hours ago Up 7 hours 0.0.0.0:5432->5432/tcp postgres2

Je regarde toutes les variables des deux containers afin de faire les modifications sur mon programme.
[root@localhost ~]# **docker exec 2fc533c55725 env**
PATH=/usr/lib/postgresql/9.5/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=2fc533c55725
POSTGRES_PASSWORD=password
GOSU_VERSION=1.7
LANG=en_US.utf8
PG_MAJOR=9.5
PG_VERSION=9.5.2-1.pgdg80+1
PGDATA=/var/lib/postgresql/data
HOME=/root
[root@localhost ~]# **docker exec 1c35469315b9 env**
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=1c35469315b9
POSTGRES2_PORT=tcp://172.17.0.2:5432
POSTGRES2_PORT_5432_TCP=tcp://172.17.0.2:5432
**POSTGRES2_PORT_5432_TCP_ADDR**=172.17.0.2
**POSTGRES2_PORT_5432_TCP_PORT**=5432
POSTGRES2_PORT_5432_TCP_PROTO=tcp
POSTGRES2_NAME=/my-server2.2/postgres2
**POSTGRES2_ENV_POSTGRES_PASSWORD**=password
POSTGRES2_ENV_GOSU_VERSION=1.7
POSTGRES2_ENV_LANG=en_US.utf8
POSTGRES2_ENV_PG_MAJOR=9.5
POSTGRES2_ENV_PG_VERSION=9.5.2-1.pgdg80+1
POSTGRES2_ENV_PGDATA=/var/lib/postgresql/data
HOME=/root

On va faire notre **server3.c**, on a une seule ligne à modifier :
/* Avant :
conninfo =
"hostaddr=127.0.0.1 port=5432 dbname=postgres user=postgres password=password";
Après
*/
conninfo =
"hostaddr=$POSTGRES2_PORT_5432_TCP_ADDR port=$POSTGRES2_PORT_5432_TCP_PORT user=postgres password=$POSTGRES2_ENV_POSTGRES_PASSWORD";

Ensuite modification du Dockerfile, puis build, ... le résultat :
[root@localhost ~]# telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

HELLO
DB

hostaddr=$POSTGRES2_PORT_5432_TCP_ADDR port=$POSTGRES2_PORT_5432_TCP_PORT user=postgres password=$POSTGRES2_ENV_POSTGRES_PASSWORD
POSTGRES

DB KO
QUIT
Connection closed by foreign host.

Cela aurait été trop simple ;) Donc on va utiliser un fonction pour faire cela, on va utiliser la fonction **getenv**. Les modifications dans server4.c
char conninfo[MAXDATASIZE];
...
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"));

Je pourrais même faire mieux en faisant en sorte que cela marche en local et dans le container.
printf("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", "postgres");
} 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"));
}

Le test ... le stress en cas de nouvel échec :) .
[root@localhost ~]# docker build -t my-server4 .
Sending build context to Docker daemon 129 kB
Step 1 : FROM fedora
---> ddd5c9c1d0f2
Step 2 : MAINTAINER toto toto@cyber-neurones.org
---> Using cache
---> bb6bc55cbbfc
Step 3 : COPY ./server4 /sbin/server4
---> 85cb6ab4dcea
Removing intermediate container 0f75d8dd2e32
Step 4 : RUN dnf install postgresql -y
---> Running in 3025055c6cfb
Last metadata expiration check performed 0:02:35 ago on Fri Apr 15 04:38:45 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 501 kB/s | 1.3 MB 00:02
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!
---> 9541c83ce007
Removing intermediate container 3025055c6cfb
Step 5 : EXPOSE 80
---> Running in 1ae2a911c314
---> 944016c4027e
Removing intermediate container 1ae2a911c314
Step 6 : CMD /sbin/server4
---> Running in 7ca20a5578e2
---> 4f8c8c3fc2e5
Removing intermediate container 7ca20a5578e2
Successfully built 4f8c8c3fc2e5
[root@localhost ~]# docker run -p 80:80 --link postgres2:postgres2 --name my-server4.1 -d my-server4
08c524d398afb37c4568399d9d1f7325feb1954a4ac1593dc68684aa36b65e45
[root@localhost ~]# telnet 127.0.0.1 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

HELLO
DBCNX

hostaddr=**172.17.0.2** port=5432 user=postgres password=password
IP

eth0
INTERFACE

**172.17.0.3**
POSTGRES

DB OK
QUIT
Connection closed by foreign host.

J'ai donc mon programme qui fait bien ce que je veux, maintenant il va falloir passer à HAProxy. A force de repousser je vais finir par ne pas mettre les pieds dedans. La notion de lien (option -link) était importante à connaitre afin de pouvoir faire un dialogue entre containers.