skip to Main Content

I’m using dockerized node, and in order to minimize the image as much as possible, I’m mixing between bookworm (Debian 12) and Alpine, in the following way:

FROM node:18.17.1-bookworm-slim AS build
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18.17.1-alpine AS production
COPY --chown=node:node --from=build /app/node_modules ./node_modules
COPY --chown=node:node --from=build /app/dist ./
COPY --chown=node:node --from=build /app/package*.json ./
USER node
EXPOSE 3000
CMD ["node", "src/app.js"] 

What is the risk I’m taking here by building my node app in Debian and deploying it in Alpine?

2

Answers


  1. None of the previous stages are included in the final image when you build a multi-stage image. However, it is strongly advised to use the same image for building the application as the production one, to keep things consistent. Since the operating systems are different, chances are the container will fail to start due to different OS being used for building and running the app.

    For a multi-stage Node.js apps where there are build stages, I would recommend using the following config:

    FROM node:lts-alpine
    WORKDIR /tmp/app
    COPY package*.json ./
    RUN npm install
    COPY . .
    RUN npm run build
    FROM node:lts-alpine
    ENV NDOE_ENV production
    WORKDIR /home/node
    COPY --from=stage-0 --chown=node /tmp/app/node_modules ./node_modules
    COPY --from=stage-0 --chown=node /tmp/app/dist ./
    RUN npm prune
    EXPOSE 3000
    USER node
    CMD [ "node", "app.js" ]
    
    Login or Signup to reply.
  2. There are a couple of notable differences between Alpine- and Debian-based images. One of the most notable is that the shared system C library libc.so has a completely different implementation. Alpine images use the smaller musl libc, where Debian images use the more full-featured GNU libc. This in turn may have some implications on the node binary itself.

    If the node_modules tree contains any libraries that work by compiling C extensions, these may just break trying to copy them from a Debian base to an Alpine base, or vice versa. You’ll probably see some sort of weird load-time dependency, maybe something mentioning a GLIBC_2.30 version constraint or similar.

    Using a multi-stage build is fine here, but you should probably use the same base Linux distribution in every stage; especially don’t mix Alpine and anything else. If you are in the state where you potentially have compiled native extensions it may be important to use the exact same starting image in both stages (caveat: I know this matters for Python, less practical experience for Node).

    You could use a shared base stage to only declare that base image once

    FROM node:18.17.1-bookworm-slim AS base
    # empty
    
    FROM base AS build
    ...
    
    FROM base
    ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search