Docker相关
Docker 容器化与微服务 完整系统学习大纲
本文面向测试工程师及后端开发初学者。Docker 早已成为软件交付与测试环境搭建的基础设施:一条命令拉起 MySQL/Redis、在容器里跑被测应用、用镜像保证”环境一致”。掌握 Docker,你的测试环境管理效率会提升一个量级。 文中命令基于 Docker 24+,Windows 用户请在 PowerShell(非 cmd)中执行。
一、Docker 概述
1.1 什么是 Docker?
- 定义:Docker 是一个开源的应用容器引擎,让开发者把应用及依赖打包到一个可移植的容器中,实现”一次构建,到处运行”。
- 历史:2013 年由 Solomon Hykes 基于 Linux 容器(LXC)技术发布;2017 年起进入 Moby 开源项目时代。
- 核心思想:容器 = 操作系统级虚拟化,共享宿主机内核,但拥有独立的文件系统、进程、网络与资源限制。
1.2 容器 vs 虚拟机
| 维度 | 容器(Docker) | 虚拟机(VM) |
|---|---|---|
| 隔离级别 | 进程级(共享宿主机内核) | 硬件级(完整独立操作系统) |
| 启动速度 | 秒级 | 分钟级 |
| 占用空间 | 镜像 MB 级 | 镜像 GB 级 |
| 资源利用率 | 高 | 低(有虚拟化开销) |
| 性能损耗 | 极小 | 有一定损耗 |
| 隔离强度 | 较弱(共享内核) | 强(完全隔离) |
| 典型代表 | Docker、containerd | VMware、VirtualBox、KVM |
一句话:容器更轻更快,虚拟机更隔离更安全。测试环境用容器足够,涉及内核级别隔离需求时才考虑 VM。
1.3 核心概念:镜像 / 容器 / 仓库
| 概念 | 类比 | 说明 |
|---|---|---|
| 镜像 (Image) | 类的定义 / 光盘模板 | 只读的、分层的应用打包文件,包含代码、运行时、依赖、配置 |
| 容器 (Container) | 类的实例 / 运行中的程序 | 镜像运行时的实例,可启动、停止、删除,互相隔离 |
| 仓库 (Repository) | 应用商店 / 网盘 | 集中存放镜像的地方(Docker Hub、阿里云 ACR 等) |
| Dockerfile | 制作镜像的”菜谱” | 描述如何构建镜像的脚本文件 |
| 数据卷 (Volume) | U 盘 | 容器持久化数据的机制 |
三者的关系链:Dockerfile 构建 → 镜像 → 运行成 容器,镜像可推送到仓库供他人拉取。
1.4 Docker 架构
┌──────────┐ Docker CLI ┌──────────────┐ REST API ┌──────────────┐
│ 客户端 │ ─────────────▶ │ 守护进程 │ ───────────▶ │ 容器/镜像/网络 │
│ docker │ │ docker daemon│ │ (containerd) │
└──────────┘ └──────────────┘ └──────────────┘
▼ 镜像下载/上传
┌──────────────┐
│ 镜像仓库 │ Docker Hub / 私有 registry
└──────────────┘
- 客户端 (Client):用户敲
docker命令。 - 守护进程 (Daemon):真正干活的后台服务,管理镜像、容器、网络、数据卷。
- 镜像仓库 (Registry):存放和分发镜像(Docker Hub 是默认公共仓库)。
1.5 应用场景
- 测试环境搭建:一条命令拉起 MySQL、Redis、MongoDB、RabbitMQ 等依赖。
- 被测应用容器化:把被测系统打成镜像,环境一致、快速复现 Bug。
- CI/CD 流水线:构建、测试、发布全部在容器中执行。
- 多版本依赖隔离:同一台机器上跑不同版本 JDK/Python/Node 互不干扰。
- 微服务架构:每个服务独立容器,配合编排工具(K8s)管理。
- 学习与实验:快速体验各种中间件,用完即删,不留垃圾。
二、安装与环境搭建
2.1 Windows 安装(Docker Desktop)
- 前置条件:Windows 10/11 专业版/企业版/教育版,开启 WSL 2(推荐)或 Hyper-V。
- 下载 Docker Desktop for Windows 并安装,安装时勾选 Use WSL 2 instead of Hyper-V。
- 安装完成后启动 Docker Desktop,等托盘图标变为稳定状态(鲸鱼图标不闪烁)。
- 验证:
docker --version docker run hello-world # 能打印 Hello from Docker! 即成功 - 如果 WSL 未启用,先执行(管理员 PowerShell):
wsl --install
⚠️ Docker Desktop 商业使用需付费授权(个人/小团队教育用途免费)。公司内部使用建议确认授权情况,或用 podman 等替代方案。
2.2 Linux 安装(Ubuntu/Debian 示例)
# 官方一键脚本(适合测试环境)
curl -fsSL https://get.docker.com | sh
# 免 sudo 使用 docker(重新登录后生效)
sudo usermod -aG docker $USER
# 启动并设置开机自启
sudo systemctl enable docker --now
sudo systemctl status docker
# 验证
docker version
docker run hello-world
2.3 配置镜像加速(国内必配)
编辑 /etc/docker/daemon.json(Windows 在 Docker Desktop → Settings → Docker Engine):
{
"registry-mirrors": [
"https://docker.m.daocloud.io",
"https://dockerproxy.com",
"https://docker.nju.edu.cn"
]
}
sudo systemctl restart docker # 重启生效
docker info | grep -A 5 "Registry Mirrors"
三、镜像与容器基础操作
3.1 镜像操作
# 搜索镜像
docker search mysql
# 拉取镜像(不写 tag 默认 latest,建议显式写版本)
docker pull mysql:8.0
docker pull nginx:1.24-alpine
# 查看本地镜像
docker images
docker image ls
# 查看镜像详情
docker inspect mysql:8.0
# 给镜像打标签(用于推送到自己的仓库)
docker tag mysql:8.0 myregistry.com/mysql:8.0
# 删除镜像(先删依赖的容器)
docker rmi mysql:8.0
docker image prune # 清理悬空镜像
3.2 容器操作
# 运行容器(核心命令)
docker run -d --name my-nginx -p 8080:80 nginx:1.24-alpine
# 查看容器列表(-a 包含已停止)
docker ps
docker ps -a
# 启动 / 停止 / 重启 / 删除
docker start my-nginx
docker stop my-nginx
docker restart my-nginx
docker rm my-nginx
docker rm -f my-nginx # 强制删除运行中的容器
# 进入容器执行命令(调试神器)
docker exec -it my-nginx /bin/sh
docker exec my-nginx nginx -t
# 查看日志(-f 实时跟踪,-n 行数)
docker logs my-nginx
docker logs -f --tail 100 my-nginx
# 查看容器资源占用
docker stats
docker top my-nginx
# 复制文件进出容器
docker cp ./test.sql my-nginx:/tmp/
docker cp my-nginx:/etc/nginx/nginx.conf ./nginx.conf
3.3 docker run 常用参数详解
| 参数 | 说明 | 示例 |
|---|---|---|
-d |
后台运行 | docker run -d nginx |
--name |
容器命名(唯一) | --name my-nginx |
-p 宿主机:容器 |
端口映射 | -p 8080:80 |
-v 宿主机:容器 |
数据卷/目录挂载 | -v /data:/var/lib/mysql |
-e KEY=VALUE |
设置环境变量 | -e MYSQL_ROOT_PASSWORD=123456 |
--rm |
容器退出后自动删除(临时容器) | --rm |
-it |
交互式终端 | -it /bin/bash |
--network |
指定网络 | --network my-net |
--restart |
重启策略 | --restart=always |
-m / --cpus |
内存/CPU 限制 | -m 512m --cpus=1 |
3.4 一次到位的 MySQL 测试环境
docker run -d \
--name test-mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=edu \
--restart=always \
mysql:8.0
💡 测试价值:之前要装半天的 MySQL,现在一条命令即可获得隔离、可丢弃、版本可选的数据库实例。想测 MySQL 8 和 MariaDB 的兼容性,各起一个容器互不影响。
四、Dockerfile 构建镜像
4.1 常用指令速查
| 指令 | 作用 | 示例 |
|---|---|---|
FROM |
基础镜像(必填,第一行) | FROM python:3.11-slim |
WORKDIR |
设置工作目录 | WORKDIR /app |
COPY |
复制文件进镜像 | COPY . /app |
ADD |
复制文件(支持 URL、自动解压 tar) | ADD app.tar.gz /app/ |
RUN |
构建时执行命令(安装依赖) | RUN pip install -r requirements.txt |
ENV |
设置环境变量 | ENV TZ=Asia/Shanghai |
EXPOSE |
声明容器监听端口(仅文档作用) | EXPOSE 8000 |
CMD |
容器启动时执行的命令(可被覆盖) | CMD ["python", "app.py"] |
ENTRYPOINT |
容器启动主命令(不可被覆盖,适合固定入口) | ENTRYPOINT ["python"] |
ARG |
构建参数(仅构建期有效) | ARG VERSION=1.0 |
USER |
指定运行用户(安全) | USER app |
4.2 示例 1:Python 应用
FROM python:3.11-slim
WORKDIR /app
# 先复制依赖文件,利用层缓存加速构建
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
ENV TZ=Asia/Shanghai
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
4.3 示例 2:Java (Spring Boot) 应用
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY target/*.jar app.jar
# JVM 时区与参数
ENV TZ=Asia/Shanghai
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
4.4 构建与推送
# 构建(-t 命名镜像,. 指当前目录的 Dockerfile)
docker build -t myapp:1.0 .
# 构建时传参
docker build --build-arg VERSION=2.0 -t myapp:2.0 .
# 运行验证
docker run -d -p 8000:8000 --name myapp myapp:1.0
# 推送(需先登录 docker login)
docker tag myapp:1.0 yourname/myapp:1.0
docker push yourname/myapp:1.0
# 清理构建缓存
docker builder prune
4.5 镜像分层与优化技巧
原理:Dockerfile 的每条指令生成一个只读层,层被缓存复用。文件被修改时才重建该层及之后所有层。
| 优化技巧 | 说明 | 收益 |
|---|---|---|
| 依赖安装放在代码复制之前 | 代码改了不用重装依赖 | 大幅减少构建时间 |
用 .dockerignore |
排除 node_modules、target、.git 等 | 减小上下文、避免误打包 |
| 使用精简基础镜像 | -slim、-alpine |
减小镜像体积 |
| 多阶段构建 | 编译镜像 → 运行镜像 | 最终镜像只留运行产物 |
| 合并 RUN 指令 | RUN a && b && c |
减少层数 |
# 多阶段构建示例(Java)
# 阶段一:编译
FROM maven:3.9-eclipse-temurin-17 AS build
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
# 阶段二:运行(只保留 jar)
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY --from=build /build/target/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
⚠️ 注意:多条
COPY若顺序颠倒(先 COPY 源码再 COPY 依赖文件),会导致依赖层缓存失效。把变动小的放前面,变动大的放后面。
五、数据管理
容器删除后内部数据随之消失,持久化数据需用数据卷或绑定挂载。
5.1 数据卷 (Volume)
# 创建数据卷
docker volume create mysql-data
# 挂载数据卷
docker run -d --name test-mysql \
-v mysql-data:/var/lib/mysql \
mysql:8.0
# 查看 / 清理
docker volume ls
docker volume rm mysql-data
- 数据由 Docker 管理(位于
docker volume inspect查看的宿主机路径),跨容器共享方便。 - 容器删除后数据卷默认保留,适合数据库等重要数据。
5.2 绑定挂载 (Bind Mount)
# 把宿主目录挂进容器(前后端联调、热更新场景)
docker run -d --name my-nginx \
-v D:/www:/usr/share/nginx/html:ro \
-p 8080:80 nginx
- 直接映射宿主机路径,修改宿主文件即时生效,适合开发调试。
:ro表示只读挂载。
5.3 对比
| 维度 | 数据卷 Volume | 绑定挂载 Bind Mount |
|---|---|---|
| 存储位置 | Docker 管理目录 | 用户指定宿主机路径 |
| 推荐程度 | 生产推荐 | 开发调试常用 |
| 备份迁移 | docker run --volumes-from 等方式 |
直接拷贝目录 |
| 跨平台兼容 | 好 | Windows 下路径格式要注意 |
六、Docker Compose
6.1 为什么用 Compose
多个容器(如 Web + MySQL + Redis)需要协同管理:一条命令同时启动、统一网络、定义依赖关系。docker-compose.yml 就是”多容器编排脚本”。
6.2 示例:Web 应用 + MySQL + Redis
version: "3.8"
services:
web:
build: .
ports:
- "8080:8080"
environment:
DB_HOST: mysql # 服务名即容器网络内主机名
DB_PASSWORD: 123456
REDIS_HOST: redis
depends_on:
- mysql
- redis
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: edu
volumes:
- mysql-data:/var/lib/mysql
ports:
- "3306:3306"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
mysql-data:
6.3 常用命令
docker compose up -d # 后台启动全部服务
docker compose up -d --build # 重新构建并启动
docker compose ps # 查看服务状态
docker compose logs -f web # 跟踪某个服务日志
docker compose exec web /bin/sh # 进入服务容器
docker compose down # 停止并删除容器(数据卷默认保留)
docker compose down -v # 连同数据卷一起删除(慎用!)
docker compose config # 校验并打印生效配置
💡 测试价值:一个
docker-compose.yml就是一套可重复的测试环境模板——团队共享、版本可控、坏了重建。配合.env文件可切换不同环境的配置。
七、网络
7.1 网络模式
| 模式 | 说明 | 使用场景 |
|---|---|---|
bridge(默认) |
容器通过虚拟网桥与宿主机通信,需端口映射暴露 | 单机多容器 |
host |
容器直接使用宿主机网络,无端口映射 | 追求性能、端口大量场景 |
none |
无网络 | 安全/隔离场景 |
container:xxx |
与指定容器共享网络栈 | 调试、sidecar 模式 |
7.2 自定义网络(推荐)
# 创建自定义网络(容器间可用服务名互相访问,并自动 DNS 解析)
docker network create my-net
docker run -d --name mysql8 --network my-net mysql:8.0
docker run -d --name myapp --network my-net -p 8080:8080 myapp:1.0
# 应用内直接连 mysql8:3306,而不是 IP
docker exec myapp ping mysql8 # 能通
- 自定义网络下容器间无需端口映射即可通信(走虚拟网络),比依赖 IP 更稳定。
- Compose 会为项目自动创建网络,服务名即主机名。
7.3 端口映射原理
宿主机 8080 端口 ──▶ docker-proxy ──▶ 容器内 80 端口
访问 http://localhost:8080 即可到达容器内 nginx
docker port my-nginx # 查看映射关系
八、镜像仓库与分发
8.1 Docker Hub
docker login # 登录 Docker Hub
docker pull nginx # 拉公共镜像
docker push yourname/myapp:1.0 # 推送自己的镜像
docker logout
8.2 私有仓库(离线/内网场景)
# 运行本地 registry(默认端口 5000,仅支持 http)
docker run -d --name registry -p 5000:5000 registry:2
# 打标签并推送
docker tag myapp:1.0 localhost:5000/myapp:1.0
docker push localhost:5000/myapp:1.0
# 验证
curl http://localhost:5000/v2/_catalog
💡 内网测试环境经常无法访问外网拉镜像,可用
registry或 Harbor(企业级)搭建内网镜像源,或提前docker pull后离线导出。
8.3 镜像导出与导入
# 导出(离线迁移场景)
docker save -o myapp.tar myapp:1.0
# 导入
docker load -i myapp.tar
# 容器导出为 tar(含运行状态文件系统,不推荐生产)
docker export -o container.tar my-nginx
docker import container.tar mynginx:imported
| 命令 | 对象 | 是否保留分层/元数据 |
|---|---|---|
docker save/load |
镜像 | ✅ 保留(推荐) |
docker export/import |
容器 | ❌ 仅文件系统 |
九、测试场景实战(重点)
9.1 秒级搭建测试依赖环境
# MySQL 8
docker run -d --name mysql8 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0
# Redis
docker run -d --name redis -p 6379:6379 redis:7-alpine
# RabbitMQ(带管理面板 http://localhost:15672)
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
# Elasticsearch + Kibana
docker run -d --name es -p 9200:9200 -e "discovery.type=single-node" elasticsearch:8.11.3
9.2 容器化被测应用
# 打包被测系统
docker build -t qa-app:latest .
# 启动被测实例(含数据库依赖)
docker compose up -d
# 验证服务
curl http://localhost:8080/actuator/health
环境一致性:开发环境、测试环境、生产环境用同一个镜像,“在我机器上是好的”这类问题大幅减少。
9.3 多版本依赖隔离
# 同一台机器跑多个 Python 版本互不干扰
docker run --rm -it python:3.9 python --version
docker run --rm -it python:3.12 python --version
# 不同 JDK 版本测试
docker run --rm -it eclipse-temurin:8 java -version
docker run --rm -it eclipse-temurin:17 java -version
9.4 问题排查常用命令
# 1. 容器是否在运行、什么状态
docker ps -a
# 2. 看启动日志(最常见:启动失败/循环重启)
docker logs --tail 200 <container>
# 3. 进入容器手动排查
docker exec -it <container> /bin/sh
# 4. 看端口是否映射成功
docker port <container>
ss -lntp | grep 8080
# 5. 看资源占用(内存爆了?CPU 飙了?)
docker stats
# 6. 看容器完整配置与健康状态
docker inspect <container> | grep -A 5 "Status"
# 7. 重启策略生效吗
docker inspect --format '' <container>
9.5 常见问题速查
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
port is already allocated |
宿主机端口被占用 | 换端口或 ss -lntp 找到占用进程 |
| 容器启动即退出 | 前台进程退出、命令错误、端口冲突 | docker logs 看日志;用 -it 交互验证 |
image not found |
镜像名/版本写错,或未拉取 | 检查 tag,docker pull |
permission denied |
普通用户无 docker 权限 | 加入 docker 组或加 sudo |
| 容器内无法连外网 | DNS 或网络模式问题 | 检查 /etc/resolv.conf、网络模式 |
| 磁盘被占满 | 镜像/容器/卷堆积 | docker system prune -a(慎用) |
| 时区不对 | 容器默认 UTC | 加 -e TZ=Asia/Shanghai |
十、资源限制与监控
10.1 资源限制
# 限制内存 512M、CPU 1 核、禁止 Swap
docker run -d --name app \
-m 512m --memory-swap 512m --cpus 1 \
myapp:1.0
💡 测试价值:压测时用
-m限制容器内存,可快速模拟”内存不足/OOM”场景,验证被测应用在资源紧张时的表现(是否优雅降级、是否崩溃)。
10.2 监控
docker stats # 实时资源监控(Ctrl+C 退出)
docker top <container> # 查看容器内进程
docker events # 实时事件流(启停、销毁等)
10.3 日志配置
# 限制日志大小,防止日志撑爆磁盘
docker run -d \
--log-opt max-size=10m \
--log-opt max-file=3 \
nginx
// 全局配置 /etc/docker/daemon.json
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }
十一、学习资源
| 资源 | 说明 |
|---|---|
| Docker 官方文档 | 最权威的入门与参考 |
| Docker Hub | 公共镜像仓库,找镜像 |
| Play with Docker | 在线免费练手环境 |
| Dockerfile 最佳实践(官方) | 写 Dockerfile 必读 |
| 《Docker 实战》/ 《深入浅出 Docker》 | 系统化学习书籍 |
| 菜鸟教程 Docker 教程 | 中文快速入门 |