Home > Mobile >  How to prevent a non-empty host folder from overriding a mounted container folder?
How to prevent a non-empty host folder from overriding a mounted container folder?

Time:08-25

I am trying to compile my assets using Docker for a Laravel project.

So, I have created a service called npm which is built from the following Dockerfile:

FROM node:16-alpine as node

WORKDIR /usr/src

ADD ./resources ./resources
COPY ["package.json", "package-lock.json", "vite.config.js", "./"]

RUN npm install --global cross-env
RUN npm install
RUN npm run build

Also, I am using the following Docker-compose configuration

  node:
    build:
      context: ./
      dockerfile: ./services/nodejs/Dockerfile
    working_dir: /var/www
    container_name: "nodejs"
    volumes:
      - ./:/var/www
    tty: true
    depends_on:
      - php

Although the service is built successfully, it seems that my host directory (which is non-empty) is overriding the content of my node container. So, eventually I end up with no "node_modules" directory and my compiled assets and resources get lost.

So, what should I do? I think that I can first copy the content of my host folder to the container, then delete the content of my host folder, and then run my scripts and then copy it back. But that seems to be a very time consuming thing to do. What is the best practice for cases like this? I'm sure I'm not the first one that has dockerized a full-stack Laravel project. Thanks in advance

CodePudding user response:

It doesn't look like you COPY your application code into the container. That leaves you in a position where you need to bind-mount things in, but since the host directory is missing some built parts, the final container image is incomplete.

There's an especially important detail here around using this container as part of your build sequence which I'll get back to.

The first thing to do is to make sure all of the things you need are in the image itself.

FROM node:16-alpine as node
WORKDIR /usr/src
RUN npm install --global cross-env

# run `npm install` first to avoid rebuilds if `package.json` is unchanged
COPY ["package.json", "package-lock.json", "vite.config.js", "./"]
RUN npm install

# then copy in the rest of the application
# (make sure `node_modules` and `build` are in `.dockerignore`)
COPY ./ ./
RUN npm run build

# and explain how to run the container (*)
CMD npm run start

Then in your docker-compose.yml file, you don't need to specify volumes: because the code is already in your image. You similarly don't need to declare a working_dir: because the Dockerfile sets WORKDIR already. This section of your Compose file can probably be trimmed down to

  node:
    build:
      context: ./
      dockerfile: ./services/nodejs/Dockerfile
    tty: true    # actually needed?
    depends_on:
      - php

I don't think you actually want this container, though, since

I am trying to compile my assets using Docker for a Laravel project.

In this case you can use this Dockerfile (and it must be the complete self-contained Dockerfile) as part of a multi-stage build. Put this Dockerfile at the start of your PHP application Dockerfile and give it a name, and then you can COPY the built assets from one stage to another.

FROM node:16-alpine AS node # <-- `AS somename` is important
...
RUN npm run build
# no specific need for a CMD here

FROM php:fpm
...
COPY --from=node /usr/src/build ./static/

Again, since this will get filled in at Docker image build time, it's important to not overwrite the image content with a volumes: mount.

If you do this then there's not a "Node container" at all, and you can just outright remove this from your docker-compose.yml file. For this setup you don't need a long-running server, you just need to have Node available to run a compilation step at build time, and including it in a Dockerfile stage is enough for that.

  • Related