Docker utilitza una interfície virtual que té el nom de docker0 que es va crear quan vas instal.lar docker.
shell
$ ip --brief addrlo UNKNOWN 127.0.0.1/8 ::1/128enp1s0 UP 192.168.123.6/22 fe80::b4a1:54f4:7454:d2fd/64enp2s0 UP 10.2.76.37/16 fe80::d18f:22b8:b29b:935c/64docker0 DOWN 172.17.0.1/16
Quan crees un contenidor aquest es connecta a aquesta xarxa:
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:
shell
$ curl localhostcurl: (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:
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 run --rm -d --name apache -p 80:80/udp httpd899d341907378ea811ac519e47b87e9c6debbb7401b5bf2cf3c687415df77d60$ curl localhostcurl: (7)Failed to connect to localhost port 80 after 0 ms: S’ha refusat la connexió$ docker stop apacheapache
Perquè apache està escoltant al port 80/tcp de la IP 172.17.0.x i no al port 80/udp.
Recordeu:
shell
0.0.0.0:8080:8080/tcp8080:8080/tcp8080:8080
Perquè aquest exemple si funciona en el port 80, 3000 i 8000 ?
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:
shell
$ 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:80iifname != "docker0" meta l4proto tcp tcp dport 3000 counter packets 0 bytes 0 dnat to 172.17.0.2:80iifname != "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?
shell
$ docker run --rm -d --name apache -p 80:80 httpd49cbdb93cfd7b09f96bbcce972ec7b54e2b7429f8c45412091852406541ba86a$ ip --brief addrlo UNKNOWN 127.0.0.1/8 ::1/128enp1s0 UP 192.168.123.6/22 fe80::b4a1:54f4:7454:d2fd/64enp2s0 UP 10.2.76.37/16 fe80::d18f:22b8:b29b:935c/64docker0 UP 172.17.0.1/16 fe80::42:89ff:fe45:9db0/64vethfdcf90a@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 ?
shell
$ docker run --rm -d --name apache -p 192.168.123.6:80:80 httpd739fed667dd61fbc1e9f7b5e015bd946d28d70a6c50f266e57569f29bae64486$ curl 127.0.0.1curl: (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.37curl: (7)Failed to connect to 10.2.76.37 port 80 after 0 ms: S’ha refusat la connexió$ curl 172.17.0.1curl: (7)Failed to connect to 172.17.0.1 port 80 after 0 ms: S’ha refusat la connexió
Si mirem la taula nat …
shell
$ 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”:
shell
$ docker run --rm -d --name apache -p 80 httpd8f962b1ebc2e338bced6e0a827a4c0d33f12479aa68128800da02c08c8b968df$ curl localhostcurl: (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:
shell
$ nmap localhost...PORT STATE SERVICE631/tcp open ipp3389/tcp open ms-wbt-server32768/tcp open filenet-tms
I provar … o mirar la taula nat:
shell
$ 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!
shell
$ docker port apache80/tcp ->0.0.0.0:3276880/tcp ->[::]:32768
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 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:
shell
$ 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.
shell
$ docker exec -it wordpress-database bash... $ mariadb... Welcome to the MariaDB monitor. Commands end with;or\g.$ show databases;...$ use wordpress;
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:
shell
$ nmap 10.10.51.0/24...Nmap scan report for 10.10.51.2...80/tcp open httpNmap scan report for 10.10.51.3...80/tcp open httpNmap scan report for 10.10.51.4...PORT STATE SERVICE80/tcp open http
Entra en el contenidor apache-1 i modifica el contingut del fitxer index.html: