🐳 Docker 核心实战与进阶笔记
一、 Dockerfile 指令全参数详解
Dockerfile 是定义镜像“静态环境”的说明书。
| 指令 | 参数与功能说明 | 代码示例 | 关键避坑 |
| FROM | 指定基础镜像。开启一个构建阶段。 | FROM node:20-slim AS builder | AS 用于起别名,方便后续多阶段引用。 |
| WORKDIR | 设定工作目录。后续指令的相对路径基准。 | WORKDIR /app | 目录不存在会自动递归创建(类似 mkdir -p)。 |
| COPY | 复制文件。从宿主机或其它阶段拷贝。 | COPY --from=builder /app/dist ./dist | --from 是跨阶段搬运产物的唯一通道。 |
| ADD | 高级复制。支持 URL 下载和自动解压缩。 | ADD source.tar.gz /data | 原则:除非需要自动解压,否则一律用 COPY。 |
| RUN | 构建时执行。用于安装软件、编译代码。 | RUN pnpm install && pnpm build | 层缓存:每一个 RUN 都会产生一层,尽量合并命令。 |
| ENV | 运行时环境变量。容器启动后程序可见。 | ENV NODE_ENV=production | 常用于切换生产/开发环境逻辑。 |
| VOLUME | 声明数据卷。定义持久化挂载点。 | VOLUME ["/opt/admin"] | 标记该目录为“数据出入口”,防止数据随容器消失。 |
| HEALTHCHECK | 健康检查。监控业务逻辑是否正常。 | HEALTHCHECK --interval=30s CMD curl -f... | 不仅看进程,更看服务是否真正可用。 |
| CMD | 默认启动命令。容器运行时的第一个进程。 | CMD ["node", "server.js"] | 限制:只能有一个,多个只有最后一个生效。 |
二、 核心进阶逻辑:多阶段构建 (Multi-stage)
在企业级 Node.js 开发中,为了解决“镜像臃肿”问题,通常采用双阶段设计:
1. 逻辑结构图
-
阶段一:Builder(施工房):安装编译器、源代码、缓存。任务是把代码编译成 dist。
-
阶段二:Runner(精装房):重新开一个干净的镜像,只通过 COPY --from=builder 把 dist 拿过来。
2. 代码演练:利用“层缓存”优化速度
# --- 第一阶段:编译 ---
FROM node:20-slim AS builder
WORKDIR /app
# 【关键】将 package.json 拷贝放在前面。
# 只要这个文件没变,Docker 就不会重新跑耗时的 install,直接复用缓存层。
COPY package.json pnpm-lock.yaml ./
RUN pnpm install
COPY . .
RUN pnpm build
# --- 第二阶段:运行 ---
FROM node:20-slim AS runner
WORKDIR /app
# 只搬运成品,丢弃源码和构建垃圾,镜像体积缩减 80%
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
# 构建自检逻辑:确保关键程序安装成功
RUN test -f ./dist/index.js || (echo "Build failed" && exit 1)
CMD ["node", "dist/index.js"]
三、 Dockerfile vs. Docker Compose:元件与组装
1. 深度解读:两者的关联性
-
关联性:在 docker-compose.yml 中使用 build: . 即可直接触发 Dockerfile 的构建流程,实现“一键代码到系统”。
-
网络互通(服务发现):Compose 会自动创建内部局域网。容器连接数据库时,主机名直接填 服务名(Service Name)(如 db),Compose 的内置 DNS 会自动解析 IP。
-
动静结合:Dockerfile 负责固化环境(静),Compose 负责动态挂载目录、配置网络、管理端口(动)。
2. 代码联动示例
# docker-compose.yml
version: '3'
services:
web-app:
build: . # 关联 Dockerfile
container_name: web_service
ports:
- "8080:3000" # 外部映射
environment:
- DB_URL=mysql_db # 直接使用下面定义的服务名
volumes:
- ./logs:/app/logs # 动态挂载日志:活数据进卷
mysql_db:
image: mysql:8.0 # 官方镜像直接用,不需 Dockerfile
volumes:
- db_data:/var/lib/mysql
volumes:
db_data: # 具名卷:确保数据库删了数据还在
四、 避坑指南与最佳实践(金句总结)
-
陷阱:
-
如果 Dockerfile 需要 COPY dist/,绝对不能在 .dockerignore 里忽略 dist/。否则 Docker 引擎会因找不到文件而报错。
-
-
镜像即光盘:
-
Dockerfile 做出来的镜像是“死”的只读光盘(ROM);启动后的容器才是“活”的运行环境。
-
-
动静分离的思想:
-
死的东西(入镜像):代码逻辑、Node 库、编译成品。
-
活的东西(入卷):数据库文件、用户上传图片、日志、配置文件。不要把活数据存在镜像里!
-
-
变量管理:
-
GitLab CI 自带的 $CI_... 变量是系统自动注入的(如仓库地址、分支名);而 $SONAR_TOKEN 类变量需在 Settings 界面手动录入。
-
-
命令顺序:
-
顺序决定速度:修改代码频繁,修改依赖不频繁。因此先 COPY package.json 再 COPY 源码,能极大加速构建。
-
-
安全原则:
-
默认容器是 root 权限。生产环境建议在 Dockerfile 最后使用 USER node 切换用户,降低被攻破后的风险。
-
💡 总结:Dockerfile 保证了环境的确定性,Docker Compose 保证了系统的协作性。掌握了卷(Volume)的挂载和多阶段构建的隔离,你就掌握了 Docker 生产级应用的核心。

浙公网安备 33010602011771号