How to use docker compose build command to build services

DockerDockerBeginner
Practice Now

Introduction

In this lab, you will learn how to effectively use the docker compose build command to build services defined in a Docker Compose file. You will begin by preparing a simple Docker Compose file to define a multi-container application.

Following the setup, you will build the services using the docker compose build command. You will then explore how to rebuild services after making changes to their corresponding Dockerfiles. Finally, you will learn how to build services with build arguments and how to utilize the --no-cache option for a clean build.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker(("Docker")) -.-> docker/ImageOperationsGroup(["Image Operations"]) docker(("Docker")) -.-> docker/DockerfileGroup(["Dockerfile"]) docker/ContainerOperationsGroup -.-> docker/run("Run a Container") docker/ImageOperationsGroup -.-> docker/pull("Pull Image from Repository") docker/ImageOperationsGroup -.-> docker/images("List Images") docker/DockerfileGroup -.-> docker/build("Build Image from Dockerfile") subgraph Lab Skills docker/run -.-> lab-555073{{"How to use docker compose build command to build services"}} docker/pull -.-> lab-555073{{"How to use docker compose build command to build services"}} docker/images -.-> lab-555073{{"How to use docker compose build command to build services"}} docker/build -.-> lab-555073{{"How to use docker compose build command to build services"}} end

Prepare a simple Docker Compose file

In this step, you will learn how to create a basic Docker Compose file to define and manage multi-container Docker applications. Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application's services. Then, with a single command, you create and start all the services from your configuration.

First, let's install Docker Compose. Since it's not pre-installed in the LabEx environment, we need to download the binary.

sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

This command downloads the Docker Compose binary from the official GitHub releases page and saves it to /usr/local/bin/docker-compose. The $(uname -s) and $(uname -m) parts automatically detect your operating system and architecture to download the correct binary.

Next, we need to give the downloaded binary executable permissions.

sudo chmod +x /usr/local/bin/docker-compose

This command makes the docker-compose command executable.

Now, let's verify the installation by checking the version.

docker-compose --version

You should see output similar to Docker Compose version v2.20.2, confirming that Docker Compose is installed correctly.

Now, let's create a simple Docker Compose file. We will define a service that uses the nginx image.

Navigate to your project directory.

cd ~/project

Create a new file named docker-compose.yml using the nano editor.

nano docker-compose.yml

Add the following content to the file:

version: "3.8"
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"

Let's break down this file:

  • version: '3.8' specifies the Docker Compose file format version.
  • services: defines the different services that make up your application.
  • web: is the name of our service. You can choose any name you like.
  • image: nginx:latest specifies the Docker image to use for this service. In this case, we are using the latest version of the official Nginx image.
  • ports: maps ports between the host machine and the container. "80:80" maps port 80 on the host to port 80 on the container.

Save the file by pressing Ctrl + X, then Y, and Enter.

Now, let's pull the nginx:latest image that we specified in our docker-compose.yml file. While Docker Compose can pull images automatically when you run docker-compose up, it's good practice to explicitly pull images beforehand, especially in a lab environment, to ensure they are available.

docker pull nginx:latest

This command downloads the nginx:latest image from Docker Hub. You will see output indicating the download progress.

Build services using docker compose build

In the previous step, we created a simple docker-compose.yml file that uses an existing Docker image (nginx). Docker Compose can also build images from a Dockerfile. This is useful when you need to customize an image or build an image for your own application.

In this step, we will modify our docker-compose.yml file to build an image from a Dockerfile instead of using a pre-built image.

First, let's create a simple Dockerfile in the ~/project directory.

nano ~/project/Dockerfile

Add the following content to the Dockerfile:

FROM ubuntu:latest
RUN apt-get update && apt-get install -y cowsay
CMD ["cowsay", "Hello, Docker Compose!"]

Let's explain this Dockerfile:

  • FROM ubuntu:latest specifies the base image for our new image. We are using the latest version of the official Ubuntu image.
  • RUN apt-get update && apt-get install -y cowsay updates the package list and installs the cowsay package. The cowsay command displays a message in a speech bubble drawn by a cow.
  • CMD ["cowsay", "Hello, Docker Compose!"] sets the default command to be executed when a container is started from this image.

Save the Dockerfile by pressing Ctrl + X, then Y, and Enter.

Now, let's modify our docker-compose.yml file to use this Dockerfile. Open the file for editing:

nano ~/project/docker-compose.yml

Change the content to the following:

version: "3.8"
services:
  cow:
    build: .

In this updated docker-compose.yml:

  • We changed the service name from web to cow to better reflect its purpose.
  • We replaced the image: directive with build: .. The build: . directive tells Docker Compose to build the image for this service using the Dockerfile located in the current directory (.).

Save the docker-compose.yml file by pressing Ctrl + X, then Y, and Enter.

Now, we can use the docker-compose build command to build the image for the cow service. Make sure you are in the ~/project directory.

cd ~/project
docker-compose build

This command will read the docker-compose.yml file, find the cow service, and build the image based on the Dockerfile in the current directory. You will see output showing the steps of the build process, including downloading the Ubuntu base image, updating packages, and installing cowsay.

After the build is complete, you can verify that the image has been created by listing your local Docker images.

docker images

You should see an image with a name like project_cow (Docker Compose automatically names images based on the directory name and service name) and a tag like latest.

Rebuild services after changing Dockerfile

In the previous step, we built a Docker image using a Dockerfile and docker-compose build. What happens if we make changes to the Dockerfile? Docker uses a caching mechanism to speed up the build process. If a layer in the Dockerfile hasn't changed, Docker will use the cached version instead of rebuilding it. However, if a layer or any subsequent layers change, Docker will rebuild those layers.

In this step, we will modify our Dockerfile and then rebuild the image to see how Docker handles changes.

First, let's modify the Dockerfile to change the message displayed by cowsay. Open the Dockerfile for editing:

nano ~/project/Dockerfile

Change the CMD line to the following:

FROM ubuntu:latest
RUN apt-get update && apt-get install -y cowsay
CMD ["cowsay", "Hello again, Docker Compose!"]

We have changed the message from "Hello, Docker Compose!" to "Hello again, Docker Compose!".

Save the Dockerfile by pressing Ctrl + X, then Y, and Enter.

Now, let's rebuild the image using the docker-compose build command again. Make sure you are in the ~/project directory.

cd ~/project
docker-compose build

Observe the output of the build process. You will notice that the first two steps (FROM ubuntu:latest and RUN apt-get update && apt-get install -y cowsay) will likely use the cached layers from the previous build. However, the last step (CMD ["cowsay", "Hello again, Docker Compose!"]) will be rebuilt because we changed that line in the Dockerfile.

After the build is complete, you can verify that the image has been updated by listing your local Docker images.

docker images

The project_cow image should now reflect the changes made in the Dockerfile. While the image ID might change, the name and tag will remain the same.

To further confirm the change, we can run a container from this newly built image and see the output.

docker run project_cow

You should see the cowsay output with the updated message: "Hello again, Docker Compose!".

Build services with build arguments and no cache

In this step, we will explore two advanced build options with Docker Compose: using build arguments and building without cache.

Build arguments allow you to pass variables to the Docker build process. This is useful for customizing the build based on different environments or configurations without changing the Dockerfile itself.

First, let's modify our Dockerfile to accept a build argument. Open the Dockerfile for editing:

nano ~/project/Dockerfile

Change the content to the following:

FROM ubuntu:latest
ARG MESSAGE="Hello from build argument!"
RUN apt-get update && apt-get install -y cowsay
CMD ["cowsay", "$MESSAGE"]

We have added an ARG MESSAGE instruction to define a build argument named MESSAGE with a default value. We also changed the CMD instruction to use this argument.

Save the Dockerfile by pressing Ctrl + X, then Y, and Enter.

Now, let's modify our docker-compose.yml file to pass a value to this build argument. Open the file for editing:

nano ~/project/docker-compose.yml

Change the content to the following:

version: "3.8"
services:
  cow:
    build:
      context: .
      args:
        MESSAGE: "Custom message from Compose!"

We have changed the build: directive to an object with context: and args:.

  • context: . specifies the build context, which is the directory containing the Dockerfile.
  • args: is a map of build arguments to pass to the Dockerfile. We are passing the value "Custom message from Compose!" to the MESSAGE argument.

Save the docker-compose.yml file by pressing Ctrl + X, then Y, and Enter.

Now, let's build the image with the build argument. Make sure you are in the ~/project directory.

cd ~/project
docker-compose build

Observe the build output. You should see that the build argument is used during the build process.

After the build is complete, let's run a container from this image to see the output.

docker run project_cow

You should see the cowsay output with the message "Custom message from Compose!". This confirms that the build argument was successfully passed and used.

Sometimes, you might want to force Docker to rebuild all layers, ignoring the cache. This is useful when you suspect caching issues or want to ensure a clean build. You can do this using the --no-cache flag with the docker-compose build command.

Let's try rebuilding the image with the --no-cache flag.

docker-compose build --no-cache

Observe the build output again. This time, you will see that Docker does not use any cached layers and rebuilds every step in the Dockerfile. This process will take longer than a cached build.

After the build is complete, you can run the container again to confirm the message is still the one passed via the build argument.

docker run project_cow

You should still see "Custom message from Compose!". The --no-cache flag only affects the build process, not the configuration defined in docker-compose.yml.

Summary

In this lab, you learned how to prepare a simple Docker Compose file by installing Docker Compose and creating a docker-compose.yml file to define a service using the nginx image. You then practiced building services using the docker compose build command, including rebuilding services after modifying the Dockerfile and building services with build arguments and without using the cache.