9个Docker最佳实践,让你的容器更安全高效
- 使用官方镜像
- 常用官方镜像
- 指定具体版本
- 版本号建议
- 多阶段构建
- 效果对比
- 使用.dockerignore
- .dockerignore示例
- 效果
- 使用最小权限用户
- 环境变量配置
- 优化缓存利用率
- 效果对比
- 给镜像打标签
- 扫描镜像漏洞
- 扫描工具
- 集成到CI/CD
- 完整示例:优秀Dockerfile
- .dockerignore
- 总结

Docker已经成为容器化的事实标准,但很多人用Docker的方式很有问题。镜像体积大、构建慢、安全性差…今天分享9个必须知道的Docker最佳实践。
我见过太多Dockerfile写得一塌糊涂,镜像几个GB,部署等到崩溃,用root用户跑应用安全风险巨大,构建一次要10分钟。
使用官方镜像
能从官方拿,就不要自己造。
自己构建基础镜像:
→ 可能有安全漏洞
→ 更新不及时
→ 兼容性问题
官方镜像:
→ 社区维护,定期更新
→ 安全漏洞修复快
→ 经过充分测试
常用官方镜像
| 镜像 | 用途 |
|---|---|
| node | Node.js应用 |
| openjdk | Java应用 |
| python | Python应用 |
| nginx | Web服务器 |
| postgresql | PostgreSQL数据库 |
| redis | Redis缓存 |
# ✅ 推荐
FROM node:18-alpine
# ❌ 不推荐
FROM my-custom-base-image
指定具体版本
永远不要用latest标签。
今天构建用的是node:18
明天构建可能变成node:19
应用炸了
latest指向最新的版本,你根本不知道会拉到什么版本
# ✅ 好
FROM node:18.17.0-alpine
# ❌ 坏
FROM node:latest
版本号建议
# 最严格:主版本.次版本.补丁版本
FROM node:18.17.0-alpine
# 次严格:主版本.次版本(允许补丁更新)
FROM node:18.17-alpine
# 一般情况:主版本
FROM node:18-alpine
看你对稳定性的要求选择。
多阶段构建
大幅减小镜像体积的神器。
构建Node.js应用:
需要安装npm依赖
需要编译TypeScript
需要打包前端资源
这些东西在运行时根本不需要
# ===== 构建阶段 =====
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ===== 运行阶段 =====
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --production
CMD ["node", "dist/index.js"]
效果对比
| 方式 | 镜像体积 |
|---|---|
| 单阶段构建 | 800MB |
| 多阶段构建 | 150MB |
减少了85%。
使用.dockerignore
不需要的文件别拷进镜像。
构建镜像时,Docker会把整个上下文都拷进去
包括node_modules(几GB)、.git(几百MB)...
构建慢、镜像大,没必要
.dockerignore示例
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.env.local
tests
*.md
coverage
效果
没有.dockerignore:
构建上下文大小:2.5GB
构建时间:8分钟
使用.dockerignore:
构建上下文大小:50MB
构建时间:30秒
使用最小权限用户
默认root用户风险很大。
容器被攻破
→ 如果是root用户
→ 攻击者可以做任何事
→ 可以修改系统文件
→ 可以安装恶意软件
# ✅ 使用非root用户
FROM node:18-alpine
# 创建专门的用户
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
# 切换到该用户
USER nodejs
WORKDIR /app
COPY --chown=nodejs:nodejs package*.json ./
| 用户 | 容器逃逸风险 |
|---|---|
| root | 高,可以完全控制宿主机 |
| 非root | 低,只能做受限操作 |
环境变量配置
通过环境变量实现配置外部化。
同一镜像不同环境:
- 开发环境:一套环境变量
- 测试环境:另一套环境变量
- 生产环境:又一套环境变量
镜像不用重新构建
# Dockerfile
ENV NODE_ENV=production
ENV PORT=3000
ENV DB_HOST=mongodb
# docker-compose.yml
services:
app:
image: myapp:1.0
environment:
- NODE_ENV=development
- PORT=3000
- DB_HOST=localhost
# Dockerfile设置默认值,docker-compose覆盖
ENV NODE_ENV=production
environment:
- NODE_ENV=${NODE_ENV:-production}
优化缓存利用率
把变化少的放前面,变化多的放后面。
Docker构建时,每一层都会被缓存
如果这一层没变化,就用缓存
如果变化了,这层和后面所有层都要重新构建
# ❌ 缓存利用率低
COPY . .
RUN npm ci
RUN npm run build
# ✅ 缓存利用率高
COPY package*.json ./
RUN npm ci
COPY src ./src
RUN npm run build
效果对比
修改一行代码:
错误做法:
→ 拷贝代码(重新构建)
→ 安装依赖(重新构建,耗时2分钟)
→ 构建应用(重新构建,耗时1分钟)
总计:3分钟
正确做法:
→ 依赖没变,用缓存
→ 拷贝代码(重新构建)
→ 构建应用(重新构建,耗时1分钟)
总计:1分钟
给镜像打标签
标签要有意义,方便管理。
# 版本标签
docker tag myapp:1.0.0 myapp:1
docker tag myapp:1.0.0 myapp:latest
# 环境标签
docker tag myapp:1.0.0 myapp:dev
docker tag myapp:1.0.0 myapp:staging
docker tag myapp:1.0.0 myapp:prod
# Git提交标签
docker tag myapp:1.0.0 myapp:git-abc123
LABEL maintainer="your-email@example.com"
LABEL version="1.0.0"
LABEL description="My awesome application"
LABEL org.opencontainers.image.source="https://github.com/user/repo"
docker inspect myapp:1.0.0 | grep -A 10 "Labels"
扫描镜像漏洞
上线前必须扫描。
你以为基础镜像是安全的?
官方镜像也可能有漏洞
2019年发现的一个漏洞
影响了数百万个容器
只是因为大家用的基础镜像没及时更新
扫描工具
Docker内置扫描
docker scan myapp:1.0.0
# 输出示例:
✗ High: CVE-2023-1234 in openssl
✗ Medium: CVE-2023-5678 in node
✓ Low: CVE-2023-9012 in libssl
Trivy(推荐)
brew install trivy
trivy image myapp:1.0.0
trivy image --format json --output result.json myapp:1.0.0
集成到CI/CD
# GitHub Actions示例
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Scan image
run: |
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:${{ github.sha }}
# 发现高危漏洞,构建直接失败
完整示例:优秀Dockerfile
# ==================== 构建阶段 ====================
FROM node:18.17.0-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# ==================== 运行阶段 ====================
FROM node:18.17.0-alpine
LABEL maintainer="your-email@example.com"
LABEL version="1.0.0"
LABEL description="My Node.js Application"
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/nodemodules ./nodemodules
COPY --chown=nodejs:nodejs package*.json ./
USER nodejs
ENV NODE_ENV=production
ENV PORT=3000
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
CMD ["node", "dist/index.js"]
.dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.env.local
.env.*.local
tests
*.md
coverage
.vscode
.idea
dist
总结
9个Docker最佳实践:
- 使用官方镜像 - 安全可靠
- 指定具体版本 - 避免意外
- 多阶段构建 - 减小体积
- 使用.dockerignore - 加速构建
- 最小权限用户 - 提升安全
- 环境变量配置 - 灵活部署
- 优化缓存利用 - 提升效率
- 给镜像打标签 - 方便管理
- 扫描镜像漏洞 - 安全最后一道防线
Docker用得好是神器,用不好是灾难。遵循这些最佳实践,让你的容器化之路更顺畅。
评论
发表评论
|
|
|