Els contenidors es poden connectar i comunicar-se entre ells o altres serveis mitjançant xarxes.
Introducció
Docker utilitza una interfície virtual que té el nom de docker0
que es va crear quan vas instal.lar docker.
$ ip --brief addr
lo UNKNOWN 127.0.0.1/8 ::1/128
enp1s0 UP 192.168.123.6/22 fe80::b4a1:54f4:7454:d2fd/64
enp2s0 UP 10.2.76.37/16 fe80::d18f:22b8:b29b:935c/64
docker0 DOWN 172.17.0.1/16
Quan crees un contenidor aquest es connecta a aquesta xarxa:
$ docker run --rm -d --name apache httpd
d16aea391c3efe464b3defb1aaf64e6d3e6a8321f5f0d9984e2d6104588d5ece
$ docker exec apache cat /etc/hosts
127.0.0.1 localhost
...
172.17.0.2 5311e760a9b7
En aquest cas el contenidor té l'adreça 172.17.0.2
de la xarxa 172.17.0.1/16
que pertany a la interfície virtual docker0
.
Si intentes conectar-te amb localhost
no pots, però si et connectes directament a la IP del contenidor si que pots:
$ curl localhost
curl: (7) Failed to connect to localhost port 80 after 1 ms: S’ha refusat la connexió
$ curl 172.17.0.2
<html><body><h1>It works!</h1></body></html>
Quan crees un contenidor a aquest se li pot assignar qualsevol IP de la xarxa docker0
.
És per aquest motiu que quan arrenquem un servidor web fem un port forward per poder accedir al servidor des de l'adreça localhost
amb l'opció -p 80:80
:
$ docker stop apache
apache
$ docker run --rm -d --name apache -p 80:80 httpd
3f74091860626a79951137c8734a38eb99f68337fbb8bc9f636b416e545d3e17
Ara podem accedir al servidor tant des de l'adreça 127.0.0.1
com l'adreça 172.17.0.2
:
$ curl localhost
<html><body><h1>It works!</h1></body></html>
$ curl 172.17.0.2
<html><body><h1>It works!</h1></body></html>
Això és possible perqué docker ha definit una regla a la taula nat
de Netfilter
$ sudo nft list table nat | grep 172.17.0.2:80
iifname != "docker0" meta l4proto tcp tcp dport 80 counter packets 0 bytes 0 dnat to 172.17.0.2:80
La regla diu que si un paquet tcp destinat al port 80 va a una interfície que no sigui docker0
, aquest serà redirigit a 172.17.0.2:80
.
Si elimines el contenidor pots verificar que la regla desapareix:
$ docker stop apache
apache
$ sudo nft list table nat | grep 172.17.0.2.:80
$
A continuació crearem 3 apaches:
$ docker run --rm -d --name apache1 -p 81:80 httpd
$ docker run --rm -d --name apache2 -p 82:80 httpd
$ docker run --rm -d --name apache3 -p 83:80 httpd
Pots veure les adreçes i ports on estan escoltant els servidors a la taula nat
:
$ sudo nft list table nat | grep "to 172.17.0."
iifname != "docker0" meta l4proto tcp tcp dport 81 counter packets 0 bytes 0 dnat to 172.17.0.2:80
iifname != "docker0" meta l4proto tcp tcp dport 82 counter packets 0 bytes 0 dnat to 172.17.0.3:80
iifname != "docker0" meta l4proto tcp tcp dport 83 counter packets 0 bytes 0 dnat to 172.17.0.4:80
A més, com tots els contenidors comparteixen la mateixa xarxa es poden comunicar entre ells!
Xarxes predefinides
De manera predeterminada, Docker inclou tres xarxes i cadascuna és proporcionada per un "driver" diferent:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
b3049ee1e177 bridge bridge local
df32681267cb host host local
3b3d0e4e7244 none null local
Bridge
La xarxa bridge
correspon a la intefície virtual docker0
que hem vist abans.
Host
Enlloc d’executar el contenidor en una xarxa privada pots executar-lo directament com si fos qualsevol altre procés amb l’opció --network host
.
D'aquesta manera el contenidor té accés als serveis que s’executen a localhost
i a qualsevol altre interfície del host.
Com pots veure a continuació un contenidor no té accés a les intefícies del host, només veu les seves:
$ docker run --rm alpine ip -f inet -4 -o addr
1: lo inet 127.0.0.1/8 scope host lo\ valid_lft forever preferred_lft forever
29: eth0 inet 172.17.0.5/16 brd 172.17.255.255 scope global eth0\ valid_lft forever preferred_lft forever
Pero si fem servir l'opció --network host
té accés a totes les interfícies de la màquina:
$ docker run --rm --network host alpine ip -f inet -4 -o addr
1: lo inet 127.0.0.1/8 scope host lo\ valid_lft forever preferred_lft forever
2: enp1s0 inet 192.168.123.6/22 brd 192.168.123.255 scope global dynamic noprefixroute enp1s0\ valid_lft 2485sec preferred_lft 2485sec
3: enp2s0 inet 10.2.76.37/16 brd 10.2.255.255 scope global dynamic noprefixroute enp2s0\ valid_lft 2485sec preferred_lft 2485sec
4: docker0 inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0\ valid_lft forever preferred_lft forever
També pots executar un servidor apache sense necessitat de fer un "port forward":
$ docker run --rm -d --name apache --network host httpd
e3b505083672b87298989e4f9d9665b0b260054ff4d7a2d597a76f95db6acc2e
$ curl localhost
<html><body><h1>It works!</h1></body></html>
None
També pots executar un contenidor sense que tingui accés a xarxa:
La única interfície que té és localhost
:
$ docker run --rm --network none alpine cat /etc/hosts
127.0.0.1 localhost
Pots verificar que el contenidor no es pot connectar a l’exterior:
$ docker run --rm --network none alpine ping -c 1 google.es
ping: bad address 'google.es'
A diferència d'un contenidor connectat a una xarxa bridge
o host
:
$ docker run --rm alpine ping -c 1 google.es
PING google.es (142.250.185.227): 56 data bytes
64 bytes from 142.250.185.227: seq=0 ttl=117 time=1.258 ms
--- google.es ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 1.258/1.258/1.258 ms
NodePort
Fins ara no haviem explicat res de la interficie bridge i només et deiem que afegixis l’opció -p 80:80
.
Quan crees un contenidor pots configurar diversos "port forward" amb l’opció -p
(o --publish
), i no es poden canviar més endavant.
L’opció -p
necessitat com argument la interfície de l'amfitrió, el port de l'amfitrió, el port de destinació i el protocol de port.
Per exemple, cadascuna d'aquestes opcions reenviarà el port TCP 8080 des de totes les interfícies d'amfitrió al port TCP 8080 del nou contenidor.
-p 0.0.0.0:8080:8080/tcp
-p 8080:8080/tcp
-p 8080:8080
El primer argument és la forma completa.
Exemple
En aquest exemple fem un "port forward2 del port 80 de interficie 0.0.0.0 al port 80 de la IP 172.17.0.x
.
$ docker run --rm -d --name apache -p 80:80 httpd
735cea84eccd6d4829eefd776e28f8ad9f550ca8fa2b7d9af4ba01a0deb9eda9
$ curl localhost
<html><body><h1>It works!</h1></body></html>
$ curl localhost:80
<html><body><h1>It works!</h1></body></html>
Perquè diem a la interfície 172.17.0.x
? Perquè el contenidor estarà connectat a la xarxa bridge, però no sabem quina serà la IP que se li assignarà i ens és indiferent.
Si vols saber quina és la IP exacta mira el fitxer /etc/hosts
:
$ docker exec apache cat /etc/hosts | grep 172
172.17.0.2 fd2c0cd862d5
$ curl 172.17.0.2
<html><body><h1>It works!</h1></body></html>
$ docker stop apache
apache
Per què aquest exemple no funciona?
$ docker run --rm -d --name apache -p 80:8000 httpd
2a2c233c194d5f7c92a6f54213cdd952a692832fc0439fd571486a5d4b1a4192
$ curl localhost
curl: (56) Recv failure: La màquina remota ha reiniciat la connexió
Perquè apache està escoltant al port 80 de la IP 172.17.0.x
i no al port 8000.
$ docker exec -it apache bash
... $ apt update && apt install -y nmap
... $ nmap localhost
...
PORT STATE SERVICE
80/tcp open http
$ exit
exit
$ docker stop apache
apache
Per què aquest exemple no funciona?
$ docker run --rm -d --name apache -p 80:80/udp httpd
899d341907378ea811ac519e47b87e9c6debbb7401b5bf2cf3c687415df77d60
$ curl localhost
curl: (7) Failed to connect to localhost port 80 after 0 ms: S’ha refusat la connexió
$ docker stop apache
apache
Perquè apache està escoltant al port 80/tcp
de la IP 172.17.0.x
i no al port 80/udp
.
Recordeu:
0.0.0.0:8080:8080/tcp
8080:8080/tcp
8080:8080
Perquè aquest exemple si funciona en el port 80
, 3000
i 8000
?
$ docker run --rm -d --name apache -p 80:80 -p 3000:80 -p 8000:80 httpd
bf6cfaed3562bea6b5f35470c03210566dd657b5e19335b33b555c4678240813
$ curl localhost
<html><body><h1>It works!</h1></body></html>
$ curl localhost:3000
<html><body><h1>It works!</h1></body></html>
$ curl localhost:8000
<html><body><h1>It works!</h1></body></html>
Perquè hi ha 3 "port forwards": 80 → 80, 3000 → 80 i 8000 → 80
I això vol dir que hi ha tres regles a la taula nat
de netfilter amb port forward a la IP del contenidor al port 80
:
$ sudo nft list table nat | grep "dnat to"
iifname != "docker0" meta l4proto tcp tcp dport 8000 counter packets 0 bytes 0 dnat to 172.17.0.2:80
iifname != "docker0" meta l4proto tcp tcp dport 3000 counter packets 0 bytes 0 dnat to 172.17.0.2:80
iifname != "docker0" meta l4proto tcp tcp dport 80 counter packets 0 bytes 0 dnat to 172.17.0.2:80
Per què aquest exemple funciona en totes les interfícies del host?
$ docker run --rm -d --name apache -p 80:80 httpd
49cbdb93cfd7b09f96bbcce972ec7b54e2b7429f8c45412091852406541ba86a
$ ip --brief addr
lo UNKNOWN 127.0.0.1/8 ::1/128
enp1s0 UP 192.168.123.6/22 fe80::b4a1:54f4:7454:d2fd/64
enp2s0 UP 10.2.76.37/16 fe80::d18f:22b8:b29b:935c/64
docker0 UP 172.17.0.1/16 fe80::42:89ff:fe45:9db0/64
vethfdcf90a@if17 UP fe80::4cef:f3ff:fe98:b5a4/64
$ curl 127.0.0.1
<html><body><h1>It works!</h1></body></html>
$ curl 192.168.123.6
<html><body><h1>It works!</h1></body></html>
$ curl 10.2.76.37
<html><body><h1>It works!</h1></body></html>
$ curl 172.17.0.1
<html><body><h1>It works!</h1></body></html>
Perquè per defecte el "port forward" es fa amb la IP 0.0.0.0
, que vol dir totes.
Per què aquest exemple només funciona amb la IP 192.168.123.6
?
$ docker run --rm -d --name apache -p 192.168.123.6:80:80 httpd
739fed667dd61fbc1e9f7b5e015bd946d28d70a6c50f266e57569f29bae64486
$ curl 127.0.0.1
curl: (7) Failed to connect to 127.0.0.1 port 80 after 0 ms: S’ha refusat la connexió
$ curl 192.168.123.6
<html><body><h1>It works!</h1></body></html>
$ curl 10.2.76.37
curl: (7) Failed to connect to 10.2.76.37 port 80 after 0 ms: S’ha refusat la connexió
$ curl 172.17.0.1
curl: (7) Failed to connect to 172.17.0.1 port 80 after 0 ms: S’ha refusat la connexió
Si mirem la taula nat
...
$ sudo nft list table nat | grep "dnat to"
iifname != "docker0" meta l4proto tcp ip daddr 192.168.123.6 tcp dport 80 counter packets 1 bytes 60 dnat to 172.17.0.2:80
Port aleatori
A vegades quan tens molts contenidors funcionant només vols fer un "port forward" des de qualsevol port que estigui disponible.
En aquest cas només has de dir el port destí sobre el qual es farà el "port forward":
$ docker run --rm -d --name apache -p 80 httpd
8f962b1ebc2e338bced6e0a827a4c0d33f12479aa68128800da02c08c8b968df
$ curl localhost
curl: (7) Failed to connect to localhost port 80 after 0 ms: S’ha refusat la connexió
Podem fer un nmap
per veure en quin port està escoltant:
$ nmap localhost
...
PORT STATE SERVICE
631/tcp open ipp
3389/tcp open ms-wbt-server
32768/tcp open filenet-tms
I provar ... o mirar la taula nat
:
$ sudo nft list table nat | grep "dnat to"
iifname != "docker0" meta l4proto tcp tcp dport 32768 counter packets 0 bytes 0 dnat to 172.17.0.2:80
Doncs és el port 32768
, però si hi ha molts contenidors ...
Amb l’ordre docker port
puc conèixer en quins ports s’està fent un "port forward" a un contenidor!
$ docker port apache
80/tcp -> 0.0.0.0:32768
80/tcp -> [::]:32768
Solucionat!
$ curl localhost:32768
<html><body><h1>It works!</h1></body></html>
Xarxes definides per l’usuari
Molts contenidors no funcionen sols sinó que depenen d'altres contenidors per funcionar, i la manera de connectar aquests contenidors és mitjançat xarxes virtuals.
Les xarxes definides per l’usuari, encara que facin servir el mateix driver que la xarxa predefinida bridge
, tenen més funcions com per exemple la resolució DNS.
Crea una xarxa virtual específica amb el nom xarxa-1
:
$ docker network create --driver bridge --attachable --subnet 10.10.41.0/24 xarxa-1
10db898153b0705a54c972fa5c8f513cd4be8e8563a02f07d76eb95496a2a836
$ docker network ls | grep xarxa-1
10db898153b0 xarxa-1 bridge local
$ ip --brief addr | grep br
br-10db898153b0 UP 10.10.41.1/24 fe80::42:c7ff:fe3e:289/64
L'opció --attachable
permet connectar i desconnectar contenidors a la xarxa en qualsevol moment.
Amb l'opció --subnet
pots definir la subxarxa.
Crea un contenidor amb name explorer
que estigui connectat a la xarxa xarxa-1
i mira les interficies disponibles del contenidor:
$ docker run -d --name explorer --network xarxa-1 alpine sleep infinity
e79785bb7a564e7136258e8040b01dc24e6d67928f934ee8a30834c6766c56f0
$ docker exec explorer ip -f inet -4 -o addr
1: lo inet 127.0.0.1/8 scope host lo\ valid_lft forever preferred_lft forever
24: eth0 inet 10.10.41.2/24 brd 10.10.41.255 scope global eth0\ valid_lft forever preferred_lft forever
Amb l'opció --network
hem fet que el contenidor es vinculi a la xarxa xarxa-1
i no a docker0
.
Crea una altre xarxa virtual amb el nom xarxa-2
:
$ docker network create --driver bridge --attachable --subnet 10.10.42.0/24 xarxa-2
8afdb8106b838d541846c04cf890865ebd6e872a9a7c7ea2ed0a270c14a45fa3
$ docker network ls | grep xarxa
10db898153b0 xarxa-1 bridge local
8afdb8106b83 xarxa-2 bridge local
$ ip --brief addr | grep br
br-10db898153b0 UP 10.10.41.1/24 fe80::42:c7ff:fe3e:289/64
br-8afdb8106b83 DOWN 10.10.42.1/24
Pots veure que:
- Al host ara hi ha dos xarxes virtuals més
- Que la interfície
br-10db898153b
estàUP
(té un contenidor) i la interfíciebr-8afdb8106b83
estàDOWN
(no té cap contenidor).
Connecta el contenidor explorer
a la xarxa xarxa-2
i verifica que ara té dos interfícies eth
:
$ docker network connect xarxa-2 explorer
$ docker exec explorer ip -f inet -4 -o addr
1: lo inet 127.0.0.1/8 scope host lo\ valid_lft forever preferred_lft forever
7: eth0 inet 10.10.41.2/24 brd 10.10.41.255 scope global eth0\ valid_lft forever preferred_lft forever
9: eth1 inet 10.10.42.2/24 brd 10.10.42.255 scope global eth1\ valid_lft forever preferred_lft forever
Una xarxa només té sentit si hi ha més d’un participant.
Com podem saber si hi ha algú més? Utilitzant Nmap
Entra dins el contenidor explorer
i instal.la nmap
:
$ docker exec -it explorer sh
... $ apk update && apk add nmap
Escaneja les xarxes a les que està connectat el contenidor:
... $ more /etc/hosts | grep 10.10
10.10.41.2 4cbb41838ee0
10.10.42.2 4cbb41838ee0
... $nmap -sn 10.10.41.* -sn 10.10.42.* -oG /dev/stdout | grep Status
Host: 10.10.41.1 (ubuntu) Status: Up
Host: 10.10.41.2 (4cbb41838ee0) Status: Up
Host: 10.10.42.1 (ubuntu) Status: Up
Host: 10.10.42.2 (4cbb41838ee0) Status: Up
Pots veure que en les dos xarxes només està el contenidor i el host.
Crea un altre contenidor connecta’t a la xarxa xarxa-2
amb el nom jupyter
:
$ docker run -d --name jupyter --network xarxa-2 alpine sleep infinity
7cc41611065226f144840578d5cf0088a257482ec6fbbb14eac693eeff9f995e
Torna a executar nmap
des del contenidor explorer:
$ docker exec explorer nmap -sn 10.10.42.* -oG /dev/stdout | grep Status
Host: 10.10.42.1 (ubuntu) Status: Up
Host: 10.10.42.3 (jupyter.xarxa-2) Status: Up
Host: 10.10.42.2 (4cbb41838ee0) Status: Up
Pots veure que hi ha un nou node amb IP 10.10.42.3
i nom jupyter.xarxa-2
.
nmap
pot resoldre aquesta IP perquè hi ha un servidor DNS que resolt IPs amb el nom de contenidor.
Verifica que pots resoldre el nom jupyter
:
$ docker exec -it explorer sh
... $ nslookup jupyter
...
Name: jupyter
Address: 10.10.42.3
... $ ping -c 1 jupyter
PING jupyter (10.10.42.3): 56 data bytes
64 bytes from 10.10.42.3: seq=0 ttl=64 time=0.121 ms
...
DNS
El Sistema de noms de domini (DNS) és un protocol per assignar noms de hosts a adreces IP.
D’aquesta manera un host pot connectar-se a un altre host mitjançant un nom enlloc d’una IP.
hostname
Per defecte docker utilitza el nom del contenidor com a hostname:
$ docker run --rm --name hello --network xarxa-1 alpine nslookup hello
...
Name: hello
Address: 10.10.41.3
Recorda que la xarxa per defecte (bridge) no té resolució DNS:
$ docker run --rm --name hello alpine nslookup hello
;; connection timed out; no servers could be reached
Amb l'opció --hostname
pots especificar un altre nom alternatiu:
$ docker run --rm -it --name hello --network xarxa-2 --hostname bye alpine sh
... $ nslookup bye | grep 10
Address: 10.10.42.4
... $ nslookup hello | grep 10
Address: 10.10.42.4
bye
és un nom alternatiu a hello
!
Servidor DNS
Per defecte, el contenidor fa servir el servei DNS del host:
$ docker run --rm alpine nslookup xtec.dev
Server: 192.168.120.1
Address: 192.168.120.1:53
...
Però si vols pots crear un contenidor configurat amb un altre servidor dns També pots especificar un o més servidors DNS per utilitzar.
Per exemple, el servidor DNS 1.1.1.1
de Cloudflare:
$ docker run --rm --dns 1.1.1.1 alpine nslookup xtec.dev
Server: 1.1.1.1
Address: 1.1.1.1:53
...
Mira com és per defecte el fitxer /etc/resolv.conf
d'un contenidor:
$ docker run --rm alpine cat /etc/resolv.conf
...
nameserver 192.168.120.1
search .
Mira com és el fitxer /etc/resolv.conf
d'un contenidor amb l'opció dns
:
$ docker run --rm --dns 1.1.1.1 alpine cat /etc/resolv.conf
nameserver 1.1.1.
Amb l'opció -dns
modifiques el fitxer /etc/resolv.conf
!
DNS Search
També pots utilitzar l’opció --dns-search
per especificar un domini de cerca DNS.
Activitats
Postgres
PostgreSQL és una de les bases de dades relacionals més utilitzades.
Crea un contenidor postgres:
$ docker run -d --name postgres --network xarxa-1 -e POSTGRES_PASSWORD=password postgres
Executa un terminal interactiu en el contenidor postgres i crea una taula client amb dos entrades:
$ docker exec -it postgres bash
... $ psql -U postgres
... $ create table client(name text);
CREATE TABLE
$ insert into client values('Mary');
INSERT 0 1
$ insert into client values('Mike');
INSERT 0 1
$ select * from client;
name
------
Mary
Mike
(2 rows)
$ exit
$ exit
exit
Crea un contenidor postgres en la mateixa xarxa:
$ docker run --rm -it --network xarxa-1 postgres bash
Amb el flag -h postgres
el client es conectarà al servidor postgres que estigui en la IP que resolgui el DNS pel nom postgres
:
$ PGPASSWORD=password psql -h postgres -U postgres
... $ select * from client,
name
------
Mary
Mike
(2 rows)
$ exit
Ara enlloc de fer servir la resolució DNS utilitzarem directament la IP:
$ apt install -y dnsutils
$ nslookup postgres | grep 10.
Address: 10.10.41.2
$ PGPASSWORD=password psql -h 10.10.41.2 -U postgres
... $ select * from client,
name
------
Mary
Mike
(2 rows)
$ exit
Pots verificar que és el contenidor que hem creat abans perquè té una taula client amb els registres 'Mary' i 'Mike'.
Això és possible perquè els dos contenidors estan en la mateixa xarxa!
Crea un contenidor postgres en la xarxa-2 i verifica que no et pots conectar al contenidor postgres
ni per nom ni per IP:
$ docker run --rm -it --network xarxa-2 postgres bash
... $ PGPASSWORD=password psql -h postgres -U postgres
psql: error: could not translate host name "postgres" to address: Temporary failure in name resolution
$ PGPASSWORD=password psql -h 10.10.41.2 -U postgres
^C
Wordpress
Si vols més informació ves a Wordpress
Hi ha moltes aplicacions que necessiten un base de dades, per exemple Wordpress:
Crea un contenidor mariadb pel wordpress:
$ docker run -d --name wordpress-database --network xarxa-2 -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=true mariadb
Crea un contenidor Wordpress:
$ docker run -d --name wordpress --network xarxa-2 -p 80:80 wordpress
Crea una base de dades pel Wordpress:
$ docker exec -it wordpress-database bash
... $ mariadb
... Welcome to the MariaDB monitor. Commands end with ; or \g.
$ create database wordpress;
$ grant all privileges on wordpress.* to 'wordpress' identified by 'password';
$ flush privileges;
$ exit
Ja pots obrir un navegador al Wordpress:
Amb el contenidor explorer
i fes un nmap
de les xarxes:
$ docker exec explorer nmap -sn 10.10.42.* -oG /dev/stdout | grep Status
...
Pots veure que la base de dades wordpress
s'ha omplert de taules.
$ docker exec -it wordpress-database bash
... $ mariadb
... Welcome to the MariaDB monitor. Commands end with ; or \g.
$ show databases;
...
$ use wordpress;
HAProxy
HAProxy és un balancejador de càrrega d’alta disponibilitat (i proxy invers) per TCP i aplicacions HTTP.
Crea un volum amb el nom apache ( a Emmagatzematge ja parlarem de volums):
$ docker volume create apache
apache
Crea una xarxa amb el nom apache :
$ docker network create --attachable --subnet 10.10.51.0/24 apache
Crea tres contenidor apache a la xarxa apache amb el volum apache
montat a /usr/local/apache2/htdocs/
:
$ docker run -d --name apache-1 --network apache -v apache:/usr/local/apache2/htdocs httpd
$ docker run -d --name apache-2 --network apache -v apache:/usr/local/apache2/htdocs httpd
$ docker run -d --name apache-3 --network apache -v apache:/usr/local/apache2/htdocs httpd
Pots veure que els tres servidor apache són accessibles des de la xarxa 10.10.51.0/24
, però només des d'aquesta xarxa:
$ nmap 10.10.51.0/24
...
Nmap scan report for 10.10.51.2
...
80/tcp open http
Nmap scan report for 10.10.51.3
...
80/tcp open http
Nmap scan report for 10.10.51.4
...
PORT STATE SERVICE
80/tcp open http
Entra en el contenidor apache-1
i modifica el contingut del fitxer index.html
:
$ docker exec -it apache-1 bash
... $ echo "Hello World!" > htdocs/index.html
Com que tots els apaches comparteixen el mateix volum, tenen el mateix fitxer index.html
:
$ apt update && apt install -y curl
$ curl localhost
Hello World!
$ curl apache-2
Hello World!
$ curl apache-3
Hello World1
Crea un fitxer de configuració haproxy.cfg
:
$ mkdir haproxy
$ echo "
frontend proxy
bind 0.0.0.0:80
default_backend webservers
backend webservers
server s1 apache-1:80 check
server s2 apache-2:80 check
server s3 apache-3:80 check
" > haproxy/haproxy.cfg
Arrenca un contenidor haproxy
en la xarxa apache
amb aquest fitxer i un "port forward" 9000:80
:
$ docker run -d --name proxy --network apache -v $(pwd)/haproxy:/usr/local/etc/haproxy:ro -p 9000:80 haproxy
Verifica que haproxy funciona amb tres, dos, un i cap apache actius.
$ curl localhost:9000
Hello World!
$ docker stop apache-1
$ curl localhost:9000
Hello World!
$ docker stop apache-2
$ curl localhost:9000
Hello World!
$ docker stop apache-3
$ curl localhost:9000
curl: (52) Empty reply from server
Quan el proxy no té cap apache que li respongui (estan tots parats) retorna una resposta buida: Empty reply from server
.
Arrenca un apache i verifica que el proxy torna a funcionar (al cap d'uns segons)
$ docker start apache-2
$ curl localhost:9000
Hello World!