Skip to content

Xarxa

Docker utilitza una interfície virtual que té el nom de docker0 que es va crear quan vas instal.lar docker.

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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 {% link “/linux/netfilter/” %}

Terminal window
$ 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:

Terminal window
$ docker stop apache
apache
$ sudo nft list table nat | grep 172.17.0.2.:80
$

A continuació crearem 3 apaches:

Terminal window
$ 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:

Terminal window
$ 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!

De manera predeterminada, Docker inclou tres xarxes i cadascuna és proporcionada per un “driver” diferent:

Terminal window
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
b3049ee1e177 bridge bridge local
df32681267cb host host local
3b3d0e4e7244 none null local

La xarxa bridge correspon a la intefície virtual docker0 que hem vist abans.

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:

Terminal window
$ 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:

Terminal window
$ 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”:

Terminal window
$ docker run --rm -d --name apache --network host httpd
e3b505083672b87298989e4f9d9665b0b260054ff4d7a2d597a76f95db6acc2e
$ curl localhost
<html><body><h1>It works!</h1></body></html>

També pots executar un contenidor sense que tingui accés a xarxa:

La única interfície que té és localhost:

Terminal window
$ 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:

Terminal window
$ 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 bridgeo host:

Terminal window
$ 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

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.

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.

Terminal window
$ 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:

Terminal window
$ 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?

Terminal window
$ 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.

Terminal window
$ 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?

Terminal window
$ 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:

Terminal window
0.0.0.0:8080:8080/tcp
8080:8080/tcp
8080:8080

Perquè aquest exemple si funciona en el port 80, 3000 i 8000 ?

Terminal window
$ 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:

Terminal window
$ 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?

Terminal window
$ 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 ?

Terminal window
$ 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

Terminal window
$ 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

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”:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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!

Terminal window
$ docker port apache
80/tcp -> 0.0.0.0:32768
80/tcp -> [::]:32768

Solucionat!

Terminal window
$ curl localhost:32768
<html><body><h1>It works!</h1></body></html>

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:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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ície br-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:

Terminal window
$ 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 {% link “/network/nmap/” %}

Entra dins el contenidor explorer i instal.la nmap:

Terminal window
$ docker exec -it explorer sh
... $ apk update && apk add nmap

Escaneja les xarxes a les que està connectat el contenidor:

Terminal window
... $ 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:

Terminal window
$ docker run -d --name jupyter --network xarxa-2 alpine sleep infinity
7cc41611065226f144840578d5cf0088a257482ec6fbbb14eac693eeff9f995e

Torna a executar nmap des del contenidor explorer:

Terminal window
$ 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:

Terminal window
$ 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
...

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.

Per defecte docker utilitza el nom del contenidor com a hostname:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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 !

Per defecte, el contenidor fa servir el servei DNS del host:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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 !

També pots utilitzar l’opció --dns-search per especificar un domini de cerca DNS.

PostgreSQL és una de les bases de dades relacionals més utilitzades.

Crea un contenidor postgres:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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

Si vols més informació ves a {% link “/web/app/wordpress/” %}

Hi ha moltes aplicacions que necessiten un base de dades, per exemple Wordpress:

Crea un contenidor mariadb pel wordpress:

Terminal window
$ docker run -d --name wordpress-database --network xarxa-2 -e MARIADB_ALLOW_EMPTY_ROOT_PASSWORD=true mariadb

Crea un contenidor Wordpress:

Terminal window
$ docker run -d --name wordpress --network xarxa-2 -p 80:80 wordpress

Crea una base de dades pel Wordpress:

Terminal window
$ 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:

{% image “postgres.png” %}

Amb el contenidor explorer i fes un nmap de les xarxes:

Terminal window
$ 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.

Terminal window
$ docker exec -it wordpress-database bash
... $ mariadb
... Welcome to the MariaDB monitor. Commands end with ; or \g.
$ show databases;
...
$ use wordpress;

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 {% link “/linux/docker/storage/” %} ja parlarem de volums):

Terminal window
$ docker volume create apache
apache

Crea una xarxa amb el nom apache :

Terminal window
$ 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/:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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:

Terminal window
$ 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.

Terminal window
$ 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)

Terminal window
$ docker start apache-2
$ curl localhost:9000
Hello World!

El contingut d'aquest lloc web té llicència CC BY-NC-ND 4.0.

©2022-2025 xtec.dev