Docker Networking Basics

The four basic resources of virtualization are CPU, memory, storage and network connection. In this chapter, we go through the various network solutions that are technically available and which solutions are recomended for software developers to implement in their work environment.

Types of Docker networks

Host contained networks

default bridge The default network driver that will be created when docker installs on the system. All containers get an internal IP address and these containers can access each other, using this internal IP. Default bridge will not support container DNS resolving. For that you need User-defined bridge

User-defined bridge networks are best when you need multiple containers to communicate on the same Docker host. Support for internal container DNS resolving

Host networks are best when the network stack should not be isolated from the Docker host, but you want other aspects of the container to be isolated. Good chose for network or VPN solution. Unfortunately Host networks will not work on Windows computers.

none disable all networking. Usually used in conjunction with a custom network driver or container that don’t need network access.

Solutions that require network device management

Overlay networks are best when you need containers running on different Docker hosts to communicate, or when multiple applications work together using swarm services.

Macvlan networks are best when you are migrating from a VM setup or need your containers to look like physical hosts on your network, each with a unique MAC address.

https://medium.com/edureka/docker-networking-1a7d65e89013 && https://docs.docker.com/network/ && https://docs.docker.com/network/bridge/

Docker Networking practice

In this lab you’ll look at the most basic networking components that come with a fresh installation of Docker.

You will complete the following steps as part of this lab.

Step 1: The docker network command

The docker network command is the main command for configuring and managing container networks.

Run a simple docker network command from any of your lab machines.

$ docker network


Usage:  docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

Run 'docker network COMMAND --help' for more information on a command.

The command output shows how to use the command as well as all of the docker network sub-commands. As you can see from the output, the docker network command allows you to create new networks, list existing networks, inspect networks, and remove networks. It also allows you to connect and disconnect containers from networks.

Step 2: List networks

Run a docker network ls command to view existing container networks on the current Docker host.

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
1befe23acd58        bridge              bridge              local
726ead8f4e6b        host                host                local
ef4896538cc7        none                null                local

The output above shows the container networks that are created as part of a standard installation of Docker.

New networks that you create will also show up in the output of the docker network ls command.

You can see that each network gets a unique ID and NAME. Each network is also associated with a single driver. Notice that the “bridge” network and the “host” network have the same name as their respective drivers.

Step 3: Inspect a network

The docker network inspect command is used to view network configuration details. These details include; name, ID, driver, IPAM driver, subnet info, connected containers, and more.

Use docker network inspect to view configuration details of the container networks on your Docker host. The command below shows the details of the network called bridge.

$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "1befe23acd58cbda7290c45f6d1f5c37a3b43de645d48de6c1ffebd985c8af4b",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

NOTE: The syntax of the docker network inspect command is docker network inspect <network>, where <network> can be either network name or network ID. In the example above we are showing the configuration details for the network called “bridge”. Do not confuse this with the “bridge” driver.

Step 4: List network driver plugins

The docker info command shows a lot of interesting information about a Docker installation.

Run a docker info command on any of your Docker hosts and locate the list of network plugins.

$ docker info
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc., v0.8.2)
  compose: Docker Compose (Docker Inc., v2.7.0)
  extension: Manages Docker extensions (Docker Inc., v0.2.8)
  sbom: View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc., 0.6.0)
  scan: Docker Scan (Docker Inc., v0.17.0)

Server:
 Containers: 1
  Running: 0
  Paused: 0
  Stopped: 1
 Images: 5
 Server Version: 20.10.17
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runtime.v1.linux runc io.containerd.runc.v2
 Default Runtime: runc
 Init Binary: docker-init
 ...

The output above shows the bridge, host, null, and overlay drivers.

Step 5: Connect a container

The bridge network is the default network for new containers. This means that unless you specify a different network, all new containers will be connected to the bridge network.

Create a new container.

$ docker run --name sleeping-ubuntu -dt ubuntu sleep infinity     
6dd93d6cdc806df6c7812b6202f6096e43d9a013e56e5e638ee4bfb4ae8779ce

This command will create a new container named sleeping-ubuntu based on the ubuntu:latest image and will run the sleep command to keep the container running in the background. As no network was specified on the docker run command, the container will be added to the bridge network.

Inspect the bridge network again to see the new container attached to it.

$ docker network inspect bridge
<Snip>
        },
        "ConfigOnly": false,
        "Containers": {
            "d74c80f164a64e4d1d13c195ac1f4acdbe78d7aa13bb5ffde25354639cff8812": {
                "Name": "sleeping-ubuntu",
                "EndpointID": "29ca85f851fcad5bc308a97a82add1072119b075f42bc60156afe27207630a69",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
<Snip>

Step 6: Test network connectivity

The output to the previous docker network inspect command shows the IP address of the new container. In the previous example it is “172.17.0.2” but yours might be different.

Ping the IP address of the container from the shell prompt of your Docker host. Remember to use the IP of the container in your environment.

$ ping 172.17.0.2
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.069 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.052 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.050 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.049 ms
64 bytes from 172.17.0.2: icmp_seq=5 ttl=64 time=0.049 ms
^C
--- 172.17.0.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 3999ms
rtt min/avg/max/mdev = 0.049/0.053/0.069/0.012 ms

Press Ctrl-C to stop the ping. The replies above show that the Docker host can ping the container over the bridge network.

Log in to the container, install the ping program and ping Yle.fi.

# Get the ID of the container started in the previous step.
$ docker ps

CONTAINER ID    IMAGE    COMMAND             CREATED  STATUS  NAMES
6dd93d6cdc80    ubuntu   "sleep infinity"    5 mins   Up      sleeping-ubuntu

# Exec into the container
$ docker exec -it 6dd93d6cdc80 /bin/bash

# Update APT package lists and install the iputils-ping package
root@6dd93d6cdc80:/# apt update
 
apt install iputils-ping


# Ping yle.fi from within the container
root@6dd93d6cdc80:/# ping yle.fi           
PING yle.fi (108.156.22.49) 56(84) bytes of data.
64 bytes from 108.156.22.49 (108.156.22.49): icmp_seq=1 ttl=37 time=28.5 ms
64 bytes from 108.156.22.49 (108.156.22.49): icmp_seq=2 ttl=37 time=32.2 ms
64 bytes from 108.156.22.49 (108.156.22.49): icmp_seq=3 ttl=37 time=34.4 ms
64 bytes from 108.156.22.49 (108.156.22.49): icmp_seq=4 ttl=37 time=33.1 ms
^C
--- yle.fi ping statistics ---
7 packets transmitted, 7 received, 0% packet loss, time 6009ms
rtt min/avg/max/mdev = 28.516/33.495/42.324/4.141 ms

This shows that the new container can ping the internet and therefore has a valid and working network configuration.

Step 7: Configure NAT for external connectivity

In this step we’ll start a new NGINX container and map port 8080 on the Docker host to port 80 inside of the container. This means that traffic that hits the Docker host on port 8080 will be passed on to port 80 inside the container.

NOTE: If you start a new container from the official NGINX image without specifying a command to run, the container will run a basic web server on port 80.

Start a new container based off the official NGINX image.

$ docker run --name web1 -d -p 8080:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
386a066cd84a: Pull complete
7bdb4b002d7f: Pull complete
49b006ddea70: Pull complete
Digest: sha256:9038d5645fa5fcca445d12e1b8979c87f46ca42cfb17beb1e5e093785991a639
Status: Downloaded newer image for nginx:latest
b747d43fa277ec5da4e904b932db2a3fe4047991007c2d3649e3f0c615961038

Check that the container is running and view the port mapping.

$ docker ps
CONTAINER ID    IMAGE               COMMAND                  CREATED             STATUS              PORTS                           NAMES
b747d43fa277   nginx               "nginx -g 'daemon off"   3 seconds ago       Up 2 seconds        443/tcp, 0.0.0.0:8080->80/tcp   web1
6dd93d6cdc80        ubuntu              "sleep infinity"         About an hour ago   Up About an hour                                    sleeping-ubuntu

There are two containers listed in the output above. The top line shows the new web1 container running NGINX. Take note of the command the container is running as well as the port mapping - 0.0.0.0:8080->80/tcp maps port 8080 on all host interfaces to port 80 inside the web1 container. This port mapping is what effectively makes the containers web service accessible from external sources (via the Docker hosts IP address on port 8080).

Now that the container is running and mapped to a port on a host interface you can test connectivity to the NGINX web server.

Point your web browser to the IP and port 8080 of your Docker host. The following example shows a web browser pointed to localhost:8080. You can also open webpage using Docker Desktop.

If for some reason you cannot open a session from a web browser, you can connect from your Docker host using the curl command.

$ curl 127.0.0.1:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
    <Snip>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

If you try and curl the IP address on a different port number it will fail.

NOTE: The port mapping is actually port address translation (PAT).

Step 8: Configure User user-defined bridges

So far in the exercises, we have used the default network connection, which has been sufficient for the exercises. However, from the point of view of data security, it is important to isolate different containers from each other if it is not necessary for the containers to talk to each other.

In addition, in user-defined networks, containers can use the names of other containers for DNS addressing, which enables working connections even if the containers’ IP space changes. DNS service is critical when we use several different docker containers to form a single service entity, such as a WWW server and Mysql databases

Lets create a user-defined bridge network named

docker network create my-nginx

Lets create and start the container. We will start it as a detached process. The -d flag means to start the container detached (in the background). The –rm option means to remove the container once it exits/stops. The -p forwards container 80 port to host 8080 port.

docker run --name my-nginx --network my-net -d --rm -p 8080:80 nginx:latest  

Next we will stop Step 6 sleeping-ubuntu container if it still running. If you have already stopped it you can skip to docker network command.

$ docker ps

CONTAINER ID    IMAGE    COMMAND             CREATED  STATUS  NAMES
6dd93d6cdc80    ubuntu   "sleep infinity"    5 mins   Up      sleeping-ubuntu


$ docker stop 6dd93d6cdc80

We will transfer sleeping-ubuntu container from default network to your new user define network, start it and inspect the my-net network for successful connection

$ docker network connect my-net sleeping-ubuntu
$ docker start sleeping-ubuntu
$ docker network inspect my-net

<Snip>
                "Name": "my-nginx",
                "EndpointID": "7f69cd1f607744cb38122ad6e884e2fd5dd0d1fdb3f66e01e7c697f70020e7e2",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            },
            "cea4adb35d4d107b531ea9add3884b2250173268afc786ee6c32683cf06eba8a": {
                "Name": "sleeping-ubuntu",
                "EndpointID": "da9266a37c8a5d05d2ea74b3d90826fa3ff5f80f9c80740aadbc1b2f6912bd1c",
                "MacAddress": "02:42:ac:13:00:03",
                "IPv4Address": "172.19.0.3/16",
                "IPv6Address": ""
            }
<Snip>

Exec into the container to log in and install the ping program if needed.

$ docker exec -it sleeping-ubuntu /bin/bash

Lets ensure that traffic between containers and DNS names work using the ping command

$ root@6dd93d6cdc80:/# ping  my-nginx
PING my-nginx (172.19.0.2) 56(84) bytes of data.
64 bytes from my-nginx.my-net (172.19.0.2): icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from my-nginx.my-net (172.19.0.2): icmp_seq=2 ttl=64 time=0.056 ms
64 bytes from my-nginx.my-net (172.19.0.2): icmp_seq=3 ttl=64 time=0.044 ms
64 bytes from my-nginx.my-net (172.19.0.2): icmp_seq=4 ttl=64 time=0.064 ms
64 bytes from my-nginx.my-net (172.19.0.2): icmp_seq=5 ttl=64 time=0.067 ms
64 bytes from my-nginx.my-net (172.19.0.2): icmp_seq=6 ttl=64 time=0.052 ms

This shows that the container can talk to each other and have a valid connect to the internet. If you want to see my-nginx webpage install curl package using apt install curl and curl my-nginx

To remove user define network you have to stop containers then remove them from network.

$ docker network disconnect my-net my-nginx 
$ docker network disconnect my-net sleeping-ubuntu
$ docker network rm my-net

Step 9: Configure Host network (only on Linux machines)

Host network setting can not be run in Windows + Docker Desktop environment because Windows network stack is incompatible to Docker host settings. You can this settings with Linux host using HAMK lab environments or your own linux servers

Lets create and start the container. We will start it as a detached process. The -d flag means to start the container detached (in the background).

$ docker run -d --network host --name hello_nginx nginxdemos/hello

Point your web browser to the IP and port 80 of your Docker host. The following example shows a web browser pointed to localhost:80. You can also open webpage using Docker Desktop. You will see a basic information of the container.

Server address:	172.17.0.2:80

Server name:	ac7bfe9a3569

Date:	30/Aug/2022:09:53:11 +0000

URI:	/

To remove the container and free up port 80 we need to stop container. Container will be removed automatically because of –rm option.

$ docker container stop hello_nginx

https://docs.docker.com/get-started/docker_cheatsheet.pdf