🐳 Docker 完整教程

IT 技术 57 阅读 更新于 2026-09-05 09:18

欢迎来到 Docker 教程

Docker 是一个开源的容器化平台,它允许开发者将应用程序及其依赖项打包到轻量级、可移植的容器中。本教程涵盖了从基础概念到高级实践的完整内容,帮助你全面掌握 Docker 技术。

🏠

第一章:什么是 Docker

Docker 的定义

Docker 是一个开源的应用容器引擎,基于 Go 语言并遵从 Apache2.0 协议。它可以让开发者将应用及其依赖项打包到一个轻量级、可移植的容器中,然后发布到任何支持 Docker 的平台上运行。

💡 核心理念

Build once, run anywhere(一次构建,到处运行)。Docker 解决了"在我的机器上能跑"的经典问题。

Docker 的历史

  • 2013年3月 — Solomon Hykes 在 PyCon 大会上首次展示 Docker
  • 2013年6月 — Docker 开源发布(由 dotCloud 开发)
  • 2013年10月 — dotCloud 更名为 Docker, Inc.
  • 2016年 — Docker 引入 Swarm Mode 内置集群功能
  • 2017年 — 推出 Docker Enterprise Edition (EE) 和 Community Edition (CE)
  • 2017年 — Moby 项目诞生,Docker 上游项目更名
  • 2020年 — Docker Desktop 对大型企业收费,社区版持续免费
  • 2022年 — Docker 推出 Docker Extensions 扩展生态
  • 2024年 — Docker 集成 AI 开发工具链,推出 Docker AI
  • 2025年 — 全面支持 WASM 容器,与 Kubernetes 深度融合

Docker vs 虚拟机

特性Docker 容器虚拟机
启动时间秒级分钟级
占用空间MB 级别GB 级别
运行效率接近原生较弱(虚拟化开销)
隔离程度进程级隔离完全隔离(独立OS)
操作系统共享宿主机内核每个VM运行完整OS
密度单机可运行数百个容器单机通常数十个VM

Docker 的核心优势

🔄 环境一致性

开发、测试、生产环境完全一致,杜绝"在我机器上能跑"的问题

⚡ 快速部署

秒级启动,资源利用率高,弹性伸缩灵活

📦 可移植性

容器可在任何支持 Docker 的平台上运行

🔧 易于维护

版本控制、回滚、扩缩容操作简单

🏗️

第二章:Docker 架构详解

客户端-服务端架构

Docker 采用客户端-服务端(C/S)架构模式,主要组件包括 Docker Client、Docker Daemon、Docker Registry、镜像和容器。

🖥️ Docker Client (客户端)

⬇️ REST API ⬇️

🔧 Docker Daemon (守护进程)

⬇️ 管理 ⬇️

🖼️ Images

📦 Containers

🌐 Networks

💾 Volumes

⬆️ 拉取/推送 ⬇️

☁️ Docker Registry

核心组件

1. Docker Daemon (dockerd)

Docker 守护进程是 Docker 引擎的核心,运行在宿主机上,负责:

  • 监听 Docker API 请求
  • 管理 Docker 对象(镜像、容器、网络、卷等)
  • 与其他 Docker Daemon 通信(集群模式)

2. Docker Client

用户与 Docker 交互的方式,包括:

  • docker 命令行工具
  • Docker Desktop GUI
  • Docker API(REST/gRPC)

3. Docker Registry

存储和分发 Docker 镜像的服务:

  • Docker Hub — 官方公共仓库
  • 私有 Registry — 企业内部使用
  • HarborGitLab Container Registry

底层技术

技术作用
Namespace实现资源隔离(PID、Network、Mount、UTS、IPC、User)
Cgroups限制容器资源使用(CPU、内存、磁盘IO)
Union FS联合文件系统,实现镜像分层(Overlay2、Btrfs 等)
Containerd容器生命周期管理(拉取镜像、创建容器等)
runcOCI 标准容器运行时

🌟 知识拓展

现代 Docker 已经不再直接使用 LXC,而是采用 containerd + runc 架构,遵循 OCI(Open Container Initiative)标准。

⚙️

第三章:安装与配置

安装方式概览

Docker 支持多种平台和安装方式,根据不同需求选择:

  • Docker Desktop Windows/macOS 图形化安装
  • Docker Engine Linux 命令行安装
  • Docker Compose 多容器编排工具
  • Docker Machine 远程主机管理(已弃用)

Linux (Ubuntu/Debian) 安装

# 卸载旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc

# 更新软件包索引
sudo apt-get update

# 安装依赖包
sudo apt-get install -y ca-certificates curl gnupg lsb-release

# 添加 Docker 官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 设置仓库
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装 Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 验证安装
sudo docker run hello-world

CentOS/RHEL 安装

# 卸载旧版本
sudo yum remove docker docker-client docker-client-latest docker-common \
  docker-latest docker-latest-logrotate docker-logrotate docker-engine

# 安装依赖
sudo yum install -y yum-utils

# 设置 Docker 仓库
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 安装 Docker
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 启动 Docker
sudo systemctl start docker
sudo systemctl enable docker

# 验证
sudo docker run hello-world

Windows 安装

  1. 确保系统为 Windows 10/11 64位(Build 19045+)
  2. 启用 WSL 2:wsl --install
  3. 启用 Hyper-V 和容器功能
  4. Docker 官网 下载 Docker Desktop
  5. 运行安装程序,按提示重启
  6. 启动 Docker Desktop,完成初始化
  7. macOS 安装

    # 方式1:使用 Homebrew 安装(推荐)
    brew install --cask docker
    
    # 方式2:从官网下载 Docker Desktop .dmg 文件
    # 双击安装,拖拽到 Applications 文件夹
    
    # 启动后验证
    docker --version
    docker compose version

    配置非 root 用户运行 Docker(Linux)

    # 创建 docker 用户组(安装时已自动创建)
    sudo groupadd docker
    
    # 将当前用户加入 docker 组
    sudo usermod -aG docker $USER
    
    # 重新登录使生效,或使用以下命令立即生效
    newgrp docker
    
    # 验证(不需要 sudo)
    docker run hello-world

    配置镜像加速器(中国用户)

    # 编辑配置文件
    sudo nano /etc/docker/daemon.json
    
    # 添加以下内容
    {
        "registry-mirrors": [
            "https://mirror.ccs.tencentyun.com",
            "https://docker.mirrors.ustc.edu.cn",
            "https://hub-mirror.c.163.com"
        ],
        "exec-opts": ["native.cgroupdriver=systemd"],
        "log-driver": "json-file",
        "log-opts": {
            "max-size": "100m",
            "max-file": "3"
        }
    }
    
    # 重启 Docker
    sudo systemctl daemon-reload
    sudo systemctl restart docker

    ⚠️ 注意

    国内部分镜像源可能已失效,建议使用阿里云容器镜像服务提供的个人加速器,或配置 proxy 访问 Docker Hub。

    🖼️

    第四章:Docker 镜像

    什么是镜像

    Docker 镜像是一个只读的可执行文件包,包含运行应用程序所需的一切:代码、运行时、系统工具、系统库和配置。镜像是容器的模板,容器是镜像的运行实例。

    镜像的分层结构

    Docker 镜像由多个只读层(Layer)组成,每一层对应 Dockerfile 中的一条指令。Union FS 将这些层叠加为一个统一的文件系统。

    # 查看镜像层结构
    docker history nginx:latest
    
    # 输出示例:
    # IMAGE          CREATED       SIZE      COMMENT
    # a]f97d...     2 days ago    142MB     最顶层:CMD 指令
    # 8b1c2...     2 days ago    0B        EXPOSE 指令
    # 5e9a2...     2 days ago    72MB      复制 Nginx 文件
    # ...

    获取镜像

    # 从 Docker Hub 拉取镜像
    docker pull ubuntu:22.04
    docker pull nginx:alpine
    docker pull python:3.11-slim
    
    # 指定完整 registry
    docker pull registry.cn-hangzhou.aliyuncs.com/library/mysql:8.0
    
    # 查看所有本地镜像
    docker images
    docker image ls
    
    # 查看镜像详细信息
    docker inspect nginx:latest

    镜像标签管理

    # 给镜像打标签
    docker tag myapp:1.0 registry.example.com/myapp:1.0
    docker tag myapp:latest registry.example.com/myapp:v1.0
    
    # 删除镜像
    docker rmi nginx:latest
    docker rmi -f $(docker images -q -f "dangling=true")  # 删除悬空镜像
    
    # 导出镜像
    docker save -o nginx.tar nginx:latest
    docker save nginx:latest | gzip > nginx.tar.gz
    
    # 导入镜像
    docker load -i nginx.tar
    docker load < nginx.tar

    构建自定义镜像

    # 创建 Dockerfile
    cat > Dockerfile << 'EOF'
    FROM node:18-alpine
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci --only=production
    COPY . .
    EXPOSE 3000
    CMD ["node", "server.js"]
    EOF
    
    # 构建镜像
    docker build -t myapp:1.0 .
    docker build -t myapp:latest --no-cache .
    docker build -t myapp:1.0 -f docker/Dockerfile.prod .
    
    # 多架构构建
    docker buildx build --platform linux/amd64,linux/arm64 -t myapp:multi .

    多阶段构建

    # 多阶段构建示例(减小镜像体积)
    # 第一阶段:构建
    FROM golang:1.21-alpine AS builder
    WORKDIR /build
    COPY . .
    RUN CGO_ENABLED=0 GOOS=linux go build -o app .
    
    # 第二阶段:运行
    FROM alpine:3.18
    RUN apk --no-cache add ca-certificates
    WORKDIR /app
    COPY --from=builder /build/app .
    EXPOSE 8080
    CMD ["./app"]

    🌟 最佳实践

    使用多阶段构建可以显著减小镜像体积,通常可从数百 MB 压缩到几十 MB 甚至更小。

    镜像安全扫描

    # 启用 Docker Scout(内置安全扫描)
    docker scout cves nginx:latest
    docker scout recommendations myapp:latest
    
    # 使用 Trivy 扫描
    docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
      aquasec/trivy image nginx:latest

    📦

    第五章:Docker 容器

    容器的生命周期

    容器有以下状态:created(创建)、running(运行)、paused(暂停)、stopped(停止)、deleted(删除)。

    create

    start

    running

    stop

    rm

    运行容器

    # 基本运行
    docker run nginx
    docker run -d nginx                    # 后台运行
    docker run -d -p 80:80 nginx          # 端口映射
    docker run -d -p 8080:80 --name web nginx
    docker run -it ubuntu /bin/bash       # 交互式运行
    
    # 完整参数示例
    docker run -d \
      --name myapp \
      --restart unless-stopped \
      -p 3000:3000 \
      -v /data:/app/data \
      -e NODE_ENV=production \
      -e DB_HOST=mysql \
      --network app-network \
      --memory 512m \
      --cpus 1.0 \
      myapp:latest

    常用参数说明

    参数说明
    -d后台运行容器
    -p host:container端口映射
    -v host:container挂载卷
    -e KEY=VALUE环境变量
    --env-file从文件加载环境变量
    --name指定容器名称
    --network指定网络
    --restart重启策略
    --memory / --cpus资源限制
    -it交互式 + TTY
    --rm退出后自动删除

    容器管理命令

    # 查看容器
    docker ps                    # 运行中的容器
    docker ps -a                 # 所有容器
    docker ps -q                 # 只显示 ID
    docker ps --filter "status=running"
    
    # 启动/停止容器
    docker start container_name
    docker stop container_name
    docker restart container_name
    docker kill container_name     # 强制停止
    
    # 进入运行中的容器
    docker exec -it container_name /bin/bash
    docker exec -it container_name sh    # Alpine 系统
    docker attach container_name
    
    # 查看日志
    docker logs container_name
    docker logs -f container_name        # 实时跟踪
    docker logs --tail 100 container_name
    docker logs --since 2h container_name
    
    # 删除容器
    docker rm container_name
    docker rm -f container_name          # 强制删除运行中的容器
    docker rm $(docker ps -aq)           # 删除所有已停止容器
    docker container prune -f            # 清理已停止容器
    
    # 查看容器资源使用
    docker stats
    docker stats container_name
    docker top container_name

    重启策略

    # 不自动重启(默认)
    --restart no
    
    # 出错时重启
    --restart on-failure
    --restart on-failure:5    # 最多重启5次
    
    # 总是重启
    --restart always
    
    # 除非手动停止,否则总是重启
    --restart unless-stopped

    容器数据复制

    # 从容器复制到宿主机
    docker cp container:/app/data /host/path
    docker cp container:/var/log/nginx/access.log ./
    
    # 从宿主机复制到容器
    docker cp /host/path container:/app/data
    
    # 查看容器挂载信息
    docker inspect container_name --format '{{json .Mounts}}'

    📝

    第六章:Dockerfile 详解

    Dockerfile 基础指令

    Dockerfile 是一个文本文件,包含一系列指令,用于自动构建 Docker 镜像。

    指令说明
    FROM指定基础镜像(必须是指令)
    RUN在构建时执行命令
    COPY从本地复制文件到镜像
    ADD类似 COPY,支持 URL 和自动解压
    WORKDIR设置工作目录
    ENV设置环境变量
    EXPOSE声明容器监听的端口
    VOLUME声明匿名卷挂载点
    CMD容器启动时执行的默认命令
    ENTRYPOINT容器启动时的入口命令
    USER指定运行用户
    ARG构建时变量(仅在构建时可用)
    LABEL添加元数据

    完整 Dockerfile 示例

    # Python Flask 应用 Dockerfile
    # 使用官方 Python 镜像作为基础
    FROM python:3.11-slim AS base
    
    # 设置环境变量
    ENV PYTHONDONTWRITEBYTECODE=1
    ENV PYTHONUNBUFFERED=1
    
    # 安装系统依赖
    RUN apt-get update && apt-get install -y --no-install-recommends \
        gcc \
        libpq-dev \
        && rm -rf /var/lib/apt/lists/*
    
    # 设置工作目录
    WORKDIR /app
    
    # 复制依赖文件(利用缓存)
    COPY requirements.txt .
    
    # 安装 Python 依赖
    RUN pip install --no-cache-dir -r requirements.txt
    
    # 复制应用代码
    COPY . .
    
    # 创建非 root 用户
    RUN useradd -m -r appuser && chown -R appuser:appuser /app
    USER appuser
    
    # 暴露端口
    EXPOSE 5000
    
    # 健康检查
    HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
        CMD curl -f http://localhost:5000/health || exit 1
    
    # 启动命令
    CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]

    CMD vs ENTRYPOINT

    # CMD - 可被覆盖
    CMD ["nginx", "-g", "daemon off;"]
    # docker run myimage nginx -g "daemon off; worker_processes 4;"
    
    # ENTRYPOINT - 不可被覆盖(参数会追加)
    ENTRYPOINT ["nginx", "-g"]
    CMD ["daemon off;"]
    # docker run myimage daemon off; worker_processes 4;
    
    # 组合使用
    ENTRYPOINT ["python"]
    CMD ["app.py"]
    # docker run myapp  -> python app.py
    # docker run myapp script.py  -> python script.py

    构建参数

    # Dockerfile
    ARG VERSION=latest
    FROM node:${VERSION}
    
    ARG APP_ENV=production
    ENV APP_ENV=${APP_ENV}
    
    # 构建时传入
    docker build --build-arg VERSION=18 --build-arg APP_ENV=dev -t myapp .

    Dockerfile 最佳实践

    ✅ 推荐做法

    • 使用 .dockerignore 文件排除不必要文件
    • 合并 RUN 指令减少层数
    • 将变化频繁的指令放在后面(利用缓存)
    • 使用 slim/alpine 基础镜像
    • 以非 root 用户运行
    • 添加 HEALTHCHECK
    • 使用多阶段构建

    ❌ 避免的做法

    • 在 Dockerfile 中存储敏感信息(密钥、密码)
    • 使用 latest 标签(应使用具体版本号)
    • 创建不必要的层
    • 安装不必要的包
    • 忽略 .dockerignore

    .dockerignore 示例

    # .dockerignore
    .git
    .gitignore
    .dockerignore
    Dockerfile
    docker-compose*.yml
    .env
    .env.*
    node_modules
    npm-debug.log*
    .vscode
    .idea
    *.md
    !README.md
    tests/
    coverage/

    🎼

    第七章:Docker Compose

    什么是 Docker Compose

    Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过 YAML 文件配置应用的服务,然后用单个命令创建和启动所有服务。

    安装 Docker Compose

    # Linux 安装最新版
    sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" \
      -o /usr/local/bin/docker-compose
    sudo chmod +x /usr/local/bin/docker-compose
    
    # 验证安装
    docker compose version
    
    # 注:新版 Docker 已集成 compose 插件,可直接使用:
    docker compose up
    docker compose down

    docker-compose.yml 示例

    # docker-compose.yml - 完整的 Web 应用示例
    version: '3.8'
    
    services:
      # Web 应用
      web:
        build:
          context: .
          dockerfile: Dockerfile
        container_name: myapp-web
        ports:
          - "3000:3000"
        environment:
          - NODE_ENV=production
          - DB_HOST=db
          - REDIS_HOST=redis
        depends_on:
          db:
            condition: service_healthy
          redis:
            condition: service_started
        restart: unless-stopped
        networks:
          - app-network
        volumes:
          - ./app:/app
          - /app/node_modules
    
      # 数据库
      db:
        image: mysql:8.0
        container_name: myapp-db
        ports:
          - "3306:3306"
        environment:
          - MYSQL_ROOT_PASSWORD=rootpass123
          - MYSQL_DATABASE=myapp
          - MYSQL_USER=appuser
          - MYSQL_PASSWORD=apppass123
        volumes:
          - db-data:/var/lib/mysql
          - ./init.sql:/docker-entrypoint-initdb.d/init.sql
        healthcheck:
          test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
          interval: 10s
          timeout: 5s
          retries: 5
        restart: unless-stopped
        networks:
          - app-network
    
      # Redis 缓存
      redis:
        image: redis:7-alpine
        container_name: myapp-redis
        ports:
          - "6379:6379"
        command: redis-server --requirepass redispass123
        volumes:
          - redis-data:/data
        restart: unless-stopped
        networks:
          - app-network
    
      # Nginx 反向代理
      nginx:
        image: nginx:alpine
        container_name: myapp-nginx
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf:ro
          - ./ssl:/etc/nginx/ssl:ro
          - ./static:/usr/share/nginx/html/static:ro
        depends_on:
          - web
        restart: unless-stopped
        networks:
          - app-network
    
    # 自定义网络
    networks:
      app-network:
        driver: bridge
    
    # 持久化卷
    volumes:
      db-data:
        driver: local
      redis-data:
        driver: local

    Compose 常用命令

    # 启动服务
    docker compose up                # 前台运行
    docker compose up -d             # 后台运行
    docker compose up --build        # 构建并启动
    docker compose up -d --scale web=3  # 扩展副本
    
    # 查看状态
    docker compose ps
    docker compose logs
    docker compose logs -f web
    
    # 管理服务
    docker compose start             # 启动已停止的服务
    docker compose stop              # 停止服务
    docker compose restart           # 重启
    docker compose pause             # 暂停
    docker compose unpause           # 恢复
    
    # 停止并清理
    docker compose down              # 停止并删除容器
    docker compose down -v           # 同时删除卷
    docker compose down --rmi all    # 同时删除镜像
    
    # 其他
    docker compose exec web bash     # 在容器中执行命令
    docker compose run web npm test  # 运行一次性命令
    docker compose pull              # 拉取镜像
    docker compose build             # 构建镜像
    docker compose config            # 验证配置

    多环境配置

    # docker-compose.override.yml(开发环境,自动加载)
    version: '3.8'
    services:
      web:
        environment:
          - NODE_ENV=development
        volumes:
          - .:/app
        command: npm run dev
    
    # docker-compose.prod.yml(生产环境)
    version: '3.8'
    services:
      web:
        build:
          target: production
        environment:
          - NODE_ENV=production
    
    # 使用生产环境
    docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
    
    # 使用 .env 文件
    # .env
    DB_PASSWORD=secretpass
    REDIS_PASSWORD=redispass
    
    # 在 compose 文件中引用
    # environment:
    #   - MYSQL_PASSWORD=${DB_PASSWORD}

    💡 提示

    新版 Docker Compose V2 已集成到 Docker CLI 中,推荐使用

    docker compose

    (空格分隔)而非

    docker-compose

    (横杠)。

    🌐

    第八章:Docker 网络管理

    Docker 网络类型

    网络类型说明使用场景
    bridge默认网络,容器间通过虚拟网桥通信单机多容器通信
    host容器共享宿主机网络栈高性能网络需求
    none无网络安全隔离场景
    overlay跨主机容器通信Swarm 集群
    macvlan为容器分配 MAC 地址需要独立网络标识的应用

    网络管理命令

    # 查看所有网络
    docker network ls
    
    # 查看网络详情
    docker network inspect bridge
    
    # 创建自定义网络
    docker network create --driver bridge my-network
    docker network create --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
    
    # 在自定义网络中运行容器
    docker run -d --name app1 --network my-network nginx
    docker run -d --name app2 --network my-network nginx
    
    # 容器间通过名称通信(仅限自定义网络)
    docker exec app1 ping app2    # 可以 ping 通!
    
    # 连接/断开网络
    docker network connect my-network container_name
    docker network disconnect my-network container_name
    
    # 删除网络
    docker network rm my-network
    docker network prune    # 清理未使用的网络

    容器 DNS 解析

    # 自定义 DNS
    docker run --dns 8.8.8.8 --dns 8.8.4.4 nginx
    
    # 添加 hostname
    docker run --hostname myapp nginx
    
    # 添加 hosts 记录
    docker run --add-host db:192.168.1.100 myapp
    
    # 在 Compose 中使用服务名作为主机名
    # services:
    #   web:
    #     depends_on: [db]
    #   db:
    #     image: mysql
    # Web 容器内可直接使用 'db' 作为主机名连接数据库

    🌟 重要

    默认 bridge 网络不支持通过容器名通信,只有自定义 bridge 网络才支持基于 DNS 的服务发现。

    💾

    第九章:数据持久化

    数据持久化方式

    容器删除后数据会丢失,需要使用持久化存储。Docker 提供三种方式:

    1. Volumes(推荐)

    由 Docker 管理,存储在 /var/lib/docker/volumes/,是持久化数据的最佳方式。

    # 创建卷
    docker volume create my-volume
    
    # 查看所有卷
    docker volume ls
    
    # 查看卷详情
    docker volume inspect my-volume
    
    # 使用卷
    docker run -d -v my-volume:/data nginx
    docker run -d --mount source=my-volume,target=/data nginx
    
    # 删除卷
    docker volume rm my-volume
    docker volume prune    # 清理未使用的卷

    2. Bind Mounts(绑定挂载)

    直接使用宿主机文件系统中的特定路径。

    # 绑定挂载
    docker run -d -v /host/path:/container/path nginx
    docker run -d --mount type=bind,source=/host/path,target=/container/path nginx
    
    # 只读挂载
    docker run -d -v /host/path:/container/path:ro nginx
    
    # 典型用途:开发时同步代码
    docker run -d -v $(pwd):/app -p 3000:3000 myapp

    3. tmpfs Mounts

    数据存储在宿主机内存中,容器停止后消失。

    # tmpfs 挂载(Linux)
    docker run -d --tmpfs /tmp nginx
    
    # --mount 语法
    docker run -d --mount type=tmpfs,destination=/tmp nginx

    数据备份与恢复

    # 备份卷
    docker run --rm -v my-volume:/data -v $(pwd):/backup \
      alpine tar czf /backup/backup.tar.gz -C /data .
    
    # 恢复卷
    docker run --rm -v my-volume:/data -v $(pwd):/backup \
      alpine tar xzf /backup/backup.tar.gz -C /data
    
    # 在容器间迁移数据
    docker run --rm -v source-volume:/data alpine tar -czf - -C /data . \
      | docker run --rm -i -v target-volume:/data alpine tar -xz -C /data

    Compose 中的卷配置

    version: '3.8'
    services:
      db:
        image: mysql:8.0
        volumes:
          - db-data:/var/lib/mysql           # 命名卷
          - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro  # 绑定挂载
          - type: volume
            source: db-data
            target: /var/lib/mysql
            volume:
              nocopy: true
    
    volumes:
      db-data:
        driver: local
        driver_opts:
          type: none
          o: bind
          device: /data/mysql    # 使用自定义路径

    ☁️

    第十章:Docker Hub 与镜像仓库

    Docker Hub

    Docker Hub 是 Docker 官方的公共镜像仓库,提供官方镜像和社区镜像,用户可以上传、存储和管理自己的镜像。

    账号与登录

    # 登录 Docker Hub
    docker login
    docker login -u username -p password
    
    # 登出
    docker logout
    
    # 登录私有仓库
    docker login registry.example.com

    推送镜像

    # 给镜像打标签(必须是用户名/镜像名格式)
    docker tag myapp:latest username/myapp:latest
    docker tag myapp:latest username/myapp:v1.0
    
    # 推送
    docker push username/myapp:latest
    docker push username/myapp:v1.0
    
    # 推送所有标签
    docker push username/myapp --all-tags

    私有 Registry

    # 运行私有 Registry
    docker run -d -p 5000:5000 --name registry registry:2
    
    # 推送镜像到私有 Registry
    docker tag myapp localhost:5000/myapp
    docker push localhost:5000/myapp
    
    # 从私有 Registry 拉取
    docker pull localhost:5000/myapp
    
    # 带认证的 Registry
    docker run -d -p 5000:5000 \
      -v /path/registry:/var/lib/registry \
      -v /path/auth:/auth \
      -e "REGISTRY_AUTH=htpasswd" \
      -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
      -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
      registry:2

    使用 Harbor(企业级 Registry)

    # Harbor 功能:
    # - RBAC 权限控制
    # - 镜像扫描(Clair/Trivy)
    # - 镜像签名
    # - 镜像复制
    # - Webhook 通知
    # - 垃圾回收
    
    # 安装 Harbor(使用 docker-compose)
    wget https://github.com/goharbor/harbor/releases/download/v2.9.0/harbor-online-installer.tgz
    tar xvf harbor-online-installer.tgz
    cd harbor
    cp harbor.yml.tmpl harbor.yml
    # 编辑 harbor.yml 配置
    sudo ./install.sh

    💡 其他镜像仓库

    • 阿里云容器镜像服务 ACR — 国内访问快
    • AWS ECR — AWS 用户首选
    • Google GCR/Artifact Registry — GCP 集成
    • Azure ACR — Azure 集成
    • GitHub Container Registry — GitHub 集成

    🔧

    第十一章:常用命令大全

    镜像相关命令

    docker images

    列出本地所有镜像

    docker pull

    从仓库拉取镜像

    docker build

    从 Dockerfile 构建镜像

    docker rmi

    删除镜像

    docker tag

    为镜像打标签

    docker push

    推送镜像到仓库

    docker history

    查看镜像构建历史

    docker save/load

    导出/导入镜像

    容器相关命令

    docker run

    创建并运行容器

    docker ps

    列出运行中的容器

    docker start/stop

    启动/停止容器

    docker rm

    删除容器

    docker exec

    在运行容器内执行命令

    docker attach

    连接到容器标准输出

    docker logs

    查看容器日志

    docker inspect

    查看容器详细信息

    docker stats

    查看资源使用情况

    docker cp

    容器与主机间复制文件

    docker top

    查看容器内进程

    docker port

    查看端口映射

    系统管理命令

    # 查看 Docker 系统信息
    docker info
    docker version
    docker system df                # 查看磁盘占用
    
    # 清理命令
    docker system prune -a --volumes  # 清理所有未使用资源
    docker container prune          # 清理已停止容器
    docker image prune -a           # 清理所有未使用镜像
    docker volume prune             # 清理未使用卷
    docker network prune            # 清理未使用网络
    docker builder prune            # 清理构建缓存
    
    # 查看构建缓存
    docker buildx du
    docker buildx prune

    实用技巧

    # 格式化输出
    docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}"
    docker images --format "{{.Repository}}:{{.Tag}} {{.Size}}"
    
    # 过滤查询
    docker ps --filter "status=running"
    docker ps --filter "ancestor=nginx"
    docker images --filter "dangling=true"
    
    # 查看特定字段
    docker inspect --format '{{.NetworkSettings.IPAddress}}' container_name
    docker inspect --format '{{range .Mounts}}{{.Source}}{{"\n"}}{{end}}' container_name
    
    # 实时监控
    watch -n 1 docker ps
    watch -n 2 docker stats

    🛡️

    第十二章:Docker 安全实践

    安全最佳实践

    1. 使用非 root 用户

    # Dockerfile 中切换用户
    RUN addgroup -S appgroup && adduser -S appuser -G appgroup
    USER appuser
    
    # 或使用 --user 参数运行
    docker run --user 1000:1000 myapp

    2. 限制容器权限

    # 删除所有额外权限
    docker run --security-opt no-new-privileges myapp
    
    # 只读根文件系统
    docker run --read-only --tmpfs /tmp myapp
    
    # 限制 Linux Capabilities
    docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp
    
    # 禁用特权模式(永远不要用 --privileged)
    # 禁用 SETUID/SETGID 位
    docker run --security-opt no-new-privileges myapp

    3. 资源限制

    # 限制内存
    docker run --memory 512m --memory-swap 1g myapp
    
    # 限制 CPU
    docker run --cpus 1.0 myapp
    docker run --cpu-quota 50000 --cpu-period 100000 myapp  # 50% CPU
    
    # 限制 PID
    docker run --pids-limit 100 myapp

    4. 镜像安全

    # 扫描镜像漏洞
    docker scout cves nginx:latest
    
    # 使用官方镜像
    FROM node:18-alpine    # 优于 FROM node:latest
    
    # 固定版本
    FROM python:3.11.5-slim-bullseye    # 具体版本
    
    # 验证镜像签名
    docker pull --platform linux/amd64 myimage@sha256:abc123...
    
    # 使用 .dockerignore 排除敏感文件
    # 禁止在镜像中包含密钥、密码、配置文件

    5. 网络安全

    # 不暴露不必要端口
    # 使用自定义网络隔离服务
    docker network create --internal backend-net    # 无外网访问
    
    # 容器只连接需要的网络
    docker run --network frontend-net webapp
    docker run --network frontend-net --network backend-net api
    
    # 限制 iptables 规则
    docker run --iptables=false myapp

    6. 敏感数据管理

    # 使用 Docker Secrets(Swarm)
    echo "my_password" | docker secret create db_password -
    docker service create --secret db_password myapp
    
    # 使用环境变量文件(注意权限)
    docker run --env-file .env.secret myapp
    chmod 600 .env.secret
    
    # 运行时注入密钥(推荐)
    # 使用 Vault、AWS Secrets Manager 等外部工具

    安全扫描工具

    工具特点
    Docker Scout官方集成工具,CVE 扫描
    Trivy开源,支持多种扫描目标
    ClairCoreOS 开发,静态分析
    Snyk全面安全平台
    Anchore企业级策略引擎

    🚨 严重警告

    永远不要在生产环境中以 root 用户运行容器,永远不要使用

    --privileged

    标志,永远不要在镜像中包含敏感凭据!

    🚀

    第十三章:生产环境部署

    生产环境清单

    ✅ 部署前检查

    • 使用多阶段构建减小镜像体积
    • 以非 root 用户运行
    • 设置资源限制(CPU、内存)
    • 配置健康检查
    • 使用命名卷持久化数据
    • 配置日志轮转
    • 使用固定版本标签
    • 扫描镜像漏洞
    • 配置自动重启策略
    • 启用监控和告警

    生产级 Dockerfile

    # 构建阶段
    FROM node:18-alpine AS builder
    WORKDIR /build
    COPY package*.json ./
    RUN npm ci
    COPY . .
    RUN npm run build
    
    # 生产阶段
    FROM node:18-alpine AS production
    WORKDIR /app
    
    # 安全:创建非 root 用户
    RUN addgroup -g 1001 -S nodejs && \
        adduser -S nodejs -u 1001
    
    # 只安装生产依赖
    COPY package*.json ./
    RUN npm ci --only=production && npm cache clean --force
    
    # 从构建阶段复制产物
    COPY --from=builder --chown=nodejs:nodejs /build/dist ./dist
    
    # 安全设置
    USER nodejs
    
    # 资源限制和健康检查
    EXPOSE 3000
    HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
        CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
    
    CMD ["node", "dist/main.js"]

    日志管理

    # 配置日志驱动
    docker run --log-driver json-file \
      --log-opt max-size=100m \
      --log-opt max-file=5 \
      myapp
    
    # 使用 syslog
    docker run --log-driver syslog \
      --log-opt syslog-address=udp://logserver:514 \
      myapp
    
    # 使用 Fluentd
    docker run --log-driver fluentd \
      --log-opt fluentd-address=localhost:24224 \
      myapp
    
    # daemon.json 全局配置
    {
      "log-driver": "json-file",
      "log-opts": {
        "max-size": "50m",
        "max-file": "3"
      }
    }

    监控方案

    # cAdvisor - Google 开发的容器监控
    docker run -d --name cadvisor \
      -v /:/rootfs:ro \
      -v /var/run:/var/run:ro \
      -v /sys:/sys:ro \
      -v /var/lib/docker/:/var/lib/docker:ro \
      -p 8080:8080 \
      gcr.io/cadvisor/cadvisor:latest
    
    # Prometheus + Grafana
    # prometheus.yml
    scrape_configs:
      - job_name: 'docker'
        static_configs:
          - targets: ['cadvisor:8080']
    
    # Docker metrics
    # 启用 Docker daemon metrics
    # daemon.json:
    {
      "metrics-addr": "0.0.0.0:9323",
      "experimental": true
    }

    CI/CD 集成

    # GitHub Actions 示例
    name: Docker Build and Push
    on: [push]
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          
          - name: Login to Docker Hub
            uses: docker/login-action@v3
            with:
              username: ${{ secrets.DOCKERHUB_USERNAME }}
              password: ${{ secrets.DOCKERHUB_TOKEN }}
          
          - name: Build and push
            uses: docker/build-push-action@v5
            with:
              context: .
              push: true
              tags: ${{ secrets.DOCKERHUB_USERNAME }}/myapp:${{ github.sha }}
          
          - name: Scan image
            uses: docker/scout-action@v1
            with:
              command: cves
              image: ${{ secrets.DOCKERHUB_USERNAME }}/myapp:${{ github.sha }}

    Kubernetes 集成

    # K8s Deployment 示例
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: myapp
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: myapp
      template:
        metadata:
          labels:
            app: myapp
        spec:
          containers:
          - name: myapp
            image: myregistry/myapp:v1.0
            ports:
            - containerPort: 3000
            resources:
              limits:
                cpu: "500m"
                memory: "512Mi"
              requests:
                cpu: "200m"
                memory: "256Mi"
            livenessProbe:
              httpGet:
                path: /health
                port: 3000
              initialDelaySeconds: 10
              periodSeconds: 30
            securityContext:
              runAsNonRoot: true
              runAsUser: 1001
              readOnlyRootFilesystem: true

    🐛

    第十四章:故障排除

    常见问题与解决方案

    1. 容器启动后立即退出

    # 查看容器日志
    docker logs container_name
    
    # 查看退出原因
    docker inspect --format='{{.State.ExitCode}} {{.State.Error}}' container_name
    
    # 常见原因:
    # - 启动命令错误(前台进程结束导致容器退出)
    # - 配置文件错误
    # - 依赖服务未就绪
    # - 权限问题
    
    # 解决:使用 exec 模式或 tail 保持运行
    CMD ["nginx", "-g", "daemon off;"]  # 正确:前台运行
    CMD ["tail", "-f", "/dev/null"]     # 调试用

    2. 无法连接到容器端口

    # 检查端口映射
    docker port container_name
    docker inspect container_name | grep -A5 Ports
    
    # 检查防火墙
    sudo iptables -L -n
    sudo ufw status
    
    # 检查容器内服务是否监听正确地址
    docker exec container_name netstat -tlnp
    # 服务应该监听 0.0.0.0 而不是 127.0.0.1
    
    # 检查 SELinux
    sudo setenforce 0    # 临时禁用测试
    sudo chcon -Rt svirt_sandbox_file_t /path/to/mount

    3. 容器间无法通信

    # 确保使用同一个自定义网络
    docker network inspect my-network
    
    # 检查网络配置
    docker inspect container1 --format '{{json .NetworkSettings.Networks}}'
    
    # 测试连通性
    docker exec container1 ping container2
    docker exec container1 nslookup container2
    
    # 默认 bridge 网络不支持容器名解析,使用自定义网络
    docker network create app-network
    docker network connect app-network container1

    4. 磁盘空间不足

    # 查看 Docker 磁盘使用
    docker system df
    docker system df -v
    
    # 清理未使用的资源
    docker system prune -a --volumes
    
    # 查看大镜像
    docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | sort -k3 -h
    
    # 查看大卷
    du -sh /var/lib/docker/volumes/*
    
    # 迁移 Docker 数据目录(Linux)
    sudo systemctl stop docker
    sudo rsync -aP /var/lib/docker/ /new/path/docker
    # 修改 daemon.json:
    {
      "data-root": "/new/path/docker"
    }
    sudo systemctl start docker

    5. 构建速度慢

    # 使用构建缓存
    # 将变化频繁的指令放后面
    # 先 COPY requirements.txt,安装依赖,再 COPY 代码
    
    # 使用 BuildKit
    DOCKER_BUILDKIT=1 docker build -t myapp .
    
    # 启用 BuildKit 缓存挂载
    RUN --mount=type=cache,target=/root/.cache/pip \
        pip install -r requirements.txt
    
    # 多阶段构建减小体积
    # 使用 .dockerignore 排除大文件
    
    # 使用并行构建
    docker buildx build --parallel .

    调试技巧

    # 进入已退出的容器(使用 commit 创建新镜像)
    docker commit container_id debug_image
    docker run -it debug_image /bin/bash
    
    # 查看容器事件
    docker events
    docker events --filter container=container_name
    
    # 查看 daemon 日志
    journalctl -u docker.service -f
    
    # 启用调试模式
    # daemon.json:
    {
      "debug": true
    }
    
    # 远程调试
    # 开启 Docker API
    # daemon.json:
    {
      "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]
    }
    # 注意安全:生产环境不要这样做!

    🔍 排查步骤

    1. 检查容器日志:docker logs
    2. 查看容器状态:docker inspect
    3. 检查网络连接:docker network inspect
    4. 验证资源限制:docker stats
    5. 查看系统日志:journalctl -u docker
    6. 🎯

      第十五章:实战案例

      案例一:部署完整的 Web 应用栈

      # 项目结构
      myapp/
      ├── docker-compose.yml
      ├── frontend/
      │   ├── Dockerfile
      │   └── src/
      ├── backend/
      │   ├── Dockerfile
      │   └── app.py
      ├── nginx/
      │   └── nginx.conf
      └── .env
      
      # docker-compose.yml
      version: '3.8'
      
      services:
        frontend:
          build: ./frontend
          environment:
            - API_URL=http://backend:5000
          depends_on:
            - backend
          networks:
            - app-net
      
        backend:
          build: ./backend
          environment:
            - DATABASE_URL=postgresql://user:pass@db:5432/myapp
            - REDIS_URL=redis://redis:6379
          depends_on:
            db:
              condition: service_healthy
            redis:
              condition: service_started
          networks:
            - app-net
      
        db:
          image: postgres:15-alpine
          environment:
            - POSTGRES_USER=user
            - POSTGRES_PASSWORD=pass
            - POSTGRES_DB=myapp
          volumes:
            - postgres_data:/var/lib/postgresql/data
          healthcheck:
            test: ["CMD-SHELL", "pg_isready -U user"]
            interval: 5s
            timeout: 5s
            retries: 5
          networks:
            - app-net
      
        redis:
          image: redis:7-alpine
          volumes:
            - redis_data:/data
          networks:
            - app-net
      
        nginx:
          image: nginx:alpine
          ports:
            - "80:80"
          volumes:
            - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
          depends_on:
            - frontend
          networks:
            - app-net
      
      networks:
        app-net:
          driver: bridge
      
      volumes:
        postgres_data:
        redis_data:

      案例二:自动化备份脚本

      #!/bin/bash
      # backup.sh - Docker 容器数据备份脚本
      
      BACKUP_DIR="/backup/docker"
      DATE=$(date +%Y%m%d_%H%M%S)
      RETENTION_DAYS=7
      
      mkdir -p $BACKUP_DIR
      
      # 备份所有卷
      for volume in $(docker volume ls -q); do
        echo "Backing up volume: $volume"
        docker run --rm \
          -v ${volume}:/source:ro \
          -v ${BACKUP_DIR}:/backup \
          alpine \
          tar czf /backup/${volume}_${DATE}.tar.gz -C /source .
      done
      
      # 备份所有镜像
      docker save -o ${BACKUP_DIR}/images_${DATE}.tar \
        $(docker images --format "{{.Repository}}:{{.Tag}}" | grep -v "")
      
      # 清理旧备份
      find $BACKUP_DIR -name "*.tar.gz" -mtime +${RETENTION_DAYS} -delete
      find $BACKUP_DIR -name "*.tar" -mtime +${RETENTION_DAYS} -delete
      
      echo "Backup completed: ${BACKUP_DIR}"

      案例三:Python Flask API 容器化

      # app.py
      from flask import Flask, jsonify
      import os
      
      app = Flask(__name__)
      
      @app.route('/health')
      def health():
          return jsonify({"status": "healthy"})
      
      @app.route('/api/data')
      def data():
          return jsonify({"message": "Hello from Docker!"})
      
      if __name__ == '__main__':
          app.run(host='0.0.0.0', port=5000)
      
      # requirements.txt
      flask==3.0.0
      gunicorn==21.2.0
      
      # Dockerfile
      FROM python:3.11-slim
      WORKDIR /app
      COPY requirements.txt .
      RUN pip install --no-cache-dir -r requirements.txt
      COPY . .
      RUN useradd -m appuser && chown -R appuser:appuser /app
      USER appuser
      EXPOSE 5000
      HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost:5000/health || exit 1
      CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
      
      # 构建和运行
      docker build -t flask-api .
      docker run -d -p 5000:5000 --name myapi flask-api
      curl http://localhost:5000/api/data

      案例四:Nginx 反向代理 + SSL

      # nginx.conf
      events {
          worker_connections 1024;
      }
      
      http {
          upstream app_servers {
              server web1:3000;
              server web2:3000;
              server web3:3000;
          }
      
          server {
              listen 80;
              server_name example.com;
              return 301 https://$host$request_uri;
          }
      
          server {
              listen 443 ssl;
              server_name example.com;
      
              ssl_certificate /etc/nginx/ssl/fullchain.pem;
              ssl_certificate_key /etc/nginx/ssl/privkey.pem;
      
              location / {
                  proxy_pass http://app_servers;
                  proxy_set_header Host $host;
                  proxy_set_header X-Real-IP $remote_addr;
                  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                  proxy_set_header X-Forwarded-Proto $scheme;
              }
          }
      }
      
      # docker-compose.yml
      version: '3.8'
      services:
        nginx:
          image: nginx:alpine
          ports:
            - "80:80"
            - "443:443"
          volumes:
            - ./nginx.conf:/etc/nginx/nginx.conf:ro
            - ./ssl:/etc/nginx/ssl:ro
          depends_on:
            - web1
            - web2
            - web3
      
        web1:
          image: myapp:latest
          environment:
            - INSTANCE_ID=1
      
        web2:
          image: myapp:latest
          environment:
            - INSTANCE_ID=2
      
        web3:
          image: myapp:latest
          environment:
            - INSTANCE_ID=3

      🎉 学习建议

      实践是最好的老师!建议按照以下顺序学习:

      1. 安装 Docker 并运行 hello-world
      2. 拉取并运行常用镜像(nginx, mysql, redis)
      3. 编写简单 Dockerfile 构建自己的镜像
      4. 使用 Docker Compose 编排多容器应用
      5. 配置网络和数据持久化
      6. 在真实项目中应用 Docker
      7. 学习 Kubernetes 和 Docker Swarm 集群
      8. 😔 没有找到匹配的内容

        请尝试其他关键词

← 返回IT 技术 yicool 百科 · 🐳 Docker 完整教程

评论 0