Docker 会按指令生成镜像层。某一层输入变化后,这一层及其后续层都需要重新执行。因此,变化少的文件应先复制。

FROM node:22-alpine
WORKDIR /app
 
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
 
COPY --chown=node:node . .
 
USER node
EXPOSE 3000
CMD ["node", "server.js"]

如果先 COPY . .,修改一行源码也会让安装依赖层失效。先复制依赖清单,只有清单或锁文件变化时才重新安装。

RUNCMD

  • RUN 在构建镜像时执行,例如安装依赖、编译代码;
  • CMD 在容器启动时提供默认命令;
  • EXPOSE 只声明监听端口,不会发布宿主机端口。

应用必须监听 0.0.0.0,只监听 127.0.0.1 时,即使配置 -p,容器外也无法访问。

别忘了 .dockerignore

node_modules
.git
coverage
*.log
.env
.env.*
!.env.example

宿主机的 node_modules 既会放大构建上下文,也可能包含与容器平台不兼容的原生二进制。依赖应在镜像内按锁文件重新安装。

参考:Optimize cache usage