__biancatcatcat

Two simple, quick methods to access the host network from a Docker container

Sometimes you need to be able to connect to the host network from inside a Docker container. Could be for debugging, or small projects, or whatever reason. I ran into this need and after googling, it took me way too long to eventually find the answer in the docs. If you're in the same situation, I hope I can save you some time!

Depending on your use case, a network of type host may not work (and requires some setup). Docker provides a way to add hosts into your container's /etc/hosts file. I'll show it here in two ways, one via CLI and one via docker-compose.

1. CLI: Using the --add-host parameter with docker run

Get the host machine's address for the docker0 interface and put it in shell var (note that docker0 doesn't exist on macOS, scroll to the next part if you're on a Mac). Of course, this part is optional if you just want to paste an IP in.

We put it in the HOST_IP shell var like so:

$ HOST_IP=`ip -4 addr show scope global dev docker0 | grep inet | awk '{print \$2}' | cut -d / -f 1`

Then we execute docker run with --add-host, using the variable we set, e.g.:

$ docker run --add-host outside:$HOST_IP --name busybox -it busybox /bin/sh

Now, within the container, we can inspect /etc/hosts, we see an extra line has been added:

[email protected]:~$ docker run --add-host outside:$HOST_IP --name busybox -it busybox /bin/sh

/ # cat /etc/hosts
127.0.0.1    localhost  
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet  
ff00::0    ip6-mcastprefix  
ff02::1    ip6-allnodes  
ff02::2    ip6-allrouters  
172.17.0.1    outside <---- THIS ONE!  
172.17.0.3    a8300156a695  

The IP address 172.17.0.1 which we passed in via docker run is now resolvable via the hostname "outside"!

We can verify it:

/ # ping outside
PING outside (172.17.0.1): 56 data bytes  
64 bytes from 172.17.0.1: seq=0 ttl=64 time=0.326 ms  
64 bytes from 172.17.0.1: seq=1 ttl=64 time=0.118 ms  
64 bytes from 172.17.0.1: seq=2 ttl=64 time=0.098 ms  
64 bytes from 172.17.0.1: seq=3 ttl=64 time=0.137 ms  
^C
--- outside ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss  
round-trip min/avg/max = 0.098/0.169/0.326 ms

note for macOS:

Docker for Mac does not have the docker0 interface1 that's used in this example. Instead, you can actually simply go into the container and use a special macOS-only DNS name that comes out of the box (version 17.06+):

# In my macOS:

$ [email protected]:~$ docker run -it busybox /bin/sh
/ # ping docker.for.mac.localhost
PING docker.for.mac.localhost (192.168.65.1): 56 data bytes  
64 bytes from 192.168.65.1: seq=0 ttl=37 time=0.278 ms  
64 bytes from 192.168.65.1: seq=1 ttl=37 time=0.529 ms  
64 bytes from 192.168.65.1: seq=2 ttl=37 time=0.494 ms  
64 bytes from 192.168.65.1: seq=3 ttl=37 time=0.430 ms  
64 bytes from 192.168.65.1: seq=4 ttl=37 time=0.482 ms  
^C
--- docker.for.mac.localhost ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss  
round-trip min/avg/max = 0.278/0.442/0.529 ms  

Easy. 🍰

From the docs:

From 17.06 onwards our recommendation is to connect to the special Mac-only DNS name docker.for.mac.localhost which will resolve to the internal IP address used by the host. [src]

2. docker-compose:

This mechanism also available docker-compose.yml files as the extra_hosts key, like so:

docker-compose.yml:

version: '2'  
services:  
  samplev2:
    image: "redis:alpine"
    extra_hosts:
       - "outside:172.17.0.1"

And since we took advantage of variable substitution in CLI example, I'll show how we can do the same here:

version: '2'  
services:  
  samplev2:
    image: "redis:alpine"
    extra_hosts:
       - "outside:${HOST_IP}"

In this example, we don't have an .env file, and HOST_IP is only a shell variable. To become an env var, we need export it first, and then run docker-compose:

$ [email protected]:~$ export HOST_IP=$HOST_IP && docker-compose up -d

Note: I don't run it as sudo here, but remember that sudo won't work with export!

The -d flag runs it in the background, and we can go into the container and check out our /etc/hosts file in almost the same way as we did earlier. Since we didn't name the container, we grab the container ID using docker ps first, which is 0dde138913ee:

[email protected]:~$ docker exec -it 0dde138913ee /bin/sh

/# cat /etc/hosts
127.0.0.1    localhost  
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet  
ff00::0    ip6-mcastprefix  
ff02::1    ip6-allnodes  
ff02::2    ip6-allrouters  
172.17.0.1    outside <---- IT'S HERE!  
172.21.0.2    0dde138913ee  

Success!

Anyway, hope this is helpful in some way. And if it is please let me know so I can write more! You can always find me on Twitter. :)

Footnotes and such:

What would you like to see me write about? Comments and questions are welcome in the comments or on Twitter!