Docker Compose Watch
Marek Semjan
DockerDocker ComposeDevOpsContainerization
1020 Words • 4 Minutes, 38 Seconds
2024-06-02 13:44 +0000
Introduction
The Docker Compose allows you to easily spin up several Docker containers in a reliable and reproducible way. It is useful for every developer who is using Docker containers, especially if more than one is used (e.g. one for database, one for caching with Redis, and one for your applications). By using Docker compose, you can avoid running multiple Docker run commands for each service.
In the Docker Compose version 2.22.0 was introduced a new feature: the Compose Watch1, which allows you to automatically update and preview your running the Compose services after you have edited and saved your code changes. This enables a hands-off development workflow once the Compose is running. The services will automatically restart as you save your changes. It is similar to Nodemon for Node.js, Air for Go, Reloadium for Python, and other similar tools that simplify and streamline development by providing hot reloading functionality.
Example
Let’s consider a minimal Node.js application with the following project structure:
my-nodejs-app/
├── web/
│ ├── App.jsx
│ └── index.js
├── Dockerfile
├── compose.yaml
└── package.json
In the Dockerfile
we will have:
# Run as a non-privileged user
FROM node:18-alpine
RUN useradd -ms /bin/sh -u 1001 app
USER app
# Install dependencies
WORKDIR /app
COPY package.json package.lock .
RUN npm install
# Copy source files into application directory
COPY --chown=app:app . /app
The compose.yaml
file will contain the following:
services:
web:
build: .
command: npm start
develop:
watch: # This part is necessary for each service you want to automatically sync in watch mode
- action: sync # Sync action ensures that changes in local files are automatically synced with the container
path: ./web
target: /src/web
ignore:
- node_modules/
- action: rebuild # Rebuild action automatically builds a new image if there are any changes to package.json,
# this is also ideal options for compiled languages
path: package.json
To use the watch feature, run the Docker Compose with --watch
flag:
docker compose up --watch
Then a container for the web
service will be launched using an image built with the Dockerfile
in the project’s root folder. The web
service will run npm start
as a command, which than launches the development version of the application with Hot Module Reload enabled in the bundler (Webpack, Vite, Turbopack, …).
The services that will be watched are specified in the watch
section in YAML. There are rules that control automatic service updates based on local file changes. Each rule requires a path
and an action
that will be performed when a change is detected. Some action
s may provide or require other fields. Besides the options shown in the example above, there is also “sync + restart” option that will sync changes with the service containers and then restart it. It is ideal for configuration changes that don’t require rebuild of the container, but need a service container restart to take effect, e.g. for database configurations or your nginx.conf
file.
The watch mode uses common executables that must be be present in the image containers, and you should ensure that they are installed:
stat
mkdir
rmdir
The watch mode also requires that the container’s USER
has write permissions and can update files. It is common to create a new user before running COPY
instruction in Docker. To ensure that the user can modify files, use COPY --chown
flag, e.g. in the example above we used:
RUN useradd -ms /bin/sh -u 1001 app
USER app
# (Omitted parts)
COPY --chown=app:app . /app
Specific paths and rules will vary from project to project, but the main idea stays the same. Moreover, you don’t need to watch all services, only those you will edit and will need a restart, e.g. only front-end you are working on.
If any changes are saved, the Docker Compose in the watch mode will trigger a sync and update corresponding files in the /src/web
folder inside the container. Once copied, the bundler will update the running application without a need for a restart.
Note: While source files can be updated on-fly, the dependencies can not. Whenever you install or remove a package, or update the package.json
, the Compose needs to rebuild the image and recreate the web
service container.
This approach can be used for many languages and frameworks, e.g. Python with Flask framework. The source files can be easily synced while a change to requirements.txt
triggers a rebuild. In case of compiled languages, the entire container will have to be rebuilt.
Path Rules
The Compose Watch follows a couple of path rules:
- All paths are relative to the project root directory
- Directories are watched recursively
- Glob patterns are not supported
- Rules from
.dockerignore
andignore
option apply - IDE files are automatically ignored
.git
folder is ignored automatically
What Is The Difference Between Compose Watch And Bind Mounts
The Compose Watch does not replace the existing support for sharing a host directory inside service containers, but it exists as a complement suited for development inside containers.
Moreover, the watch mode allows for increased granularity than bind mounts. The rules in the watch
section let you watch or ignore specific files or directories within the watched tree. This is useful if you have many small files that would cause high I/O load (e.g. node_modules/
in Javascript projects) or if the compiled artifacts can not be shared across different architectures, because they are platform dependent (e.g. Node packages can contain native code).
Conclusion
The Docker Compose with the new watch mode adds a new functionality to a tried and tested tool. It is amazing for people who want/need to do their development in Docker containers. Despite the fact that such development was possible before with bound mounts, or simply by using docker-compose down && docker-compose up
after each meaningful change, now it is easier than ever.
Moreover, the watch mode provides an option to exclude files and folders that will be synced with improved granularity, and is general improvement to containerized development. If you use the Docker Compose, consider using the watch mode, since it is very useful and simplifies any workflow.
Sources 📚️
“Use compose watch.” (2024, May 20). Docker Documentation. https://docs.docker.com/compose/file-watch ↩︎