基础 学会编写Dockerfile,将应用打包成可复现的Docker镜像
Dockerfile是一个纯文本文件,包含构建Docker镜像所需的全部指令。它是基础设施即代码(IaC)在容器领域的体现——镜像的构建过程完全可追踪、可复现。
# 必须是第一条指令(除ARG外)✅
FROM node:20-alpine
# 多阶段构建中使用多次
FROM node:20-alpine AS builder
# ...构建阶段
FROM node:20-alpine AS runtime
# ...运行阶段
# 使用精简镜像
FROM gcr.io/distroless/nodejs20-debian12
# 设置工作目录(目录不存在会自动创建)✅
WORKDIR /app
# 后续的RUN/CMD/ENTRYPOINT都在此目录执行
WORKDIR /app
COPY package.json . # 复制到/app/package.json
RUN npm install # 在/app下执行
WORKDIR!RUN cd /app && npm install只在那一层有效,下一层又会回到根目录。WORKDIR是持久的,影响后续所有指令。
# COPY:基本复制(推荐)✅
COPY package.json package-lock.json ./
COPY src/ ./src/
COPY *.conf /etc/app/
# ADD:额外支持URL下载和自动解压
ADD https://example.com/app.tar.gz /opt/ # 自动下载
ADD app.tar.gz /opt/ # 自动解压tar
# COPY --chown:复制并设置所有权
COPY --chown=node:node . .
# COPY --from:从其他阶段复制(多阶段构建)
COPY --from=builder /app/dist ./dist
| 特性 | COPY | ADD |
|---|---|---|
| 基本复制 | ✅ | ✅ |
| URL下载 | ❌ | ✅ |
| 自动解压tar | ❌ | ✅ |
| 推荐程度 | ⭐⭐⭐ | ⭐(仅用于解压场景) |
# shell格式(通过/bin/sh -c执行)
RUN apt-get update && apt-get install -y curl
# exec格式(直接执行)
RUN ["apt-get", "install", "-y", "curl"]
# 最佳实践:合并RUN减少层数 ✅
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
git \
vim && \
rm -rf /var/lib/apt/lists/*
# 注意:每层独立,下行清理不会缩减上层数据!
# ❌ 错误示范:
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/* # 这只删除了本层,上两层的数据还在!
# CMD:容器默认命令(可被docker run参数覆盖)
CMD ["node", "server.js"] # exec格式(推荐)
CMD node server.js # shell格式
# ENTRYPOINT:容器入口点(不会被覆盖,参数会追加)
ENTRYPOINT ["node"]
CMD ["server.js"] # 默认参数
# docker run myapp → 执行: node server.js
# docker run myapp worker.js → 执行: node worker.js
| 组合 | docker run myapp | docker run myapp arg |
|---|---|---|
| 只有CMD | 执行CMD | arg替换CMD |
| 只有ENTRYPOINT | 执行ENTRYPOINT | arg追加到ENTRYPOINT |
| ENTRYPOINT + CMD | CMD作为默认参数 | arg替换CMD参数 |
# ENV:运行时环境变量(持久到容器)✅
ENV NODE_ENV=production
ENV APP_PORT=3000
# ARG:构建时变量(只在构建期有效)✅
ARG VERSION=1.0.0
RUN echo "Building version ${VERSION}"
# ARG配合ENV使用
ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine
# 运行时覆盖ENV
docker run -e NODE_ENV=staging my-app
# EXPOSE:声明端口(文档作用,不实际映射)
EXPOSE 3000
EXPOSE 80/tcp 443/tcp
# VOLUME:声明数据卷目录
VOLUME ["/data"]
VOLUME /var/lib/postgresql/data
# 定义健康检查 ✅
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# 禁用健康检查
HEALTHCHECK NONE
# 创建并切换到非root用户 ✅
RUN addgroup -g 1001 appgroup && \
adduser -u 1001 -G appgroup -s /bin/sh -D appuser
USER appuser
# 使用已有用户
USER node # node:alpine镜像自带node用户
# 项目结构
my-app/
├── Dockerfile
├── package.json
├── src/
│ └── index.js
└── .dockerignore
# Dockerfile ✅
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production
COPY src/ ./src/
ENV NODE_ENV=production
EXPOSE 3000
USER node
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "src/index.js"]
# .dockerignore ✅
node_modules
npm-debug.log
.git
.env
Dockerfile
# 构建镜像 ✅
docker build -t my-app:v1.0 .
# 运行容器 ✅
docker run -d -p 3000:3000 --name my-app my-app:v1.0
# 查看健康状态
docker inspect my-app --format='{{.State.Health.Status}}'
# 基本构建 ✅
docker build -t my-app:v1.0 .
# 指定Dockerfile路径
docker build -f Dockerfile.prod -t my-app:v1.0 .
# 传入构建参数 ✅
docker build --build-arg VERSION=2.0.0 -t my-app:v2.0 .
# 不使用缓存
docker build --no-cache -t my-app:v1.0 .
# 多平台构建
docker buildx build --platform linux/amd64,linux/arm64 -t my-app:v1.0 .
# 查看构建历史
docker history my-app:v1.0
❓ .dockerignore有什么用?类似.gitignore,指定构建上下文中要排除的文件。最重要的排除
node_modules——如果包含会导致:①构建上下文巨大 ②COPY . .会覆盖npm install的结果 ③可能泄露.env等敏感文件。
❓ CMD和ENTRYPOINT到底用哪个?大多数场景只用
CMD。需要固定入口程序时用ENTRYPOINT。典型模式:ENTRYPOINT ["node"] + CMD ["server.js"],这样docker run my-app worker.js可以灵活改变参数。
下一课:学习多阶段构建——让镜像更小更安全!
| 要点 | 说明 | 最佳实践 |
|---|---|---|
| 资源规划 | 根据业务负载合理分配CPU/内存 | 先压测再上线,设置requests和limits |
| 监控告警 | 设置关键指标阈值和告警规则 | Prometheus + AlertManager,5分钟P99延迟告警 |
| 备份策略 | 定期备份关键数据和配置 | 自动化备份脚本 + 异地存储 + 定期恢复演练 |
| 灰度发布 | 新版本逐步放量降低风险 | 金丝雀发布5%→20%→50%→100% |
| 回滚预案 | 部署前确认回滚方案和步骤 | 保留前一版本镜像,数据库迁移向前兼容 |
| 文档更新 | 配置变更必须同步更新文档 | GitOps管理配置,变更即文档 |
| 安全基线 | 遵循CIS Docker Benchmark | 非root运行、只读FS、最小能力 |
| 日志规范 | 结构化日志,统一格式 | JSON格式日志,包含traceId |
# 容器生命周期
docker create/start/stop/restart/rm/pause/unpause
docker logs/top/stats/inspect/exec diff
# 镜像构建
docker build/pull/push/tag/rmi/images/history
docker save/load/import/manifest
# 网络与存储
docker network create/ls/inspect/connect/disconnect/rm/prune
docker volume create/ls/inspect/rm/prune
# Docker Compose
docker compose up/down/ps/logs/build/exec
docker compose config/stop/start/scale/top/cp
# 系统维护
docker system df/prune/info
docker builder prune
docker container/prune/image prune
# K8s常用命令
kubectl get/describe/logs/exec/apply/delete
kubectl rollout status/undo/history
kubectl scale/autoscale/set