欢迎来到 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 | 容器生命周期管理(拉取镜像、创建容器等) |
| runc | OCI 标准容器运行时 |
🌟 知识拓展
现代 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 安装
- 确保系统为 Windows 10/11 64位(Build 19045+)
- 启用 WSL 2:
wsl --install - 启用 Hyper-V 和容器功能
- 从 Docker 官网 下载 Docker Desktop
- 运行安装程序,按提示重启
- 启动 Docker Desktop,完成初始化
- 使用 .dockerignore 文件排除不必要文件
- 合并 RUN 指令减少层数
- 将变化频繁的指令放在后面(利用缓存)
- 使用 slim/alpine 基础镜像
- 以非 root 用户运行
- 添加 HEALTHCHECK
- 使用多阶段构建
- 在 Dockerfile 中存储敏感信息(密钥、密码)
- 使用 latest 标签(应使用具体版本号)
- 创建不必要的层
- 安装不必要的包
- 忽略 .dockerignore
- 阿里云容器镜像服务 ACR — 国内访问快
- AWS ECR — AWS 用户首选
- Google GCR/Artifact Registry — GCP 集成
- Azure ACR — Azure 集成
- GitHub Container Registry — GitHub 集成
- 使用多阶段构建减小镜像体积
- 以非 root 用户运行
- 设置资源限制(CPU、内存)
- 配置健康检查
- 使用命名卷持久化数据
- 配置日志轮转
- 使用固定版本标签
- 扫描镜像漏洞
- 配置自动重启策略
- 启用监控和告警
- 检查容器日志:
docker logs - 查看容器状态:
docker inspect - 检查网络连接:
docker network inspect - 验证资源限制:
docker stats - 查看系统日志:
journalctl -u docker - 安装 Docker 并运行 hello-world
- 拉取并运行常用镜像(nginx, mysql, redis)
- 编写简单 Dockerfile 构建自己的镜像
- 使用 Docker Compose 编排多容器应用
- 配置网络和数据持久化
- 在真实项目中应用 Docker
- 学习 Kubernetes 和 Docker Swarm 集群
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 示例
# .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
💡 其他镜像仓库
🔧
第十一章:常用命令大全
▶
镜像相关命令
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 | 开源,支持多种扫描目标 |
| Clair | CoreOS 开发,静态分析 |
| Snyk | 全面安全平台 |
| Anchore | 企业级策略引擎 |
🚨 严重警告
永远不要在生产环境中以 root 用户运行容器,永远不要使用
--privileged
标志,永远不要在镜像中包含敏感凭据!
🚀
第十三章:生产环境部署
▶
生产环境清单
✅ 部署前检查
生产级 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"]
}
# 注意安全:生产环境不要这样做!
🔍 排查步骤
🎯
第十五章:实战案例
▶
案例一:部署完整的 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
🎉 学习建议
实践是最好的老师!建议按照以下顺序学习:
😔 没有找到匹配的内容
请尝试其他关键词