-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A way of mounting a directory where files from the container overwrite host files with docker compose watch
#12510
Comments
AFAICT your last solution is close to a solution, you could rely on services:
app:
build:
context: ./
dockerfile: ./backend/Dockerfile
volumes:
- ./backend/vendor:/app/vendor
develop:
watch:
- action: sync
path: ./backend
target: /app
ignore:
- backend/vendor
- app/vendor
- vendor
- action: sync=exec
path: backend/composer.lock
target: backend/composer.lock
exec:
command: composer install Anyway, I'm a bit confused with the initial state "This requires each developer to keep track of changes in Composer's lock files and run composer install (which installs dependencies into vendor) every time the lock file changes" - doesn't your IDE detect updates to lock file and suggest running this command ? This actually sounds like a local workflow automation issue, as source code is synced from upstream repo, vs a compose issue |
Would love to try your solution, but it seems that It does seem like it will work, but it would also mean that RUN --mount=type=cache,target=/root/.composer/cache composer install It does seem like this could be extracted into a named volume and be mounted in IDEThe IDE does detect updates, and it does suggest running the install command. However:
And, most importantly, it still does not solve the issue of unifying different Dockerfile "strategies" we use for local and production deployment. Unifying those would be great in of itself, but it would also allow running additional commands during build on local environments as part of build process, which we currently cannot do because there are no project files during Docker build on local environments. They are only copied into a container with a volume, so we have to also run these commands after containers start separately. I get where you're coming from. But |
New Docker for Mac was released, so I tried the solution you suggested. Unfortunately it still does not work. I'm not sure if the "exec" portion is even executed the first time I do
So I'm not sure if You can try doing |
A similar issue I've stumbled upon, but it is also kind of relevant: I want to set up a tool called Prettier in services:
prettier:
image: jauderho/prettier:3.4.2-alpine
restart: no
command: --cache --cache-location=/work/storage/tmp/.prettier-cache --cache-strategy=content --log-level warn --write .
volumes:
- ./:/work
deploy:
replicas: 0 However, there's an issue with the IDE, where it requires you to have the services:
prettier:
image: jauderho/prettier:3.4.2-alpine
restart: no
command: --cache --cache-location=/work/storage/tmp/.prettier-cache --cache-strategy=content --log-level warn --write .
volumes:
- ./:/work
- ./node_modules:/var/lib/node_modules
deploy:
replicas: 0 But if I do that, the Could it be considered to add a flag to bind mounts specifying this exact behaviour? E.g.: services:
prettier:
image: jauderho/prettier:3.4.2-alpine
restart: no
command: --cache --cache-location=/work/storage/tmp/.prettier-cache --cache-strategy=content --log-level warn --write .
volumes:
- ./:/work
- type: bind
source: ./node_modules
target: /var/lib/node_modules
copy_from_container: true
deploy:
replicas: 0 That should solve both use cases. I understand that this isn't |
A bind mount, by nature, replaces the container's filesystem on target path with the one from bind source. New files written by container will be actually created on host directly. If container image comes with some initial content for this mount path, it will just be hidden by the mount. This is how Unix mount works, there's no voodoo magic to be expected here, and the challenge is not about declaring a new attribute in compose.yaml but for docker engine to manage such a scenario that is contradictory to the core concepts |
I see that this is the case with bind mounts. I just thought that Docker has access to the image and would be able to copy and replace the files from the image directly to the mount. This does not seem possible in user land. I understand this might not actually be possible or feasible, and I fully get that it looks like a crutch, not a proper solution. That's just the first thing that came in mind. But also as you can see, this is a valid use case. I'm not sure how others utilize https://stackoverflow.com/questions/47664107/docker-mount-to-folder-overriding-content So it seems that a named volume is closer to a solution than a bind mount, but still doesn't really work:
services:
app:
build:
context: ./
dockerfile: ./backend/Dockerfile
volumes:
- ./backend:/app
- type: volume
source: backend-vendor
target: /app/vendor
develop:
watch:
- action: rebuild
path: backend/composer.lock
cli:
image: composer:2.7.4
working_dir: /app
volumes:
- ./backend:/app
volumes:
backend-vendor:
driver: local
driver_opts:
type: none
o: bind
device: ./backend/vendor Would named volumes maybe be a better starting point? Maybe something like: services:
app:
build:
context: ./
dockerfile: ./backend/Dockerfile
volumes:
- ./backend:/app
- type: volume
source: backend-vendor
target: /app/vendor
develop:
watch:
- action: rebuild
path: backend/composer.lock
+ - action: host_exec
+ command: rm -rf backend/vendor
cli:
image: composer:2.7.4
working_dir: /app
volumes:
- ./backend:/app
volumes:
backend-vendor:
driver: local
driver_opts:
type: none
o: bind
device: ./backend/vendor
+ create_host_path: true Still looks like a workaround, especially the |
Description
Hey.
First of all, it seems like there already was a similar issue, but it lacked context to understand why it's important to have this implemented in some way. Which is why I'm creating another issue, sorry: #11658
Our app
Our app is a PHP app and uses Composer package manager, but all of this is also relevant for NodeJS apps as well. All packages are installed into
/vendor
directory, so the entire project structure looks something like this:For development, each team member uses an IDE. The IDE uses files in
backend/vendor/
to provide type information, auto-complete and to show sources of vendor packages whenever necessary. Moreover, since PHP is an interpreted language, sometimes we modify the files inbackend/vendor/
directly to assist with debugging. Of course, any changes inbackend/vendor/
are only ever done locally, during development and with full understanding that the changes are going to be gone when Composer re-installs dependencies.docker-compose.yml
docker-compose.yml
is only used for local development. Hence, it currently uses bind mounts to share the entirebackend
directory into the container:This works, but requires each developer to keep track of changes in Composer's lock files and run
composer install
(which installs dependencies intovendor
) every time the lock file changes, by running something likedocker compose run --rm -it app composer install
ordocker compose exec app composer install
. It works this way:/backend/vendor
to/app/vendor
/app/vendor
/app/vendor
back to the host to/backend/vendor
Dockerfile
Locally, no project files are copied into the container;
Dockerfile
is just a base PHP image with some configurationOn production, the app runs on AWS Fargate (which means no way to mount anything), so we pre-build our application into a Docker image, with all Composer dependencies and project files.
This is how it looks:
docker compose watch
Now, there are several services like these in our project. Each requires developers to keep track of lock files and re-run package managers whenever they change. This is inconvenient and creates a lot of situations that could have been avoided. It also completely means our production build works in an entirely different way from our local builds.
This is where
docker compose watch
helps - not only would it allow us to use the same (production) Dockerfile for all environments, but it would also eliminate all unnecessary movements developers currently have to make. So let's say we modify the abovedocker-compose.yml
to include thewatch
configuration, and remove the volume:This works, but now developers no longer have access to
backend/vendor
on the host, meaning the IDE has no idea what dependencies are installed, and neither do developers. This is a problem.Let's say we remove the
ignore: [backend/vendor/]
part. Still,backend/vendor/
is not synced back to the host if it didn't exist in the first place.Okay, let's try adding the volume back, just for the
vendor
directory, and ignore it for watch:Still broken. Now both the host and container have an empty
vendor
folder.Summary
We need a way of syncing the
backend/vendor
folder between the host and the container, but for image built files to always overwrite the host contents.The text was updated successfully, but these errors were encountered: