Docker Network Basics

DockerDockerBeginner
Practice Now

Introduction

In this lab, we will explore the fundamentals of Docker networking. Docker networks enable containers to communicate with each other and the outside world. We'll cover various network types, creating custom networks, connecting containers, and managing network configurations. This hands-on experience will provide you with a solid foundation in Docker networking concepts and practices.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("`Docker`")) -.-> docker/ContainerOperationsGroup(["`Container Operations`"]) docker(("`Docker`")) -.-> docker/NetworkOperationsGroup(["`Network Operations`"]) linux(("`Linux`")) -.-> linux/RemoteAccessandNetworkingGroup(["`Remote Access and Networking`"]) docker/ContainerOperationsGroup -.-> docker/exec("`Execute Command in Container`") docker/ContainerOperationsGroup -.-> docker/port("`List Container Ports`") docker/ContainerOperationsGroup -.-> docker/run("`Run a Container`") docker/ContainerOperationsGroup -.-> docker/inspect("`Inspect Container`") docker/NetworkOperationsGroup -.-> docker/network("`Manage Networks`") linux/RemoteAccessandNetworkingGroup -.-> linux/ip("`IP Managing`") subgraph Lab Skills docker/exec -.-> lab-8445{{"`Docker Network Basics`"}} docker/port -.-> lab-8445{{"`Docker Network Basics`"}} docker/run -.-> lab-8445{{"`Docker Network Basics`"}} docker/inspect -.-> lab-8445{{"`Docker Network Basics`"}} docker/network -.-> lab-8445{{"`Docker Network Basics`"}} linux/ip -.-> lab-8445{{"`Docker Network Basics`"}} end

Understanding Docker Network Types

Docker provides several built-in network drivers. Let's start by examining the default networks on your system.

In your terminal, run the following command to list all available Docker networks:

docker network ls

This command lists all the networks that Docker has created on your system. You should see output similar to this:

NETWORK ID     NAME      DRIVER    SCOPE
79dce413aafd   bridge    bridge    local
91199fc6ad2e   host      host      local
1078d2c781b6   none      null      local

Let's break down the default network types:

  1. bridge: This is the default network driver. When you start a container without specifying a network, it automatically connects to the bridge network. Containers on the same bridge network can communicate with each other using their IP addresses.

  2. host: This driver removes network isolation between the container and the Docker host. The container shares the host's networking namespace, which means it uses the host's IP address and port space directly. This can be useful for optimizing performance in certain scenarios.

  3. none: This driver disables all networking for a container. Containers using this network type will have no access to external networks or other containers. It's useful when you want to completely isolate a container.

The SCOPE column indicates whether the network is limited to a single host (local) or can span across multiple hosts in a Docker swarm (swarm).

Inspecting the Default Bridge Network

Now that we've seen the list of networks, let's take a closer look at the default bridge network. This network is created automatically by Docker and is used by containers unless specified otherwise.

Run the following command to inspect the bridge network:

docker network inspect bridge

This command provides detailed information about the bridge network, including its subnet, gateway, and connected containers. You'll see output similar to this (truncated for brevity):

[
  {
    "Name": "bridge",
    "Id": "79dce413aafdd7934fa3c1d0cc97decb823891ce406442b7d51be6126ef06a5e",
    "Created": "2024-08-22T09:58:39.747333789+08:00",
    "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,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
      "Network": ""
    },
    "ConfigOnly": 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": {}
  }
]

Let's break down some key information from this output:

  • Subnet: The subnet used by containers in this network is 172.17.0.0/16. This means containers will be assigned IP addresses within this range.
  • Gateway: The gateway for this network is 172.17.0.1. This is the IP address that containers use to communicate with networks outside their own.
  • Containers: This field is empty because we haven't started any containers yet.
  • Options: These are various configuration options for the bridge network. For example, enable_icc set to "true" means that inter-container communication is allowed on this network.

Understanding this information is crucial when troubleshooting network issues or when you need to configure your containers to communicate with specific IP ranges.

Creating a Custom Bridge Network

While the default bridge network is suitable for many use cases, creating custom networks allows for better isolation and control. Custom networks are particularly useful when you want to group related containers together or when you need to control which containers can communicate with each other.

Let's create a custom bridge network named my-network:

docker network create --driver bridge my-network

This command creates a new bridge network. The --driver bridge option is actually optional here because bridge is the default driver, but it's included for clarity.

Now, let's verify that our new network has been created:

docker network ls

You should see my-network in the list of networks:

NETWORK ID     NAME         DRIVER    SCOPE
1191cb61c989   bridge       bridge    local
91199fc6ad2e   host         host      local
47ac4e684a72   my-network   bridge    local
1078d2c781b6   none         null      local

Our new my-network appears in the list, confirming that it was created successfully. This network is now available for containers to connect to.

Connecting Containers to Networks

Now that we have our custom network, let's create two containers and connect them to it. We'll use the nginx image for this example, which provides a lightweight web server.

Run the following commands to create two containers:

docker run -d --name container1 --network my-network nginx
docker run -d --name container2 --network my-network nginx

Let's break down these commands:

  • -d: This flag runs the container in detached mode, meaning it runs in the background.
  • --name: This assigns a name to our container, making it easier to reference later.
  • --network: This specifies which network the container should connect to.
  • nginx: This is the name of the image we're using to create our containers.

These commands create two detached (-d) containers named container1 and container2, both connected to our my-network.

Let's verify that the containers are running and connected to our network:

docker ps

This command lists all running containers. You should see both containers listed in the output:

CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
1234567890ab   nginx     "/docker-entrypoint.…"   10 seconds ago   Up 9 seconds    80/tcp    container2
abcdef123456   nginx     "/docker-entrypoint.…"   20 seconds ago   Up 19 seconds   80/tcp    container1

This output shows that both containers are running the Nginx image and are exposing port 80 inside the container.

Testing Inter-container Communication

One of the key benefits of Docker networking is that containers on the same network can communicate with each other using their container names as hostnames. This makes it easy to set up communication between services without needing to know their IP addresses.

Let's test this by using container1 to send a request to container2:

docker exec container1 curl -s container2

Let's break down this command:

  • docker exec: This tells Docker to execute a command inside a running container.
  • container1: This is the name of the container we want to execute the command in.
  • curl -s container2: This is the command we're executing inside the container. It sends a GET request to container2 and the -s flag makes curl operate in silent mode.

This command executes the curl command inside container1, sending a request to container2. You should see the default Nginx welcome page HTML in the output:

<!doctype html>
<html>
  <head>
    <title>Welcome to nginx!</title>
    <style>
      html {
        color-scheme: light dark;
      }
      body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
      }
    </style>
  </head>
  <body>
    <h1>Welcome to nginx!</h1>
    <p>
      If you see this page, the nginx web server is successfully installed and
      working. Further configuration is required.
    </p>

    <p>
      For online documentation and support please refer to
      <a href="http://nginx.org/">nginx.org</a>.<br />
      Commercial support is available at
      <a href="http://nginx.com/">nginx.com</a>.
    </p>

    <p><em>Thank you for using nginx.</em></p>
  </body>
</html>

This successful response demonstrates that container1 can communicate with container2 using its container name. Docker's embedded DNS server resolves the container name to its IP address within the network.

Exposing Container Ports

By default, containers in a custom network can communicate with each other, but they're not accessible from outside the Docker host. To make a container accessible from the host or external networks, we need to expose its ports.

Let's create a new container with an exposed port:

docker run -d --name exposed-container -p 8080:80 --network my-network nginx

Let's break down this command:

  • -d: Run the container in detached mode.
  • --name exposed-container: Name the container "exposed-container".
  • -p 8080:80: Map port 80 inside the container to port 8080 on the host.
  • --network my-network: Connect the container to our custom network.
  • nginx: Use the Nginx image.

This command creates a new container named exposed-container, maps the container's port 80 to the host's port 8080, and connects it to our my-network.

Now, you can access this container's Nginx server from your host machine by opening a web browser and navigating to http://localhost:8080, or by using curl:

curl localhost:8080

You should see the same Nginx welcome page HTML as before. This time, however, we're accessing the container directly from the host, not from another container.

Using Host Networking

For scenarios where you want a container to share the host's network stack, you can use the host network driver. This removes network isolation between the container and the host, which can be useful for certain applications but should be used carefully due to potential port conflicts.

Let's create a container using host networking:

docker run -d --name host-networked --network host nginx

This command creates a new container named host-networked using the host network. Note that you can't use -p with host networking, as the container is already using the host's network interfaces.

To verify that the container is using host networking, we can inspect its network settings:

docker inspect --format '{{.HostConfig.NetworkMode}}' host-networked

This command inspects the container and formats the output to show only the NetworkMode. It should output host, confirming that the container is using host networking.

When using host networking, the container shares the host's IP address and can access all of the host's network interfaces directly. This can be useful for maximizing performance, but it also means that any ports the container uses will be opened on the host directly, which could lead to conflicts if you're not careful.

Summary

In this lab, we explored the fundamentals of Docker networking. We covered various network types, creating custom networks, connecting containers, testing inter-container communication, exposing container ports, and using host networking. These concepts form the foundation of Docker networking and are essential for designing and managing containerized applications.

We learned how to:

  • List and inspect Docker networks
  • Create custom bridge networks
  • Connect containers to networks
  • Test communication between containers
  • Expose container ports to the host
  • Use host networking for containers

Understanding these networking concepts will help you design more robust and secure containerized applications. As you continue working with Docker, you'll encounter more advanced networking scenarios, but the principles we've covered here will serve as a solid foundation for your journey into container orchestration and microservices architecture.

Remember, Docker networking is a powerful tool that allows you to create isolated environments for your applications while still allowing controlled communication between containers and with the outside world. Practice these concepts and explore more advanced topics to become proficient in managing Docker networks.

Other Docker Tutorials you may like