Quando si lavora in sviluppo locale è comune definire domini come api.test o frontend.test
nel file /etc/hosts della macchina host. Con Docker però nasce un problema: il container non vede
automaticamente le voci presenti nel /etc/hosts dell'host e quindi non riesce a risolvere quei domini.
In questo articolo vediamo in dettaglio:
- come Docker gestisce DNS e
/etc/hostsnei container; - come far risolvere domini
.testdefiniti sull'host; - pro e contro delle varie soluzioni;
- alcuni esempi pratici con
docker rune Docker Compose.
1. Come funziona la risoluzione DNS nei container Docker
Ogni container Docker è isolato dal sistema host. Questo significa che:
- il container ha il proprio file
/etc/hosts, generato da Docker al momento dell'avvio; - il container non legge il
/etc/hostsdell'host; - il container utilizza un resolver DNS configurato da Docker (tipicamente l'internal DNS di Docker o quello specificato nel daemon o nel comando
docker run).
Se quindi sulla macchina host hai qualcosa come:
# /etc/hosts dell'host
127.0.0.1 api.test
127.0.0.1 frontend.test
il container non vedrà queste voci a meno che tu non le aggiunga esplicitamente al suo /etc/hosts
o non configuri un DNS che le conosca.
2. Obiettivo: risolvere domini .test definiti nell'host
L'obiettivo tipico è questo: dall'interno del container vuoi poter raggiungere, ad esempio, api.test, che sull'host punta a un certo IP (spesso 127.0.0.1 o un altro indirizzo locale).
Hai essenzialmente tre strade principali:
- passare esplicitamente le voci hosts al container (
--add-hostoextra_hosts); - usare la parola chiave speciale
host-gatewayper far puntare il dominio all'IP dell'host visto dal container; - configurare un DNS locale (es. dnsmasq, Pi-hole, Bind) e dire ai container di usare quel DNS.
3. Soluzione 1: usare --add-host / extra_hosts
Il modo più diretto e semplice per far sì che un container risolva un dominio .test è aggiungerlo
al suo /etc/hosts al momento dell'avvio.
3.1. Esempio con docker run
Supponiamo che sull'host tu abbia:
# /etc/hosts dell'host
127.0.0.1 api.test
Puoi avviare il container così:
docker run --add-host api.test:127.0.0.1 myimage
Nel container verrà generato un /etc/hosts che, tra le altre cose, conterrà una riga simile a:
127.0.0.1 api.test
In questo modo, qualunque processo dentro il container che provi a risolvere api.test userà quell'indirizzo.
3.2. Esempio con Docker Compose
Con Docker Compose, l'equivalente è la direttiva extra_hosts:
services:
app:
image: myimage
extra_hosts:
- "api.test:127.0.0.1"
Anche in questo caso, Docker aggiungerà la voce al /etc/hosts del container.
3.3. Pro e contro della soluzione --add-host
- Pro:
- semplice da configurare;
- non richiede un DNS esterno;
- funziona ovunque, anche senza privilegi particolari sull'host.
- Contro:
- devi specificare esplicitamente l'IP (se cambia, va aggiornato dappertutto);
- se hai molti domini
.test, la configurazione può diventare verbosa.
4. Soluzione 2: usare host-gateway per puntare all'host
Docker fornisce una parola chiave speciale, host-gateway, che rappresenta l'indirizzo IP dell'host visto dal container.
Invece di scrivere un IP fisso, puoi fare:
docker run --add-host api.test:host-gateway myimage
Oppure in Docker Compose:
services:
app:
image: myimage
extra_hosts:
- "api.test:host-gateway"
In questo modo, api.test punterà all'IP dell'host della rete Docker, indipendentemente dal valore numerico concreto.
4.1. Quando usare host-gateway
Questa modalità è molto comoda quando:
- il servizio che ti interessa gira sull'host, non in un altro container;
- non vuoi dover scoprire e mantenere aggiornato l'IP dell'host;
- vuoi una configurazione più portabile tra ambienti diversi.
5. Soluzione 3: usare un DNS locale per i domini .test
Se stai usando molti domini .test o vuoi una soluzione più vicina a un ambiente “reale”, puoi configurare un DNS locale che risolva i tuoi domini di sviluppo e far sì che sia i container sia l'host lo usino.
Esempio tipico: installi e configuri dnsmasq su una macchina della tua LAN (o sulla stessa macchina host) per far sì che tutti i domini *.test puntino a un certo IP.
5.1. Configurare il DNS nei container
Una volta che hai un server DNS (ad esempio 192.168.1.10) che sa risolvere api.test, puoi dire ai container di usare quel DNS con:
docker run --dns=192.168.1.10 myimage
Oppure, a livello di Docker daemon, modificando /etc/docker/daemon.json sull'host:
{
"dns": ["192.168.1.10"]
}
Dopo il riavvio del servizio Docker, tutti i container useranno quel DNS, a meno che non venga specificato diversamente al momento del run.
5.2. Pro e contro del DNS locale
- Pro:
- gestione centralizzata dei domini;
- l'host e i container condividono la stessa visione del DNS;
- molto scalabile quando i domini diventano numerosi.
- Contro:
- richiede la configurazione e manutenzione di un DNS server;
- è leggermente più complesso rispetto a un semplice
--add-host.
6. Perché non si può “ereditare” /etc/hosts dell'host
Una domanda frequente è: “Posso dire a Docker di usare direttamente il /etc/hosts dell'host?”.
La risposta, ad oggi, è: no, non in modo supportato e automatico. Il motivo è legato al modello di isolamento dei container:
- ogni container ha un suo namespace di rete e un suo filesystem;
- Docker genera il
/etc/hostsdel container in base ai parametri del run, alla rete, ai link tra container, ecc.; - agganciare il
/etc/hostsdell'host così com'è romperebbe vari assunti di isolamento e potrebbe creare inconsistenze.
In teoria potresti montare manualmente il file di hosts dell'host nel container, ma è una pratica sconsigliata perché:
- può cambiare il file sull'host in modi non voluti dal container (e viceversa, se montato in lettura/scrittura);
- può creare effetti collaterali difficili da diagnosticare.
7. Pattern consigliato per domini .test in sviluppo
Un pattern pratico e relativamente semplice da mantenere è:
- Sull'host, far girare i servizi che devono rispondere a
.test(o esporli da altri container). - Nel file
/etc/hostsdell'host, definire i domini.testper uso del browser e di altri tool locali. - Per i container che devono raggiungere tali domini:
- usare
--add-host dominio.test:host-gatewayoextra_hostsconhost-gateway; - oppure, se usi già un DNS locale, configurare correttamente il DNS con
--dnsodaemon.json.
- usare
Esempio completo con Docker Compose che usa host-gateway:
version: "3.9"
services:
app:
image: myimage
extra_hosts:
- "api.test:host-gateway"
environment:
- API_BASE_URL=http://api.test:8080
In questo scenario:
- l'applicazione nel container può contattare
http://api.test:8080; api.testviene risolto all'IP dell'host visto dal container;- sull'host puoi avere una voce in
/etc/hostsche punta lo stesso dominio a127.0.0.1, così il browser dell'host vede lo stesso indirizzo simbolico.
8. Riepilogo
- I container Docker non leggono automaticamente il
/etc/hostsdell'host. - Per far risolvere domini
.testdefiniti sull'host hai tre soluzioni principali:- passare le voci hosts esplicitamente con
--add-hostoextra_hosts; - usare
host-gatewayper evitare di specificare un IP fisso e puntare all'host; - configurare un DNS locale e dire ai container di usare quel resolver.
- passare le voci hosts esplicitamente con
- La soluzione più rapida nella maggior parte dei casi è usare
--add-hostoextra_hostsconhost-gateway, così non devi gestire manualmente gli indirizzi IP.
Con questa configurazione, i tuoi container potranno risolvere senza problemi i domini .test che usi sulla macchina host, mantenendo al tempo stesso l'isolamento e la coerenza dell'ambiente Docker.