6-1 容器化:Dockerfile创建与镜像打包
Dockerfile 基础结构
Dockerfile 是构建 Docker 镜像的核心配置文件。一个典型的 NestJS 项目 Dockerfile 采用多阶段构建(multi-stage build)策略,将构建过程和生产运行过程分离。
建议在 VS Code 中安装 Docker 插件,提供 Dockerfile 语法高亮和关键词提示。
基础配置说明
# 定义构建参数,指定 Node 版本
ARG NODE_VERSION=18
# 构建阶段:使用完整 Node 环境进行编译
FROM node:${NODE_VERSION}-alpine AS builder
# 指定非 root 用户运行,提升安全性
USER node
# 设置工作目录
WORKDIR /home/node/app
dockerfile
关键配置要点:
- 基础镜像选择:
node:18-alpine基于 Alpine Linux,体积远小于完整 Debian 镜像。如果不加-alpine,打包出来的镜像会大得多 - 用户指定:使用
USER node而非默认的 root 用户,避免权限过高带来的安全风险 - 工作目录:
WORKDIR指定项目代码(或 dist 目录)的存放位置
.dockerignore 文件
与 .gitignore 类似,.dockerignore 指定在 COPY 命令时需要忽略的文件:
node_modules
dist
.git
.env
*.md
.vscode
text
多阶段构建详解
第一阶段:构建(Builder)
构建阶段负责安装全部依赖(包括 devDependencies)、编译项目、生成 Prisma 客户端:
FROM node:${NODE_VERSION}-alpine AS builder
USER node
WORKDIR /home/node/app
# 1. 安装 pnpm(Alpine 环境)
RUN wget -qO /bin/pnpm "https://github.com/pnpm/pnpm/releases/latest/download/pnpm-linuxstatic-x64" \
&& chmod +x /bin/pnpm
# 2. 先复制依赖声明文件(利用 Docker 缓存层)
COPY --chown=node:node package*.json pnpm-lock.yaml ./
# 3. 安装全部依赖
RUN pnpm install --frozen-lockfile
# 4. 复制项目源码
COPY --chown=node:node . .
# 5. 生成 Prisma 客户端
RUN pnpm run build:clients
# 6. 编译项目
RUN pnpm run build:prod
dockerfile
缓存优化技巧:先复制 package.json 和 pnpm-lock.yaml,再执行 pnpm install。这样只有依赖变化时才会重新安装,源码变更时可以复用缓存层。
build:clients 和 build:prod 是自定义的 npm script,将 Prisma 客户端生成与 SWC 编译过程分离:
{
"scripts": {
"build:clients": "prisma generate --schema=prisma/schema.prisma",
"build:prod": "swc src -d dist --config-file .swcrc && prisma generate --client=false"
}
}
json
第二阶段:生产运行(Production)
生产阶段只安装运行时依赖,不包含开发工具:
FROM node:${NODE_VERSION}-alpine AS production
USER node
WORKDIR /home/node/app
# 设置生产环境变量
ENV NODE_ENV=production
# 1. 安装 pnpm
RUN wget -qO /bin/pnpm "https://github.com/pnpm/pnpm/releases/latest/download/pnpm-linuxstatic-x64" \
&& chmod +x /bin/pnpm
# 2. 复制依赖声明文件
COPY --chown=node:node package*.json pnpm-lock.yaml ./
# 3. 只安装生产依赖
RUN pnpm install --prod --frozen-lockfile
# 4. 从构建阶段复制 Prisma 客户端
COPY --from=builder --chown=node:node /home/node/app/prisma ./prisma
# 5. 从构建阶段复制编译产物
COPY --from=builder --chown=node:node /home/node/app/dist ./dist
# 启动应用
CMD ["node", "dist/main.js"]
dockerfile
pnpm install --prod 只安装 dependencies 中的依赖,跳过 devDependencies,大幅减小最终镜像体积。
在 Alpine 环境中安装 pnpm
直接使用 pnpm 官方文档推荐的 Docker 安装方式在 Alpine 镜像中无法成功。需要通过 wget 下载静态二进制文件:
RUN wget -qO /bin/pnpm "https://github.com/pnpm/pnpm/releases/latest/download/pnpm-linuxstatic-x64" \
&& chmod +x /bin/pnpm
dockerfile
配置 Docker 镜像加速
在 Docker Desktop 的 Settings -> Docker Engine 中配置国内镜像加速源,可以显著提升基础镜像和依赖包的拉取速度。
构建与查看镜像
# 构建镜像
docker build -t nest-starter:1.0 .
# 如果需要推送到远端 Registry,加上地址前缀
# docker build -t registry.example.com/nest-starter:1.0 .
# 查看构建结果
docker images | grep nest
# 输出示例:
# nest-starter 1.0 abc123 800MB
bash
首次构建的镜像大小约 800MB,包含了 node_modules 中的生产依赖、dist 目录中的编译产物以及 Prisma 客户端文件。后续章节将逐步优化镜像体积。
小结
- 使用多阶段构建分离编译环境和运行环境
- Alpine 镜像体积小,适合作为 Node.js 应用的基础镜像
- 先复制
package.json再安装依赖,利用 Docker 缓存层加速构建 - 生产阶段使用
--prod参数只安装运行时依赖 USER node指定非 root 用户运行,提升安全性
↑