How to Modify /etc/hosts File in Dockerfile: Persistent Hosts Configuration for Containers


2 views

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