Two simple, quick ways to access docker host container IP from inside a container
Last updated: April 6, 2019
Last tested with version Docker version 18.09.3 on Ubuntu 16.04, Debian 9 (stretch), macOS Mojave (10.14.4).
NOTE: If your problem is connecting TO containers FROM a macOS host, see this post: https://biancatamayo.me/blog/docker-troubleshooting-macos-network/
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!
Update April 2019: This won’t work for Kubernetes pods/services. Kubernetes networking works differently from plain Docker networking.
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 as a bonus.
1. CLI: Using the --add-host
parameter with docker run
If you’re on macOS using Docker Desktop, it’s easier. Scroll down or skip to note for macOS.
Main idea: pass in the docker0
IP address to the container via --add-host
:
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 the 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`
(To find the IP address without using the above snippet, you can use the command ifconfig docker0
).
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
## now we're in the container:
/ $ 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 (and Windows):
This supposedly also works on Windows, but as I don’t have a Windows dev machine, I can’t test it.
Docker for Mac does not have the docker0
interface1 that’s used in the above example. Instead, you can actually simply go into the container and use a special macOS-only DNS name (docker.for.mac.localhost
) that comes out of the box (version 17.06+):
Update April 2019: The DNS name is now called host.docker.internal
in the docs, though docker.for.mac.localhost
works just as well for now in Docker 18.09.3. Additionally, you can also now also use gateway.docker.internal
to access the host’s gateway.
# In my macOS:
$ [email protected]:~$ docker run -it busybox /bin/sh
## now we're in the container!:
## pinging docker.for.mac.localhost
/ $ ping docker.for.mac.localhost
PING docker.for.mac.localhost (192.168.65.2): 56 data bytes
64 bytes from 192.168.65.2: seq=0 ttl=37 time=0.420 ms
64 bytes from 192.168.65.2: seq=1 ttl=37 time=0.564 ms
^C
--- docker.for.mac.localhost ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.420/0.492/0.564 ms
## pinging host.docker.internal
/ $ ping host.docker.internal
PING host.docker.internal (192.168.65.2): 56 data bytes
64 bytes from 192.168.65.2: seq=0 ttl=37 time=0.289 ms
^C
--- host.docker.internal ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.289/0.289/0.289 ms
## pinging the host's gateway:
/ $ ping gateway.docker.internal
PING gateway.docker.internal (192.168.65.1): 56 data bytes
64 bytes from 192.168.65.1: seq=0 ttl=37 time=0.265 ms
64 bytes from 192.168.65.1: seq=1 ttl=37 time=0.625 ms
^C
--- gateway.docker.internal ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.265/0.445/0.625 ms
Easy. 🍰
From the docs:
The host has a changing IP address (or none if you have no network access). From 18.03 onwards our recommendation is to connect to the special DNS name
host.docker.internal
, which resolves to the internal IP address used by the host. This is for development purpose and will not work in a production environment outside of Docker Desktop for Mac.The gateway is also reachable as
gateway.docker.internal
. [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
:
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. 🙂
Update December 2019: I understand there’s a desire for the convenience hostname host.docker.internal
to be made available on all platforms, and not just macOS or Windows. I don’t have an opinion on that, but if you do you can follow the lengthy discussion here: https://github.com/docker/for-linux/issues/264
Again, if your problem is connecting TO containers FROM a macOS host, see this post: https://biancatamayo.me/blog/docker-troubleshooting-macos-network/
What would you like to see me write about? Comments and questions are welcome in the comments or on Twitter!