A la lliçó 03-05 vas fer servir les xarxes de Docker com una caixa negra: creaves una xarxa, hi connectaves contenidors i els noms resolien. Funcionava, però no sabies per què. Aquesta lliçó obre la caixa: ponts de Linux, parells veth, regles d'iptables, un servidor DNS amagat a 127.0.0.11 i drivers que donen a un contenidor una IP pròpia a la teva LAN física.
Tot el que ve a continuació es demostra sobre la plataforma Aurora Libros en marxa. Les comandes del host assumeixen Linux; si fas servir Docker Desktop, s'executen dins de la màquina virtual (lliçó 05-07).
Contingut
- Anatomia d'una xarxa bridge: ponts de Linux
- Els parells
vethi com aparellar-ne els extrems - El camí d'un paquet, pas a pas
iptables: les cadenes que crea Docker- NAT de sortida i DNAT de publicació
- El tallafocs del host, saltat (avís de seguretat)
DOCKER-USER: recuperar el control- El DNS incrustat a
127.0.0.11 - Adreçament: subxarxes, rangs, IP fixa i MTU
- Els drivers
hostinoneen profunditat macvlan: una IP pròpia a la LAN físicaipvlanen mode L2 i L3- Taula comparativa dels sis drivers
- IPv6 a Docker
- Diagnòstic real:
tcpdumpinsenter
- Anatomia d'una xarxa bridge: ponts de Linux
Una xarxa bridge de Docker és un pont de programari del kernel de Linux: un commutador Ethernet virtual. La xarxa per defecte fa servir el pont docker0; cada xarxa d'usuari en crea un anomenat br-<12 primers caràcters de l'ID de xarxa>.
docker network ls --filter driver=bridge --format "{{.ID}}\t{{.Name}}"
ip -brief link show type bridge9f3a1c7d5e2b aurora-libros_frontal
c81be4f0a7d9 aurora-libros_posterior
docker0 UP 02:42:8e:1c:44:a1 <BROADCAST,MULTICAST,UP,LOWER_UP>
br-9f3a1c7d5e2b UP 02:42:3b:9c:10:7e <BROADCAST,MULTICAST,UP,LOWER_UP>
br-c81be4f0a7d9 UP 02:42:af:22:d5:03 <BROADCAST,MULTICAST,UP,LOWER_UP>La correspondència és directa i comprovable: els dotze caràcters que segueixen br- són el principi de l'ID de la xarxa. El pont té la seva pròpia adreça IP al host, que és la porta d'enllaç dels contenidors d'aquella xarxa:
ip -brief addr show br-9f3a1c7d5e2b
docker network inspect aurora-libros_frontal --format '{{(index .IPAM.Config 0).Subnet}} gw={{(index .IPAM.Config 0).Gateway}}'I bridge link show master br-9f3a1c7d5e2b llista les interfícies endollades a aquell pont: una per cada contenidor connectat a la xarxa.
- Els parells
veth i com aparellar-ne els extrems
veth i com aparellar-ne els extremsUn veth (virtual Ethernet) és un parell d'interfícies connectades per un cable virtual: el que entra per un extrem surt per l'altre. Docker en crea un per cada connexió contenidor-xarxa: un extrem es queda al host i s'endolla al pont; l'altre es mou dins del contenidor i es reanomena eth0. L'aparellament no és evident, perquè els noms són aleatoris; la clau és l'índex d'interfície, ja que cada extrem apunta a l'índex de l'altre mitjançant iflink.
docker compose exec aurora-api cat /sys/class/net/eth0/iflink # -> 7
ip link show | grep '^7:' # quina interfície és la 7?Ja tens el parell: eth0 d'aurora-api ↔ veth3a1f9c2 al host. La notació @if6 del nom mateix confirma la simetria: l'extrem del host apunta a l'índex 6, que és l'eth0 del contenidor dins del seu propi espai de noms de xarxa.
Amb el parell identificat, pots mesurar el trànsit d'un contenidor concret des del host, sense entrar-hi:
Fixa't en peer_ifindex: és la manera més directa de confirmar l'aparellament. I compte amb la inversió de sentit: el que el contenidor envia és rx al veth del host, perquè el paquet entra al host per aquell extrem.
- El camí d'un paquet, pas a pas
flowchart LR
subgraph NSAPI["Espai de noms de xarxa d'aurora-api"]
P["procés node<br/>172.21.0.5"] --> E0["eth0 (if6)"]
end
E0 -->|"cable veth"| V["veth3a1f9c2 (if7)"]
subgraph HOST["Host"]
V --> BR["br-9f3a1c7d5e2b<br/>172.21.0.1"]
BR --> IPT["iptables: nat + filter"]
IPT --> ETH["eth0 del host"]
end
BR -->|"mateix pont:<br/>commutació directa"| V2["veth5d80a3f"]
V2 --> DB["aurora-db 172.22.0.3"]
ETH --> NET(("Internet"))
Aquí hi conviuen dos camins molt diferents:
| Destinació | Recorregut | Cost |
|---|---|---|
| Un altre contenidor de la mateixa xarxa | eth0 → veth → pont → veth → eth0 |
Commutació al kernel, sense NAT |
| Una altra xarxa o Internet | eth0 → veth → pont → encaminat → iptables (MASQUERADE) → eth0 del host |
NAT i seguiment de connexions |
| Des de fora cap a un port publicat | eth0 del host → iptables (DNAT) → pont → veth → eth0 |
NAT de destinació |
Que la comunicació aurora-api ↔ aurora-db sigui pura commutació explica per què el seu rendiment és pràcticament el de la xarxa del host: en aquell camí no hi ha cap traducció d'adreces.
iptables: les cadenes que crea Docker
iptables: les cadenes que crea DockerEn arrencar, dockerd instal·la un conjunt de cadenes pròpies. Conèixer-les pel nom t'estalvia hores de depuració:
| Cadena | Taula | Funció |
|---|---|---|
DOCKER |
nat i filter |
Regles DNAT dels ports publicats i el seu permís de reenviament |
DOCKER-USER |
filter |
Buida i reservada per a tu; s'avalua abans que DOCKER |
DOCKER-ISOLATION-STAGE-1 |
filter |
Detecta trànsit que surt d'un pont cap a un altre |
DOCKER-ISOLATION-STAGE-2 |
filter |
El descarta: és el que aïlla les xarxes entre elles |
DOCKER-INGRESS |
nat i filter |
Només amb Swarm (lliçó 06-03) |
num target prot opt source destination
1 DROP all -- 0.0.0.0/0 0.0.0.0/0
2 RETURN all -- 0.0.0.0/0 0.0.0.0/0Aquí el tens, en dues línies: l'aïllament que vas comprovar a la lliçó 04-04 quan aurora-web no podia arribar a aurora-db. Un paquet que surt d'un pont i intenta entrar en un altre cau al DROP.
- NAT de sortida i DNAT de publicació
Chain PREROUTING (policy ACCEPT)
DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
MASQUERADE all -- 172.21.0.0/16 0.0.0.0/0
MASQUERADE all -- 172.22.0.0/16 0.0.0.0/0
MASQUERADE tcp -- 172.21.0.2 172.21.0.2 tcp dpt:80
Chain DOCKER (2 references)
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.21.0.2:80Tres regles, tres mecanismes:
MASQUERADEde subxarxa: tot el que surt de172.21.0.0/16cap a fora es reescriu amb la IP del host. És la raó que un contenidor pugui descarregar d'Internet sense tenir IP pública.DNATde publicació: el-p 8080:80d'aurora-webes tradueix en aquesta regla. Qualsevol paquet que arribi al port 8080 de qualsevol adreça local es redirigeix a172.21.0.2:80.MASQUERADEamb origen i destinació iguals: l'anomenat hairpin NAT, que permet que un contenidor s'arribi a si mateix a través del port publicat del host.
Comprova la correspondència amb la publicació real:
Si publiques restringint la interfície —"127.0.0.1:8080:80"—, la regla canvia i hi afegeix -d 127.0.0.1. Aquesta diferència d'una paraula és la que separa "accessible des del meu portàtil" d'"accessible des de tota la xarxa de l'oficina".
- El tallafocs del host, saltat (avís de seguretat)
Aquest és el punt més important de la lliçó i el que més sorpreses desagradables provoca en producció.
Quan publiques un port, Docker insereix el seu DNAT a PREROUTING, que s'avalua abans que les regles de la cadena INPUT on ufw o firewalld posen les seves. El trànsit redirigit passa per FORWARD, no per INPUT. Resultat: el teu tallafocs no veu aquell trànsit i no el bloqueja.
sudo ufw status | head -4
docker run -d --name exposat -p 5000:80 nginx:alpine
curl -s -o /dev/null -w '%{http_code}\n' http://<IP-del-host>:5000/El tallafocs diu que només el 22 està obert. El port 5000 respon igualment des de qualsevol màquina de la xarxa. Servidors sencers de PostgreSQL i Redis han acabat a Internet exactament així.
Les tres defenses, de més simple a més completa:
| Defensa | Com | Abast |
|---|---|---|
| Publicar només en local | "127.0.0.1:5432:5432" |
Impedeix l'accés remot d'arrel. La primera opció sempre |
| No publicar | Fer servir xarxes internes i docker compose exec |
El que fa aurora-db des de la lliçó 04-04 |
Regles a DOCKER-USER |
Filtrar el trànsit reenviat | Control fi per origen |
Advertència de seguretat. L'exposició de ports i les regles de tallafocs d'un servidor s'han de revisar amb el responsable de seguretat o de compliance de la teva organització. El que aquí es mostra explica el mecanisme; la política concreta —què s'exposa, a qui i amb quins controls compensatoris— no la decideix qui escriu el
compose.yamltot sol.
DOCKER-USER: recuperar el control
DOCKER-USER: recuperar el controlDocker mai no toca DOCKER-USER i l'avalua abans que les seves pròpies regles. És el lloc previst per a les teves polítiques:
# Permetre només des de la xarxa corporativa; descartar la resta
sudo iptables -I DOCKER-USER -i eth0 -j DROP
sudo iptables -I DOCKER-USER -i eth0 -s 10.0.0.0/8 -j RETURN
sudo iptables -L DOCKER-USER -n --line-numbersnum target prot opt source destination
1 RETURN all -- 10.0.0.0/8 0.0.0.0/0
2 DROP all -- 0.0.0.0/0 0.0.0.0/0Dues advertències imprescindibles. La primera: l'ordre importa, -I insereix al principi, així que la regla permissiva s'ha d'inserir en darrer lloc per acabar a dalt. La segona: aquestes regles no sobreviuen a un reinici; cal persistir-les amb iptables-persistent, nftables o l'eina de la teva distribució. I si penses desactivar la manipulació d'iptables del tot ("iptables": false a /etc/docker/daemon.json), assumeix que perds la sortida a Internet dels contenidors i la publicació de ports fins que escriguis tu totes les regles: poques vegades compensa.
- El DNS incrustat a
127.0.0.11
127.0.0.11En una xarxa d'usuari, els noms de servei resolen perquè Docker executa un servidor DNS per contenidor escoltant a 127.0.0.11:53.
docker compose exec aurora-api cat /etc/resolv.conf
docker compose exec aurora-api getent hosts aurora-dbAquella adreça de loopback no existeix en cap interfície visible. El truc: dins de l'espai de noms del contenidor hi ha una regla DNAT (-A DOCKER_OUTPUT -d 127.0.0.11/32 -p tcp --dport 53 -j DNAT --to-destination 127.0.0.11:38765) que redirigeix el trànsit a un port alt on escolta un procés del daemon.
L'algorisme de resolució, per ordre:
- És un nom de servei o àlies d'una xarxa que compartim? → respon el daemon amb la IP del contenidor.
- És un contenidor de la mateixa xarxa pel seu nom o
container_name? → igual. - Si no, reenvia als servidors DNS del host (o als de
dns:del servei).
Punts que convé tenir clars:
- La resolució està acotada a les xarxes compartides.
aurora-webno resolaurora-dbperquè no comparteixen xarxa: no és una fallada de DNS, és el disseny. - Amb
--scale, un mateix nom retorna diverses adreces en ordre rotatori: un balanceig rudimentari del costat del client. Comprova-ho ambdocker compose up -d --scale aurora-api=3seguit degetent hosts aurora-api. options ndots:0evita que s'afegeixin sufixos de cerca i estalvia consultes fallides.- Moltes biblioteques guarden en memòria cau la resolució. Si un contenidor es recrea i canvia d'IP, una aplicació que va resoldre una vegada pot quedar-se parlant amb una IP morta. És un motiu real per reiniciar clients després de recrear un servei.
- Adreçament: subxarxes, rangs, IP fixa i MTU
Per defecte Docker tria subxarxes de 172.17.0.0/16 en endavant, cosa que xoca amb moltes VPN corporatives. Les pots fixar:
docker network create --driver bridge \
--subnet 10.80.0.0/24 --gateway 10.80.0.1 --ip-range 10.80.0.128/25 \
--aux-address "reservada-nas=10.80.0.20" \
--opt com.docker.network.driver.mtu=1450 \
--opt com.docker.network.bridge.name=br-aurora \
aurora-fixa| Opció | Què fa |
|---|---|
--subnet |
Rang complet de la xarxa |
--gateway |
IP del pont al host |
--ip-range |
Subconjunt del qual Docker assigna automàticament; la resta queda lliure per a IP fixes |
--aux-address |
Adreces que Docker no ha d'assignar (equips reals dins del rang) |
mtu |
Mida màxima de trama; abaixar-la evita fragmentació després de VPN o túnels |
bridge.name |
Nom llegible del pont en lloc de br-<id> |
Assignar una IP fixa exigeix que la xarxa tingui subxarxa pròpia: docker run -d --network aurora-fixa --ip 10.80.0.10 nginx:alpine. A Compose es declara amb ipv4_address dins de networks. Tot i això, la bona pràctica continua sent dependre dels noms DNS i no de les IP: les IP fixes es reserven per a casos on alguna cosa externa (una regla de tallafocs, una llicència, un equip antic) exigeix una adreça estable.
El valor per defecte de la MTU es defineix a /etc/docker/daemon.json amb "mtu": 1450. El símptoma típic d'una MTU mal ajustada és cruel: les connexions s'estableixen i les peticions petites funcionen, però les respostes grans es queden penjades.
- Els drivers
host i none en profunditat
host i none en profunditathost elimina l'espai de noms de xarxa: el contenidor fa servir directament la pila del host.
docker run -d --name api-host --network host auroralibros/aurora-api:1.2.0
docker exec api-host ip -brief addr | head -2 && ss -tlnp | grep 3000El procés escolta directament al port 3000 del host. El que hi guanyes i el que hi perds:
| Guanyes | Perds |
|---|---|
| Sense NAT: menys latència i més rendiment en càrregues de molts paquets petits | Aïllament de xarxa: zero |
| Accés a interfícies reals (útil en monitoratge, VPN, DHCP) | Resolució per nom de servei: no existeix |
| Sense límit pràctic de ports publicats | Col·lisions de ports entre contenidors |
| Multicast i protocols que el NAT trenca | -p s'ignora amb un avís |
Casos legítims: agents de monitoratge (node-exporter, lliçó 05-06), balancejadors de molt alt rendiment i eines de diagnòstic. Per a aurora-api seria un error: perdria l'aïllament sense guanyar res apreciable.
none deixa el contenidor únicament amb lo: docker run --rm --network none alpine:3 ping -c1 -W1 8.8.8.8 respon Network is unreachable. És l'opció correcta per a processos de càlcul pur o per tractar fitxers d'origen dubtós: si no hi ha xarxa, no hi ha exfiltració.
macvlan: una IP pròpia a la LAN física
macvlan: una IP pròpia a la LAN físicamacvlan dona al contenidor la seva pròpia adreça MAC a la xarxa física. Per a la resta de l'oficina, el contenidor és un equip més: obté una IP del rang real i no necessita NAT ni publicació de ports.
# 1) Esbrina la interfície física i la subxarxa reals
ip -brief addr show eth0
# 2) Crea la xarxa macvlan sobre aquella interfície
docker network create -d macvlan \
--subnet 192.168.1.0/24 \
--gateway 192.168.1.1 \
--ip-range 192.168.1.240/28 \
-o parent=eth0 \
lan-oficina
# 3) Un contenidor amb IP de la LAN
docker run -d --name web-lan --network lan-oficina --ip 192.168.1.241 nginx:alpine
docker exec web-lan ip -brief addr show eth0Des d'un altre equip de l'oficina, http://192.168.1.241/ respon sense haver publicat cap port.
Els tres paranys, per ordre de freqüència:
- El host no pot parlar amb els seus propis contenidors macvlan. No és una fallada: el kernel impedeix el trànsit entre la interfície pare i les seves interfícies macvlan filles. La solució és crear una interfície macvlan addicional al host i encaminar-hi:
sudo ip link add macvlan-host link eth0 type macvlan mode bridge
sudo ip addr add 192.168.1.250/32 dev macvlan-host && sudo ip link set macvlan-host up
sudo ip route add 192.168.1.240/28 dev macvlan-host- Mode promiscu. El commutador o l'hipervisor han d'acceptar diverses MAC per port. A la majoria de serveis de núvol (i a moltes xarxes Wi-Fi) està prohibit, i macvlan senzillament no funciona.
- Col·lisió amb el DHCP. Docker no parla DHCP: reserva un
--ip-rangefora de l'àmbit del servidor DHCP o acabaràs amb dos equips compartint IP.
ipvlan en mode L2 i L3
ipvlan en mode L2 i L3ipvlan resol el problema del mode promiscu: tots els contenidors comparteixen la MAC de la interfície pare i es distingeixen per IP.
# L2: mateix domini de difusió que el host, sense MAC pròpia
docker network create -d ipvlan --subnet 192.168.1.0/24 --gateway 192.168.1.1 \
-o parent=eth0 -o ipvlan_mode=l2 lan-l2
# L3: el host encamina; sense difusió, subxarxa independent
docker network create -d ipvlan --subnet 10.90.1.0/24 \
-o parent=eth0 -o ipvlan_mode=l3 lan-l3| Aspecte | macvlan |
ipvlan L2 |
ipvlan L3 |
|---|---|---|---|
| MAC | Una per contenidor | Compartida amb el pare | Compartida |
| Mode promiscu | Necessari | No | No |
| Difusió i DHCP | Sí | Sí | No |
| Encaminament | Via gateway de la LAN | Via gateway de la LAN | El fa el host |
| Rutes externes | Automàtiques | Automàtiques | Cal afegir-les al router |
El mode L3 és el més net en centres de dades amb encaminament controlat, però exigeix que algú ensenyi al router com arribar a 10.90.1.0/24. Si no ho fas, els contenidors surten i no torna res.
- Taula comparativa dels sis drivers
| Driver | Aïllament | Rendiment | DNS intern | Publicació de ports | Cas d'ús típic |
|---|---|---|---|---|---|
bridge (usuari) |
Alt | Bo (NAT a la sortida) | Sí | -p amb DNAT |
El 95 % dels casos, inclosa Aurora Libros |
bridge per defecte |
Mitjà | Igual | No (només --link, obsolet) |
-p |
Compatibilitat; evita-la |
host |
Cap | El millor | No | No aplica | Agents de monitoratge, alt rendiment |
none |
Total | No aplica | No | No | Processos sense xarxa |
macvlan |
Mitjà (LAN plana) | Molt bo, sense NAT | Sí, a la xarxa Docker | Innecessària | Integrar amb equips de la LAN o sistemes antics |
ipvlan |
Mitjà | Molt bo | Sí | Innecessària | Com macvlan on el mode promiscu està prohibit |
El driver overlay, per comunicar contenidors de diversos hosts, es tracta a la lliçó 06-03 juntament amb la malla d'encaminament de Swarm.
- IPv6 a Docker
Des de la versió 27, IPv6 s'habilita per xarxa sense tocar el daemon:
docker network create --ipv6 --subnet 2001:db8:aur::/64 aurora-v6
docker run --rm --network aurora-v6 alpine:3 ip -6 -brief addr show eth0
# eth0 UP 2001:db8:aur::2/64 fe80::42:acff:fe14:2/64A Compose n'hi ha prou amb enable_ipv6: true a la xarxa. Tres avisos: fes servir adreces ULA (fd00::/8) si no tens un prefix públic delegat; activa "ip6tables": true a /etc/docker/daemon.json perquè funcionin el NAT i la publicació; i comprova que les teves regles de tallafocs existeixen també en IPv6, perquè una política només IPv4 deixa una porta oberta que ningú no mira.
- Diagnòstic real:
tcpdump i nsenter
tcpdump i nsenterLa imatge nicolaka/netshoot amb --network container: (lliçó 03-04) et posa dins de l'espai de noms de xarxa del contenidor amb totes les eines:
docker run --rm -it --network container:aurora-libros-aurora-api-1 nicolaka/netshoot \
sh -c 'ip -brief addr; ip route; ss -tlnp'Dues interfícies, perquè aurora-api és a frontal i a posterior; la ruta per defecte surt per frontal, ja que posterior és internal i no té porta d'enllaç.
Capturar el trànsit real entre l'API i la base de dades:
docker run --rm --net container:aurora-libros-aurora-api-1 nicolaka/netshoot \
timeout 10 tcpdump -n -i any 'host 172.22.0.3 and port 5432' -c 6IP 172.22.0.4.51442 > 172.22.0.3.5432: Flags [S], seq 2451
IP 172.22.0.3.5432 > 172.22.0.4.51442: Flags [S.], seq 8891, ack 2452
IP 172.22.0.4.51442 > 172.22.0.3.5432: Flags [P.], length 96
IP 172.22.0.3.5432 > 172.22.0.4.51442: Flags [P.], length 1284Les adreces són les de la xarxa posterior i no hi ha cap traducció: comunicació directa a través del pont, tal com anticipava l'apartat 3. Des del host, sense entrar en cap contenidor, la captura equivalent és sudo tcpdump -n -i veth3a1f9c2 -c 5 'tcp port 5432'.
nsenter és la via de més baix nivell: entra a l'espai de noms de xarxa d'un procés fent servir les eines del host.
pid=$(docker inspect --format '{{.State.Pid}}' aurora-libros-aurora-api-1)
sudo nsenter -t "$pid" -n ip -brief addr
sudo nsenter -t "$pid" -n ss -tnp state establishedÉs la tècnica que salva el dia quan un contenidor és distroless i no té ni sh (lliçó 05-03): tu no necessites res a dins, perquè fas servir els binaris del host sobre el seu namespace. El perquè exacte que això funcioni és a la lliçó 05-07.
Errors Habituals i Consells
Creure que el tallafocs del host protegeix els ports publicats. No ho fa: el DNAT de Docker s'avalua abans. Publica a 127.0.0.1 o filtra a DOCKER-USER.
Afegir regles a INPUT per bloquejar un contenidor. El trànsit va per FORWARD. La cadena correcta és DOCKER-USER.
Escriure regles dins de la cadena DOCKER. Docker la reescriu en arrencar o en publicar un port, i les teves regles desapareixen.
Dependre de les IP dels contenidors. Canvien en recrear-los. Fes servir noms de servei i reserva les IP fixes per a requisits externs reals.
Fer servir --network host "perquè vagi més ràpid". Perds l'aïllament i la resolució per nom, i en una API HTTP la diferència sol ser negligible. Mesura abans.
Muntar macvlan sense comprovar el mode promiscu, o oblidar-se d'abaixar la MTU després d'una VPN: en el primer cas tot sembla ben configurat i no respon res; en el segon, les connexions s'obren però es pengen en transferir dades grans.
Consell: davant d'un problema de xarxa, segueix sempre el mateix ordre: resol el nom? (getent hosts), hi ha ruta? (ip route), escolta algú? (ss -tlnp dins de la destinació), arriba el paquet? (tcpdump). Cada pas descarta una capa sencera.
Exercicis
Exercici 1. Amb la plataforma aixecada, identifica el parell veth d'aurora-db, demostra que el seu extrem del host està endollat al pont de la xarxa posterior i mesura el trànsit que hi ha passat. Explica per què rx al host correspon al que envia el contenidor.
Exercici 2. Demostra el salt del tallafocs: publica un contenidor en un port, comprova que ufw no el declara obert i que tot i així respon des d'una altra màquina; després bloqueja'l correctament amb DOCKER-USER i verifica que continua funcionant des de localhost.
Exercici 3. Captura amb tcpdump una consulta real entre aurora-api i aurora-db provocada per curl /llibres, i demostra amb docker exec sobre Redis per què la segona petició no genera trànsit cap a la base de dades.
Solucions
Solució 1.
idx=$(docker compose exec -T aurora-db cat /sys/class/net/eth0/iflink | tr -d '\r')
veth=$(ip -o link | awk -v i="$idx:" '$1==i {sub(/@.*/,"",$2); print $2}')
xarxa=$(docker network inspect aurora-libros_posterior --format '{{.Id}}' | cut -c1-12)
echo "veth=$veth pont esperat=br-$xarxa"
ip -o link show "$veth" | grep -o 'master [^ ]*'
ethtool -S "$veth" | grep -E 'peer_ifindex|rx_packets|tx_packets'veth=veth5d80a3f pont esperat=br-c81be4f0a7d9
master br-c81be4f0a7d9
peer_ifindex: 10
rx_packets: 3921
tx_packets: 4877El master coincideix exactament amb el pont derivat de l'ID de la xarxa posterior: aquell veth és el cable d'aurora-db cap a aquella xarxa i no cap a una altra. I peer_ifindex: 10 apunta a l'índex de l'eth0 de dins del contenidor.
Sobre la inversió de sentit: les estadístiques es llegeixen des del punt de vista del host. Quan aurora-db respon a una consulta, el paquet surt pel seu eth0, viatja pel cable virtual i entra al host per veth5d80a3f; per al host això és recepció, per tant rx. Confondre-ho porta a diagnòstics invertits: si veus el rx disparat al veth d'una base de dades, no és que li estiguin enviant molt, és que està retornant molt, i probablement falti un LIMIT en alguna consulta.
Solució 2.
docker run -d --name exposat -p 5000:80 nginx:alpine
sudo ufw status | grep -c 5000 # 0: ufw no sap res d'aquell port
curl -s -o /dev/null -w 'host: %{http_code}\n' http://127.0.0.1:5000/
# des d'una altra màquina: curl -s -o /dev/null -w 'remot: %{http_code}\n' http://192.168.1.42:5000/
sudo iptables -I DOCKER-USER -i eth0 -p tcp --dport 5000 -j DROP
curl -s -o /dev/null -w 'host després de la regla: %{http_code}\n' http://127.0.0.1:5000/
# des d'una altra màquina: curl -m 3 http://192.168.1.42:5000/
sudo iptables -D DOCKER-USER -i eth0 -p tcp --dport 5000 -j DROP && docker rm -f exposat0
host: 200
remot: 200
host després de la regla: 200
curl: (28) Connection timed out after 3001 millisecondsLa regla filtra per interfície d'entrada (-i eth0), així que el trànsit que arriba per la interfície física es descarta mentre que el que neix al host mateix —i que per tant no entra per eth0— continua passant. Aquest matís és el que la fa utilitzable: bloqueja l'exterior sense trencar la depuració local.
La lliçó de fons: ufw informava d'un sistema amb un sol port obert i era fals. Publicar un port en un servidor amb IP pública equival a obrir-lo a Internet, tret que lliguis la publicació a 127.0.0.1 o filtris explícitament. És exactament el motiu pel qual aurora-db no publica res des de la lliçó 04-04.
Solució 3.
docker compose exec aurora-cache redis-cli FLUSHALL
docker run --rm --net container:aurora-libros-aurora-api-1 nicolaka/netshoot \
timeout 12 tcpdump -n -i any 'host 172.22.0.3 and port 5432' &
sleep 1
curl -s http://localhost:8080/api/llibres | head -c 58; echo # primera: buida la memòria cau
curl -s http://localhost:8080/api/llibres | head -c 58; echo # segona: memòria cau calenta
docker compose exec aurora-cache redis-cli KEYS 'llibres:*'
wait{"origen":"db","total":9,"llibres":[{"id":1,"titol":"El
{"origen":"cache","total":9,"llibres":[{"id":1,"titol":
1) "llibres:tots"
IP 172.22.0.4.51488 > 172.22.0.3.5432: Flags [P.], length 112
IP 172.22.0.3.5432 > 172.22.0.4.51488: Flags [P.], length 1284
2 packets capturedLa primera petició retorna origen: db i a la captura hi apareix el diàleg amb PostgreSQL al 5432, amb adreces de la xarxa posterior sense traduir. La segona retorna origen: cache i no afegeix ni un paquet a la captura: el patró cache-aside troba la clau llibres:tots a Redis i ni tan sols obre una consulta.
Dues conclusions útils. La primera, d'arquitectura: tcpdump acaba de convertir en observable una cosa que fins ara era un camp JSON en el qual calia confiar. La segona, de diagnòstic: si un dia /llibres respongués origen: db sempre, aquesta mateixa captura et diria si el problema és a l'escriptura de la clau a Redis o a la seva lectura, sense tocar ni una línia de codi.
Conclusió
Les xarxes de Docker han deixat de ser màgia. Saps que una xarxa bridge és un pont de Linux —docker0 o br-<id>— amb un extrem veth per contenidor endollat a sobre, i saps aparellar els extrems amb iflink i ethtool -S per mesurar el trànsit d'un contenidor concret des del host. Coneixes els dos camins d'un paquet: commutació pura entre contenidors de la mateixa xarxa, i MASQUERADE quan surt a l'exterior. I has llegit les regles reals: la cadena DOCKER amb el seu DNAT per cada -p, i DOCKER-ISOLATION-STAGE-2 amb el DROP de dues línies que explica tot l'aïllament entre xarxes que fas servir des del mòdul 3.
T'endús també un avís que val més que moltes configuracions: publicar un port salta el tallafocs del host, perquè el DNAT s'avalua abans que INPUT; la defensa és publicar a 127.0.0.1, no publicar en absolut o escriure regles a DOCKER-USER, l'única cadena que Docker respecta. Saps com resol realment un nom el DNS incrustat de 127.0.0.11 i per què la resolució està acotada a les xarxes compartides; controles l'adreçament (--subnet, --ip-range, --aux-address, mtu) per conviure amb VPN i equips reals; coneixes en profunditat els sis drivers, inclosos macvlan amb el seu parany del mode promiscu i ipvlan en L2 i L3; i diagnostiques amb netshoot, ss, tcpdump sobre el trànsit real entre aurora-api i aurora-db, i nsenter quan dins del contenidor no hi ha ni un sh.
La capa següent que cal obrir és la de les dades. A la lliçó 05-02 veuràs l'emmagatzematge a fons: què és un storage driver i com funciona overlay2 per dins amb els seus lowerdir, upperdir i merged; quant costa realment el copy-on-write —mesurat— i per què això obliga que una base de dades faci servir volums; els volume drivers i les seves opcions, inclosos NFS i els volums compartits entre piles; i una estratègia de còpies de seguretat d'Aurora Libros amb restauració provada, perquè una còpia que no s'ha restaurat mai no és una còpia.
Docker: De Principiant a Avançat
Mòdul 1: Introducció a Docker
- Què és Docker?
- Instal·lant Docker
- Arquitectura de Docker
- Comandes Bàsiques de Docker
- Entenent les Imatges de Docker
- Creant el teu Primer Contenidor Docker
- El Projecte del Curs: la Plataforma Aurora Libros
Mòdul 2: Treballant amb Imatges Docker
- Docker Hub i Repositoris
- Construint Imatges Docker
- Conceptes Bàsics de Dockerfile
- Instruccions Avançades del Dockerfile
- Gestionant Imatges Docker
- Etiquetatge i Publicació d'Imatges
Mòdul 3: Contenidors Docker
- Executant Contenidors
- Cicle de Vida del Contenidor
- Gestionant Contenidors
- Inspecció i Depuració de Contenidors
- Xarxes a Docker
- Persistència de Dades amb Volums
- Límits de Recursos i Polítiques de Reinici
Mòdul 4: Docker Compose
- Introducció a Docker Compose
- Definint Serveis a Docker Compose
- Comandes de Docker Compose
- Aplicacions Multi-Contenidor
- Variables d'Entorn a Docker Compose
- Perfils, Overrides i Múltiples Entorns
- Desenvolupament Local amb Docker Compose
Mòdul 5: Conceptes Avançats de Docker
- Aprofundiment en Xarxes Docker
- Opcions d'Emmagatzematge Docker
- Millors Pràctiques de Seguretat a Docker
- Optimitzant Imatges Docker
- Builds Avançades amb BuildKit i Buildx
- Registre i Monitoratge a Docker
- El Runtime per Dins: Namespaces, Cgroups i Capes
Mòdul 6: Docker en Producció
- Preparar una Imatge per a Producció
- CI/CD amb Docker
- Orquestrant Contenidors amb Docker Swarm
- Introducció a Kubernetes
- Desplegant Contenidors Docker a Kubernetes
- Escalat i Balanceig de Càrrega
- Estratègies de Desplegament i Rollback
