Mounting a volume overwrites files stored in the Docker image

I am trying to containerize the front-end of my website and automate its deployment. My goal is to be able to have a new image be generated and hosted when a change is pushed, and have the server automatically fetch it and restart the container. Here are the steps that I am taking:

  1. I create the image by first building my Node application and then bundling the distribution and nginx configuration files into the latest linuxserver/letsencrypt image. This is the Dockerfile:

    # Use the NodeJS image as builder
    FROM node:alpine AS builder
    
    # Create the workspace
    RUN mkdir -p /usr/src/app
    WORKDIR /usr/src/app
    
    # Copy the package file and source code
    COPY package.json /usr/src/app
    COPY . ./
    
    # Install dependencies
    RUN npm install
    
    # Build the application
    RUN npm run build
    
    # The nginx server, this builds the final image
    FROM linuxserver/letsencrypt
    
    # Copy the nginx configuration
    COPY ./config/nginx.conf /config
    
    # Copy the output of the builder
    COPY --from=builder /usr/src/app/dist /config/www
    
    # Inform Docker to listen on port 443 and 80
    EXPOSE 443 80  
    
  2. This image is uploaded to GitHub’s package registry and I poll for updates using Watchtower.

  3. The image is started using this docker-compose file:

    version: "3"
    services:
      ...
      frontend:
        image: [IMAGE]
        container_name: frontend
        cap_add:
          - NET_ADMIN
        environment:
          - PUID=1000
          - PGID=1000
          - TZ=[TIMEZONE]
          - URL=[URL]
          - SUBDOMAINS=www,
          - VALIDATION=http
        ports:
          - 443:443
          - 80:80
        volumes:
          - ./frontend:/config
        restart: unless-stopped
      ...  
    

The issue is that the files that were packaged into the image using the COPY instruction are being overwritten when I use the following line in my docker-compose:

volumes:
  - ./frontend:/config  

If I remove that section from my docker-compose file everything works fine, however this is not a solution because that folder stores important data.

I have read that mounting a volume completely overwrites any previous data, however I like the fact that I can easily load the image onto my server and have all the required files already embedded. Is there anything that I can do to fix my issue, or am I misusing/misunderstanding docker images?

I have tried setting the volume to read only as suggested here, however this did not work and instead caused the image to continually stop and restart.

I have also briefly read about bind mounts and am wondering if they will be of any use.

This behavior is expected. Docker mounts work in the same way as Linux mounts, i.e. overwriting contents of the target directory with the source directory contents.

My suggestion is to use another destination directory for your volume, e.g.

volumes:
 - ./frontend:/someotherdir 

And then adjust your nginx configuration to look for JS files there.

I found out that I could retain the data in the image by first creating a named volume:

volumes:
  frontend_data:

And then mounting the container to that volume:

services:
  frontend:
    ...
    volumes:
      - frontend_data:/config
    ...

Leave a Comment