Book Image

A Developer's Essential Guide to Docker Compose

By : Emmanouil Gkatziouras
Book Image

A Developer's Essential Guide to Docker Compose

By: Emmanouil Gkatziouras

Overview of this book

Software development is becoming increasingly complex due to the various software components used. Applications need to be packaged with software components to facilitate their operations, making it complicated to run them. With Docker Compose, a single command can set up your application and the needed dependencies. This book starts with an overview of Docker Compose and its usage and then shows how to create an application. You will also get to grips with the fundamentals of Docker volumes and network, along with Compose commands, their purpose, and use cases. Next, you will set up databases for daily usage using Compose and, leveraging Docker networking, you will establish communication between microservices. You will also run entire stacks locally on Compose, simulate production environments, and enhance CI/CD jobs using Docker Compose. Later chapters will show you how to benefit from Docker Compose for production deployments, provision infrastructure on public clouds such as AWS and Azure, and wrap up with Compose deployments on said infrastructure. By the end of this book, you will have learned how to effectively utilize Docker Compose for day-to-day development.
Table of Contents (19 chapters)
1
Part 1: Docker Compose 101
6
Part 2: Daily Development with Docker Compose
12
Part 3: Deployment with Docker Compose

Your first Docker Compose file

Imagine a scenario of wanting to run a static page on a server. For this task, an NGINX server is a good choice. We have a simple HTML file on the static-site/index.html path:

<!DOCTYPE html>
<html>
    <head>
        <title>Hello World</title>
    </head>
    <body>
       <p>Hi! This application should run on docker-compose</p>
    </body>
</html>

By using Docker, we will run an NGINX server using the official image found at https://www.docker.com/blog/how-to-use-the-official-nginx-docker-image/:

$ docker run --rm -p 8080:80 --name nginx-compose nginx

Let’s break this down a little bit:

  • Docker Engine will run a Docker NGINX image.
  • The default port on the image is 80, so we shall map it locally to 8080 to avoid using a privileged port.
  • The name we assign will be constant in order to make interactions with the container easier.
  • By using the —rm argument, we ensure that once we are done with our task and stop the container, the container will be deleted.

Our container is up and running. In a different Terminal session, we should access the default NGINX page:

$ curl 127.0.0.1:8080
<!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>

Since we have successfully run NGINX, we need to adapt our command in order to use the customized HTML page. A simple and fast way to do this is to mount the file at the path of a container. Let’s exit the previous command using Ctrl + C and then refine the previous command:

docker run --rm -p 8080:80 --name nginx-compose -v $(pwd)/static-site:/usr/share/nginx/html nginx

As expected, the page changes to the one we have specified:

$ curl localhost:8080/index.html
<!DOCTYPE html>
<html>
    <head>
        <title>Hello World</title>
    </head>
    <body>
       <p>Hi! This application should run on docker-compose</p>
    </body>
</html>
$

Now we have everything needed to migrate this application to Compose. We will create a Compose file for the default NGINX installation:

services:
  nginx:
    image: nginx
    ports:
      - 8080:80

Let’s break down what we just did:

  • The name of the service will be NGINX.
  • The image is the same NGINX image.
  • The ports are the same ports used previously.

The content shall be saved to a file named docker-compose.yaml.

Next, we will execute the Compose command on the Terminal:

$ docker compose up
[+] Running 2/0
  Network chapter1_default    Created                          0.0s
  Container chapter1-nginx-1  Created                          0.0s
Attaching to chapter1-nginx-1
chapter1-nginx-1  | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
chapter1-nginx-1  | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
…
$

As expected, the result from the HTTP request is the same as the one that we experienced by just running the Docker container.

The naming of the file is important. We did execute the Compose command to spin up the Compose file, but we did not specify the file to be used. As it happens with docker build and Dockerfile, by running docker compose in a directory, Compose will search for a file named docker-compose.yaml. If the file exists, it’ll be picked up as the default Compose file. Be aware that we are not limited to just one filename; we can use a different filename for our Compose applications. In the following chapters, there are cases where we can use a different name for the Compose files and run the application using the –f option.

Next, we shall mount the custom HTML page through the Compose configuration:

services:
  nginx:
    image: nginx
    ports:
      - 8080:80
    volumes:
      - ./static-site:/usr/share/nginx/html

As simple as our previous Docker command seemed to be, behind the scenes, it created a Docker volume pointing to a path of our filesystem and then it was attached to the container. The same applies to Compose. We specify a volume that points to our filesystem. Then, based on our location, it is mounted to a directory of the container:

$  curl localhost:8080/index.html
<!DOCTYPE html>
<html>
    <head>
        <title>Hello World</title>
    </head>
    <body>
        <p>Hi! This application should run on docker-compose</p>
    </body>
</html>

As expected, the result is the same one with the result of the Docker example.

To review this section, we ran an NGINX instance using Docker CLI and made the transition to Compose by adding the corresponding YAML sections for the Docker command parameters that were used. Now, we are ready to move on to the next stage of this chapter’s journey, where we’ll build and run a Docker image on Docker Compose.