前置知识: Git

容器与 Docker

5 min中级

容器原理、Docker 架构、镜像构建、多阶段构建、Docker Compose 与镜像优化。

学习目标

本文是「运维与中间件」模块的第 5 篇,难度定位为进阶。重点内容:容器原理、Docker 架构、镜像构建、多阶段构建、Docker Compose 与镜像优化。

主要章节:

    1. 容器原理
    1. Docker 架构
    1. Dockerfile
    1. Docker Compose
    1. 镜像优化
    1. 私有仓库
  • ……共 16 个章节

1. 容器原理

1.1 容器 vs 虚拟机

维度虚拟机容器
隔离级别硬件级(Hypervisor)操作系统级
启动速度分钟级秒级
资源占用GB 级MB 级
镜像大小GB 级MB 级
性能有虚拟化开销接近原生
密度几个/主机数百个/主机

1.2 Linux 容器技术

技术作用说明
Namespace资源隔离PID/NET/MNT/UTS/IPC/USER
Cgroup v2资源限制CPU/内存/IO/网络
UnionFS镜像分层OverlayFS(现代默认)
Seccomp系统调用过滤限制可用 syscall

注意:Linux 自 systemd 248+/内核 4.x 起全面默认 cgroup v2(统一层级), 排障时应查看 /sys/fs/cgroup/<组>/memory.max 等 v2 接口,老的 memory.limit_in_bytes 等 v1 文件在新系统上已不存在。

# Namespace 示例
unshare --pid --fork --mount-proc bash   # 创建新的 PID namespace
ls /proc                                  # 只能看到新 namespace 的进程

# Cgroup v2 示例(当前发行版默认;v1 的 cgcreate/limit_in_bytes 已过时)
sudo mkdir /sys/fs/cgroup/mycontainer
echo "512M" | sudo tee /sys/fs/cgroup/mycontainer/memory.max   # 内存上限 512M
echo 50000 100000 | sudo tee /sys/fs/cgroup/mycontainer/cpu.max # 50% CPU(配额/周期)

2. Docker 架构

2.1 核心概念

flowchart LR
    C[Client docker] --> D[Docker Daemon] --> R[Registry Hub/私有]
    D --> I[Image]
    D --> CT[Container]
    D --> N[Network]
概念描述
Image只读模板,包含运行应用所需的一切
ContainerImage 的运行实例
Volume数据持久化
Network容器间通信
Registry镜像仓库

2.2 基础命令

# 镜像操作
docker pull nginx:1.28              # 拉取镜像
docker images                       # 列出镜像
docker rmi nginx:1.28               # 删除镜像
docker build -t myapp:v1 .          # 构建镜像(Docker 23.0+ 默认使用 BuildKit,无需 DOCKER_BUILDKIT=1)
docker tag myapp:v1 registry/myapp:v1  # 打标签
docker push registry/myapp:v1       # 推送镜像

# 容器操作
docker run -d --name web -p 80:80 nginx:1.28    # 运行容器
docker ps                                       # 运行中的容器
docker ps -a                                    # 所有容器
docker stop web                                 # 停止
docker start web                                # 启动
docker restart web                              # 重启
docker rm web                                   # 删除
docker logs -f web                              # 查看日志
docker exec -it web bash                        # 进入容器
docker inspect web                               # 详细信息

# 清理
docker system prune -a              # 清理所有未使用资源
docker volume prune                 # 清理未使用卷

3. Dockerfile

3.1 指令详解

# 基础镜像
FROM python:3.12-slim

# 元数据
LABEL maintainer="dev@example.com"
LABEL version="1.0"
LABEL description="Python Web Application"

# 设置工作目录
WORKDIR /app

# 环境变量
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PORT=8000

# 复制依赖文件并安装(利用缓存)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 8000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

# 非root用户
RUN useradd -m appuser
USER appuser

# 启动命令
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

3.2 多阶段构建

# 阶段1:构建
FROM node:22-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 阶段2:运行
FROM nginx:1.28-alpine

# 仅复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

多阶段构建优势:

  • 最终镜像只包含运行时所需文件
  • 构建工具和源码不会留在最终镜像
  • 镜像大小从 GB 级降到 MB 级

3.3 常用基础镜像大小

镜像大小适用场景
ubuntu:22.04~77MB需要完整 Linux 环境
debian:bookworm-slim~74MB较完整的 Linux
alpine:3.22~8MB极致轻量
python:3.12-slim~150MBPython 应用
python:3.12-alpine~50MBPython 轻量
node:22-alpine~180MBNode.js 应用
nginx:1.28-alpine~40MBWeb 服务器
gcr.io/distroless/*~2MB静态编译程序最优先

4. Docker Compose

4.1 完整示例

# docker-compose.yml
# 说明:Compose V2(docker compose 子命令)已废弃顶层 version 字段——写了会被忽略并告警,直接省略即可
services:
  # Web 应用
  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - '8000:8000'
    environment:
      - DATABASE_URL=postgresql://app:secret@db:5432/appdb
      - REDIS_URL=redis://cache:6379/0
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    volumes:
      - ./app:/app # 开发时挂载代码
    networks:
      - frontend
      - backend
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
    restart: unless-stopped
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:8000/health']
      interval: 30s
      timeout: 5s
      retries: 3

  # PostgreSQL 数据库
  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - backend
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U app -d appdb']
      interval: 10s
      timeout: 5s
      retries: 5

  # Redis 缓存
  cache:
    image: redis:7-alpine
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
    networks:
      - backend
    volumes:
      - redisdata:/data

  # Nginx 反向代理
  nginx:
    image: nginx:1.28-alpine
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - web
    networks:
      - frontend
    restart: unless-stopped

volumes:
  pgdata:
    driver: local
  redisdata:
    driver: local

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true # 不暴露到外部

4.2 Compose 命令

# 启动
docker compose up -d                    # 后台启动
docker compose up -d --build            # 重新构建并启动

# 管理
docker compose ps                       # 查看状态
docker compose logs -f web              # 查看日志
docker compose exec web bash            # 进入容器
docker compose restart web              # 重启服务

# 扩缩容
docker compose up -d --scale web=3      # 扩展到3个实例

# 停止与清理
docker compose down                     # 停止并删除容器
docker compose down -v                  # 同时删除卷

5. 镜像优化

5.1 优化策略

策略效果示例
选择小基础镜像减少 50-80%alpine 替代 ubuntu
多阶段构建减少 60-90%分离构建和运行
合并 RUN 指令减少层数RUN cmd1 && cmd2
清理缓存减少 20-40%--no-cache-dir
.dockerignore减少上下文排除 node_modules 等
利用缓存加速构建先 COPY 依赖文件

5.2 .dockerignore

# Git
.git
.gitignore

# 依赖
node_modules
__pycache__
*.pyc
.venv

# IDE
.vscode
.idea

# 文档
*.md
docs/

# 测试
tests/
.pytest_cache
.coverage

# Docker
Dockerfile
docker-compose*.yml

# 其他
.env
*.log
.DS_Store

5.3 优化前后对比

#  优化前(~800MB)
FROM python:3.12
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
CMD ["python", "main.py"]

#  优化后(~150MB)
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY . .
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
CMD ["python", "main.py"]

6. 私有仓库

6.1 部署 Registry

# docker-compose.yml
services:
  registry:
    image: registry:3 # CNCF Distribution v3(2025 起当前主线,v2 仍可用)
    ports:
      - '5000:5000'
    environment:
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: 'Registry Realm'
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
    volumes:
      - ./data:/data
      - ./auth:/auth
    restart: always
# 创建认证文件
mkdir auth
docker run --rm -entrypoint htpasswd httpd:2 -Bbn admin password > auth/htpasswd

# 使用私有仓库
docker tag myapp:v1 localhost:5000/myapp:v1
docker push localhost:5000/myapp:v1
docker pull localhost:5000/myapp:v1

6.2 Harbor(企业级)

Harbor 提供更完善的私有仓库功能:RBAC、镜像扫描、镜像签名、复制策略。

# 安装 Harbor
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-online-installer-v2.10.0.tgz
tar xvf harbor-online-installer-*.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml
# 编辑 harbor.yml 配置
./install.sh --with-trivy  # 包含漏洞扫描

7. 小结

容器技术是现代运维的基石:

  1. 容器原理基于 Namespace(隔离)和 Cgroup(限制),理解原理有助于排查问题
  2. Dockerfile 编写需遵循最佳实践:小基础镜像、多阶段构建、利用缓存
  3. Docker Compose 是单机多容器编排的标准工具,适合开发和测试环境
  4. 镜像优化可大幅减小镜像体积,加速部署和降低存储成本
  5. 私有仓库是企业必需,小型团队用 Registry,大型组织用 Harbor
  6. 生产环境建议使用 Kubernetes 进行容器编排

docker run 创建并启动容器

基本写法:运行容器 docker run [选项] <镜像> [命令]

# 启动 nginx 容器
docker run nginx

基本写法:后台运行容器 docker run -d <镜像>

# 后台运行 nginx 容器
docker run -d nginx

基本写法:交互式运行容器 docker run -it <镜像> <命令>

# 进入 ubuntu 容器的 bash
docker run -it ubuntu bash

基本写法:命名容器并映射端口 docker run --name <名称> -p <宿主端口>:<容器端口> <镜像>

# 启动命名为 web 的 nginx,映射 8080 到 80
docker run --name web -p 8080:80 nginx

基本写法:挂载数据卷 docker run -v <宿主路径>:<容器路径> <镜像>

# 挂载当前目录到容器的 /app
docker run -v $(pwd):/app node

docker ps 查看容器

基本写法:查看运行中容器 docker ps

# 列出正在运行的容器
docker ps

基本写法:查看所有容器(含已停止) docker ps -a

# 列出所有容器
docker ps -a

基本写法:只显示容器 ID docker ps -q

# 获取所有运行容器的 ID
docker ps -q

docker start/stop/restart 生命周期管理

基本写法:启动已停止的容器 docker start <容器>

# 启动容器 web
docker start web

基本写法:停止容器 docker stop [选项] <容器>

# 优雅停止容器 web
docker stop web

基本写法:强制停止容器 docker stop -t 0 <容器>

# 立即停止容器
docker stop -t 0 web

基本写法:重启容器 docker restart <容器>

# 重启容器 web
docker restart web

docker rm 删除容器

基本写法:删除已停止容器 docker rm <容器>

# 删除容器 web
docker rm web

基本写法:强制删除运行中容器 docker rm -f <容器>

# 强制删除运行中的容器
docker rm -f web

基本写法:删除所有停止的容器 docker container prune

# 清理所有停止的容器
docker container prune -f

docker exec 进入容器执行命令

基本写法:进入容器交互式 shell docker exec -it <容器> <shell>

# 进入 web 容器的 bash
docker exec -it web bash

基本写法:在容器中执行命令 docker exec <容器> <命令>

# 查看 web 容器的进程列表
docker exec web ps aux

基本写法:以指定用户执行命令 docker exec -u <用户> <容器> <命令>

# 以 root 用户进入容器
docker exec -u root -it web sh

docker logs 查看日志

基本写法:查看容器日志 docker logs <容器>

# 查看 web 容器的全部日志
docker logs web

基本写法:实时跟踪日志 docker logs -f <容器>

# 实时跟踪 web 容器日志
docker logs -f web

基本写法:查看最后 N 行日志 docker logs --tail <行数> <容器>

# 查看最后 100 行日志
docker logs --tail 100 web

基本写法:查看指定时间后的日志 docker logs --since <时间> <容器>

# 查看最近 10 分钟的日志
docker logs --since 10m web

docker inspect 查看容器详情

基本写法:查看容器详细信息 docker inspect <容器>

# 查看 web 容器的完整信息
docker inspect web

基本写法:查看容器 IP 地址 docker inspect --format '{{.NetworkSettings.IPAddress}}' <容器>

# 提取容器的 IP 地址
docker inspect --format '{{.NetworkSettings.IPAddress}}' web

基本写法:查看容器状态 docker inspect --format '{{.State.Status}}' <容器>

# 获取容器当前状态
docker inspect --format '{{.State.Status}}' web

docker stats 资源监控

基本写法:查看所有容器资源使用 docker stats

# 实时显示所有容器资源占用
docker stats

基本写法:查看指定容器资源使用 docker stats <容器>

# 监控 web 容器的 CPU 和内存
docker stats web

基本写法:只输出一次结果 docker stats --no-stream

# 一次性输出所有容器资源使用
docker stats --no-stream

docker cp 文件拷贝

基本写法:从容器拷贝文件到宿主机 docker cp <容器>:<容器路径> <宿主路径>

# 从 web 容器拷贝配置文件到当前目录
docker cp web:/etc/nginx/nginx.conf ./

基本写法:从宿主机拷贝文件到容器 docker cp <宿主路径> <容器>:<容器路径>

# 拷贝本地文件到容器
docker cp ./app.conf web:/etc/nginx/conf.d/