🐳 Docker 完整教程

IT 技术 81 阅读 更新于 2026-09-25 17:37

欢迎来到 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 — 企业内部使用
  • Harbor、GitLab 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,完成初始化

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

🎯

第十五章:实战案例

▶

案例一:部署完整的 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 集群

😔 没有找到匹配的内容

请尝试其他关键词

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

评论 0