skip to Main Content

I’m trying to set up dev, preview-staging and prod images of Vite+ReactTS via single Dockerfile using multistaging

Here’s Dockerfile’s content:

#
# ---- Base Image ----
# Use to set up defaults
#
ARG APP_DIR_PATH=app
ARG BASE_IMAGE_VER=20.5.1-alpine3.18
ARG BUILD_PLATFORM=linux/amd64
FROM --platform=${BUILD_PLATFORM} node:${BASE_IMAGE_VER} AS base

# see https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md
RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]

WORKDIR /${APP_DIR_PATH}

ENV NODE_PM=pnpm
RUN npm i -g ${NODE_PM}

COPY package.json ./
COPY pnpm-lock.yaml ./

#
# ---- Dependencies Image ----
# Use to hold cached node_modules ?and prod_modules separate?
#
ARG DEV_NODE_MODULES_DIR_PATH=node_modules
ARG PROD_NODE_MODULES_DIR_PATH=prod_${DEV_NODE_MODULES_DIR_PATH}
FROM base AS dependencies
RUN ${NODE_PM} i -P

# Possibly we don't need prod copy of packages due to Vite uses tsc and itself for build and preview
# for now they are in devDependencies, so...
RUN cp -R ./${DEV_NODE_MODULES_DIR_PATH} ./${PROD_NODE_MODULES_DIR_PATH}

RUN ${NODE_PM} i

#
# ---- Development Image ----
# Use in development
# Note: rebuild image after every package.json|.configs changing
#
ARG VITE_PORT=8080
FROM dependencies AS dev
COPY ./ ./

# keep tracking ./src/
RUN --mount=type=bind,target=./src/,source=./src/,rw=false

ENV VITE_PORT=${VITE_PORT}
EXPOSE ${VITE_PORT}

CMD ["pnpm", "dev"]

#
# ---- Build Image ----
# Use for production's preview
# Note: rebuild image after every package.json|.configs changing
#
ARG BUILD_DIR_PATH=dist
FROM dev AS build

ENV NODE_ENV=production

COPY ./ ./
RUN ${NODE_PM} build --outDir ./${BUILD_DIR_PATH}

CMD ["pnpm", "preview", "--port", "${VITE_PORT}"]

#
# ---- Production Image ----
# Use in production
# Note: rebuild image after every new change
#
# ARG BASE_PROD_IMAGE_VER=1.25.2-alpine
FROM --platform=${BUILD_PLATFORM} nginx:1.25.2-alpine AS prod
WORKDIR /

COPY ./.configs/nginx/nginx.conf /etc/nginx/nginx.conf

RUN rm -rf /usr/share/nginx/html/*

COPY --from=build /app/dist /usr/share/nginx/html/

EXPOSE 80 443

CMD ["nginx", "-g", "daemon off;"]

Always getting error at prod image staging at line

COPY --from=build /app/dist /usr/share/nginx/html/

With this output

 => ERROR [prod 4/5] COPY --from=build /app/dist /usr/share/nginx/html/                                                                      0.0s 
------
 > [prod 4/5] COPY --from=build /app/dist /usr/share/nginx/html/:
------
build.Dockerfile:85
--------------------
  83 |     RUN rm -rf /usr/share/nginx/html/*
  84 |
  85 | >>> COPY --from=build /app/dist /usr/share/nginx/html/
  86 |
  87 |     EXPOSE 80 443
--------------------
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref 122aaccf-8f31-4e47-aff8-56e3d80edefb::zni94o6alhuq2gp7tryq3q8t0: failed to walk /var/lib/docker/tmp/buildkit-mount959429879/app: lstat /var/lib/docker/tmp/buildkit-mount959429879/app: no such file or directory

I don’t have any idea what is going on in stderr

I’m using Docker(v24.0.5) on Windows

What I’ve tried

Nothing at all over stackoverflow

2

Answers


  1. Chosen as BEST ANSWER

    Weird output: It was caching issue

    Problem solve: change

    COPY --from=build /app/dist /usr/share/nginx/html/
    

    to

    COPY --from=build /dist /usr/share/nginx/html/
    

    reason: WORKDIR of base stage-image, in this case build image


  2. There is a specific bug in the way you’re using build-time ARG.

    Each FROM line starts a new image and resets the build environment. In particular that resets the sets of ARG that are "in scope". You can put ARG before FROM but the only things you can do with these ARGs are set default values and use them in FROM lines.

    Your Dockerfile approximately starts with (in this order)

    ARG APP_DIR_PATH=app
    FROM node AS base
    WORKDIR /${APP_DIR_PATH}
    

    Since you don’t repeat the ARG after the FROM line, it’s not set in the base build stage. That means the $APP_DIR_PATH variable is empty at this point in the setup. That’s not an error, you just execute WORKDIR / and carry on from here. When you get to the build stage, you build into /dist and not /app/dist and that results in the problem you eventually see.

    This error seems to be repeated for every build stage; you have ARG declared immediately before the FROM line starting the stage that uses it. I suspect you’re avoiding trouble here only because this Dockerfile is so linear, every stage inherits from its immediate predecessor. If you had a separate path FROM base that installed only production modules it might see similar issues around undefined variables.

    You have a lot of variables for things like filesystem paths and command names that don’t quite make sense here. This is doubly true for things like the node_modules directory that have fixed names. (Ask, would you ever change these things? Platform or Node version, yes; changing pnpm to yarn, not without some other rearrangement.) I’d remove many of these variables, which avoids some ambiguity

    WORKDIR /app       # fixed filesystem layout inside the image
    RUN npm i -g pnpm  # fixed npm package name of alternate package manager
    RUN pnpm i -P      # different package managers will have different options
    EXPOSE 8080        # matches listen() call in code
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search