问题
I have a compose file:
version: "3"
services:
db:
image: postgres:12.5
ports:
- "15432:5432"
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test
volumes:
- ./postgres-data:/var/lib/postgresql/data
backend:
image: backend
depends_on:
- db
restart: always
ports:
- "6969:8000"
volumes:
- ./app:/app
When I run docker-compose up to start the 2 containers, I notice that:
- Docker auto creates the directory postgres-data, and it transfers the content of /var/lib/postgresql/data from container to host directory postgres-data
- With the backend service, Docker also auto creates the directory ./app, but instead of transfer the content of the /app directory (from container) to the ./app directory in host, it did the opposite: it transfer the content from the ./app directory in host to the /app in container.
Both service uses bind mount, and as I understand: bind mount always transfer the content from the host directory to the container. But this does not happen in the case of the db service
So where did I understand wrong here ?
Thanks in advance
回答1:
Nothing ever gets "transferred". The contents of the host directory always hide what was in the underlying image, and once the container has started, the host and container directories are "the same"; writes in one side should be visible in the other.
The Docker Hub database images in particular know to look at their data directories at startup time. The sequence is roughly like this:
- Docker creates a container, with the host's
$PWD/postgres-data
directory replacing/var/lib/postgresql/data
in the container. - The
postgres
image's entrypoint script looks at the data directory and sees it is totally empty. It then creates a new database and runs any first-time-initialization scripts. Since that directory is a bind-mounted host directory, this content is also visible on the host. - The database starts up normally with whatever its data directory is.
This work is done on the mounted directory at container startup time, so it happens to be visible on the host as well. (If you docker run --rm -it --entrypoint /bin/sh postgres
and look around, bypassing its entrypoint script, you'll probably find the /var/lib/postgresql/data
directory is totally empty; there is nothing there to be "transferred to the host".)
This also means that your bind mount over the application container's /app
directory hides whatever the Dockerfile does; if you run a build sequence it will get lost, and if the directory layouts in the host and container aren't identical, you will have non-reproducible problems. This further means you can't directly use volumes to copy file out of an image; you have to run a container that runs a cp
command.
回答2:
I must admit that I thought this behaviour only worked with volume mounts and not bind mounts. The documentation for the volume long syntax indicates the copy mode is only available to volume mounts.
来源:https://stackoverflow.com/questions/65955098/docker-strange-behaviour-of-bind-mount