When building Docker containers, many developers encounter a frustrating scenario: they try to append custom host entries to /etc/hosts
during image build, but the changes don't persist in the final container. This happens because Docker treats /etc/hosts
as a special file that gets regenerated when containers start.
The conventional methods like these won't work:
# Doesn't persist
RUN cat /tmp/hosts >> /etc/hosts
# Also ineffective
RUN bash -c 'cat /tmp/hosts | tee -a /etc/hosts'
Docker intentionally prevents direct modification of /etc/hosts
during build for security and networking consistency reasons.
Here are three reliable ways to configure custom hosts in your containers:
1. Using Docker Run --add-host
The most Docker-native approach is to specify hosts at runtime:
docker run --add-host=myhost:192.168.1.100 myimage
You can combine this with environment variables in your Dockerfile:
FROM alpine
ENV EXTRA_HOSTS=""
CMD echo "$EXTRA_HOSTS" >> /etc/hosts && exec your_app
2. Pre-build Script Execution
Modify the hosts file right before container startup by using an entrypoint script:
#!/bin/sh
# entrypoint.sh
cat /tmp/hosts >> /etc/hosts
exec "$@"
Then in your Dockerfile:
COPY entrypoint.sh /entrypoint.sh
COPY hosts /tmp/hosts
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["your_app"]
3. Using System-Level Configuration
For complex setups, consider configuring the hosts through DNS or container orchestration:
- Kubernetes: Use hostAliases in pod specifications
- Docker Compose: Use the
extra_hosts
directive
Here's a complete working example for a development environment:
FROM python:3.9
# Copy custom hosts file
COPY dev-hosts /tmp/hosts
# Create and make executable our entrypoint
RUN echo '#!/bin/bash\ncat /tmp/hosts >> /etc/hosts\nexec "$@"' > /entrypoint.sh \
&& chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["python", "app.py"]
When dealing with host modifications:
- Changes to
/etc/hosts
are container-specific and don't affect the host machine - In Kubernetes environments, prefer using Service Discovery over manual host entries
- For production, consider using proper DNS configuration instead of host file edits
When building Docker images, many developers encounter a frustrating scenario: attempting to modify the /etc/hosts
file during the build process appears to succeed, but the changes mysteriously disappear in the final container. This happens because Docker treats /etc/hosts
as a special file that gets regenerated during container startup.
The typical methods like:
RUN echo "192.168.1.100 myserver" >> /etc/hosts
# Or
RUN cat /tmp/hosts >> /etc/hosts
don't work because:
- Docker's internal DNS system overwrites the file
- The build process doesn't persist these changes
- Container networking takes precedence
Here are proven methods to handle host entries in Docker:
1. Using docker-compose (Recommended)
For runtime configuration:
version: '3'
services:
myapp:
image: myimage
extra_hosts:
- "hostname:192.168.1.100"
- "otherhost:10.0.0.1"
2. Custom Entrypoint Script
Create an entrypoint.sh:
#!/bin/bash
echo "192.168.1.100 myserver" >> /etc/hosts
exec "$@"
Then in Dockerfile:
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["java", "-jar", "/app.jar"]
3. Using Network Aliases
For Docker networks:
docker network create mynet
docker run --network mynet --network-alias myserver myimage
If you absolutely need host entries during build:
RUN echo "192.168.1.100 buildserver" > /etc/hosts && \
curl http://buildserver/resource && \
echo "" > /etc/hosts
- Changes to /etc/hosts are ephemeral in containers
- For development, use docker-compose extra_hosts
- For production, consider proper DNS configuration
- Host entries may violate container portability principles