Adding Host Entries to Docker Containers: Precise Networking Control
Modern development workflows often depend on containers communicating by predefined hostnames. Custom host mapping is a frequent necessity—especially when integrating legacy services, mocking endpoints, or bypassing DNS for rapid iteration.
A typical scenario: running a service that expects another component at a specific hostname (e.g., db.internal.local
). However, container DNS isolation prevents seamless resolution unless you configure it explicitly.
Direct Host Mapping: docker run --add-host
Cut to the chase—inject a host-to-IP record into a container’s /etc/hosts
file:
docker run --rm -it --add-host api.mocked.local:172.18.0.50 nginx:1.25-alpine sh
Inside the container, inspect the entries:
cat /etc/hosts
Expected output (with Docker 23.x):
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
172.18.0.50 api.mocked.local
Networking operations now use the custom IP for api.mocked.local
. Particularly useful when simulating backend services or working offline. Note: --add-host
does not affect containers created with docker network create
, which already resolve service names by default—different mechanisms, different use cases.
Multiple Hostnames, Multiple Mappings
Stack mappings by repeating the flag:
docker run --rm -it \
--add-host cache.test.local:10.0.10.1 \
--add-host metrics.local:192.168.4.7 \
busybox:1.36 sh
You can specify up to several dozen hosts before hitting shell or Docker daemon limits (rare in normal workflows).
Docker Compose: extra_hosts
in Practice
For complex stacks or CI pipelines, use Compose v3+ to persist and version mappings.
docker-compose.yml
example:
version: '3.8'
services:
app:
image: python:3.11.6-alpine
command: python -m http.server
extra_hosts:
- "svc.local:172.22.0.20"
- "upstream:192.168.30.8"
Brings the mappings into every container lifecycle event (docker compose up --force-recreate
required to update changes).
Use Case: Isolating Integration Tests
A typical integration suite in CI might require shunting a domain like auth.staging
to a stub:
extra_hosts:
- "auth.staging:127.0.0.2"
Gotcha: If you bind a local IP not attached to any real interface, test traffic will blackhole—intentional in some cases.
Notes and Known Issues
- Modifies only container internals. No global or host-wide change.
- Entries are ephemeral—restart your container and the mapping only persists if scripted or included via Compose.
- Not suitable for production, except for rapid patching or one-off troubleshooting. For robust solutions, deploy an internal DNS resolver (CoreDNS, Consul).
- Advanced: Multi-network containers may have ambiguous preferences between
/etc/hosts
, container DNS, and network aliases. See Docker networking docs for resolution order.
Non-Obvious Tip
If a container unexpectedly fails host resolution—even with correct --add-host
—check for lingering outdated Compose networks or conflicts between extra_hosts
and service discovery. Remove and recreate with:
docker compose down -v
docker compose up --build
This resets the network layer and clears hidden state.
Summary Table
Method | Suitable For | Persistence | Scale |
---|---|---|---|
--add-host | Ad hoc/manual runs | No | Single |
extra_hosts (Compose) | Declarative config, repeatability | Yes | Medium |
Internal DNS (e.g. CoreDNS) | Dynamic, large-scale environments | Yes | Large |
Add host entries into Docker with --add-host
or extra_hosts
for fine-grained, testable, and isolated networking. For anything persistent or at scale, adopt declarative Compose configs or managed DNS. It’s not complex, but subtle missteps can lead to elusive networking bugs—always verify effective mappings inside the container environment, not outside.