Port binding using EXPOSE and -P option

So far, we have discussed the four distinct methods to publish a service running inside a container to the outside world. In all these four methods, the port binding decision is taken during the container launch, and the image has no information about the ports on which the service is being offered. It has worked well so far because the image is being built by us, and we are pretty much aware of the port in which the service is being offered.

However, in the case of third-party images, the port usage inside a container has to be published unambiguously. Besides, if we build images for third-party consumption or even for our own use, it is a good practice to explicitly state the ports in which the container offers its service. Perhaps, the image builders could ship a README document along with the image. However, it is even better to embed the port details in the image itself so that you can easily find the port details from the image both manually as well as through automated scripts.

The Docker technology allows us to embed the port information using the EXPOSE instruction in the Dockerfile, which we introduced in Chapter 3, Building Images. Here, let's edit the Dockerfile we used to build the apache2 HTTP server image earlier in this chapter, and add an EXPOSE instruction, as shown in the following code. The default port for the HTTP service is port 80, hence port 80 is exposed:

########################################### 
# Dockerfile to build an apache2 image
###########################################
# Base image is Ubuntu
FROM ubuntu:16.04
# Author: Dr. Peter
MAINTAINER Dr. Peter <[email protected]>
# Install apache2 package
RUN apt-get update &&
apt-get install -y apache2 &&
apt-get clean
# Set the log directory PATH
ENV APACHE_LOG_DIR /var/log/apache2
# Expose port 80
EXPOSE 80
# Launch apache2 server in the foreground
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

Now that we have added the EXPOSE instruction to our Dockerfile, let's move to the next step of building the image using the docker build command. Here, let's reuse the apache2 image name, as shown here:

$ sudo docker build -t apache2 .  

Having successfully built the image, let's inspect the image to verify the effects of the EXPOSE instruction to the image. As we learned earlier, we can resort to the docker inspect subcommand, as shown here:

$ sudo docker inspect apache2  

On a close review of the output generated by the preceding command, you will realize that Docker stores the exposed port information in the ExposedPorts field of the Config object. The following is an excerpt to show how the exposed port information is being displayed:

"ExposedPorts": {
"80/tcp": {}
},

Alternatively, you can apply the --format option to the docker inspect subcommand in order to narrow down the output to a very specific information. In this case, the ExposedPorts field of the Config object is shown in the following example:

$ sudo docker inspect --format='{{.Config.ExposedPorts}}'  apache2
map[80/tcp:map[]]

To resume our discussion on the EXPOSE instruction, we can now spin up containers using an apache2 image, we just crafted. Yet, the EXPOSE instruction by itself cannot create a port binding on the Docker host. In order to create a port binding for the port declared using the EXPOSE instruction, the Docker Engine provides a -P option in the docker run subcommand.

In the following example, a container is launched from the apache2 image, which was rebuilt earlier. Here, the -d option is used to launch the container in the detached mode, and the -P option is used to create the port binding on the Docker host for all the ports declared, using the EXPOSE instruction in the Dockerfile:

$ sudo docker run -d -P apache2
fdb1c8d68226c384ab4f84882714fec206a73fd8c12ab57981fbd874e3fa9074

Now that we have started the new container with the image that was created using the EXPOSE instruction, like the previous containers, let's review the port mapping as well the NAT entry for the preceding example:

  • The following text is an excerpt from the output of the docker ps subcommand that shows the details of this container:
      ea3e0d1b18cf        apache2:latest      "/usr/sbin/apache2ct   
5 minutes ago Up 5 minutes 0.0.0.0:49159->80/tcp
nostalgic_morse
  • The following text is an excerpt from the output of the iptables -t nat -L -n command that shows the DNAT entry created for this container:
      DNAT    tcp -- 0.0.0.0/0      0.0.0.0/0      
tcp dpt:49159 to:172.17.0.19:80

The -P option of the docker run subcommand does not take any additional arguments, such as an IP address or a port number; consequently, fine-tuning of the port binding is not possible, such as the -p option of the docker run subcommand. You can always resort to the -p option of the docker run subcommand if fine-tuning of port binding is critical to you.

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

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