Connecting Docker Containers, Part One
Docker containers are self-contained, isolated environments. However, they’re often only useful if they can talk to each other.
There are many ways to connect containers. And we won’t attempt to cover them all. But in this miniseries, we will look at some common ways.
This topic seems elementary, but grasping these techniques and the underlying design concepts is important for working with Docker.
Understanding this topic will:
- Help developers and ops people explore the broad spectrum of container deployment choices
- Let developers and ops people to embark more confidently with a microservice design architecture
- Empower developers and ops people to better orchestrate more complex distributed applications
Fortunately, the large number of connection options for containers enables a broad range of approaches, giving us the flexibility to choose an architecture that suits the needs of any application.
In this post, we'll look at three of the older, more basic ways of connecting Docker containers. Using this knowledge and experience as a foundation, we'll then move on to two newer, easier, more powerful ways in the next post.
Before we can demonstrate how containers can be connected, we need to create a pair of them for use in our examples.
The first image will be derived from a simple Ubuntu installation. It will act as a client container.
First, we create the container and attach to it:
Then, once we have a shell inside the container, we run:
If you do not see the shell, click the up arrow.
Now, detach from the client container using CTRL+p then CTRL+q.
Then, stop it, and commit:
We now have an image called
client_img to use.
The second container we want to use is, again, derived from an Ubuntu installation. But this time, we’ll modify it to run a Apache HTTP server.
First, we create it and attach, like before:
Then, once we have a shell inside the container, we install the Apache HTTP server:
When the installation is complete, detach from the container using CTRL+p and CTRL+q.
Now, stop the container, and commit it:
We now have two images:
Now we have this set up, we can explore the various connection possibilities.
The Docker Bridge
By default, a Docker container is isolated from other containers and the external network. Docker provides a bridge, the
docker0 interface, which is created with the installation of the Docker Engine.
It is through the Docker bridge that communication is possible amongst containers and between containers and the host machine.
You can see the Docker bridge by running this command on a Docker host:
You should see something like this in the output:
The bridge interface works locally, on a single Docker host, and is the connection mechanism behind all three approaches we cover in this post. In the next post, we’ll move on to the overlay interface, which allows us to network containers across multiple Docker hosts.
First, let’s see how we can run a server container so that it exposes port 80 (HTTP) to other containers.
To do so, I run the container with the
expose command, which tells Docker to expose port number specified when it runs the container. An exposed port is one that other containers can reach.
server_img as a container called
server1, exposing port 80:
$ sudo docker run -itd --expose=80 --name=server1 server_img /bin/bash
We’ll name our containers sequentially (
server2, and so on) as we go.
Then, attach to the container:
Again, If you do not see the shell, click the up arrow.
Start the Apache HTTP server:
And get the IP address:
$ ifconfig eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:03 inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0
Okay, so we have an IP address of
172.17.0.3. Let’s test we can see that from a client container.
Open a second terminal.
Attach to it:
If you do not see the shell, click the up arrow.
Make a test connection to the
server1 container’s IP address:
If everything works, you should see the HTML of the Apache HTTP server’s default page. This indicates the the
client1 container is able to make connections to the
server1 container’s HTTP port.
What if we want to expose our HTTP server to the host network, including application on the host machine, and other machines on the host network? In this scenario, we need to bind a host port to a container port.
To expose the Apache HTTP server to the host network, we need to bind port 80 on the server container to port 8080 on the host machine.
We can do this like so:
$ sudo docker run -itd -p 8080:80 --name=server2 server_img /bin/bash
-p 8080:80 option is the thing to pay attention to here.
Now, attach to the container:
If you do not see the shell, click the up arrow. And start the Apache HTTP server:
Now, from the host system, visit http://localhost:8080/ and you should see the Apache HTTP server default page.
Any machine on your host network that can access port 8080 of your host machine will also be able to access this.
Another approach to connecting containers involves something Docker calls linking.
When you link one container to another, Docker will make some information about the linked container available via environment variables.
Let’s take a look.
First, start the server container:
Now, start the client container and link it to the server container, like so:
$ sudo docker run -itd --link server3 --name=client3 client_img /bin/bash
--link server3 option being used here.
Now attach to the client container:
And check out the available environment variables:
Docker also updates the
/etc/hosts file in the client container to add
server3 as a local hostname pointing to the server container.
To demonstrate this, run:
You should see the same default HTML again.
In part one of this miniseries, we introduced the Docker bridge interface, which lets us connect containers on the same host.
We looked at three connection methods:
- Connection through port exposure
- Binding of the host port to the container port
- Linking two containers through the link option
In part two, we’ll look at isolating containers inside user-defined networks. We’all also introduce the overlay interface, and take a look at how to use it for networking Docker containers across multiple Docker hosts. Even across datacenters and cloud providers!