非多阶段

以node项目为例:

FROM alpine

RUN mkdir -p /opt/app

WORKDIR /opt/app

COPY package.json package-lock.json ./

RUN apk add --no-cache --update nodejs npm

RUN apk add --no-cache \
        gcc \
        g++ \
        python3=3.10.10-r0 \
        make=4.3-r1  \
        pkgconf 

COPY . .

RUN npm install --production

EXPOSE 8080

CMD ["node", "main.js"]

这样虽然可以使用,但是很多依赖是生产环境下不需要受用的,比如build阶段的gcc以及npm等等

多阶段构建

doc: 多阶段构建 (docker.com)

在Docker 17.05版本以后,就可以使用Multi-stage builds(多阶段构建)

FROM alpine AS builder

RUN mkdir -p /opt/app

WORKDIR /opt/app

COPY package.json package-lock.json ./

RUN apk add --no-cache --update nodejs npm

RUN apk add --no-cache \
        gcc \
        g++ \
        python3=3.10.10-r0 \
        make=4.3-r1  \
        pkgconf 

RUN npm install --production



FROM alpine

RUN mkdir -p /opt/app

WORKDIR /opt/app

RUN apk add --no-cache --update nodejs

COPY --from=builder /opt/app/node_modules ./node_modules

COPY . .

EXPOSE 8080

CMD ["node", "main.js"]

将build与实际运行环境剥离出来了,第一个阶段作为builder,将node依赖install好,生成node_modules,然后在实际运行容器中COPY --from=builder /opt/app/node_modules ./node_modules将依赖复制进来,这样各种编译依赖就会被舍弃,npm也不用出现在运行环境中,减少了包体积

这样做的好处不止是减少包体积,在其他项目中还可以隐藏源代码,生产环境只有编译好的可执行文件。