名称: docker 描述: 创建和优化Docker配置,包括Dockerfiles、docker-compose文件和容器编排。涵盖多阶段构建、层优化、安全加固、网络、卷和调试。触发关键词:docker、container、dockerfile、image、compose、registry、build、layer、cache、multi-stage、volume、network、port、environment、containerize、orchestration、registry、push、pull、tag、alpine、slim、distroless。 允许工具:Read、Grep、Glob、Edit、Write、Bash
Docker
概述
此技能提供全面的Docker专业知识,用于所有容器相关任务。涵盖:
- 策略与架构:应用程序的容器策略、部署模式、编排决策
- 实施:编写优化的Dockerfiles、docker-compose文件和CI/CD集成
- 安全:容器加固、漏洞扫描、秘密管理、运行时保护
- 操作:镜像优化、层缓存、调试、注册表管理、性能调优
使用此技能处理与容器化相关的任何事务,从初始策略到生产部署。
说明
1. 分析应用程序需求
创建容器配置前:
- 运行时依赖:识别语言运行时、系统库、原生扩展
- 构建与运行时分离:规划多阶段构建以分离构建工具和运行时
- 配置管理:规划环境变量、秘密、配置文件
- 数据持久性:识别有状态与无状态组件、卷挂载点
- 网络需求:记录端口、服务依赖、外部集成
- 资源约束:考虑内存、CPU、磁盘需求
- 部署目标:开发、预生产、生产环境
2. 编写高效Dockerfiles
基础镜像选择
- 官方镜像:优先使用Docker Hub的官方语言/操作系统镜像
- 最小镜像:生产环境使用Alpine (-alpine)、Slim (-slim)或Distroless
- 固定版本:使用特定标签(python:3.12-alpine),而非latest
- 多阶段模式:分离构建器和运行时阶段
层优化
- 顺序重要:将变化最少的指令放在前面(基础镜像、系统依赖)
- 合并命令:使用&&将相关RUN命令链接到单个层
- 清除缓存:在同一RUN命令中清理包管理器缓存
- 策略性复制:为更好缓存,先复制依赖文件,再复制源代码
镜像大小减少
- 多阶段构建:仅复制运行时所需的工件
- 移除构建工具:不要在最终镜像中包含编译器、开发头文件
- 最小化层:在逻辑上合并RUN命令
- 使用.dockerignore:从构建上下文中排除不必要文件
安全最佳实践
- 非root用户:创建并切换到非特权用户
- 只读文件系统:尽可能使用只读根文件系统
- 层中无秘密:使用构建秘密,而非ENV或COPY处理凭据
- 扫描镜像:在CI中运行漏洞扫描器(trivy、grype)
3. 配置Docker Compose文件
服务定义
- 服务依赖:使用depends_on带条件(service_healthy)
- 健康检查:为关键服务定义健康检查命令
- 重启策略:设置适当的重启行为(unless-stopped、on-failure)
- 资源限制:为生产定义内存和CPU限制
网络
- 自定义网络:定义命名网络以隔离服务
- 内部服务:将数据库、缓存标记为内部(无外部端口)
- 服务发现:使用服务名进行基于DNS的发现
- 端口映射:仅映射必要端口到主机
卷和持久性
- 命名卷:使用命名卷进行数据持久化
- 绑定挂载:用于开发(代码更改),而非生产数据
- 卷所有权:确保容器中的正确用户/组所有权
- 备份策略:记录卷备份程序
环境配置
- 环境文件:使用.env文件进行本地开发
- 秘密管理:使用docker秘密或外部秘密管理器
- 环境继承:使用环境块处理共享配置
- 变量插值:使用${VAR:-default}处理默认值
4. 容器安全加固
运行时安全
- 最小基础镜像:使用distroless或alpine减少攻击面
- 丢弃能力:移除不必要的Linux能力
- 只读根:将根文件系统挂载为只读
- 无特权模式:除非绝对必要,否则不使用–privileged
- AppArmor/SELinux:在可用时使用安全配置文件
漏洞管理
- 定期扫描:使用trivy、grype或Docker Scout扫描镜像
- 依赖更新:保持基础镜像和依赖最新
- CVE监控:跟踪和修复已知漏洞
- SBOM生成:为合规性创建软件材料清单
秘密管理
- 绝不在Dockerfile中:不在ENV、ARG或提交文件中包含秘密
- 构建秘密:使用–mount=type=secret处理构建时秘密
- 运行时秘密:使用docker秘密、vault或k8s秘密
- 环境变量:仅用于非敏感配置
5. 镜像优化技术
多阶段构建模式
- 构建器阶段:安装构建依赖、编译代码
- 运行时阶段:仅复制工件、最小依赖
- 共享阶段:跨镜像重用公共基础阶段
- 并行构建:使用BuildKit进行并行阶段执行
层缓存策略
- 依赖层:为缓存重用,先复制包文件,再复制代码
- 缓存挂载:使用–mount=type=cache处理包管理器缓存
- 有序指令:结构化Dockerfile以实现最大缓存命中
- 构建上下文:使用.dockerignore最小化上下文大小
注册表管理
- 镜像标记:使用语义版本控制和git SHA标记
- 多架构:使用buildx构建amd64和arm64
- 注册表镜像:使用本地注册表镜像以加速拉取
- 垃圾回收:定期清理注册表中的旧镜像
6. 调试容器
交互式调试
- Shell访问:docker exec -it <容器> /bin/sh
- 调试镜像:临时使用非最小基础进行故障排除
- 临时容器:在Kubernetes中使用调试sidecar
- 日志检查:docker logs -f --tail 100 <容器>
常见问题
- 权限错误:检查用户/组ID是否匹配卷所有权
- 网络问题:验证网络配置、DNS解析
- 缺失依赖:检查最终阶段中的运行时依赖
- 构建失败:使用–progress=plain获取详细构建输出
- 层大小:使用dive工具分析层大小
工具和技术
- Dive:分析镜像层并查找膨胀
- Hadolint:对Dockerfile进行最佳实践检查
- Docker Scout:扫描漏洞并提供建议
- Trivy:全面的漏洞扫描
- Ctop:容器资源监控
最佳实践
通用原则
- 使用官方基础镜像:从可信源开始(Docker官方镜像)
- 多阶段构建:分离构建和运行时环境以最小化大小
- 最小化层:使用&&合并相关命令以减少层数
- 不以root运行:创建并使用非root用户以提高安全
- 使用.dockerignore:从构建上下文中排除不必要文件
- 固定版本:使用特定标签(python:3.12-alpine),而非latest
- 健康检查:添加HEALTHCHECK指令以监控容器健康
- 定期扫描:在CI/CD管道中运行漏洞扫描器
- 清除缓存:在创建缓存的同一层中移除包管理器缓存
- 彻底文档化:添加注释解释非明显决策
语言特定模式
Python
- 使用pip wheel缓存编译的依赖
- 使用–no-cache-dir防止pip缓存留在层中
- 考虑uv以加速依赖解析
- 使用python:3.x-slim以平衡大小和兼容性
Node.js
- 为更好缓存,先复制package*.json,再复制源代码
- 使用npm ci而非npm install以实现可重复构建
- 在生产构建中移除devDependencies
- 考虑node:alpine以最小化大小
Rust
- 使用cargo chef进行依赖缓存
- 使用–release构建优化二进制文件
- 仅复制二进制文件到运行时阶段,而非整个target/
- 考虑scratch或distroless基础以最小化大小
Go
- 使用多阶段构建,构建阶段用golang:alpine
- 构建静态链接二进制文件(CGO_ENABLED=0)
- 使用scratch或distroless以最小化运行时
- 仅复制二进制文件,Go不需要运行时
开发与生产
开发
- 使用绑定挂载进行实时代码重载
- 在镜像中包含调试工具
- 暴露更多端口以进行检查
- 使用详细日志
- 将源代码挂载为卷
生产
- 使用命名卷进行持久化
- 仅包含运行时依赖的最小镜像
- 限制端口和能力
- 结构化日志到stdout/stderr
- 最终镜像中无SSH、调试工具或shell
示例
示例1:多阶段Python Dockerfile
# 构建阶段
FROM python:3.12-slim AS builder
WORKDIR /app
# 安装构建依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# 安装Python依赖
COPY requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt
# 运行时阶段
FROM python:3.12-slim AS runtime
# 创建非root用户
RUN groupadd --gid 1000 appgroup && \
useradd --uid 1000 --gid appgroup --shell /bin/bash --create-home appuser
WORKDIR /app
# 从构建器复制wheel
COPY --from=builder /app/wheels /wheels
RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels
# 复制应用程序代码
COPY --chown=appuser:appgroup . .
# 切换到非root用户
USER appuser
# 暴露端口
EXPOSE 8000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
# 运行应用程序
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "app:create_app()"]
示例2:带安全的Node.js Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
# 复制包文件
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制源代码
COPY . .
# 构建应用程序
RUN npm run build
# 生产阶段
FROM node:20-alpine AS production
# 添加安全更新
RUN apk update && apk upgrade && rm -rf /var/cache/apk/*
# 创建非root用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
WORKDIR /app
# 复制构建的资产
COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./
USER nextjs
EXPOSE 3000
ENV NODE_ENV=production
CMD ["node", "dist/server.js"]
示例3:开发的Docker Compose
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
- DATABASE_URL=postgres://user:pass@db:5432/myapp
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
networks:
- app-network
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 5s
timeout: 5s
retries: 5
networks:
- app-network
cache:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- app-network
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- app
networks:
- app-network
volumes:
postgres_data:
redis_data:
networks:
app-network:
driver: bridge
示例4:带Cargo Chef的Rust Dockerfile
# Chef阶段 - 规划依赖
FROM rust:1.75-alpine AS chef
RUN apk add --no-cache musl-dev && \
cargo install cargo-chef
WORKDIR /app
# 规划阶段 - 分析依赖
FROM chef AS planner
COPY Cargo.toml Cargo.lock ./
COPY src ./src
RUN cargo chef prepare --recipe-path recipe.json
# 构建器阶段 - 先构建依赖,再构建应用
FROM chef AS builder
COPY --from=planner /app/recipe.json recipe.json
# 构建依赖(缓存层)
RUN cargo chef cook --release --recipe-path recipe.json
# 复制源代码并构建应用程序
COPY . .
RUN cargo build --release && \
strip target/release/myapp
# 运行时阶段 - 最小distroless镜像
FROM gcr.io/distroless/cc-debian12
# 仅复制二进制文件
COPY --from=builder /app/target/release/myapp /usr/local/bin/myapp
# 以非root运行(distroless提供nonroot用户)
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/usr/local/bin/myapp"]
示例5:带静态二进制的Go Dockerfile
# 构建器阶段
FROM golang:1.22-alpine AS builder
WORKDIR /app
# 安装构建依赖
RUN apk add --no-cache git ca-certificates tzdata
# 复制go mod文件以缓存
COPY go.mod go.sum ./
RUN go mod download
# 复制源代码
COPY . .
# 构建静态二进制文件
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags='-w -s -extldflags "-static"' \
-o /app/bin/server ./cmd/server
# 运行时阶段 - scratch(空基础)
FROM scratch
# 复制CA证书以支持HTTPS
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# 复制时区数据
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
# 复制二进制文件
COPY --from=builder /app/bin/server /server
# 暴露端口
EXPOSE 8080
# 以非root运行(必须定义)
USER 65534:65534
ENTRYPOINT ["/server"]
示例6:带秘密的Docker Compose
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
- APP_VERSION=${APP_VERSION:-latest}
image: myapp:${APP_VERSION:-latest}
ports:
- "8080:8080"
environment:
- DATABASE_URL_FILE=/run/secrets/db_url
- API_KEY_FILE=/run/secrets/api_key
secrets:
- db_url
- api_key
depends_on:
db:
condition: service_healthy
networks:
- backend
restart: unless-stopped
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
reservations:
cpus: "0.5"
memory: 256M
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
POSTGRES_USER: myapp
POSTGRES_DB: myapp
secrets:
- db_password
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myapp"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
secrets:
db_url:
file: ./secrets/db_url.txt
api_key:
file: ./secrets/api_key.txt
db_password:
file: ./secrets/db_password.txt
volumes:
postgres_data:
networks:
backend:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
示例7:使用BuildKit的构建缓存优化
# syntax=docker/dockerfile:1.4
FROM node:20-alpine AS base
# 启用BuildKit缓存挂载
WORKDIR /app
# 带缓存挂载安装依赖
FROM base AS deps
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci --only=production
# 构建阶段带独立开发依赖
FROM base AS builder
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci
COPY . .
RUN npm run build
# 生产阶段
FROM base AS production
# 复制生产node_modules
COPY --from=deps /app/node_modules ./node_modules
# 复制构建的应用程序
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
# 创建非root用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
USER nextjs
EXPOSE 3000
CMD ["node", "dist/index.js"]
示例8:.dockerignore
# Git
.git
.gitignore
# 依赖
node_modules
__pycache__
*.pyc
.venv
venv
# 构建工件
dist
build
*.egg-info
# IDE
.idea
.vscode
*.swp
# 测试
coverage
.pytest_cache
.nyc_output
# 环境文件
.env
.env.local
.env.*.local
# 文档
docs
*.md
!README.md
# Docker
Dockerfile*
docker-compose*
.docker
# 其他
.DS_Store
*.log
tmp
常见模式和解决方案
模式:处理配置
基于环境的配置
# 支持多环境
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# 默认生产,可在运行时覆盖
ENV NODE_ENV=production
# 按环境使用配置文件
CMD ["sh", "-c", "node server.js --config /app/config/${NODE_ENV}.json"]
从文件读取配置(12-Factor)
# 在运行时从挂载的文件读取配置
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# 应用程序在运行时从/config读取
VOLUME /config
CMD ["python", "app.py", "--config", "/config/settings.yaml"]
模式:多架构构建
# 使用buildx构建多架构
docker buildx create --name multiarch --use
docker buildx build --platform linux/amd64,linux/arm64 \
-t myapp:latest \
--push \
.
# 在Dockerfile中处理架构差异
FROM --platform=${BUILDPLATFORM} golang:1.22-alpine AS builder
ARG TARGETARCH
ARG TARGETOS
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
go build -o /app/bin/server ./cmd/server
FROM alpine:latest
COPY --from=builder /app/bin/server /server
ENTRYPOINT ["/server"]
模式:数据库迁移
# 带迁移服务的docker-compose
version: "3.8"
services:
migrate:
image: myapp:latest
command: ["./migrate", "up"]
environment:
DATABASE_URL: postgres://user:pass@db:5432/myapp
depends_on:
db:
condition: service_healthy
networks:
- backend
app:
image: myapp:latest
depends_on:
migrate:
condition: service_completed_successfully
environment:
DATABASE_URL: postgres://user:pass@db:5432/myapp
ports:
- "8080:8080"
networks:
- backend
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 5s
timeout: 5s
retries: 5
networks:
- backend
volumes:
db_data:
networks:
backend:
模式:构建时秘密
# syntax=docker/dockerfile:1.4
FROM node:20-alpine AS builder
WORKDIR /app
# 在构建时使用秘密,不留在层中
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]
# 带秘密构建
docker build --secret id=npmrc,src=$HOME/.npmrc -t myapp .
模式:带依赖的健康检查
FROM python:3.12-slim
# 安装健康检查工具
RUN apt-get update && apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# 全面健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8000/health && \
python -c "import redis; redis.Redis(host='cache').ping()" || exit 1
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
故障排除指南
问题:构建上下文过大
症状:构建缓慢,“发送构建上下文”需要几分钟
解决方案:
- 添加全面的.dockerignore文件
- 检查意外包含的大文件(node_modules、.git、构建工件)
- 使用.dockerignore模式,如
**/.git以排除嵌套git仓库 - 从子目录构建:
docker build -f Dockerfile.app ./app
问题:层缓存不工作
症状:尽管无变化,但重新构建所有内容
解决方案:
- 确保依赖文件在源代码之前复制
- 不要在Dockerfile开头使用通配符COPY
- 检查命令是否有动态输出(日期、随机值)
- 为包管理器使用BuildKit缓存挂载
- 验证构建上下文未更改(检查.dockerignore)
问题:镜像大小过大
症状:镜像应较小,但达到数百MB
解决方案:
- 使用多阶段构建以排除构建依赖
- 选择较小基础镜像(alpine、slim、distroless)
- 在同一RUN命令中清理包管理器缓存:
apt-get install ... && rm -rf /var/lib/apt/lists/* - 在复制到运行时阶段前移除不必要文件
- 使用
docker image history myapp:latest查找大层 - 使用
dive工具分析层内容
问题:容器中权限被拒绝
症状:无法写入文件,“权限被拒绝”错误
解决方案:
- 检查卷所有权是否匹配容器用户
- 在COPY指令中使用
--chown=user:group - 创建用户时指定UID/GID以匹配主机:
useradd -u 1000 - 在入口点初始化卷以设置正确所有权
- 对于绑定挂载,确保主机目录权限正确
问题:容器无法连接到其他服务
症状:“连接被拒绝”、“名称未找到”错误
解决方案:
- 验证服务在同一Docker网络上
- 使用服务名进行DNS(非localhost)
- 检查docker-compose中的
depends_on - 确保端口已暴露(Dockerfile中的EXPOSE)
- 检查服务是否实际在正确接口上监听(0.0.0.0而非127.0.0.1)
- 验证主机防火墙规则
问题:更改未反映在容器中
症状:代码更改未出现,运行旧版本
解决方案:
- 检查是否对开发使用卷挂载
- 如果未使用绑定挂载,则重建镜像:
docker-compose build - 移除容器并重新创建:
docker-compose up --force-recreate - 如果需要,清除构建缓存:
docker builder prune - 验证运行的是正确镜像:
docker ps并检查IMAGE列
问题:容器立即退出
症状:容器启动后立即退出,无错误消息
解决方案:
- 检查日志:
docker logs <容器> - 交互式运行:
docker run -it myapp /bin/sh - 验证CMD/ENTRYPOINT正确且可执行
- 检查应用程序是否需要环境变量
- 确保依赖可用(缺失共享库)
- 临时添加
tail -f /dev/null以保持容器运行进行调试
问题:构建失败,提示“设备无剩余空间”
症状:构建中途失败,磁盘空间错误
解决方案:
- 清理未使用的容器:
docker container prune - 移除未使用的镜像:
docker image prune -a - 清理构建缓存:
docker builder prune - 移除未使用的卷:
docker volume prune - 检查Docker磁盘使用:
docker system df - 在设置中增加Docker Desktop磁盘限制
问题:容器启动缓慢
症状:容器需要长时间才变健康
解决方案:
- 优化应用程序启动(延迟加载、并行初始化)
- 使用较小基础镜像以减少初始I/O
- 实施健康检查并设置适当的启动周期
- 减少层数以加速镜像拉取
- 使用本地注册表或注册表镜像以缓存镜像
- 预拉镜像:
docker-compose pull
CI/CD集成
GitHub Actions示例
name: 构建并推送Docker镜像
on:
push:
branches: [main]
tags: ["v*"]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: 设置Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 登录容器注册表
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 提取元数据
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: 构建并推送
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: 扫描镜像漏洞
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ steps.meta.outputs.tags }}
format: "sarif"
output: "trivy-results.sarif"
- name: 上传扫描结果
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: "trivy-results.sarif"
GitLab CI示例
stages:
- build
- test
- push
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
build:
stage: build
image: docker:24-cli
services:
- docker:24-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build --pull -t $IMAGE_TAG .
- docker push $IMAGE_TAG
only:
- main
- tags
security-scan:
stage: test
image: aquasec/trivy:latest
script:
- trivy image --exit-code 1 --severity HIGH,CRITICAL $IMAGE_TAG
needs:
- build
push-latest:
stage: push
image: docker:24-cli
services:
- docker:24-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker pull $IMAGE_TAG
- docker tag $IMAGE_TAG $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
only:
- main
needs:
- security-scan
快速参考
基本命令
# 构建
docker build -t myapp:latest .
docker build -f Dockerfile.prod -t myapp:prod .
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest --push .
# 运行
docker run -d -p 8080:8080 --name myapp myapp:latest
docker run -it --rm myapp:latest /bin/sh
docker run --env-file .env myapp:latest
# Compose
docker-compose up -d
docker-compose down -v
docker-compose logs -f app
docker-compose exec app /bin/sh
docker-compose build --no-cache
# 检查
docker ps
docker logs -f <容器>
docker inspect <容器>
docker exec -it <容器> /bin/sh
docker stats
# 清理
docker system prune -a
docker volume prune
docker builder prune
docker image prune -a
# 调试
docker run --rm -it --entrypoint /bin/sh myapp:latest
docker cp <容器>:/app/logfile.log ./local-logfile.log
docker diff <容器>
性能优化检查清单
- [ ] 使用多阶段构建
- [ ] 最小基础镜像(alpine、slim、distroless)
- [ ] 依赖先于源代码复制
- [ ] 包管理器缓存在同一层中清除
- [ ] .dockerignore排除不必要文件
- [ ] 为包管理器使用构建缓存挂载
- [ ] 层数最小化(合并RUN命令)
- [ ] 定义健康检查
- [ ] 配置非root用户
- [ ] 特定版本标签(非latest)
- [ ] CI/CD中安全扫描
- [ ] 镜像大小 < 200MB(根据用例调整)
安全检查清单
- [ ] 使用官方/可信基础镜像
- [ ] 基础镜像固定到特定版本
- [ ] Dockerfile或环境变量中无秘密
- [ ] 以非root用户运行
- [ ] 尽可能使用只读根文件系统
- [ ] 安装的包最少
- [ ] 应用安全更新
- [ ] 启用漏洞扫描
- [ ] 无不必要能力
- [ ] 应用AppArmor/SELinux配置文件
- [ ] 通过Docker秘密或外部vault管理秘密
- [ ] HTTPS证书已验证