Why is my docker-compose which targets the prod phase in my dockerfile also running the dev target?

Viewed 455

Why is my docker-compose which targets the prod phase in my dockerfile also running the dev target?

command:

docker-compose -f 'docker-compose-prod.yml' up --build

I am specifically targeting prod in docker-compose-prod.yml but dev target is also being run.

Step 4/18 : FROM base as dev
 ---> 89ae35cdccf6
Step 5/18 : RUN npm install
 ---> Using cache
 ---> 8d6693e78ce0
Step 6/18 : COPY . .
 ---> 93518e386a6e
Step 7/18 : RUN npm run build
 ---> Running in 44199ae5793a

dockerfile:

# base
FROM node:lts-alpine as base
WORKDIR /usr/src/app
COPY package*.json ./
 
# dev
FROM base as dev
RUN npm install
COPY . .
RUN npm run build
EXPOSE 8080
CMD ["npm", "run", "serve"]

FROM base as prod-build
RUN npm install
COPY . .
RUN npm run build:production

# prod
FROM nginx:stable-alpine as prod
COPY --from=prod-build /usr/src/app/dist /usr/share/nginx/html
COPY nginx/nginx.conf /etc/nginx/conf.d
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

docker-compose-prod.yml:

version: "3.7"

services:
  app:
    image: my-app:prod
    build:
      context: .
      target: prod
    ports:
      - 80:80
    restart: always
1 Answers

With the classic builder, a multi-stage Dockerfile is parsed from the beginning to end, and can be stopped from going all the way to the end by specifying a target stage. All of the stages leading up to the target stage are built in the process.

Docker has been moving to use buildkit which performs a dependency graph analysis of the Dockerfile and builds all of the dependencies and target stages concurrently, skipping any stage that is not a dependency. You can switch to that by either setting a variable in the shell running the build or configuring the feature flag in the engine.

export DOCKER_BUILDKIT=1
docker build ...

or just

DOCKER_BUILDKIT=1 docker build ...

or for the feature flag:

# cat /etc/docker/daemon.json
{  "features": {"buildkit": true } }

# systemctl reload docker

The other option is to split up your Dockerfile into separate dockerfiles since there's few dependencies between the dev and prod image, the base image could be completely externalized from this. Or redesign the Dockerfile so these two stages are nearly identical and either dev or prod are a slight extension of the other. Then there's no downside to building the dependent stage.

Related