Risoluzione dei problemi di rete Docker: Risolvere efficacemente i problemi di connettività
Risolvi i problemi di rete Docker con DNS dei container, reti definite dall'utente, pubblicazione delle porte, accesso all'host, DNS e firewall.
Risoluzione dei problemi di rete Docker: Risolvere efficacemente i problemi di connettività
I problemi di rete Docker sono molto più facili da risolvere quando si nomina la direzione della connessione fallita. "Il container non può connettersi" è troppo vago. L'host sta cercando di raggiungere un container? Un container sta cercando di raggiungerne un altro? Un container sta cercando di raggiungere Internet? Il traffico sta entrando da un'altra macchina? Ogni percorso utilizza un comportamento Docker diverso.
Inizia scrivendo il percorso in linguaggio semplice:
browser sull'host -> localhost:8080 -> porta container 80
container api -> container db -> porta 5432
container worker -> Internet pubblico -> api.example.com:443
laptop remoto -> IP pubblico del server -> porta pubblicata del container
Una volta che conosci il percorso, puoi testare ogni salto invece di cambiare le reti a caso.
Conoscere le modalità di rete Docker di base
La maggior parte delle configurazioni Docker su singolo host utilizza il networking bridge. Docker crea una rete virtuale sull'host, assegna indirizzi IP privati ai container e può pubblicare porte selezionate dei container sull'host.
La rete bridge predefinita funziona, ma le reti bridge definite dall'utente sono migliori per le applicazioni perché forniscono DNS integrato tramite il nome del container. Ciò significa che un container api può raggiungere un container db all'indirizzo db:5432 se entrambi sono collegati alla stessa rete definita dall'utente.
Creane una in questo modo:
docker network create appnet
docker run -d --name db --network appnet postgres:16
docker run -d --name api --network appnet my-api
Esistono altre modalità. Il networking host condivide il namespace di rete dell'host e rimuove il normale comportamento di pubblicazione delle porte; è utile in alcuni casi Linux ma riduce l'isolamento. none non fornisce alcuna rete al container. overlay è per il networking multi-host di Docker Swarm. Compose crea reti definite dall'utente per i progetti automaticamente, a meno che non configurato diversamente.
"Rete non trovata"
Questo errore di solito significa che il nome della rete è sbagliato o che la rete esiste in un contesto diverso da quello previsto dal comando.
Controlla le reti disponibili:
docker network ls
Ispeziona quella che intendi utilizzare:
docker network inspect appnet
Se non esiste, creala:
docker network create appnet
Con Compose, il nome effettivo della rete potrebbe essere preceduto dal nome del progetto. Una rete chiamata backend in compose.yml potrebbe apparire come myproject_backend. Usa:
docker compose ps
docker network ls
Se hai dichiarato una rete Compose esterna, Compose non la creerà per te:
networks:
appnet:
external: true
In tal caso, creala manualmente o rimuovi external: true se Compose deve gestirla.
La comunicazione container-to-container fallisce
Affinché due container possano comunicare per nome, di solito devono essere sulla stessa rete definita dall'utente. Confermalo prima:
docker network inspect appnet
Cerca entrambi i container nella sezione Containers.
Quindi testa da un container che ha strumenti di base. La tua immagine dell'applicazione potrebbe non includere curl, dig o ping, e va bene. Usa un container di debug temporaneo sulla stessa rete:
docker run --rm -it --network appnet nicolaka/netshoot
Dall'interno:
dig db
curl -v http://api:8080/health
nc -vz db 5432
Se il DNS fallisce, probabilmente i container non sono sulla stessa rete definita dall'utente o stai usando la rete bridge predefinita aspettandoti una risoluzione dei nomi che non fornisce allo stesso modo. Se il DNS funziona ma la connessione fallisce, controlla se il servizio di destinazione è in ascolto sulla porta prevista.
All'interno del container di destinazione:
docker exec -it api sh
ss -ltnp || netstat -ltnp
Un errore comune è associare l'app a 127.0.0.1 all'interno del container. Questo ascolta solo sul loopback all'interno di quel container. Altri container non possono raggiungerlo. Configura l'app per ascoltare su 0.0.0.0.
Assicurati anche di usare la porta del container, non la porta pubblicata sull'host, per il traffico container-to-container. Se il database ascolta sulla porta 5432 nel container, gli altri container dovrebbero usare db:5432, non localhost:15432 o la porta host pubblicata.
L'host non può raggiungere un container
Affinché l'host possa raggiungere un servizio in un container con bridge, di solito è necessaria una porta pubblicata:
docker run -d --name web -p 8080:80 nginx
Questo mappa la porta host 8080 alla porta container 80. Testa dall'host:
curl -v http://localhost:8080
Controlla cosa ha pubblicato Docker:
docker port web
docker ps --format 'table {{.Names}} {{.Ports}}'
Se non c'è mapping di porte, EXPOSE nel Dockerfile non pubblica la porta. EXPOSE è documentazione e metadati. Hai ancora bisogno di -p o ports: in Compose.
Se la porta è pubblicata ma la connessione fallisce, controlla quattro cose:
- L'applicazione è in ascolto all'interno del container sulla porta del container.
- L'applicazione è in ascolto su
0.0.0.0, non solo su127.0.0.1. - Nessun firewall host blocca la porta host.
- Nessun altro processo possiede già la porta host.
Trova conflitti di porte host:
sudo lsof -i :8080
# oppure
sudo ss -ltnp 'sport = :8080'
Per Compose, ricorda la sintassi:
ports:
- "8080:80"
Il lato sinistro è la porta host. Il lato destro è la porta del container.
Il container non può raggiungere Internet
Testa la connettività IP e il DNS separatamente:
docker exec -it app sh
ping -c 2 1.1.1.1
ping -c 2 example.com
Alcune immagini non includono ping. Usa curl se disponibile:
curl -I https://example.com
Se l'IP funziona ma i nomi falliscono, è un problema DNS. Controlla:
cat /etc/resolv.conf
Docker normalmente inietta le impostazioni del resolver. Le VPN aziendali, i DNS personalizzati e il networking di Docker Desktop possono complicare la situazione. Puoi configurare il DNS a livello di demone nelle impostazioni del demone Docker, o passare il DNS per un container specifico:
docker run --dns 1.1.1.1 ...
Non usare DNS pubblici ciecamente in ambienti aziendali dove i nomi interni devono essere risolti. Usa i server DNS appropriati per la rete.
Se né IP né DNS funzionano, controlla se il container è su --network none, se le regole del firewall host/NAT sono rotte, se il demone Docker ha impostazioni di rete personalizzate e se l'host stesso ha accesso a Internet.
Un container deve raggiungere un servizio sull'host
Da un container, localhost significa il container stesso, non l'host. Questo è uno degli errori di rete Docker più comuni.
Su Docker Desktop, host.docker.internal di solito si risolve nell'host. Su moderno Docker Engine per Linux, puoi aggiungere una voce di gateway host:
docker run --add-host=host.docker.internal:host-gateway ...
Quindi il container può chiamare:
curl http://host.docker.internal:3000
Assicurati che il servizio host ascolti su un indirizzo raggiungibile da Docker, non solo un binding loopback a cui Docker non può accedere nel tuo ambiente. Se un server di sviluppo locale si lega solo a 127.0.0.1, potresti doverlo legare a 0.0.0.0 o all'interfaccia host, a seconda del sistema operativo e dei requisiti di sicurezza.
Macchine remote non possono raggiungere il container
Se l'host può raggiungere localhost:8080 ma un'altra macchina non può raggiungere server-ip:8080, Docker potrebbe essere a posto. Controlla il firewall host, il gruppo di sicurezza cloud, il router/NAT e se Docker ha pubblicato solo sul loopback.
Questo pubblica su tutte le interfacce host:
docker run -p 8080:80 nginx
Questo pubblica solo su localhost:
docker run -p 127.0.0.1:8080:80 nginx
La pubblicazione solo su loopback è spesso desiderabile per lo sviluppo locale o configurazioni di proxy inverso, ma bloccherà l'accesso remoto per progettazione.
Su server cloud, controlla anche i firewall del provider. Aprire ufw sulla VM non aiuta se il gruppo di sicurezza cloud blocca ancora la porta.
Errori di rete in Compose
Compose assegna a ogni servizio un nome DNS basato sul nome del servizio. Se il tuo servizio si chiama db, altri servizi dovrebbero di solito connettersi a db, non a localhost.
Esempio:
services:
api:
build: .
environment:
DATABASE_URL: postgres://postgres:postgres@db:5432/app
depends_on:
- db
db:
image: postgres:16
depends_on controlla l'ordine di avvio, non la prontezza. Il container del database potrebbe avviarsi prima che Postgres sia pronto ad accettare connessioni. La tua applicazione dovrebbe ritentare le connessioni o utilizzare un pattern di avvio che tenga conto dei healthcheck.
Distinguere anche ports da expose. ports pubblica sull'host. expose documenta o espone le porte ai servizi collegati ma non le rende raggiungibili dall'host allo stesso modo.
Debug a livello di pacchetto
Quando i controlli normali non spiegano il problema, usa un'immagine di debug di rete:
docker run --rm -it --network container:<container-target> nicolaka/netshoot
Questo si unisce al namespace di rete del container target, permettendoti di ispezionare il networking dallo stesso punto di vista senza installare strumenti nell'immagine dell'app.
Comandi utili includono:
ip addr
ip route
cat /etc/resolv.conf
dig nome-servizio
curl -v http://nome-servizio:porta
tcpdump -nn -i any port 8080
Usa tcpdump quando devi sapere se i pacchetti arrivano. Se i pacchetti non arrivano mai, guarda prima del container: pubblicazione, firewall, routing, bilanciatore di carico. Se i pacchetti arrivano e nessuna risposta esce, guarda dentro il container o l'applicazione.
Un breve flusso di risoluzione dei problemi
Usa questo ordine per la maggior parte dei problemi di rete Docker:
- Definisci il percorso esatto: host a container, container a container, container a Internet, o remoto a host a container.
- Controlla l'attaccamento alla rete con
docker network inspect. - Controlla la risoluzione dei nomi dal lato sorgente.
- Controlla se il processo di destinazione è in ascolto sull'interfaccia e porta giuste.
- Controlla la pubblicazione delle porte solo per il traffico che attraversa dall'host al container.
- Controlla firewall, VPN, proxy, DNS e regole di sicurezza cloud al di fuori di Docker.
La maggior parte dei problemi di rete Docker non sono bug profondi di Docker. Di solito sono nomi sbagliati, porte sbagliate, binding loopback, porte pubblicate mancanti, assunzioni DNS o traffico testato dal lato sbagliato del confine.