2014-10-22

Docker is an open platform for building, shipping, running and orchestrating distributed applications. NGINX, being a software application, is a great use case for Docker and we have created an open source NGINX image on Docker Hub, the repository of Docker images. This article will describe how you can deploy NGINX with Docker using the image from Docker Hub or create your own Docker image using NGINX Plus,  the enhanced and commercially supported version of NGINX.

Introduction

The Docker open platform includes the Docker Engine – the open source runtime that builds, runs and orchestrates containers, and Docker Hub – a hosted service where Dockerized applications are distributed, shared, and collaborated on across the entire development community or within the confines of a specific organization. Docker containers allow developers to focus their efforts on application “content” by separating applications from the constraints of infrastructure. Dockerized applications are instantly portable to any infrastructure – laptop, bare-metal server, VM or cloud – making them modular components that can be readily assembled/re-assembled into full featured distributed applications that can be continuously innovated on in-real time. For more information about Docker please see: What is Docker.

Using the NGINX Docker Image

You can create an instance of NGINX in a Docker container using the NGINX image from Docker Hub. For more information on Docker please see the NGINX Docker Hub page and the Docker documentation.

Lets start with a very simple example. To launch an instance of NGINX running in a container, using the default NGINX configuration, run the command:

This will create a container named mynginx1, based off of the NGINX image and will run it in detached mode, which means that the container will be started and will stay running until stopped but will not be listening to the command line. We will discuss later how we will interact with the container.

The NGINX image exposes ports 80 and 443 in the container and the -P option tells Docker to map those ports to ports on the Docker host using random port numbers between 49153 and 65535. We do this because if we create multiple NGINX containers on the same Docker host, we will create a conflict on ports 80 and 443. The port mappings are dynamic and are set each time the container is started or restarted. If you want the port mappings to be static you can set them manually with the -p option. The long form of the Container Id will be returned.

We can see that the container was created, is running and the port mappings by running the command:

We can also see that NGINX is running by making an HTTP request to port 49166 on the Docker host, the port on the host to which port 80 in the container has been mapped to, and we should see the default NGINX welcome page:

Working with the NGINX Docker container

So now we have a working NGINX Docker container, but how do we manage the content and the NGINX configuration?  And what about logging?  It is common to have SSH access to NGINX instances, but Docker containers are generally intended to be for a single purpose, in this case running NGINX, so the NGINX image does not have OpenSSH installed and for normal operations there is no need to get shell access directly to the NGINX container. We will use other methods supported by Docker. For a detailed discussion of alternatives to SSH access see Why you don’t need to run SSHd in your Docker Containers.

Managing Content and Configuration files

There are multiple ways you can mange the NGINX content and configuration files and we will cover a few options.

Maintain the content and configuration on the Docker host

When the container is created we can tell Docker to mount a local directory on the Docker host to a directory in the container. The NGINX image uses the default NGINX configuration, so the root directory is /usr/nginx/share/html and the configuration files are in /etc/nginx. For example, lets say that the content is in the local directory /var/www and the configuration files are in /var/nginx/conf. To start a container that uses the files in these local directories we would use the command:

Now any change made to the files in the local directories /var/www and /var/nginx/conf will be reflected in the directories /usr/nginx/share/html and /etc/nginx in the container. The :ro option causes these directors to be read only inside the container.

Copy the files from the Docker host

Another option is to have Docker copy the content and configuration files from a local directory on the Docker host when a container is created. Once a container is created, the files will be maintained by creating a new container when the files change or by modifying the files in the container. A simple way of copying the files is to create a Dockerfile to generate a new Docker image, based off of the NGINX image from Docker Hub. When copying files in the Dockerfile, the path to the local directory is relative to the build context where the Dockerfile is located. For this example, the content is in the directory content and the configuration files are in the directory conf, both in the same directory as the Dockerfile. The NGINX image has the default NGINX configuration files, including default.conf and example_ssl.conf in /etc/nginx/conf.d. Since we want to use the configuration files from the host, we will add commands in the Dockerfile to delete these default files. We can create the following Dockerfile:

We can then create our own NGINX image by running the following command from the directory where the Dockerfile is located:

Note the “.” at the end of the command. This tells Docker that the build context is the current directory. The build context contains the Dockerfile and the directories to be copied. Now we can create a container using the image by running the command:

If we want to make changes to the files in the container you can use a helper container as described below.

Maintain files in the container

As mentioned previously, we are not able to get SSH access to the NGINX container, so if we want to edit the content or configuration files directly we can use a helper container that has shell access. In order for the helper container to have access to the files, volumes must be specified for the image. We can do that by creating a new image that has the proper volumes specific. Assuming we want to copy the files as in the example above while also specifying volumes for the content and configuration files we can use the following Dockerfile:

We can then create the new NGINX image by running the following command:

Now we can create an NGINX container using the image by running the command:

We can then start a helper container with a shell and access the content and configuration directories of the NGINX container we created in the previous example by running the command:

This creates an interactive container named mynginx4_files that runs in the foreground with a persistent standard input (-i) and a tty (-t)  and mounts all the volumes defined in the container mynginx4 as local directories in the new mynginx4_files container. This container will use the Debian image from Docker Hub which is the same operating system used by the NGINX image. Since all of the examples shown so far are using the NGINX image and therefore Debian, it is more efficient to use Debian for the helper container rather then having Docker load another operating system. After the container is created it will run the bash shell. You will be presented with a shell prompt for the container and can then modify the files as needed. You can also install other tools in this container, such as Puppet or Chef to manage these files. If you exit the shell with exit, the container will terminate. If you want to exit while leaving the container running use Control-p followed by Control-q. The container can be started and stopped with the commands:

and

Shell access can be regained to a running container with the command:

Managing Logging

Default Logging

The NGINX image has setup the main NGINX access and error logs to go to the Docker log collector. This is done by linking them to stdout and stderr. This will cause all messages to either log to be stored in the file /var/lib/docker/containers/<container id>/<container id>-json.log on the Docker Host. <container id> is the long form Container Id returned when you create a container. You can get the long form Id for a container with the command:

The access and error message are combined into this one log file. You can use both the Docker command line and the Docker Remote API to extract the log messages. From the command line you can use the command:

The Docker Remote API can be used to extract just the access log messages (stdout) or error log messages (stderr). To enable the Docker Remote API, add the following line to the file /etc/default/docker:

When Docker is restarted, it will listen on port 4243 (the port can be changed) for HTTP API requests and also on a socket. To get all the messages you can issue the GET request:

To limit the output to the access log messages, include only stdout=1 and to limit the output to the error log messages, include only stderr=1. There are additional options available that are described in the Docker documentation.

Customized Logging

If you want to implement another method of log collection or if you want to specify logging at different levels of the NGINX configuration such as servers and locations, you can use a volume for the directory or directories where you want to store the log files in the container. You can then use a helper container to access the log files and you can use whatever logging tools you like. To implement this, a new image can be created that contains the volume or volumes for the logging files. For example, if we are going to configure NGINX to store log files in /var/log/nginx/log, then we can start with the Dockerfile shown in the earlier example of copying files from the Docker host to the container and we can simply add a volume declation for this directory:

We can then create an image as described above and using this image we can create an NGINX container and a helper container which will now have access to the log directory. This helper container can have any desired logging tools installed.

Controlling NGINX

Since we do not have access to the command line of the NGINX container directly we cannot control NGINX using the nginx command. Fortunately NGINX can be controlled by signals and Docker provides the ability to send signals to a container using the Docker kill command. For example, to reload the NGINX configuration you can run the command:

If you want to restart the NGINX process you should restart the container with the command:

Deploying NGINX Plus with Docker

So far we have been discussing using the open source version of NGINX with Docker, but the commercial version, NGINX Plus, can also be used with Docker. The difference is that since NGINX Plus is a commercial offering, an image is not available at Docker Hub, so you have to create your own. Fortunately that is quite easy to do.

Creating a Docker Image of NGINX Plus

In order to generate your own image of NGINX Plus, you have to first create a Dockerfile. We have provided example Dockerfiles for Ubuntu 14.04 and CentOS 7 along with instructions on how to create the images, and these Dockerfiles can be used as templates for other operating systems. For both Ubuntu and CentOS you have to download your version of the files nginx-repo-crt and nginx-repo-key from cs.nginx.org. A login to cs.nginx.org is provided to customers who have purchased or are evaluating NGINX Plus and this key and certificate provide access to the NGINX Plus repository. These files should be copied to the Docker build context, which is the directory where the Dockerfile resides.

As with the NGINX open source Dockerfile, the default NGINX access and error logs are linked to the Docker log collector. No volumes are specified, but they can be added if descried, or these Dockerfiles can be used to create base images from which new images can be created which have volumes specified, as described above.

No files are copied from the Docker host when creating a container. This can also be added to the Dockerfiles, or the image created can be used as the basis for another image as described above.

Ubuntu Dockerfile

CentOS Dockerfile

Creating the NGINX Plus Image

Once you have Dockerfile and the nginx-repo.crt and nginx-repo.key files in the same directory, you can generate a Docker image named nginxplus by running the following command from that directory:

Note the –no-cache option. This tells Docker to build the image from scratch and ensures that the latest version of NGINX Plus will be installed. If this option is not specified and an image has been built from this Dockerfile previously, then the new image will use the NGINX Plus version from the Docker cache. This is because we have not specified the NGINX version in the Dockerfile so the Dockerfile does not need to be changed for each new release of NGINX Plus. If you want to use the NGINX Plus version from the previously built image, then you can leave this option off.

If the image was created successfully you will see it by running the command:

You can then use this NGINX Plus image to create a container named mynginxplus with the command:

These containers can be controlled and managed in the same way as the NGINX open source containers described above.

Summary

NGINX and Docker are tools that work extremely well together. By using the NGINX open source image from the Docker Hub repository or by creating your own NGINX Plus image, you can easily spin up new instances of NGINX in Docker containers. You can also take these images and easily create new Docker images from them to give you even more control of your containers and how you manage them. One thing to keep in mind is that NGINX Plus is sold on a per instance basis, so each Docker container running NGINX Plus will require an NGINX Plus subscription.

There is much more to Docker then we have been able to cover in this article.  More information is available at www.docker.com.

The post Deploying NGINX and NGINX Plus with Docker appeared first on NGINX.

Show more