Skip to content

Conversation

ndeloof
Copy link
Collaborator

@ndeloof ndeloof commented Apr 29, 2022

What this PR does / why we need it:
Introduce a new sub-section develop to collect developer workflow and how a Compose Implementation can hook into developer inner-loop to make developer experience better.

update: this proposal has been adjusted to reflect experiment in Docker Compose with x-develop and the watch command

Copy link
Collaborator

@EricHripko EricHripko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a very promising addition - especially the idea potential idea of Compose better supporting remote filesystems out of the box 😍 I've left a few comments and questions inline to better understand this 💬

development.md Outdated

While Compose implementations can support custom values, the specification defines:
- `build`: rebuild service image based on the `build` section and restart the service with updated image
- `sync`: synchronize source files with container content. `path` attribute is REQUIRED to define the mapping
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate a bit more on how this interacts with host mounts in volumes?

Copy link
Collaborator Author

@ndeloof ndeloof Apr 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intentionally unspecified so implementation can be flexible. Most obvious approach is to add an implicit bind mount for sources.

For illustration, a classic nodeJS application uses a COPY directive in Dockerfile to add sources into /app folder. With such a sync directive, docker compose dev would add a new bind mount so that local sources override this /app folder and get synced inside container, assuming node runtime manages hot-reload.
But this is just a possible implementation, and something more clever could be offered, without the need to change the specification

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for explaining 👍 My concern is that we are potentially adding another way to mount files into the containers to the spec without necessarily drawing a clear distinction for when users should do volumes and when they should be using develop section instead. Is there a use case that this would cover that volumes are not able to?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still unclear for me.

Copy link
Collaborator

@EricHripko EricHripko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did another pass on this PR and left a few comments and suggestions inline 💬 Thank you for iterating on this!

development.md Outdated
Comment on lines 53 to 55
strategy: sync
# get service to reload configuration
signal: SIGHUP
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this example include a path for what's being synced? According to the definition, build context would be used as a default but one is not defined here.

development.md Outdated
signal: SIGHUP
```

## Developemnt mode definition
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Developemnt mode definition
## Development mode definition

typo

development.md Outdated
#### quiet_period

If a `quiet_period` is set, Compose Implementations MUST wait at least configured delay before actually refreshing
service image. Using this allows to avoid service image to be re-created many times in a row as multiple files get
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this attribute applies to sync strategy too, then we should make this paragraph a bit more abstract. Currently, it focuses a lot on rebuilding the image.

development.md Outdated

#### trigger

`trigger` define the actions to take place as changes have been detected.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`trigger` define the actions to take place as changes have been detected.
`trigger` defines the actions to take place as changes have been detected.

typo

development.md Outdated
is REQUIRED:

- `build` strategy will rebuild service image based on the `build` section and restart the service with updated image.
- `sync` strategy keep existing service contianers running, but can synchronize source files with container content.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `sync` strategy keep existing service contianers running, but can synchronize source files with container content.
- `sync` strategy keep existing service containers running, but can synchronize source files with container content.

typo

@simonmallet
Copy link

simonmallet commented May 15, 2023

Hello! I'm not sure if this is the right place to post comments on the develop file-watch feature ; but that's what it says in the docs at https://docs.docker.com/compose/file-watch/

I have a docker-compose file with 12 services in it.
Most of them will use the watch feature, but not all of them.

For instance I have 2 services that do not mention "x-develop -> watch" in the service, yet when some files get updated, they are rebuilt automatically.

Rebuilding indexer-typescript, azfunc-all-v4-5 after changes were detected:

  • /Users/simonmallet/Sites/cbc/CMS-clone/typescript/current/dist/libs/rcgraph/src/lib/interfaces/withShortStoryTileTemplate.d.ts
  • /Users/simonmallet/Sites/cbc/CMS-clone/typescript/current/dist/libs/rcgraph/src/lib/valueObjects/rightType.js
azfunc-all-v4-5:
    build:
      context: ../typescript/current
      dockerfile: apps/content-notification/docker-local/Dockerfile.azfunc-all
    env_file:
      - .env
      - ../typescript/current/.env.local
    environment:
      environment: ${Environment}
      DeployedEnvironmentWithIndex: ${EnvironmentWithIndex}
    depends_on:
      - "mongo"
      - "elasticsearch"

I'd like to be able to use docker-compose alpha watch command and that it does NOT watch apps that do not mention the x-develop option. Or an alternative would be to specify x-develop -> watch and use a pre-defined option : none.

When I build an app it writes a lot of files to the dist folder and the docker-compose alpha watch command goes in frenzy rebuilding everything forever using all my hard-disk space.

@ndeloof
Copy link
Collaborator Author

ndeloof commented May 15, 2023

@simonmallet github.com/docker/compse would be the right place for this as watch at this point is experimental

@tr00st
Copy link

tr00st commented Jun 5, 2023

(Assuming this is the right place for this discussion, as per the announcement blog post linking back here...)

Related to @EricHripko's comments re: watch.source paths being relative to the build.context, if this is the intention, it would be useful to specify a reference to build.additional_contexts to allow syncing of code outside the main build context. Something like a from_context entry (named based on COPY --from= syntax from the Dockerfile, though "watch from" probably makes less sense semantically).

@ndeloof
Copy link
Collaborator Author

ndeloof commented Jun 5, 2023

@tr00st see #253 (comment) ;)

@tr00st
Copy link

tr00st commented Jun 5, 2023

@tr00st see #253 (comment) ;)

Aah. Apologies, thought that was specifically a bug, hadn't read all the way to the end. I'll try and find the right place to report the dodgy advice for feedback in docs and blog posts ;)

@UserQuant
Copy link

UserQuant commented Jun 20, 2023

Automatically update services with file watch.
Very nice feature, works well if the changes occur in one file. But, if you copy several files or a folder with files, the terminal freezes and nothing is copied. This also happens if you change the development branch. Action rebuild does not rebuild the image and restart the container, it just syncs with the container. Config i used for compose just like in documentation.

@lonix1
Copy link

lonix1 commented Jul 31, 2023

Hi @ndeloof I was directed here from the blog post.

The blog states that the draft spec consists of actions: "sync" and "rebuild+recreate".

There is another action which just as important, and FAR simpler than those: "recreate only".

In a CI/CD environment:

  • the new image will be built and uploaded to some registry
  • the running app must then be restarted with the new version
  • the app probably has the current version specified in .env or docker-compose.yml, so that file will be updated by the CD tooling
  • docker compose should simply detect that file was changed, and recreate the container... that's all!

I saw you going back and forth on this with some doubters in other threads. But this new watch experiment is a brilliant idea. Maybe consider this use case as the foot in the door - it's simple to explain and justify, and sorely needed. Doing CD with docker is hard, but a watch-restart feature would make it trivial.

Please consider giving us a "restart only" action - I would use it in production immediately and toss out half a dozen scripts and tools and kludges!

Thanks!

@nemchik
Copy link

nemchik commented Jul 31, 2023

There is another action which just as important, and FAR simpler than those: "restart only".

Just to clarify, you're looking for a watch with a pull and recreate, not just a restart, correct?

I know this thread isn't about 3rd party tooling, but just to mention a few ways I've been doing this to make life easier:

  • watchtower pretty much does exactly this, although I would encourage caution with configuring it to globally update all containers (better to be specific and configure it using labels)
  • renovate can keep a compose file in a git repo up to date, and can do so with pull requests so incoming changes are visible rather than blindly applied. Updating a git repository with a compose file is only a part of the puzzle though, and you'll need to consider how to deploy that version controlled compose to your system (there are many options for this, potentially even the new watch options coming to compose).

@lonix1
Copy link

lonix1 commented Jul 31, 2023

Just to clarify, you're looking for a watch with a pull and recreate, not just a restart, correct?

Yes, you are right, it's a pull + recreate - the equivalent of docker compose down && docker compose up.

3rd party tooling

Thank you so much for your advice - I'm looking into those options right now. Appreciated!

For anyone who needs more options, there's also webhook and webhookd.

To eliminate all that stuff for a native and dead-simple docker compose watch feature would be a game changer. Complex CI/CD toolchains would be much shorter and easier to deploy and manage.

@Sevi7
Copy link

Sevi7 commented Aug 24, 2023

Hi, in the documentation it says:

Rules from .dockerignore apply

  • Use include / exclude to override

However, include attribute does not work. Thanks

@ndeloof
Copy link
Collaborator Author

ndeloof commented Aug 24, 2023

@Sevi7 this PR is an early proposal for develop section, it doesn't match the current syntax used by watch in Docker Compose. Please open an issue on https://github.com/docker/compose

@ndeloof ndeloof force-pushed the dev branch 2 times, most recently from c8ff5bb to 98583c8 Compare September 19, 2023 14:42
Copy link
Contributor

@ulyssessouza ulyssessouza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🥳

Copy link
Member

@milas milas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@glours glours merged commit 98de002 into compose-spec:master Sep 20, 2023
@ndeloof ndeloof deleted the dev branch September 20, 2023 15:24
@lonix1
Copy link

lonix1 commented Sep 20, 2023

@ndeloof Now that this issue was closed, where can we discuss/propose concepts like I did above regarding the watch feature? I was directed here from the blog post.

@glours
Copy link
Contributor

glours commented Sep 21, 2023

@lonix1 please open a new proposal (issue) for your need. We had to ship a first version of this new section of the spec to move forward and now we're in position to start incremental evolution of it.

@Avihais12344
Copy link

Hello, from what I have read here, this is the place to report bugs and give feedback on the new feautre: docker compose watch command.

I am loving this feature, and it works pretty fine, but I have a problem. When I exit the watch command by using ctrl + c, or by using the command: docker compose down --timeout=0 --volumes --remove-orphans, there's still a prosess that holds some lock file. As I get the error:

cannt take exclusive lock for project "my_project": process with PID 11324 is still running

What can I do? The only solution I have found is to reset the computer.
The output of the: docker-compose version command:

Docker Compose version v2.22.0-desktop.2

Thanks in ahead for any help :)

@ndeloof
Copy link
Collaborator Author

ndeloof commented Oct 4, 2023

@Avihais12344 this is an implementation issue, please report on https://github.com/docker/compose

@mhabsaoui
Copy link

mhabsaoui commented Oct 12, 2023

Hi,

First thanks for this very nice feature, it is a lot granular and user friendly than bind mounting ;-)

I used it and it's simply awsome 👍

I just wanted to make a small feedback about the logs : with docker compose watch command we get the compose watch mode logs only, not those related to service container app.

As the watch command can't be launched in detached mode like docker compose up and doesn't give the hand back, you have to open another terminal to launch the command docker compose -f compose.dev.yml logs -f -t to get them !
PS: See screenshot below...

AFAIK, there isn't any detached ou logs flag dedicated to watch command, as for up one. It would be very usefull though :-)

Thanks.

image

@mhabsaoui
Copy link

Hi,

First thanks for this very nice feature, it is a lot granular and user friendly than bind mounting ;-)

I used it and it's simply awsome 👍

I just wanted to make a small feedback about the logs : with docker compose watch command we get the compose watch mode logs only, not those related to service container app.

As the watch command can't be launched in detached mode like docker compose up and doesn't give the hand back, you have to open another terminal to launch the command docker compose -f compose.dev.yml logs -f -t to get them ! PS: See screenshot below...

AFAIK, there isn't any detached ou logs flag dedicated to watch command, as for up one. It would be very usefull though :-)

Thanks.

image

Just my 2 cents, could be the compose up command with a watch flag : docker compose up --watch

Thanks

@MarcusElevait
Copy link

Do i always have to have a build section for the watch mode?

So for example we have a simple js application and i want to run this one in a container watching file changes for hot reload.
The easiest thing i could imagine would be to just use a simple node-alpine image and copy all the files into it and run an npm command to start the app.

If i understand the watch feature correctly i now need a Dockerfile that covers all the stuff i mentioned above and use this one in the compose file.

But couldn't it make sense, that i just define the node image in the compose file and the copying is done by the watch section.

So instead of this in the compose file:

    web:
        build:
            context: .
            dockerfile: ./Dockerfile
        command: npm start
        develop:
            watch:
                - action: sync
                  path: .
                  target: /src

where the Dockerfile looks like this:

FROM node:18.16.0-alpine

WORKDIR /app

COPY . .

it could be just this in the compose file:

    web:
        image: node
        command: npm start
        develop:
            watch:
                - action: sync
                  path: .
                  target: /src

Because now i always have to build the image.

@ndeloof
Copy link
Collaborator Author

ndeloof commented Oct 26, 2023

@MarcusElevait the solution you describe would mean application can't run correctly without watch to manage file sync, i.e. docker compose up would just fail.
watch is designed to make the inner-loop faster, without the need to stop-rebuild-restart on any code change, but still the application should be well defined without this feature enabled.

For your specific scenario, you could use inlined dockerfile:

    web:
        build:
            context: .
            dockerfile-inline: |
FROM node
COPY . /src
        command: npm start
        develop:
            watch:
                - action: sync
                  path: .
                  target: /src

@MarcusElevait
Copy link

What i've done now is this:

  web:
        image: node
        command: npm start
        volumes:
            - ./:/src

the downsides i see currently when using watch instead are:

  • have to build the image with the copy command, which takes longer
  • cannot use a service name in the docker compose watch command to just start and watch this service and it's dependend services and ignore other services in the compose file (even tough this should be possible according to documentation)
  • it is way slower and more resource intensive with a bigger application
  • when shutting down the watch container, making some file changes and then starting the container again, it does not rebuild the image and therefore also does not recognize the changes that were made during the downtime.

@g0t4
Copy link

g0t4 commented Nov 2, 2023

+1 @MarcusElevait dotnet watch needs a --build arg at a minimum (if not as the default behavior) given its intended use as dev tooling.

@g0t4
Copy link

g0t4 commented Nov 2, 2023

dotnet watch also needs a way to restart itself when the compose.yaml is modified, or an action like restart_watch that I can manually map to the path of the compose file.

And dotnet watch should take the name of a compose file! Not just require compose.yaml/docker-compose.yaml

@Chokhonelidze
Copy link

docker compose watch is always rebuilding image while docker compose up --build is skipping rebuild.
is there any way to make it work as docker compose up --build ?

@maciej-wakula-opuscapita

related: #418

@aruku
Copy link

aruku commented Feb 19, 2024

I submitted this feedback a few days ago to a Google Docs Form I found, but I just discovered this seems to be the official way, so I'll leave here too:
Why not adding a bidirectional sync setting? When I run a container for development, all my binaries are there, including the package manager, so that is where I add and remove packages. But with the current workflow, I have to do docker cp to bring the updated dependencies and lock files down to the host. This option would eliminate that step.

@i-am-unknown-81514525
Copy link

Would it be possible to just restart instead of sync+restart as sometime those file might already been updated through volume mount and so it do not have to be sync again

@ndeloof
Copy link
Collaborator Author

ndeloof commented Jul 3, 2024

watch configuration is designed to avoid you set a bind mount on your own, so doesn't really make sense

@i-am-unknown-81514525
Copy link

i-am-unknown-81514525 commented Jul 3, 2024

does it?
(I was just finding this feature interesting because sync take less time than rebuilding the whole image, and restart would be faster than sync+restart as well
for instance, I just want restart when config file change

@leandrodesouzadev
Copy link

Hello there!
When I have a "container_name" directive on my compose file, and using the "rebuild" option on the watch action, i get an error looking like:

time="2024-07-23T09:23:26-03:00" level=warning msg="Error handling changed files for service celeryworker: Error response from daemon: Conflict. The container name \"/0eb11b45dc0b_local_django\" is already in use by container \"c8590d3b762fafcd826f7964516442d08ad3c3edb56c67db8e926d8f31d112de\". You have to remove (or rename) that container to be able to reuse that name."

Compose file (partial):

services:
  django: &django
    build:
      context: .
      dockerfile: ./compose/local/django/Dockerfile
    image: local_django
    container_name: local_django
    depends_on:
      - postgres
      - redis
    env_file:
      - path: ./.envs/.local/.django
      - path: ./.envs/.local/.postgres
      - path: .env
        required: false
    ports:
      - '8001:8000'
    command: /start
    extra_hosts:
      - "host.docker.internal:host-gateway"
    develop:
      watch:
        - action: sync
          path: .
          target: /app
          ignore: 
            - ./requirements
        - action: rebuild
          path: requirements

The goal here was to rebuild the application when the "requirements" folder content was changed.

@derekrprice
Copy link

does it? (I was just finding this feature interesting because sync take less time than rebuilding the whole image, and restart would be faster than sync+restart as well for instance, I just want restart when config file change

This is my use case for a plain "restart" action. I want to leave the bind in place. Then I don't need to worry about changing users to get write permissions to files that I normally leave read-only in my production environment. When my pnpm run build:watch rebuilds my Typescript sources into executable JS, I just want the docker container to restart. It's hosting a websocket server, not a hot-reloading development webserver, so it needs a full restart too. The simple sync from the example in the docs won't do the trick.

@ei-grad
Copy link

ei-grad commented Nov 21, 2024

Just found this functionality, and also concerned about the missing plain "restart" action, which will restart container if path is changed.

Also, it will be convenient to watch files by mask and allow to specify several paths per rule (like, allow path to be a list for the rebuild action).

@ei-grad
Copy link

ei-grad commented Nov 21, 2024

It also would be nice if there was a documented way to disable "w Enable watch" message in docker compose up <service>.

@ndeloof
Copy link
Collaborator Author

ndeloof commented Nov 22, 2024

@ei-grad see docker/compose#11446
About compose navigation menu, this is specific to docker compose, not compose-spec. You can disable by running docker compose up --menu=false or set COMPOSE_MENU=false in your environment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.