Docker Network

Published in category Opinion
on Christian Mayer's Weblog.

I’m using Docker since around Oktober 2017. Since I started using it I’m constantly searching for a way to get access to the host via the host’s IP address.

I want a solution without any dependencies. This means using as less as possible extra software. The goal is not to rely on tools or scripts other than Docker.

It doesn’t matter what you do with Docker Network, it’s always a mess.

For a better understanding, I also use Host as a synonym for the host machine, where the Docker daemon is running. And Container for what’s running inside Docker.

Host LAN IP address

This would be the easiest way to access the host: using the host’s LAN IP address inside the container. But I would not use it as the host’s IP address may be assigned dynamically. This is perfect for test cases, but not acceptable as a long-term solution or production.

Also on root-servers with static IP addresses this solution is not very reliable. Consider moving the container to another host machine. You don’t want to change the IP address on multiple locations.

Host Loopback Interface Alias

The loopback interface is also sometimes called localhost, or 127.0.0.1.

You can set an alias on the host’s loopback interface. Then using this alias IP address inside the container to access the host. You cannot use 127.0.0.1 inside the container. This would point inside the container.

Using an alias works well. The problem is when you are working in a team. Every developer has to setup the exact same alias. On each working machine.

To set 10.254.254.254 as an alias under macOS use the following command:

$ sudo ifconfig lo0 alias 10.254.254.254

Create your own hostname

Creating your own hostname and using it through all projects is one of the best solutions. Especially when the container has to access the host machine, go for this. Like all other solutions, it requires work to do on the host machine. I would rather do nothing at all on the host system, but sadly, this is how Docker is designed. You have to adapt and prepare stuff on the host system. In most use cases it’s normal to prepare the host as well.

Even more work, when you have different host systems running. But let’s focus only on Debian Linux. The following shell commands have to be executed before the image will be started. So, creating a separate run_docker.sh script here, to prepare everthing, is a good decision.

This command returns the default network interface of the host system.

$ route -4 | awk '/^default/ { print $8 }'

Or more advanced for Bash scripts:

default_if=$(route -4 | awk '/^default/ { print $8 }')

Next, get the IP address for the default network interface.

host_ip=$(ifconfig "${default_if}" | awk '/inet / { print $2 }' | head -1)

When starting the image, use $host_ip to set host.docker.local. This will add a new entry to /etc/hosts inside the container.

docker run \
    --add-host="host.docker.local:$host_ip" \
    ...

You can use host.docker.local as a hardcoded hostname in configurations to access the host machine. Do not use .localhost as top-level domain (TLD) here since some DNS servers have a *.localhost catch-all rule which resolves to 127.0.0.1. Which is senseless in this case.

You are more independent when you already know forefront that the data on the host and the Docker container will always be on the same machine. Even if you move both together you don’t have to change anything in regarding of hostnames because host.docker.local will always point to the host machine.

Use DNS

The most Docker container I’m working with have to access a MySQL database. The databases are always outside of Docker. And they never ever will. (It’s the worst idea ever, having a database inside Docker.)

When you have such a container it’s better to use DNS. Even if the database is on the same machine as the Docker container, I would not go with the previous (Create your own hostname) solution. Just add the hostname to your DNS server and use it in the configurations inside the container. For example, db.your-company.tld will do the job well. It’s more comfortable using a fixed DNS hostname when moving the container to another host machine. At least you have one thing less to change.

Don’t underestimate this. It’s still a shitload of work manually moving a container from one host to another. So being as host independent as possible should be always your intention.

Docker for Mac

From StackOverflow:

On Docker for Mac, as of version 18.03, you can use host.docker.internal as the host’s IP. […] This is an update from docker.for.mac.localhost, available since version 17.06, and docker.for.mac.host.internal, available since version 17.12, which may also still work.

This is actually very stupid. I want to use the same hostname regardless on which host system I run the container. This is the whole point of Docker, right? To be independent.

As I said above, you always have work to do on the host system. Let’s escalate a bit. I was introduced to Docker like Build it once, run it everywhere. Do not get fooled by that. This is delusional, since you always have to configure the host system somehow.

So, docker.for.mac.localhost is useless since in most cases you don’t have a Linux- or Mac-only environment in your company. It’s mixed. You have developers using Linux and Mac and Windows. This hostname makes no sense since in 99.99 % it’s a mixed Host OS environment. I don’t develop a container under macOS and deploy it to a macOS server. I deploy it to Linux. This is how everyone does. At least in my sphere. What’s even the whole point of docker.for.mac.localhost? Only a development utility? I cannot even use it on all dev machines. Don’t use it at all.

Conclusion

The best solution would be to use an alias (like host.docker.internal as in Docker for Mac) provided by Docker as a build-in functionality, for all host systems. Regardless which host system the container is running on. Sadly, this is not a build-in feature of Docker. As long as Docker is not providing such a feature out-of-the-box we have to use our own solution to be host independent. You can see in the solutions above, it’s about which data you want to access from inside the container.

As I said before, being as host independent as possible should be always your intention when dealing with Docker.

More Resources

Recent Posts

About the Author

Christian is a professional software developer living in Vienna, Austria. He loves coffee and is strongly addicted to music. In his spare time he writes open source software. He is known for developing automatic data processing systems for Debian Linux.