Docker容器化技能Skill docker

此技能提供全面的Docker容器化专业知识,涵盖从策略架构、Dockerfile编写、安全加固到生产部署的全过程。适用于开发、测试和生产环境,帮助优化容器配置、减少镜像大小、提高安全性和性能。关键词:Docker, 容器技术, Dockerfile, 安全优化, CI/CD, 多阶段构建, 镜像管理, 云计算, DevOps

Docker/K8s 0 次安装 0 次浏览 更新于 3/24/2026

名称: 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:容器资源监控

最佳实践

通用原则

  1. 使用官方基础镜像:从可信源开始(Docker官方镜像)
  2. 多阶段构建:分离构建和运行时环境以最小化大小
  3. 最小化层:使用&&合并相关命令以减少层数
  4. 不以root运行:创建并使用非root用户以提高安全
  5. 使用.dockerignore:从构建上下文中排除不必要文件
  6. 固定版本:使用特定标签(python:3.12-alpine),而非latest
  7. 健康检查:添加HEALTHCHECK指令以监控容器健康
  8. 定期扫描:在CI/CD管道中运行漏洞扫描器
  9. 清除缓存:在创建缓存的同一层中移除包管理器缓存
  10. 彻底文档化:添加注释解释非明显决策

语言特定模式

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"]

故障排除指南

问题:构建上下文过大

症状:构建缓慢,“发送构建上下文”需要几分钟

解决方案

  1. 添加全面的.dockerignore文件
  2. 检查意外包含的大文件(node_modules、.git、构建工件)
  3. 使用.dockerignore模式,如**/.git以排除嵌套git仓库
  4. 从子目录构建:docker build -f Dockerfile.app ./app

问题:层缓存不工作

症状:尽管无变化,但重新构建所有内容

解决方案

  1. 确保依赖文件在源代码之前复制
  2. 不要在Dockerfile开头使用通配符COPY
  3. 检查命令是否有动态输出(日期、随机值)
  4. 为包管理器使用BuildKit缓存挂载
  5. 验证构建上下文未更改(检查.dockerignore)

问题:镜像大小过大

症状:镜像应较小,但达到数百MB

解决方案

  1. 使用多阶段构建以排除构建依赖
  2. 选择较小基础镜像(alpine、slim、distroless)
  3. 在同一RUN命令中清理包管理器缓存:apt-get install ... && rm -rf /var/lib/apt/lists/*
  4. 在复制到运行时阶段前移除不必要文件
  5. 使用docker image history myapp:latest查找大层
  6. 使用dive工具分析层内容

问题:容器中权限被拒绝

症状:无法写入文件,“权限被拒绝”错误

解决方案

  1. 检查卷所有权是否匹配容器用户
  2. 在COPY指令中使用--chown=user:group
  3. 创建用户时指定UID/GID以匹配主机:useradd -u 1000
  4. 在入口点初始化卷以设置正确所有权
  5. 对于绑定挂载,确保主机目录权限正确

问题:容器无法连接到其他服务

症状:“连接被拒绝”、“名称未找到”错误

解决方案

  1. 验证服务在同一Docker网络上
  2. 使用服务名进行DNS(非localhost)
  3. 检查docker-compose中的depends_on
  4. 确保端口已暴露(Dockerfile中的EXPOSE)
  5. 检查服务是否实际在正确接口上监听(0.0.0.0而非127.0.0.1)
  6. 验证主机防火墙规则

问题:更改未反映在容器中

症状:代码更改未出现,运行旧版本

解决方案

  1. 检查是否对开发使用卷挂载
  2. 如果未使用绑定挂载,则重建镜像:docker-compose build
  3. 移除容器并重新创建:docker-compose up --force-recreate
  4. 如果需要,清除构建缓存:docker builder prune
  5. 验证运行的是正确镜像:docker ps并检查IMAGE列

问题:容器立即退出

症状:容器启动后立即退出,无错误消息

解决方案

  1. 检查日志:docker logs <容器>
  2. 交互式运行:docker run -it myapp /bin/sh
  3. 验证CMD/ENTRYPOINT正确且可执行
  4. 检查应用程序是否需要环境变量
  5. 确保依赖可用(缺失共享库)
  6. 临时添加tail -f /dev/null以保持容器运行进行调试

问题:构建失败,提示“设备无剩余空间”

症状:构建中途失败,磁盘空间错误

解决方案

  1. 清理未使用的容器:docker container prune
  2. 移除未使用的镜像:docker image prune -a
  3. 清理构建缓存:docker builder prune
  4. 移除未使用的卷:docker volume prune
  5. 检查Docker磁盘使用:docker system df
  6. 在设置中增加Docker Desktop磁盘限制

问题:容器启动缓慢

症状:容器需要长时间才变健康

解决方案

  1. 优化应用程序启动(延迟加载、并行初始化)
  2. 使用较小基础镜像以减少初始I/O
  3. 实施健康检查并设置适当的启动周期
  4. 减少层数以加速镜像拉取
  5. 使用本地注册表或注册表镜像以缓存镜像
  6. 预拉镜像: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证书已验证