How to use docker compose watch command to automatically rebuild services

DockerDockerBeginner
Practice Now

Introduction

In this lab, you will learn how to leverage the docker compose watch command to automatically rebuild and update your Docker services in response to file changes. We will begin by setting up a simple Docker Compose project with a build context, including a basic application file, a Dockerfile, and a docker-compose.yaml file.

Following the project setup, you will explore the core functionality of docker compose watch to monitor file modifications and trigger automatic rebuilds. We will also examine the --no-up option to watch for changes without an initial service startup and the --quiet option to suppress build output, allowing you to observe the watch behavior more cleanly.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker(("Docker")) -.-> docker/DockerfileGroup(["Dockerfile"]) docker/ContainerOperationsGroup -.-> docker/run("Run a Container") docker/DockerfileGroup -.-> docker/build("Build Image from Dockerfile") subgraph Lab Skills docker/run -.-> lab-555098{{"How to use docker compose watch command to automatically rebuild services"}} docker/build -.-> lab-555098{{"How to use docker compose watch command to automatically rebuild services"}} end

Prepare a simple Docker Compose project with a build context

In this step, we will prepare a simple Docker Compose project that includes a build context. A build context is the set of files at a specified location (PATH or URL) that are sent to the Docker daemon to build a Docker image. This is important because the Dockerfile and any files it needs (like application code) must be within the build context.

First, let's create a directory for our project. We will name it my-watch-app.

mkdir ~/project/my-watch-app
cd ~/project/my-watch-app

Now, we need to create a simple application file. We will use a basic Python script that prints a message.

nano app.py

Add the following content to app.py:

print("Hello from the Docker container!")

Save and close the file (Ctrl+X, Y, Enter).

Next, we need to create a Dockerfile that will build an image for our application. The Dockerfile will copy our Python script into the image and then run it.

nano Dockerfile

Add the following content to the Dockerfile:

FROM python:3.9-slim

WORKDIR /app

COPY app.py .

CMD ["python", "app.py"]

This Dockerfile uses a slim Python 3.9 image as the base, sets the working directory to /app, copies app.py into the /app directory, and finally sets the command to run the Python script when the container starts.

Finally, we need to create a docker-compose.yaml file to define our service. This file will tell Docker Compose how to build and run our application.

nano docker-compose.yaml

Add the following content to docker-compose.yaml:

version: "3.8"

services:
  myapp:
    build: .
    volumes:
      - .:/app

This docker-compose.yaml file defines a service named myapp. The build: . instruction tells Docker Compose to build the image using the Dockerfile in the current directory (which is our build context). The volumes: - .:/app line mounts the current directory (.) on the host machine to the /app directory inside the container. This is crucial for docker compose watch as it allows changes on the host to be reflected in the container.

Now, let's build and run our service using Docker Compose to ensure everything is set up correctly. Since Docker Compose is not pre-installed, we need to install it first.

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
sudo chmod +x /usr/local/bin/docker-compose

Now we can use docker-compose.

docker-compose up --build

You should see output indicating that the image is being built and the container is running, printing "Hello from the Docker container!". Press Ctrl+C to stop the container.

Use docker compose watch to monitor file changes and rebuild

In this step, we will use the docker compose watch command to automatically rebuild and restart our service when we make changes to the application code. This is a powerful feature for development workflows, allowing for rapid iteration.

The docker compose watch command monitors the files in your build context and, when changes are detected, it can automatically rebuild the image and restart the service.

Make sure you are in the ~/project/my-watch-app directory.

cd ~/project/my-watch-app

Now, run the docker compose watch command.

docker-compose watch

You will see output indicating that Docker Compose is starting the service and watching for file changes. The initial output will be similar to running docker-compose up.

While docker compose watch is running in your terminal, open another terminal or tab. Navigate to the project directory in the new terminal.

cd ~/project/my-watch-app

Now, let's modify the app.py file.

nano app.py

Change the content to:

print("Hello again from the updated Docker container!")

Save and close the file (Ctrl+X, Y, Enter).

Go back to the terminal where docker compose watch is running. You should see output indicating that a change was detected, the image is being rebuilt, and the container is being restarted. After the restart, the new message "Hello again from the updated Docker container!" will be printed.

This demonstrates how docker compose watch automatically handles the build and restart process when your code changes.

Press Ctrl+C in the terminal running docker compose watch to stop the process.

Explore the --no-up option to watch without initial build

In this step, we will explore the --no-up option with docker compose watch. By default, docker compose watch will build and start the services defined in your docker-compose.yaml file before starting to watch for file changes. The --no-up option prevents this initial build and startup. This is useful if you want to start watching for changes without immediately bringing up the services, perhaps because you plan to start them manually later or they are already running.

Make sure you are in the ~/project/my-watch-app directory.

cd ~/project/my-watch-app

Now, run the docker compose watch command with the --no-up option.

docker-compose watch --no-up

You will notice that the output is different from the previous step. Docker Compose will start watching for file changes but will not build the image or start the container initially. The output will indicate that it is watching the specified paths.

While docker compose watch --no-up is running in your terminal, open another terminal or tab. Navigate to the project directory in the new terminal.

cd ~/project/my-watch-app

Now, let's modify the app.py file again.

nano app.py

Change the content to:

print("Watching without initial up!")

Save and close the file (Ctrl+X, Y, Enter).

Go back to the terminal where docker compose watch --no-up is running. You should see output indicating that a change was detected and the image is being rebuilt. However, the container will not automatically restart because we used the --no-up option.

To see the effect of the change, you would need to manually bring up the service in another terminal after the rebuild is complete.

docker-compose up

You will see the new message "Watching without initial up!" printed by the container.

Press Ctrl+C in the terminal running docker compose watch --no-up to stop the watching process. Press Ctrl+C in the terminal running docker-compose up to stop the container.

Observe the --quiet option to hide build output

In this step, we will observe the effect of the --quiet option with docker compose watch. By default, when docker compose watch detects a change and rebuilds an image, it displays the full output of the build process. The --quiet option suppresses this detailed build output, showing only essential information about the watch process and service restarts. This can make the output cleaner, especially for frequent small changes.

Make sure you are in the ~/project/my-watch-app directory.

cd ~/project/my-watch-app

Now, run the docker compose watch command with the --quiet option. We will also include the --no-up option again so that we only see the output related to the watch and rebuild process, not the initial service startup.

docker-compose watch --quiet --no-up

You will see output indicating that Docker Compose is watching for file changes, but there will be no detailed build output initially.

While docker compose watch --quiet --no-up is running in your terminal, open another terminal or tab. Navigate to the project directory in the new terminal.

cd ~/project/my-watch-app

Now, let's modify the app.py file one last time.

nano app.py

Change the content to:

print("Quietly watching changes!")

Save and close the file (Ctrl+X, Y, Enter).

Go back to the terminal where docker compose watch --quiet --no-up is running. You should see output indicating that a change was detected and the image is being rebuilt, but the detailed steps of the Docker build process will be hidden. You will only see a concise message about the rebuild.

This demonstrates how the --quiet option reduces the verbosity of the output during the build phase triggered by docker compose watch.

Press Ctrl+C in the terminal running docker compose watch --quiet --no-up to stop the watching process.

Summary

In this lab, we learned how to prepare a simple Docker Compose project with a build context, which is essential for building Docker images from local files. We created a project directory, a basic Python application file (app.py), a Dockerfile to build an image for the application, and a docker-compose.yaml file to define the service and its build context.

We then explored the docker compose watch command, which allows us to automatically monitor file changes within the build context and trigger rebuilds of the associated service. We learned how to use the command to observe this automatic rebuild process and also explored the --no-up option to watch without an initial build and the --quiet option to suppress build output, providing a streamlined workflow for development.