Docker networks explained - part 1
Tags: docker
Published: 2022-02-21 07:02:31

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:
```bash
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:
```bash
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:

```bash
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:
```bash
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:

```bash
$ 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.

```bash
$ 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:

```bash
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
```bash 
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:

```yaml=
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:

```bash
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 article with networks in docker-compose, microservices and simulating network issues (chaos monkey). Subscribe to our newsletter to make sure you won't miss them. 
<br>
Update: [Docker Networks - part 2](https://accesto.com/blog/docker-networks-explained-part-2/) is now released.
<br>
Also, if you are interested in more advanced Docker techniques, check my recent eBook - <a href="https://accesto.com/books/docker-deep-dive/">Docker Deep Dive</a>.
<br>