Docker compose watch and rebuild

Hi all,

I struggle to make docker compose watch and rebuild the container on code change.

$ /usr/local/bin/docker-compose -v
Docker Compose version v2.24.6
version: '3.9'

services:
  cloud-solution-db:
    image: mysql:8.0.33
    command: mysqld --default-authentication-plugin=mysql_native_password
    restart: always
    env_file:
      - manual/.env
    ports:
      - 3307:3306
    volumes:
      - cloud_solution_db_data:/var/lib/mysql
      - ./my.cnf:/etc/mysql/conf.d/my.cnf

  cloud-solution-server:
    container_name: sample-cloud-solution
    env_file:
      - manual/.env
    build:
      context: .
      dockerfile: Dockerfile
    hostname: recommender
    restart: always
    volumes:
      - ./src:/var/www/app
      - cloud_solution_server_uploads:/opt/uploads
    ports:
      - 81:8000
    depends_on:
      - cloud-solution-db
    develop:
      watch:
        - action: rebuild
          path: ./src/**/*

volumes:
  cloud_solution_db_data:
    external: false
  cloud_solution_server_uploads:
    external: false

$ /usr/local/bin/docker-compose -f docker-compose.yml up --build --force-recreate
$ /usr/local/bin/docker-compose watch

 ✔ Container cloud-solution-cloud-solution-db-1  Started                                                             16.5s 
 ✔ Container sample-cloud-solution               Started                                                             11.8s 
WARN[0064] path '/home/user1/path/src/**/*' also declared by a bind mount volume, this path won't be monitored! 
Watch configuration for service "cloud-solution-server":

Please advise.

You already mounted src into the container so why do you need syncing the code? It is already “synced” as it is mounted right into the container so when you change it on the host, the exact same files will be visible from the container too. I assume your problem is the warning, but it describes the reason already. Use either bind mounts or syncronize the files by using the watch feature.

It wouldn’t make sense to copy the files into the container to a fodler which is on the host. It is like running cp ./README.md ./README.md. You can’t copy files to the same location as the source.

Ok, I don’t really understand what I’m doing. My need is to work on code development while it is in the running Docker container. Somehow I must rebuild the container every time I need to see changes I’ve just made. Could you please suggest a possible fix so that it rebuilds automatically when I save the code?

The thing is that it worked fine before when I developed the app in a Docker container using the Flask framework. But this framework is not mature enough, so I started migrating it into FastAPI. It goes slowly because I’m new to this framework and also because I need to rebuild the container with every change to see how it looks.

Please advise.

I never really used this watch feature, just tested when it came out. I also realized that it doesn1t just synchronize source code but can rerun the build and this is what you are trying, so sorry for not reading your question carfully enough.

But the solution still seems to be clear to me. Remove the bind mount and use the sync action too.

If it worked with bind mount before, it could be a change in compose. If you think it is a bug or it doesn’t work with the sync action either, you can report it on GitHub, but I hope the sync action helps.

It worked for me this way:

    develop:
      watch:
        - action: sync+restart
          path: ./src/app.py
          target: /var/www/app/app.py

Thank you for sharing the working solution!

I would still need further advise.

    develop:
      watch:
        - action: sync+restart
          path: ./src/app.py
          target: /var/www/app/app.py
        - action: sync+restart
          path: ./src/templates/*.html
          target: /var/www/app/templates/*.html

It works fine for single file app.py but now I also need to include a bunch of html templates, I did it like this: templates/*.html (it did not work for me).
Please advise.

According to the docs @rimelek shared in his last post file globing is not supported.
Some relevant constraints from the docs:

  • Directories are watched recursively
  • Glob patterns aren’t supported
  • Rules from .dockerignore apply

So this should do the trick:

    develop:
      watch:
        - action: sync+restart
          path: ./src/app.py
          target: /var/www/app/app.py
        - action: sync+restart
          path: ./src/templates/
          target: /var/www/app/templates/

Ok, it works for whole directory, but there is downside, temporary files created by IDE like Jupyter Notebook are tracked as well.

 ✔ Container cloud-app-cloud-app-db-1  Started                                                             13.3s 
 ✔ Container sample-cloud-app               Started                                                             11.3s 
Watch configuration for service "cloud-app-server":
  - Action sync+restart for path "/home/user1/path1/cloud-app/src/app.py"
  - Action sync+restart for path "/home/user1/path1/cloud-app/src/templates"
Syncing "cloud-app-server" after changes were detected:
  - /home/user1/path1/cloud-app/src/templates/localfile.html
  - /home/user1/path1/cloud-app/src/templates/.~localfile.html
  - /home/user1/path1/cloud-app/src/templates/.ipynb_checkpoints/localfile-checkpoint.html
[+] Restarting 1/1
 ✔ Container sample-cloud-app  Started

Is there a way to exclude files like .~. and folders like .ipynb_checkpoints ?

There is a reason why I quoted this part in my last response as well:

Works great, thanks to all.