Search code examples
cssdockersassdocker-volumedocker-multi-stage-build

How to keep compiled files after starting a docker container with volume mounted?


I have an image with multi-stage build for compiling some files and copy them into my final image.

I also set a volume between the directory of my app on the host machine and inside the container.

But when I start the container, the compiled files are not here. As I understand how volumes work, it makes perfect sense: the container replaces the content of his directory with the content of the directory on the host machine, where the compiled files are not generated as they are generated by the container when it is building.

But I am wondering if there is a way to keep the volume and have the compiled files in the container when it starts. I assume that I am doing it wrong.

To give you more info about my need, I want to compile .css files from .scss inside a nodejs image and I copy the compiled .css to /app/<my_app>/static/css/ folder of my app docker image.

Here is my project's structure:

- docker-compose.yml
- production.env
- web/
- - Dockerfile
- - build/
- - - scss/
- - app/
- - - <my_app>/
- - - - static/
- - - - - css/

docker-compose.yml

version: '3'

services:
  web:
    build: web/
    ports:
      - "5000:5000"
    env_file: 
      - ./production.env
    volumes:
      - ./web/app:/app

Dockerfile

FROM node:alpine as builder

WORKDIR /build

COPY build/ .

RUN npm install && mkdir -p css

RUN npm run scss # Compile .scss files to .css into /build/css/ folder

FROM python:alpine

WORKDIR /app

COPY app/ .

COPY --from=builder /build/css ./<my_app>/static/css

/* ... Some instructions ... */

CMD flask run

Here, when I build the container the css files do not exist yet, they are compiled, copied to the final image. When I start the image, as there is a volume between ./web/app:/app, the content of the image is replaced with the content in the host machine and so the .css files are missing.


Solution

  • Finally I have found a solution by myself, so I post the answer here hoping it will help someone else.

    I abandoned the multi-stage build and try to create an image dedicated to scss compiling.

    Here is the Dockerfile of this image:

    FROM node:alpine
    
    WORKDIR /build
    
    COPY package.json ./
    
    RUN mkdir -p ./scss ./css
    
    RUN npm install
    
    CMD npm run scss
    

    Note that I use the module node-sass for compiling scss in a nodejs environment.

    For now, it just compiles files from scss/ and puts the output into css/. But there is nothing in those folders yet.

    I edit my docker-compose.yml to run this new image at start and set two volumes from static folders of my app to scss/ and css/ folder in the container of this new image called scss. So when web will start, static/css will be filled by this new service using files from static/scss as source.

    version: '3'
    
    services:
      web:
        build: web/
        ports:
          - "5000:5000"
        depends_on:
          - scss
        env_file: 
          - ./production.env
        volumes:
          - ./web/app:/app
      scss:
        build: scss/
        env_file:
          - ./production.env
        volumes:
          - ./web/app/<my_app>/static/css:/build/css
          - ./web/app/<my_app>/static/scss:/build/scss  
    
    

    Finally, it works.

    After running $ docker-compose up -d, css files are here. The container of scss image is not running as it is a one-shot command, not a proper service running, but you can run it again if you made some changes to your .scss files and you want to compile .css again.