Linking containers

Before the introduction of the concept of the user-defined network, container linking was predominantly used for inter-container discovery and communication. That is, cooperating containers can be linked together to offer complex and business-aware services. The linked containers have a kind of source-recipient relationship, wherein the source container gets linked to the recipient container, and the recipient securely receives a variety of information from the source container. However, the source container will know nothing about the recipients to which it is linked. Another noteworthy feature of linking containers in a secured setup is that the linked containers can communicate using secure tunnels without exposing the ports used for the setup to the external world. Though you will find lots of deployments that use container-linking techniques, they are cumbersome and time-consuming to configure. Also, they are error-prone. So the new method of embedded DNS is highly preferred over the traditional container-linking techniques.

The Docker Engine provides the --link option in the docker run subcommand to link a source container to a recipient container.

The format of the --link option is as follows:

--link <container>:<alias>

Here, <container> is the name of the source container and <alias> is the name seen by the recipient container. The name of the container must be unique in a Docker host, whereas alias is very specific and local to the recipient container, and hence, the alias need not be unique in the Docker host. This gives a lot of flexibility to implement and incorporate functionalities with a fixed source alias name inside the recipient container.

When two containers are linked together, the Docker Engine automatically exports a few environment variables to the recipient container. These environment variables have a well-defined naming convention, where the variables are always prefixed with the capitalized form of the alias name. For instance, if src is the alias name given to the source container, then the exported environment variables will begin with SRC_. Docker exports three categories of environment variables, as enumerated here:

  • NAME: This is the first category of environment variables. These variables take the form of <ALIAS>_NAME, and they carry the recipient container's hierarchical name as their value. For instance, if the source container's alias is src and the recipient container's name is rec, then the environment variable and its value will be SRC_NAME=/rec/src.
  • ENV: This is the second category of environment variables used to export the environment variables configured in the source container by the -e option of the docker run subcommand or the ENV instruction of the Dockerfile. This type of an environment variable takes the form of <ALIAS>_ENV_<VAR_NAME>. For instance, if the source container's alias is src and the variable name is SAMPLE, then the environment variable will be SRC_ENV_SAMPLE.
  • PORT: This is the final and third category of environment variables that is used to export the connectivity details of the source container to the recipient. Docker creates a bunch of variables for each port exposed by the source container through the -p option of the docker run subcommand or the EXPOSE instruction of the Dockerfile.

These variables take the <ALIAS>_PORT_<port>_<protocol> form. This form is used to share the source's IP address, port, and protocol as a URL. For example, if the source container's alias is src, the exposed port is 8080, the protocol is tcp, and the IP address is 172.17.0.2, then the environment variable and its value will be SRC_PORT_8080_TCP=tcp://172.17.0.2:8080. This URL further splits into the following three environment variables:

  • <ALIAS>_PORT_<port>_<protocol>_ADDR: This form carries the IP address part of the URL (for example, SRC_PORT_8080_TCP_ADDR= 172.17.0.2)
  • <ALIAS>_PORT_<port>_<protocol>_PORT: This form carries the port part of the URL (for example, SRC_PORT_8080_TCP_PORT=8080)
  • <ALIAS>_PORT_<port>_<protocol>_PROTO: This form carries the protocol part of the URL (for example, SRC_PORT_8080_TCP_PROTO=tcp)

In addition to the preceding environment variables, the Docker Engine exports one more variable in this category, that is, of the <ALIAS>_PORT form, and its value will be the URL of the lowest number of all the exposed ports of the source container. For instance, if the source container's alias is src, the exposed port numbers are 7070, 8080, and 80, the protocol is tcp, and the IP address is 172.17.0.2, then the environment variable and its value will be SRC_PORT=tcp://172.17.0.2:80.

Docker exports these autogenerated environment variables in a well-structured format so that they can be easily discovered programmatically. Thus, it becomes very easy for the recipient container to discover the information about the source container. In addition, Docker automatically updates the source IP address and its alias as an entry in the /etc/hosts file of the recipient.

In this chapter, we will dive deep into the mentioned features provided by the Docker Engine for container linkage through a bevy of pragmatic examples.

To start with, let's choose a simple container linking example. Here, we will show you how to establish a linkage between two containers, and transfer some basic information from the source container to the recipient container, as illustrated in the following steps:

  1. We begin with launching an interactive container that can be used as a source container for linking, using the following command:
      $ sudo docker run --rm --name example -it  
busybox:latest

The container is named example using the --name option. In addition, the --rm option is used to clean up the container as soon as you exit from the container.

  1. Display the /etc/hosts entry of the source container using the cat command:
      / # cat /etc/hosts
172.17.0.3 a02895551686
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Here, the first entry in the /etc/hosts file is the source container's IP address (172.17.0.3) and its hostname (a02895551686).

  1. We will continue to display the environment variables of the source container using the env command:
      / # env
HOSTNAME=a02895551686
SHLVL=1
HOME=/root
TERM=xterm
PATH=
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
  1. We have now launched the source container. From another Terminal of the same Docker host, let's launch the interactive recipient container by linking it to our source container using the --link option of the docker run subcommand, as shown here:
      $ sudo docker run --rm --link example:ex  
-it busybox:latest

Here, the source container named example is linked to the recipient container with ex as its alias.

  1. Let's display the content of the /etc/hosts file of the recipient container using the cat command:
      / # cat /etc/hosts
172.17.0.4 a17e5578b98e
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
72.17.0.3 ex

Of course, as always, the first entry in the /etc/hosts file is the IP address of the container and its hostname. However, the noteworthy entry in the /etc/hosts file is the last entry, where the IP address (172.17.0.3) of the source container and its alias (ex) are added automatically.

  1. We will continue to display the recipient container's environment variable using the env command:
      / # env
HOSTNAME=a17e5578b98e
SHLVL=1
HOME=/root
EX_NAME=/berserk_mcclintock/ex
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/

Apparently, a new EX_NAME environment variable is added automatically to /berserk_mcclintock/ex, as its value. Here EX is the capitalized form of the alias ex and berserk_mcclintock is the autogenerated name of the recipient container.

  1. As a final step, ping the source container using the widely used ping command for two counts and use the alias name as the ping address:
      / # ping -c 2 ex
PING ex (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64
time=0.108 ms
64 bytes from 172.17.0.3: seq=1 ttl=64
time=0.079 ms

--- ex ping statistics ---
2 packets transmitted, 2 packets received,
0% packet loss
round-trip min/avg/max = 0.079/0.093/0.108 ms

Evidently, the alias ex of the source container is resolved to the 172.17.0.3 IP address, and the recipient container is able to successfully reach the source. In the case of secured container communication, pinging between containers is not allowed. We will see more details on the aspect of securing containers in Chapter 11, Securing Docker Containers.

In the preceding example, we can link two containers together, and also, observe how elegantly networking is enabled between the containers by updating the IP address of the source container in the /etc/hosts file of the recipient container.

The next example is to demonstrate how container linking exports the environment variables of the source container, which are configured using the -e option of the docker run subcommand or the ENV instruction of Dockerfile, to the recipient container. For this purpose, we are going to craft a file named Dockerfile with the ENV instruction, build an image, launch a source container using this image, and then launch a recipient container by linking it to the source container:

  1. We begin with composing a Dockerfile with the ENV instruction, as shown here:
      FROM busybox:latest 
ENV BOOK="Learning Docker"
CHAPTER="Orchestrating Containers"

Here, we are setting up two environment variables, BOOK and CHAPTER.

  1. Proceed to build a Docker image envex using the docker build subcommand from the preceding Dockerfile:
      $ sudo docker build -t envex .
  1. Now, let's launch an interactive source container with the example name using the envex image we just built:
      $ sudo docker run -it --rm 
--name example envex
  1. From the source container prompt, display all the environment variables by invoking the env command:
      / # env
HOSTNAME=b53bc036725c
SHLVL=1
HOME=/root
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
BOOK=Learning Docker
CHAPTER=Orchestrating Containers
PWD=/

In all the preceding environment variables, both the BOOK and the CHAPTER variables are configured with the ENV instruction of the Dockerfile.

  1. As a final step, to illustrate the ENV category of environment variables, launch the recipient container with the env command, as shown here:
      $ sudo docker run --rm --link example:ex 
busybox:latest env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=a5e0c07fd643
TERM=xterm
EX_NAME=/stoic_hawking/ex
EX_ENV_BOOK=Learning Docker
EX_ENV_CHAPTER=Orchestrating Containers
HOME=/root

Strikingly, in the preceding output, the variables that are prefixed with EX_ are the outcome of container linking. The environment variables of our interest are EX_ENV_BOOK and EX_ENV_CHAPTER, which were originally set through the Dockerfile as BOOK and CHAPTER but modified to EX_ENV_BOOK and EX_ENV_CHAPTER, as an effect of container linking. Though the environment variable names get translated, the values stored in these environment variables are preserved as is. We already discussed the EX_NAME variable name in the previous example.

In the preceding example, we experienced how elegantly and effortlessly Docker exports the ENV category variables from the source container to the recipient container. These environment variables are completely decoupled from the source and the recipient, thus a change in the value of these environment variables in one container does not impact the other. To be even more precise, the values the recipient container receives are the values set during the launch of the source container. Any changes made to the value of these environment variables in the source container after its launch have no effect on the recipient container. It does not matter when the recipient container is launched because the values are being read from the JSON file.

In our final illustration of linking containers, we are going to show you how to take advantage of the Docker feature to share the connectivity details between two containers. In order to share the connectivity details between containers, Docker uses the PORT category of environment variables. The following are the steps used to craft two containers and share the connectivity details between them:

  1. Craft a Dockerfile to expose port 80 and 8080 using the EXPOSE instruction, as shown here:
      FROM busybox:latest 
EXPOSE 8080 80
  1. Proceed to build a portex Docker image using the docker build subcommand from the Dockerfile, we created just now, by running the following command:
      $ sudo docker build -t portex .
  1. Now, let's launch an interactive source container with the example name using the earlier built portex image:
      $ sudo docker run -it --rm --name example portex
  1. Now that we have launched the source container, let's continue to create a recipient container on another Terminal by linking it to the source container, and invoke the env command to display all the environment variables, as shown here:
      $ sudo docker run --rm --link example:ex 
busybox:latest env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=c378bb55e69c
TERM=xterm
EX_PORT=tcp://172.17.0.4:80
EX_PORT_80_TCP=tcp://172.17.0.4:80
EX_PORT_80_TCP_ADDR=172.17.0.4
EX_PORT_80_TCP_PORT=80
EX_PORT_80_TCP_PROTO=tcp
EX_PORT_8080_TCP=tcp://172.17.0.4:8080
EX_PORT_8080_TCP_ADDR=172.17.0.4
EX_PORT_8080_TCP_PORT=8080
EX_PORT_8080_TCP_PROTO=tcp
EX_NAME=/prickly_rosalind/ex
HOME=/root

From the preceding output of the env command, it is quite evident that the Docker Engine exported a bunch of four PORT category environment variables for each port that was exposed using the EXPOSE instruction in the Dockerfile. In addition, Docker also exported another PORT category variable EX_PORT.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset