01-Docker 简介与核心概念
这个交付链路把传统部署痛点、镜像构建、仓库分发和容器运行串成一条标准路径。

1. 概述
这个交付链路把传统部署痛点、镜像构建、仓库分发和容器运行串成一条标准路径。
Docker 是目前最流行的容器化平台,自 2013 年发布以来彻底改变了软件的开发、交付和运行方式。它允许开发者将应用及其所有依赖打包到一个轻量级、可移植的容器中,在任何 Linux 环境上一致地运行。
1.1 为什么需要 Docker?
在传统的软件部署中,有一个经典问题:"在我机器上能跑啊!"
- 开发者的 Windows/Mac 环境和生产环境的 CentOS 不同
- 应用依赖的 Python 3.11 版本和生产环境用的 Python 3.6 不一致
- 数据库版本、系统库、环境变量都有差异
Docker 的解决方案极其简洁:把应用和环境一起打包。这个打包物就是"镜像(Image)",运行时就是"容器(Container)"。
Docker 的出现解决了以下痛点:
| 痛点 | 传统方案 | Docker 方案 |
|---|---|---|
| 环境不一致 | 写复杂的部署文档 | 标准化的 Dockerfile |
| 依赖冲突 | 虚拟环境隔离 | 每个容器独立文件系统 |
| 部署缓慢 | 手动配置服务器 | docker run 秒级启动 |
| 资源浪费 | 虚拟机占用数 GB 空间 | 容器共享内核,MB 级开销 |
| 扩展困难 | 重新部署整个服务 | 容器编排自动扩缩容 |
1.2 Docker 的应用场景
- 开发环境标准化:团队统一使用同一镜像,消除"在我机器上能跑"的问题
- 微服务架构:每个服务独立容器化,独立部署和扩展
- CI/CD 流水线:Docker 镜像作为标准交付物,从构建到部署路径一致
- DevOps 实践:开发环境和生产环境一致,减少运维风险
- 本地测试:快速启动 MySQL、Redis、Nginx 等依赖服务而不污染宿主机
1.3 学习路线
本系列计划从零开始,系统性地学习 Docker 容器化技术:
- Docker 简介与核心概念(本文) — 容器、镜像、仓库三大核心概念
- Docker 安装与基础命令 — 各平台安装、容器生命周期管理
- Dockerfile 编写指南 — 镜像构建的最佳实践
- Docker Compose 编排 — 多容器应用管理
- 数据持久化 — Volume 和 Bind Mount
- 网络配置 — 容器网络模型与通信
- 镜像仓库 — Docker Hub 与私有仓库搭建
- Docker 安全 — 权限控制和安全最佳实践
- Docker 监控与日志 — 容器监控和日志收集
- CI/CD 集成 — Docker 在自动化流水线中的应用
前置知识:
- Linux 基本命令操作
- 了解进程、文件系统等操作系统的概念
2. Docker 核心概念
这个原理视图把容器背后的三类内核能力放在一起:Namespace 提供隔离视图,Cgroup 提供资源边界,UnionFS 提供镜像分层和容器可写层。理解这三点,才能把容器和虚拟机的边界真正分清楚。
2.1 什么是容器?
容器是一种轻量级的操作系统级虚拟化技术。与虚拟机(VM)不同,容器共享宿主机的操作系统内核,但通过 Linux 内核的 Namespace 和 Cgroup 技术实现进程隔离和资源限制。
容器 vs 虚拟机对比:
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ 虚拟机 (VM) │ │ 容器 (Container) │
│ │ │ │
│ ┌───────┐ ┌───────┐ │ │ ┌───────┐ ┌───────┐ │
│ │ App A │ │ App B │ │ │ │ App A │ │ App B │ │
│ ├───────┤ ├───────┤ │ │ ├───────┤ ├───────┤ │
│ │ Libs │ │ Libs │ │ │ │ Libs │ │ Libs │ │
│ ├───────┤ ├───────┤ │ │ └───┬───┘ └───┬───┘ │
│ │GuestOS│ │GuestOS│ │ │ │ │ │
│ └───┬───┘ └───┬───┘ │ │ ┌───┴─────────┴───┐ │
│ │ │ │ │ │ Docker Engine │ │
│ ┌───┴─────────┴───┐ │ │ └────────┬─────────┘ │
│ │ Hypervisor │ │ │ │ │
│ └────────┬────────┘ │ │ ┌────────┴────────┐ │
│ │ │ │ │ Host OS (Linux) │ │
│ ┌────────┴────────┐ │ │ └─────────────────┘ │
│ │ Host OS │ │ │ │
│ └─────────────────┘ │ └─────────────────────────────┘
关键区别:
| 特性 | 虚拟机 | 容器 |
|---|---|---|
| 启动时间 | 30-60 秒 | 毫秒到秒级 |
| 磁盘占用 | GB 级别(含完整 OS) | MB 级别(仅应用 + 依赖) |
| 内核 | 独立内核 | 共享宿主机内核 |
| 资源开销 | 高(Hypervisor 层开销) | 极低(仅 Namespace/Cgroup) |
| 隔离性 | 完全隔离 | 进程级隔离(较弱) |
| 密度 | 一台服务器数十台 | 一台服务器数百上千个 |
| 迁移性 | 依赖 Hypervisor | 标准 OCI 镜像,跨平台 |
2.2 三大核心组件
Docker 由三个核心概念构成:
1. 镜像(Image) — 打包规范
镜像是一个只读的、包含应用及其所有依赖的打包文件。它由多层文件系统叠加而成,每一层代表一个 Dockerfile 中的指令。
镜像层(只读):
┌─────────────────┐ ← CMD ["python", "app.py"] (第5层)
├─────────────────┤ ← COPY app.py /app/ (第4层)
├─────────────────┤ ← RUN pip install flask (第3层)
├─────────────────┤ ← RUN apt-get install python (第2层)
├─────────────────┤ ← FROM ubuntu:22.04 (第1层/基础层)
└─────────────────┘
每一层只记录与上一层的差异(增量)。这就是 Docker 镜像高效的原因——多个镜像可以共享相同的基础层。
2. 容器(Container) — 运行实例
容器是镜像的运行实例,在只读镜像层之上添加一个可写层:
容器运行态:
┌─────────────────┐ ← 可写层(容器运行时修改的内容) (第6层/临时层)
├─────────────────┤ ← CMD ["python", "app.py"] (第5层/镜像)
├─────────────────┤ ← COPY app.py /app/ (第4层/镜像)
├─────────────────┤ ← RUN pip install flask (第3层/镜像)
├─────────────────┤ ← RUN apt-get install python (第2层/镜像)
├─────────────────┤ ← FROM ubuntu:22.04 (第1层/镜像)
└─────────────────┘
容器停止后,可写层的修改默认不会保存。如果要持久化数据,需要使用 Volume 或 Bind Mount。
3. 仓库(Registry) — 镜像分发中心
- Docker Hub:官方公共仓库(hub.docker.com),包含数百万个公开镜像
- 私有仓库:企业自建的镜像仓库(如 Harbor、Nexus)
- 云仓库:阿里云 ACR、AWS ECR、GCR 等
镜像的命名格式:[仓库地址/]镜像名[:标签]
docker pull nginx:latest # Docker Hub 上的 nginx 最新版
docker pull registry.example.com/myapp:v1.0 # 私有仓库的指定版本
3. Docker 核心技术原理
3.1 Namespace — 进程隔离
Linux Namespace 是容器的隔离基础。每个容器拥有独立的 Namespace,使其看起来像是一台独立的机器。
| Namespace 类型 | 隔离内容 | Linux 内核版本 |
|---|---|---|
| PID | 进程号空间 | 2.6.24 |
| Network | 网络设备、协议栈、端口 | 2.6.29 |
| Mount | 文件系统挂载点 | 2.6.19 |
| UTS | 主机名和 NIS 域名 | 2.6.19 |
| IPC | System V IPC 和 POSIX 消息队列 | 2.6.19 |
| User | 用户和用户组 ID | 3.8 |
Namesapce 的工作方式: 当 Docker 启动一个容器时,会为这个容器的每个进程创建独立的 Namespace,进程在容器内看到的 PID 是 1(类似在独立操作系统中),但在宿主机上仍有一个真实的 PID。
宿主机视角:
PID 10023 → 容器内 PID 1 (nginx master)
PID 10024 → 容器内 PID 2 (nginx worker)
PID 10025 → 容器内 PID 3 (nginx worker)
容器内视角:
PID 1 (nginx master)
PID 2 (nginx worker)
PID 3 (nginx worker)
3.2 Cgroup — 资源限制
Control Groups(cgroup)负责限制容器可以使用的资源量。Docker 通过 cgroup 实现:
# 限制容器最多使用 1 个 CPU 核心和 512MB 内存
docker run --cpus=1 --memory=512m nginx
# cgroup 在宿主机上的对应路径
ls /sys/fs/cgroup/cpu/docker/<container_id>/
ls /sys/fs/cgroup/memory/docker/<container_id>/
关键限制参数:
| 参数 | 作用 | 示例 |
|---|---|---|
| --cpus | 限制 CPU 核心数 | --cpus=1.5 |
| --memory | 限制最大内存 | --memory=2g |
| --memory-swap | 限制 Swap 用量 | --memory-swap=4g |
| --blkio-weight | 限制磁盘 I/O 权重 | --blkio-weight=500 |
| --pids-limit | 限制进程数 | --pids-limit=100 |
3.3 UnionFS — 分层文件系统
Docker 镜像采用 Union 文件系统(如 OverlayFS、AUFS)实现分层存储。核心思想是:多个只读层叠加在一起,对外呈现为一个完整的文件系统。
OverlayFS 工作原理:
┌─────────────────────────┐
│ 容器视角的文件系统 │
│ (merged) │
├─────────────────────────┤
│ 上层 (upperdir) │ ← 容器的可写层
├─────────────────────────┤
│ 下层 (lowerdir) │ ← 镜像的多个只读层
│ layer5 │
│ layer4 │
│ layer3 │
│ layer2 │
│ layer1 (基础镜像) │
└─────────────────────────┘
写时复制(Copy-on-Write): 当容器需要修改镜像层中的文件时,不会直接修改只读层,而是把文件复制到可写层再进行修改。这样可以:
- 节省空间:多个容器共享相同的镜像层
- 提高性能:不修改原始层,不需要复制整个镜像
- 保持镜像一致性:镜像始终是只读的
4. Docker 架构
这张图说明 Docker CLI 并不直接运行容器,而是通过 API 与 dockerd 通信,再由 containerd、runc 和 OCI 运行时规范完成镜像拉取、容器创建和生命周期管理。
4.1 C/S 架构
Docker 采用客户端-服务器架构:
┌─────────┐ REST API ┌───────────┐ ┌─────────────┐
│ docker │ ◄─────────────────► │ dockerd │ ◄────► │ 容器 1 │
│ (客户端) │ (Unix Socket) │ (守护进程) │ ├─────────────┤
└─────────┘ │ │ │ 容器 2 │
│ │ ◄────► ├─────────────┤
│ │ │ 容器 3 │
└───────────┘ └─────────────┘
- dockerd:Docker 守护进程,运行在宿主机上,负责管理镜像、容器、网络、数据卷等
- docker CLI:命令行客户端,通过 REST API 与 dockerd 通信
- containerd:底层容器运行时(从 Docker 1.11 开始分离),负责容器的生命周期管理
- runc:OCI 容器运行时规范的标准实现,真正创建和运行容器的组件
4.2 通信方式
Docker 客户端与守护进程通过 REST API 通信,默认使用 Unix Socket:
# 默认通信方式(本地)
/var/run/docker.sock
# 也可以配置为 TCP(远程管理)
dockerd -H tcp://0.0.0.0:2375
# 客户端指定远程守护进程
docker -H tcp://remote-server:2375 ps
4.3 OCI 标准
Docker 推动了 OCI(Open Container Initiative)标准的发展,使得容器技术更加标准化和开放:
- OCI Runtime Spec:定义容器的运行时规范(runc 是其参考实现)
- OCI Image Spec:定义镜像的打包规范
- OCI Distribution Spec:定义镜像的分发规范
这意味着不仅仅 Docker 可以创建和运行容器——Podman、containerd、CRI-O 等都能运行符合 OCI 标准的容器。
5. Docker 常用命令速览
在深入学习之前,先快速了解最常用的命令:
# 镜像管理
docker pull nginx # 拉取镜像
docker images # 列出本地镜像
docker rmi nginx # 删除镜像
docker build -t myapp . # 从 Dockerfile 构建镜像
# 容器生命周期
docker run nginx # 创建并启动容器
docker run -d --name web nginx # 后台运行并命名
docker ps # 列出运行中的容器
docker ps -a # 列出所有容器(包括已停止的)
docker stop web # 停止容器
docker start web # 启动已停止的容器
docker rm web # 删除容器
# 容器交互
docker logs web # 查看容器日志
docker exec -it web bash # 进入容器执行命令
docker cp file.txt web:/tmp/ # 复制文件到容器
docker top web # 查看容器内进程
# 资源管理
docker stats # 查看所有容器的资源使用
docker inspect web # 查看容器详细信息
docker system df # 查看 Docker 磁盘使用
docker system prune # 清理未使用的资源
6. 验证方法
6.1 确认 Docker 已安装
# 检查 Docker 版本
docker --version
# 预期输出
# Docker version 26.0.0, build 2ae903e
# 检查 Docker 守护进程状态
sudo systemctl status docker
# 预期输出(部分)
# ● docker.service - Docker Application Container Engine
# Loaded: loaded (/lib/systemd/system/docker.service; enabled; preset: enabled)
# Active: active (running) since ...
6.2 运行 Hello World 验证
# 最经典的 Docker 验证方法
docker run hello-world
# 预期输出:
# Hello from Docker!
# This message shows that your installation appears to be working correctly.
# To generate this message, Docker took the following steps:
# 1. The Docker client contacted the Docker daemon.
# 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
# (amd64)
# 3. The Docker daemon created a new container from that image which runs the
# executable that produces the output you are currently reading.
# 4. The Docker daemon streamed that output to the Docker client, which sent it
# to your terminal.
6.3 验证 Namespace 隔离
# 启动一个后台容器
docker run -d --name test-vm nginx:alpine
# 查看容器 PID
CONTAINER_PID=$(docker inspect --format '{{.State.Pid}}' test-vm)
echo "容器在宿主机上的 PID: $CONTAINER_PID"
# 对比宿主机和容器内的 PID 空间
echo "--- 宿主机视角的进程 ---"
ps aux | grep nginx | head -5
echo ""
echo "--- 容器内视角的进程 ---"
docker exec test-vm ps aux
# 查看容器的 Namespace
lsns -p $CONTAINER_PID
7. 常见问题
Q1: Docker 和虚拟机哪个更适合我?
如果需要在不同操作系统上运行应用(如 Linux 上的 Windows 应用),需要完整的内核隔离,选虚拟机。如果应用是 Linux 原生应用,追求快速部署和资源效率,选 Docker 容器。大多数 DevOps 场景同时使用二者——VM 提供隔离,容器提供密度。
Q2: Docker 容器能运行 Windows 应用吗?
Linux 容器不能直接运行 Windows 应用。但 Docker Desktop for Windows 可以使用 Hyper-V 后台运行 Linux 容器,也可以使用 Windows 容器(基于 Windows Server Core)。生产环境建议保持宿主机和容器 OS 类型一致。
Q3: 容器内的 root 用户安全吗?
容器内的 root 并不等同于宿主机的 root(受 User Namespace 限制),但仍有一定的风险。最佳实践是使用 --user 参数以非 root 用户运行容器进程,或者在镜像创建时设置非 root 用户。
Q4: 容器重启后数据会丢失吗?
默认情况下会的。容器的可写层在容器删除后会丢失。要持久化数据,需要使用 Volume(docker run -v mydata:/data)或 Bind Mount(docker run -v /host/path:/container/path)。
Q5: 为什么 Docker 镜像有时候很大?
主要原因是基础镜像过大(如 ubuntu:22.04 约 77MB,但含工具链的镜像更大)。可以通过使用 alpine 版本(约 5MB、含 musl libc)或 distroless 镜像来减小体积。后续 Dockerfile 的文章会详细介绍镜像瘦身技巧。
Q6: Docker 和 containerd 是什么关系?
containerd 是 Docker 从 1.11 版本开始分离出来的底层容器运行时组件。Docker 在 containerd 之上提供了完整的开发者工具链(Dockerfile、docker build、docker-compose 等)。Kubernetes 也可以直接使用 containerd(跳过 Docker 层)。
Q7: Docker 支持哪些架构?
Docker 支持 x86_64(amd64)、ARM64(aarch64)、ARMv7、s390x、ppc64le 等多种架构。拉取镜像时会自动选择对应架构的版本,也可以使用 --platform 参数指定。
8. 从“能运行”到“可交付”的理解方式
很多人第一次接触 Docker,会把它理解成“轻量虚拟机”或者“一个运行应用的命令”。这两个说法都有一点道理,但都不完整。更准确的理解是:Docker 把应用运行所需的文件系统、启动命令、环境变量、依赖和运行边界封装成镜像,再通过统一的容器运行接口在不同宿主机上启动。它解决的核心问题不是“能不能运行”,而是“能不能以同样的方式构建、分发、启动、回滚和验证”。
传统部署最大的问题是环境漂移。开发机装了某个库,测试机版本不同,生产机路径不同,系统服务启动顺序不同,最后应用故障时很难判断是代码问题、依赖问题还是机器问题。Docker 不能消除所有环境差异,但它把差异收敛到几个可见对象:镜像版本、启动参数、挂载卷、网络、资源限制和宿主机内核能力。只要这些对象被记录下来,部署就从“人工配置一台机器”变成“按声明启动一个容器”。
所以学习 Docker 时,不要只记 docker run。docker run 是入口,但生产交付还需要回答:镜像从哪里构建,基础镜像是否可信,镜像标签如何管理,配置从哪里注入,数据放在哪里,端口暴露给谁,日志如何收集,容器异常退出谁发现,升级失败如何回滚。后续安装、Dockerfile、网络、数据卷和 Compose 的文章,本质上都在回答这些问题。
9. Docker 不是哪些东西
Docker 不是完整虚拟化平台。它不会为每个容器启动独立内核,容器共享宿主机 Linux 内核。这个特性带来轻量和高密度,也意味着内核版本、内核模块、cgroup、namespace、安全模块和宿主机配置会影响容器行为。如果一个应用强依赖不同内核或完整操作系统边界,虚拟机仍然更合适。
Docker 不是安全沙箱的全部。Namespace、Cgroup、Capabilities、seccomp、AppArmor/SELinux、只读文件系统、非 root 用户等能力可以降低风险,但容器逃逸、镜像供应链、Docker socket 暴露、特权容器、宿主机路径挂载都会扩大攻击面。不能因为应用跑在容器里,就默认它安全。
Docker 也不是配置管理系统。容器镜像应该包含应用和运行依赖,但不应该把生产密码、证书、环境差异和业务数据固化进去。配置应通过环境变量、配置文件挂载、secret 管理或编排平台注入;业务数据应通过卷、对象存储、数据库或外部持久化系统保存;运行策略应沉淀到 Compose、Kubernetes、CI/CD 或运维平台里。
Docker 更不是“随便下载镜像就能上线”。公共镜像可能存在过期依赖、未修复漏洞、未知维护者、默认账号、过大攻击面或不适合生产的启动方式。生产镜像要有来源、版本、扫描、构建记录和更新节奏。尤其是数据库、中间件、反向代理和安全敏感服务,不要只因为 Docker Hub 上有现成镜像就直接使用。
10. 一条完整的容器交付链路
一条健康的 Docker 交付链路通常包含七个环节。
第一,选择基础镜像。基础镜像决定包管理器、系统库、默认用户、证书、时区和漏洞面。开发阶段可以使用功能完整的镜像,生产阶段更关注可维护、体积、漏洞和运行权限。
第二,编写 Dockerfile。Dockerfile 不只是把命令写进去,还要考虑缓存顺序、依赖安装、构建产物复制、非 root 用户、启动命令、健康检查和密钥处理。一个糟糕的 Dockerfile 可能能构建成功,但会让镜像巨大、缓存失效、密钥泄露或运行时权限过高。
第三,构建镜像并打标签。latest 适合临时实验,不适合生产发布。生产镜像应该包含版本号、提交号、构建时间或渠道标签,方便回滚和追踪。镜像构建应在 CI 中完成,而不是在某台个人电脑上手工 build 后上传。
第四,推送到仓库。镜像仓库是交付链路的分发中心,需要认证、权限、保留策略、漏洞扫描和镜像清理。企业内部通常需要私有 registry 或云厂商镜像仓库。
第五,拉取并运行容器。运行时要明确端口、网络、卷、环境变量、资源限制、重启策略和日志策略。不要把所有参数散落在命令历史里,至少要写成 Compose 文件、启动脚本或自动化任务。
第六,验证运行状态。验证不是只看容器状态为 Up,还要看应用监听、健康检查、日志、端口访问、数据持久化、依赖服务和监控指标。容器启动成功但应用不可用,是最常见的初学者误判。
第七,升级和回滚。容器化的价值之一是让升级变成可替换的镜像版本。升级前要确认数据兼容、配置兼容和外部依赖;升级失败时,要能回到旧镜像和旧配置。没有回滚路径的容器化,只是换了一种部署格式。
11. Docker 对运维角色的影响
Docker 改变了应用、系统和平台之间的边界。过去应用团队把安装包交给运维,运维在服务器上安装依赖、调整配置、启动服务。容器化之后,应用团队需要对镜像质量负责,平台或运维团队需要对宿主机、运行时、网络、存储、镜像仓库和监控负责。边界不清时,Docker 会把问题从“机器上能不能跑”变成“谁对镜像、配置、数据和运行平台负责”。
一个实用分工可以这样划分:
| 对象 | 主要责任 | 验收问题 |
|---|---|---|
| Dockerfile | 应用/平台共同维护 | 是否可复现、无密钥、非 root、体积可控 |
| 镜像仓库 | 平台团队 | 是否有权限、扫描、保留和回滚 |
| 容器启动参数 | 应用/运维共同维护 | 环境变量、端口、卷、资源限制是否明确 |
| 宿主机 | 运维/平台团队 | Docker Engine、磁盘、网络、安全基线是否正常 |
| 数据卷 | 应用/运维共同维护 | 数据是否可备份、可恢复、可迁移 |
| 监控日志 | 运维/平台团队 | 容器、应用、宿主机是否都可观测 |
这张表不是组织架构要求,而是提醒团队:Docker 不会自动解决责任边界。容器化越深入,越需要把构建、运行、数据和平台的责任写清楚。
12. 初学 Docker 的实验路径
建议按五个小实验学习 Docker,而不是一次性学习所有命令。
第一个实验是运行现成镜像,例如 hello-world 和 nginx,理解镜像拉取、容器启动、端口发布和容器删除。第二个实验是进入容器查看进程、文件系统和网络,理解容器不是虚拟机,而是宿主机上的隔离进程。第三个实验是写一个最小 Dockerfile,把自己的静态页面或小应用打成镜像。第四个实验是使用命名卷保存数据,删除容器后重建,确认数据还在。第五个实验是创建自定义网络,让两个容器用服务名互相访问。
这五个实验分别对应后续章节:安装与基础命令、Dockerfile、网络、数据卷和 Compose。每做完一个实验,都要留下验证命令和失败记录。比如端口访问失败时,记录是应用没监听、容器没启动、端口没发布,还是防火墙拦截;数据丢失时,记录是写到了容器可写层,还是卷挂载路径错了。学习时就养成证据习惯,后续生产排障会轻很多。
13. 生产使用前的最低检查清单
在把 Docker 用到生产前,至少要完成以下检查:
| 检查项 | 为什么重要 |
|---|---|
| 镜像来源明确 | 避免使用未知维护者或过期镜像 |
不使用 latest 部署生产 |
保证版本可追踪、可回滚 |
| 容器不以特权模式运行 | 降低宿主机风险 |
| 应用尽量非 root 运行 | 降低容器内进程权限 |
| 数据不写入容器可写层 | 避免删除容器导致数据丢失 |
| 日志有大小限制或集中采集 | 避免磁盘被日志打满 |
| Docker 数据目录容量受监控 | 避免镜像、容器、卷撑爆磁盘 |
| Docker socket 不暴露给普通容器 | 避免容器控制宿主机 Docker |
| 配置和密钥不写入镜像层 | 避免泄露和环境固化 |
| 升级和回滚路径已验证 | 避免发布失败无法恢复 |
这个清单不要求初学阶段全部自动化,但至少要知道每一项对应的风险。Docker 的学习曲线看似平缓,真正的复杂度往往出现在生产治理阶段。
14. 三个典型应用场景
第一个场景是开发环境一致化。过去一个新同事加入项目,需要安装语言运行时、数据库、缓存、消息队列和各种系统依赖,任何一步版本不一致都可能导致“我这里能跑,你那里不行”。Docker 可以把这些依赖封装成镜像和 Compose 配置,让团队用更接近生产的方式启动本地环境。但这里要注意,开发环境容器化不代表生产环境已经准备好。开发环境可以为了方便暴露端口、挂载代码、使用弱口令;生产环境必须重新审视权限、数据、网络和监控。
第二个场景是交付中间件和基础服务。Nginx、Redis、PostgreSQL、Prometheus、Grafana 等服务都有成熟镜像,适合快速搭建测试环境或小规模内部服务。这里的重点不是“镜像能启动”,而是配置、数据和升级。比如数据库容器必须有持久化卷和备份策略;Nginx 配置要挂载或构建进镜像;监控服务要考虑数据保留和容量;Redis 要明确是否允许持久化、是否需要密码、是否可以被外部访问。
第三个场景是应用发布。应用团队把代码打包成镜像,CI 构建后推送到镜像仓库,运行环境只负责拉取指定版本镜像并启动。这个场景最能体现 Docker 的价值:发布产物可追踪,回滚可以切换镜像版本,环境依赖封装在镜像中,运行参数由平台管理。但它也要求团队具备 Dockerfile 质量、镜像扫描、版本标签、日志输出、健康检查和数据外置等能力。
这三个场景难度逐步提升。学习时可以先从开发环境和测试中间件开始,理解容器生命周期;再进入应用镜像构建,理解交付链路;最后再考虑生产治理和平台化。不要一开始就把 Docker 当成生产平台,也不要因为几个本地实验成功就忽略安全和运维边界。
15. Docker 常见风险地图
Docker 的风险并不神秘,大多来自几个固定位置。
| 风险位置 | 典型问题 | 控制方法 |
|---|---|---|
| 镜像来源 | 使用未知镜像、过期镜像、latest |
可信仓库、固定版本、扫描 |
| 构建过程 | 密钥写入镜像层、构建不可复现 | BuildKit secret、CI 构建、锁定依赖 |
| 运行权限 | root、privileged、过多 capability | 非 root、最小权限、只读文件系统 |
| Docker socket | 容器挂载 socket 后控制宿主机 | 避免暴露 socket,使用受控代理 |
| 数据存储 | 数据写入容器可写层 | 命名卷、bind mount、外部数据库 |
| 网络暴露 | 数据库端口直接暴露到公网 | 最小端口发布、防火墙、内网访问 |
| 日志磁盘 | 容器日志无限增长 | 日志轮转、集中采集、容量监控 |
| 配置密钥 | .env、证书、token 进入镜像 |
secret 管理、只读挂载、脱敏审计 |
掌握这张风险地图后,学习 Docker 命令就不会变成孤立操作。每一个参数都能对应到一个风险控制点:-p 对应网络暴露,-v 对应数据边界,--user 对应运行权限,--restart 对应异常恢复,--memory 对应资源边界,--read-only 对应文件系统保护。
16. 容器化是否适合当前应用
不是所有应用都适合立刻容器化。适合优先容器化的应用通常具备几个特征:运行依赖清晰,启动命令明确,配置可以外置,日志能输出到标准输出,数据可以放到外部数据库或卷,服务可以通过端口暴露,健康状态可以被探测。
暂时不适合直接容器化的应用也很常见。比如强依赖桌面环境、依赖宿主机特定驱动、需要复杂 systemd 服务编排、数据路径混乱、配置散落在多个目录、无法前台运行、许可证绑定硬件或主机名。这些应用不是永远不能容器化,而是需要先整理运行边界。
判断时可以问六个问题:应用怎么启动?依赖哪些文件和系统库?配置从哪里读取?数据写到哪里?日志输出到哪里?异常时如何判断健康?如果这六个问题答不清,先不要急着写 Dockerfile。把运行手册补清楚,再容器化会更稳。
17. 从 Docker 到后续技术栈
Docker 是容器化入口,但不是终点。单机 Docker 能帮助理解镜像、容器、网络、卷和运行参数;Compose 能把多容器应用写成声明式配置;Kubernetes、Nomad、Swarm 或云平台容器服务则进一步处理调度、服务发现、滚动更新、弹性伸缩和集群级治理。
学习顺序不应该跳太快。没有理解容器网络,就很难理解 Kubernetes Service 和 CNI;没有理解数据卷,就很难理解 PV/PVC 和存储类;没有理解 Dockerfile,就很难做好镜像供应链;没有理解日志和健康检查,就很难做好平台可观测性。后续系列如果进入 Compose 或 Kubernetes,本文的概念仍然是基础。
18. 团队落地 Docker 的路线
团队引入 Docker,最好不要从“所有系统立刻容器化”开始。更稳的路线是先选一个低风险内部应用,完成镜像构建、容器运行、日志、配置、数据和回滚的完整闭环。这个应用不一定要很重要,但要能代表真实交付流程。只有跑通一个完整闭环,团队才知道自己缺的是 Dockerfile 能力、镜像仓库、配置管理、网络规划、数据备份,还是监控告警。
第二阶段可以把通用中间件和开发环境容器化。比如为开发团队提供统一的数据库、缓存、消息队列、对象存储模拟服务,减少本地环境差异。这一阶段要强调“开发便利”和“生产标准”分开,不要把开发 Compose 文件直接当生产部署文件。
第三阶段再进入核心应用容器化。核心应用往往涉及数据库连接、文件上传、定时任务、证书、外部系统、灰度发布和回滚。此时 Docker 只是基础,真正挑战是发布流程和运维边界。团队需要明确镜像谁构建、镜像谁扫描、配置谁维护、数据谁备份、发布谁批准、事故谁回滚。
第四阶段才考虑平台化。平台化可以是 Compose 管理多容器应用,也可以是 Kubernetes、Nomad、云容器服务或内部 PaaS。不要在团队还没有镜像质量标准、日志规范和数据边界时直接上平台。平台会放大标准,也会放大混乱。
这条路线的核心是循序渐进。Docker 是工具,不是组织流程的替代品。没有清楚的构建、发布、监控和责任边界,容器化只会把原来散落在服务器上的问题换一种形式继续存在。
19. 读完本篇后的复盘问题
可以用下面几个问题检查自己是否真正理解 Docker 核心概念:镜像和容器的区别是什么?删除容器会不会删除镜像?删除容器会不会删除数据?容器为什么比虚拟机轻?Docker daemon、containerd、runc 分别处在哪一层?为什么生产不推荐只用 latest?为什么 Docker socket 很危险?为什么日志应该输出到 stdout/stderr?为什么配置不应该写死在镜像里?
如果这些问题都能回答清楚,再进入安装和基础命令会更顺。否则很容易只会执行命令,不知道命令背后的边界。后续每篇文章都会围绕这些问题继续展开。
20. 最小生产样板
如果要把本文概念落到一个最小生产样板,可以从一个只读静态网站开始。应用代码通过 Dockerfile 构建为 Nginx 镜像,镜像推送到私有仓库,运行时只暴露 80 或 443 端口,配置文件只读挂载,日志输出到标准输出,容器使用明确版本标签,宿主机监控 Docker daemon、磁盘和容器状态。这个样板不复杂,但已经覆盖镜像、容器、仓库、网络、配置、日志和监控。
下一步可以把样板换成 API 服务。API 服务需要环境变量、健康检查、数据库连接、资源限制和回滚策略。再下一步才是带状态服务,例如数据库或文件上传服务,此时必须引入数据卷、备份恢复和容量巡检。按这种顺序推进,团队能逐步理解 Docker 的边界,而不是一开始就把无状态、有状态、网络和安全问题混在一起。
这个样板也适合作为团队培训。让每个人完成同样的构建、运行、验证、删除、重建和回滚练习,比单纯讲概念更有效。Docker 的核心不是命令数量,而是能不能用一套一致的方法把应用从源码交付到可运行状态,并且在失败时知道如何恢复。
21. 概念文章的验收方式
学完 Docker 概念后,可以用一次小型复盘验收。先画出一条从源码到容器运行的链路:源码进入 Dockerfile,Dockerfile 构建镜像,镜像推送仓库,宿主机拉取镜像,容器启动时注入配置、网络和卷,日志进入采集系统,监控发现异常后可以回滚到上一镜像版本。画完后再逐项标出哪些内容属于镜像,哪些属于运行时,哪些属于宿主机,哪些属于外部平台。
如果一条链路里没有镜像标签、配置来源、数据位置、日志路径和回滚方法,就说明概念还没有落到交付。Docker 的价值不是让命令变短,而是让交付对象更清楚、验证方式更标准、失败恢复更可控。
这也是本系列后续文章的主线:安装解决运行入口,Dockerfile 解决镜像交付,网络解决访问边界,数据卷解决状态保存,Compose 解决多服务编排。每一步都不是孤立知识点,而是在补齐容器交付链路。
因此,判断一个人是否真正入门 Docker,不是看他记住多少命令,而是看他能否解释清楚镜像、容器、仓库、网络、卷、配置和日志之间的关系,并能在容器删除、主机重启、镜像升级时判断哪些状态会保留、哪些状态会丢失。
这些判断能力会直接决定后续排障效率和交付质量。
也会决定团队能否安全推广容器化,并持续复盘改进落地执行闭环。
22. 总结
本文从零开始介绍了 Docker 的核心概念和基本原理:
- 容器是轻量级的进程隔离技术,通过 Namespace 和 Cgroup 实现
- 镜像是只读的打包规范,采用分层存储和写时复制机制
- 仓库是镜像的分发中心,Docker Hub 是最流行的公共仓库
- Docker 采用 C/S 架构,客户端通过 REST API 与守护进程通信
- OCI 标准保证了不同容器运行时之间的互操作性
核心要点:
- 容器共享宿主机内核,比虚拟机更轻量、启动更快
- 镜像分层存储,多个镜像可共享基础层
- 容器运行态在镜像层之上叠加可写层,修改不持久
- 数据持久化需要使用 Volume 或 Bind Mount
- Docker 是 OCI 标准的推动者和主要实现者
下篇预告: Docker 容器化实战 02 — 将详细介绍 Docker 在各平台的安装方法、容器生命周期管理命令,以及常见的开发环境配置。
参考资料
- Docker 官方文档
- OCI 容器运行时规范
- Docker: Lightweight Linux Containers for Consistent Development and Deployment
- Understanding the Docker Internals
- Linux Namespace 文档
- cgroups(v2) 文档
- [验证环境:Ubuntu 22.04 / Docker 26.0.0 / Linux Kernel 6.5 / 2026-05-17]