Jonathan Tuzman
Jonathan Tuzman

Reputation: 13278

Docker volumes not mounting/linking

I'm in Docker Desktop for Windows. I am trying to use docker-compose as a build container, where it builds my code and then the code is in my local build folder. The build processes are definitely succeeding; when I exec into my container, the files are there. However, nothing happens with my local folder -- no build folder is created.

docker-compose.yml

version: '3'
services:
  front_end_build:
    image: webapp-build
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 5000:5000
    volumes:
      - "./build:/srv/build"

Dockerfile

FROM node:8.10.0-alpine

EXPOSE 5000

# add files from local to container
ADD . /srv

# navigate to the directory
WORKDIR /srv

# install dependencies
RUN npm install --pure-lockfile --silent

# build code (to-do: get this code somewhere where we can use it)
RUN npm run build

# install 'serve' and launch server.
# note: this is just to keep container running
# (so we can exec into it and check for the files).
# once we know that everything is working, we should delete this.
RUN npx serve -s -l tcp://0.0.0.0:5000 build

I also tried removing the final line that serves the folder. Then I actually did get a build folder, but that folder was empty.

UPDATE: I've also tried a multi-stage build:

FROM node:12.13.0-alpine AS builder
WORKDIR /app
COPY . .
RUN yarn
RUN yarn run build

FROM node:12.13.0-alpine
RUN yarn global add serve
WORKDIR /app
COPY --from=builder /app/build .
CMD ["serve", "-p", "80", "-s", "."]

When my volumes aren't set (or are set to, say, some nonexistent source directory like ./build:/nonexistent), the app is served correctly, and I get an empty build folder on my local machine (empty because the source folder doesn't exist).

However when I set my volumes to - "./build:/app" (the correct source for the built files), I not only wind up with an empty build folder on my local machine, the app folder in the container is also empty!

It appears that what's happening is something like 1. Container is built, which builds the files in the builder. 2. Files are copied from builder to second container. 3. Volumes are linked, and then because my local build folder is empty, its linked folder on the container also becomes empty!

I've tried resetting my shared drives credentials, to no avail.

How do I do this?!?!

Upvotes: 2

Views: 10702

Answers (2)

chaosaffe
chaosaffe

Reputation: 856

tl;dr; Volumes aren't mounted during the build stage, only while running a container. You can run the command docker run <image id> -v ./build/:/srv/build cp -R /app /srv/build to copy the data to your local disk


While Docker is building the image it is doing all actions in ephemeral containers, each command that you have in your Dockerfile is run in a separate container, each making a layer that eventually becomes the final image.

The result of this is that the data flow during the build is unidirectional, you are unable to mount a volume from the host into the container. When you run a build you will see Sending build context to Docker daemon, because your local Docker CLI is sending the context (the path you specified after the docker build, ususally . which represents the current directory) to the Docker daemon (the process that actually does the work). One key point to remember is that the Docker CLI (docker) doesn't actually do any work, it just sends commands to the Docker Daemon dockerd. The build stages shouldn't change anything on your local system, the container is designed to encapsulate the changes only into the container image, and give you a snapshot of the build that you can reuse consistently, knowing that the contents are the same.

Upvotes: 1

BMitch
BMitch

Reputation: 264861

I believe you are misunderstanding how host volumes work. The volume definition:

./build:/srv/build

In the compose file will mount ./build from the host at /srv/build inside the container. This happens at run time, not during your image build, so after the Dockerfile instructions have been performed. Nothing from the image is copied out to the host, and no files in the directory being mounted in top of will be visible (this is standard behavior of the Linux mount command).

If you need files copied back out of the container to the host, there are various options.

  1. You can perform your steps to populate the build folder as part of the container running. This is common for development. To do this, your CMD likely becomes a script of several commands to run, with the last step being an exec to run your app.

  2. You can switch to a named volume. Docker will initialize these with the contents of the image. It's even possible to create a named bind mount to a folder on your host, which is almost the same as a host mount. There's an example of a named bind mount in my presentation here.

  3. Your container entrypoint can copy the files to the host mount on startup. This is commonly seen on images that will run in unknown situations, e.g. the Jenkins image does this. I also do this in my save/load volume scripts in my example base image.

Upvotes: 5

Related Questions