Docker Community Forums

Share and learn in the Docker community.

Bind-mounting a volume: inconsistent experience

I’m running up-to-date stable Docker (client and server) on MX Linux 19.2. I recently ran the strapi/strapi container that I saw on Docker Hub and used a bind mount in the docker run command to have easy access to the /srv/app folder which had been configured as a VOLUME in the Dockerfile (below).
FROM strapi/base:{BASE_VERSION} ARG STRAPI_VERSION RUN yarn global add strapi@{STRAPI_VERSION}
RUN mkdir /srv/app && chown 1000:1000 -R /srv/app
WORKDIR /srv/app
VOLUME /srv/app
COPY /usr/local/bin/
CMD [“strapi”, “develop”]

Bolstered by that experience, I figured that I could do the same with a VueJS/nginx multistage build Dockerfile (below) and was shocked to find that upon bind-mounting the volume, it was empty. My application files that should have been copied into nginx’s html folder (during image build via Dockerfile) weren’t to be found. To troubleshoot, I used docker run -it --rm container-name to login to intermediate container layers from the image build and found the files upon navigating to the nginx html folder. The best I could tell was that trying to bind mount the volume in docker run with the -v option is what cleared out the contents of this folder. I also tried a variation where I removed the VOLUME line in the Dockerfile but this also resulted in an empty bind mount folder. Would anyone know why there is this inconsistency between relatively similar scenarios and how I can fix this, i.e., get local folder (bind mount) access to my application files freshly moved over to nginx folder.

FROM node:lts-alpine as build-stage
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
VOLUME /usr/share/nginx/html
CMD [“nginx”, “-g”, “daemon off;”]

I also noticed that the nginx container by itself did the same thing, in that its bound volume was empty, when its standard to have few defaults files in its the nginx/html folder. There were no errors found during either image creation or running the container. Can anyone explain?

Exactly, you mount the folder of your host into the container, not the folder of the container into the host. This means the files and folder of your host replace (or hide) those in the container, not the other way round. You find the same behavior with the Linux mount command.

That’s a handy theory but it doesn’t explain why I’m seeing this inconsistency between the nginx container and the strapi container? Why did my bind-mount on the strapi container allow me to see what was in the container, yet the bind-mount on the nginx container caused the existing nginx starter files such as 50x.html & index.html to disappear? I was specifying a non-existing folder on the left side of the colon in the -v option in both of these instances.

At the same time, instead of an explanation, I’d simply like to know how I could use a bind-mount to see what’s in the nginx container w/o wiping it out. Thanks.

Bind mounts use the linux command mount --bind /src/host/path /target/container/path to mount a host folder on top of a container folder - its original content will become invisible.

You can reproduce the behavior on your host: 1. create a test folder add a file to it. 2. create a second test folder and add a file to it. 3.mount --bind the second test folder on top of the first test. 4 investigate the outcome. This is exactly the behavior causing your observation within the nginx container.

If you want to retain the original content of the container path when mapping volumes to them, then there is no way arround a) use volumes to benefit from the copy on first use machanism of volumes or b) modify the Dockerfile to mimik that behavior in the entrypoint script.

Thanks. I think you’re on to something here. Looking at the strapi Dockerfile it runs a which creates a new strapi.js project (in the bind-mounted folder) unless there’s one there already. That seems to be why this is happening. I still have much to learn and I need to read those articles on using Docker containers to develop with, since that’s basically what I’m getting at here – accessing the container’s filesystem from the host system while developing and changing files.

It is a good practice to make it a habit to lookup details in the official docs.

Though, this is not exactly how volume or bind mounts work. With both a source folder is mounted into a container folder. Changes applied to the source folder will become visible in the mount target in the container. The source folder can be a bind mount, a volume backed by bind mount, a volume backed by remote shares (nfs/cifs) or a volume backed by another volume plugin.

I’ll show the issue with a simple example of no practical use.

I build an image from this Dockerfile:

FROM python:3.6-slim-buster

USER root

groupadd --gid=2000 luca &&
useradd -m --uid=2000 --gid=2000 luca

USER luca
WORKDIR /home/luca
CMD ["/bin/bash"]
with the command

docker build -t luca .
Both on MacOSX and Ubuntu the user I use to create and start the containers has uid=1000,gid=1000.

If on Mac OSX I run the command

docker run -it --rm --name=luca --mount type=bind,source="$PWD",target=/home/luca luca touch in-docker.txt