Docker networks explained - part 1

Have you ever wondered how networks in Docker work? Maybe you are interested in the less known things that you can do with the networking layer with Docker? Here are some interesting facts and use cases, that might help in every-day use.

Exposing ports

Let’s start with the basics. Ports exposing is the most commonly used thing around Docker networking, but do you know all the things about it?

Let’s take a look at a simple command like this:

docker run -p 127.0.0.1:80:8080/tcp ubuntu bash

What does this mean? Well, might be tricky, but it means: Listen for TCP connections on 127.0.0.1 on port 80, and forward the traffic to port 8080 inside the container.

If we simplify that a bit:

docker run -p 80:8080/tcp ubuntu bash

We have omitted the IP part, and now Docker will listen on all interfaces, so it will be possible to access the service from the outside.

We can change the notation even more, and run:

docker run -p 80:8080/udp ubuntu bash

This will forward udp connections. Another option is sctp but it is not widely used for web related stuff. TCP is obviously the most common one, so if we skip the /protocol part - it will be set to TCP by default.

And what happens if we run just this:

docker run -p 8080 ubuntu bash

This will forward TCP traffic, from a randomly chosen port to port 8080 in the container. Wait? Randomly?! How do I know which port was used?

Just take a look at docker ps - there is a column for that:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
2f82dac833ae        mariadb:10.3        "docker-entrypoint.s…"   10 days ago         Up 9 hours          3306/tcp               project_db_1
86f00e7f41a2        phpmyadmin          "/docker-entrypoint.…"   10 days ago         Up 9 hours          0.0.0.0:8080->80/tcp   project_phpmyadmin_1
31ea70729fbf        redis:6             "docker-entrypoint.s…"   6 weeks ago         Up 9 hours          6379/tcp               project_redis_1

In the PORTS column is all you need plus more. It also shows exposed ports that are not forwarded. Such port is not accessible from the outside (except docker networks, but this will come alter), but you get this info in case you would like to forward it.

You can also run docker port to check mapping for a given container:

$ docker port project_phpmyadmin_1
80/tcp -> 0.0.0.0:8080

But it is missing the part for not mapped ports, so I guess you won’t use that command too often ;)

There is one last thing that we need to mention, and that is the -P argument for docker run.

$ docker run -P ubuntu bash 

-P exposes all ports mentioned in the Dockerfile on random ports on the host machine.

Connecting containers

Let's start a simple web-server:

docker run -d --name test_web nginx:alpine

If we then lunch a second container, lets say ubuntu, install curl on it and try to access the web page:

docker run -t -i --rm ubuntu bash
apt update
apt install curl
curl test_web

This wont work, the name is not resolved! We could make use of docker inspect and check that the IP of the test_web container is 172.17.0.2, then run

curl 172.17.0.2

And it would work. So the connectivity is limited, but it is possible.

If you are familiar with docker-compose, this might be confusing. Services inside docker-compose can easily communicate with each other using their names! If you have a simple file like:

version: '3.6'
services:
  db:
    image: mariadb:10.3
    environment:
      ...
  phpmyadmin:
    image: phpmyadmin
    restart: always
    ports:
      - 8080:80
    environment:
      - PMA_HOSTS=db

Then the phpmyadmin can obviously connect to the db service using its name - db! The reason for that is quite simple, it works for containers within the same network, except for the default one.

Lets give it a try!

We can create a new network by running:

docker network create test

and connect existing containers to it running:

docker network connect test test_web
docker network connect test NameOfYourBashContainer

I assume the test bash container is still alive, you just need to use its name in the second line above. Now switching back to it and running:

curl test_web

Will work! Notice that a port does not need to be exposed in order to access it from a second container as long as both containers share the same network.

Disconnect one of the containers from the newly created network by running:

docker network disconnect test NameOfYourBashContainer

And the name wont be resolved anymore!

It is also possible to connect a container to a network while creating it, just pass the network as one of the input options:

docker run -t -i --rm --network test ubuntu bash

Use cases

One sample use cases would be to connect different projects or microservices, without having all of the running containers in one network. This allows to quite freely adjust the matrix of connections between containers. You can use this to test security rules that are configured on production - ex. on AWS.

Another use case would be to test connection issues (chaos monkey). We will cover a better approach to this in follow up articles, but networks will do the work for basic scenarios.

More info soon

I plan to write follow up articles with networks in docker-compose and a short article on simulating network issues (chaos monkey). Subscribe to our newsletter to make sure you won't miss them.

Also, if you are interested in more advanced Docker techniques, check my recent eBook - Docker Deep Dive.

Docker Deep Dive Book

scale

Ready to make your SaaS Scalable?

Fix most important issues within days from the kick-off

ESTIMATE PROJECTOr contact us directly at: [email protected]

Related posts