Docker01-入门与生态
Docker 入门与生态:从概念到选型
目录
- 为什么要学 Docker
- Docker 是什么:从容器到平台
- 镜像与容器:Docker 的两个核心对象
- 端口映射:让外部访问到容器
- 数据卷:容器重启数据不丢
- Docker 与虚拟机的本质区别
- Docker 生态全景:Engine / CLI / Compose / Hub / Desktop
- Docker 能做什么:典型应用场景
- 学 Docker 的价值与前置基础
- 总结
- 参考资料
0. 为什么要学 Docker
0.1 一个经典痛点:环境不一致
几乎每个开发者都遇到过这样的对话:
「在我电脑上明明能跑,怎么到了服务器上就报错?」
问题的根源是环境不一致:代码运行依赖操作系统版本、运行库、依赖包、配置文件、环境变量……这些在你的开发机、同事的机器、测试服务器、生产服务器上不可能完全一样。一个依赖版本差异,就可能让程序行为彻底改变。
Docker 正是为了解决这个问题而生。
0.2 Docker 的答案:把环境和应用一起打包
Docker 的思路很直接:把应用以及它运行所需的一切——操作系统基础层、运行时、依赖库、配置文件——打包进一个标准化的「镜像」(Image)。这个镜像是自包含、不可变、可复制的。任何一台装有 Docker 的机器,只要基于这个镜像运行一个「容器」(Container),就能得到和当初构建时完全一致的环境。
一句话:镜像 = 应用 + 完整运行环境(一次打包),容器 = 这份环境的可运行实例(处处运行)。
0.3 为什么值得系统学 Docker
- 生态事实标准:K8s、CI/CD、微服务、云原生教程,几乎都以 Docker 为默认语言;社区里绝大多数资料、示例都是 docker 命令。
- 镜像生态:Docker Hub 是最大的容器镜像仓库,nginx、mysql、redis、python 等海量官方镜像都从这里分发。
- 工具链完整:Docker 有构建(build)、分发(push/pull)、运行(run)、编排(compose)的全套工具链。
- 可移植:一份镜像,开发/测试/生产处处运行,是「一次构建,到处运行」的现代实践。
0.4 阅读前提
- 熟悉 Linux 命令行(cd、ls、sudo、systemctl);
- 会用文本编辑器编辑文件;
- 有一点 YAML 语法概念(后续 Compose 篇需要);
- 有一台可以动手的 Rocky Linux 或 RHEL 9 测试机(建议虚拟机)。
如果你还没有任何容器基础也没关系——这一篇从零讲清楚核心概念,不需要前置容器知识。
一、Docker 是什么:从容器到平台
1.1 Docker 的起源与定位
Docker 是 2013 年由 Solomon Hykes 在 dotCloud 公司内部发起的开源项目,2013 年 3 月在 PyCon 上首次公开。它最初就是为了解决「环境不一致」这个应用交付的顽疾。
此后 Docker 迅速发展成整个云原生生态的基石技术。如今 Docker 已经远不止一个「容器运行时」,而是一个完整的容器平台,涵盖:
- 构建(build):用 Dockerfile 描述并构建镜像;
- 分发(ship):把镜像推送到仓库、从仓库拉取;
- 运行(run):把镜像实例化为容器运行;
- 编排(orchestrate):用 Compose / Swarm / K8s 管理多个容器。
1.2 Docker 的组成部分
一个完整的 Docker 平台由以下组件构成:
| 组件 | 作用 | 通俗类比 |
|---|---|---|
| Docker Engine | 核心守护进程 dockerd,管理镜像、容器、网络、卷 | 操作系统的内核 |
| docker CLI | 命令行客户端,给 Engine 下命令 | 操作系统的 shell |
| Dockerfile | 描述如何构建镜像的脚本 | 安装/构建脚本 |
| 镜像(Image) | 只读模板,容器由它实例化 | 操作系统的安装镜像 |
| 容器(Container) | 镜像的运行实例,可写 | 运行中的系统 |
| 镜像仓库(Registry) | 存储和分发镜像(Docker Hub 是最大的公共仓库) | 应用商店 / 软件源 |
| Docker Compose | 用 YAML 定义并运行多容器应用 | 一键启动整套服务的编排脚本 |
1.3 一次完整的「镜像到容器」流程
在装好 Docker 的机器上(第 2 篇讲安装),一条命令就能把 nginx 跑起来:
docker run -d --name web -p 8080:80 nginx:1.25
命令拆解:
- docker run:运行容器;
- -d:后台运行(detach),否则会占用当前终端;
- --name web:给容器命名,方便后续管理;
- -p 8080:80:把宿主机 8080 端口映射到容器 80 端口;
- nginx:1.25:要运行的镜像,格式是「仓库名:标签」;
- 如果本机没有这个镜像,Docker 会先从仓库拉取,再基于它创建并启动容器。
运行后浏览器访问 http://本机IP:8080 就能看到 nginx 默认页面。
这个例子里已经包含了 Docker 的三个基本动作:拉取镜像(pull)、运行容器(run)、端口映射(-p)。下面几节我们把每个概念单独讲透。
1.4 Docker 与 Podman、RHEL 的现实
学习 Docker 时,Linux 使用者尤其是 RHEL/Rocky 用户经常会遇到一个困惑:为什么 RHEL 上 dnf install docker 会提示找不到这个包? 这里把背景讲清楚。
Podman 是 Red Hat 主导的开源容器引擎,在设计上完全兼容 Docker CLI——大多数情况下把命令里的 docker 直接换成 podman 就能用。它与 Docker 在架构上有根本差异:
- Docker Engine 是「守护进程 + 客户端」架构:docker 客户端把命令发给常驻守护进程 dockerd,由它拉镜像、启容器;
- Podman 是「无守护进程」(daemonless)架构:podman 命令直接以独立进程方式工作,不需要常驻守护进程,更轻量、更安全。
关键的现实是:从 RHEL 8 开始,Red Hat 官方仓库不再提供 docker 软件包,官方主推 Podman、Buildah、Skopeo 这套容器方案。这对你的影响是:
- 在 RHEL/Rocky 上装 Docker Engine,不能 dnf install docker,必须用 Docker 官方仓库(或国内镜像源如阿里云)添加软件源后再装(第 2 篇给出精确步骤);
- 这个 docker 包装上后不受 Red Hat 官方支持,出问题要自己到 Docker 社区或厂商求助;
- 纯 RHEL 生产环境,Red Hat 更希望你用 Podman;但 Docker 的技能和概念完全通用,两者命令几乎互通。
一句话总结现实:概念与命令通用,安装路径不同。这是 RHEL 系与 Ubuntu/Debian 系在容器工具上最大的区别之一(Debian 系同样要加 Docker 官方源,但 Docker 官方对 Ubuntu 的支持和文档更充分)。
对学习者而言这不是「二选一」:学 Docker(教程、镜像、K8s 生态都以它为基准),纯 RHEL 生产用 Podman(官方支持、更契合 SELinux/rootless)。本系列以 Docker 为主线,并在关键处点明与 Podman 的差异。
二、镜像与容器:Docker 的两个核心对象
镜像和容器是 Docker 里最重要的两个概念,几乎所有操作都围绕它们展开。这一节把两者的关系、内部结构彻底讲清楚。
2.1 镜像(Image):只读的模板
镜像是一个只读的、分层的文件系统模板,它打包了运行某个应用所需的全部内容:操作系统基础层、运行时、依赖、应用代码、配置、环境变量等。
你可以把镜像理解成一种「类」(面向对象里的 class):它是蓝图/模板本身,只读、不可修改,本身不能「运行」。
镜像有几个关键特性:
- 只读:镜像一旦构建完成,内容不可变(要改只能重新构建新镜像);
- 分层:镜像由多个「层」(layer)叠加而成,每个层对应 Dockerfile 里的一条构建指令;
- 可复用:多个镜像可以共享相同的底层,节省磁盘空间、加快拉取;
- 不可变:正因为只读,所以能保证「同一份镜像,处处行为一致」。
镜像的分层结构(层 layer / UnionFS)
这是理解 Docker 的关键。一个镜像从底到顶由若干层组成,例如一个 nginx 镜像可能是:
第3层 CMD [nginx, -g, daemon off;] <- 顶部
第2层 COPY nginx.conf /etc/nginx/ <- 配置
第1层 apt-get install -y nginx <- 安装 nginx
第0层 debian:bookworm-slim <- 基础层(Linux 发行版)
这些层通过 UnionFS(联合文件系统) 叠加成一个统一的、看起来完整的文件系统。不同的镜像如果共用相同的底层,这些底层只存一份,这是 Docker 能高效存储和分发的根本原因。
类比:镜像分层就像「图层」。基础层是画布,往上每一层叠一部分内容。多个不同的画作可以共用同一块画布,不必每个人重新画一遍底色。
2.2 容器(Container):可写的运行实例
容器是镜像的运行实例。基于一个镜像可以启动任意多个容器,每个容器:
- 拥有一个可写层:容器启动时,Docker 在只读镜像之上叠加一层可写层,容器内的所有修改(写入文件、装软件)都发生在这层;
- 有自己独立的命名空间(namespace):进程、网络、挂载点、PID、用户等都是隔离的,容器看起来像一台独立的小机器;
- 受 cgroups 资源限制约束:可以限制 CPU、内存等用量。
你可以把容器理解成**「对象」**(面向对象里的 instance):它是基于模板(镜像)创建的具体实例,有状态、可运行、可被删除。
镜像(只读模板)
+----------------------+
| CMD 层 |
| COPY 层 |
| 安装层 |
| 基础层 |
+----------------------+
| docker run(实例化)
v
容器(可写运行实例)
+----------------------+
| 可写层(运行时的修改)| <- 容器独有,删除容器即丢失
+----------------------+
| CMD 层(只读) |
| COPY 层(只读) |
| 安装层(只读) |
| 基础层(只读) |
+----------------------+
2.3 镜像与容器的一目了然对比
| 特性 | 镜像(Image) | 容器(Container) |
|---|---|---|
| 可读性 | 只读 | 可写(有可写层) |
| 是否可运行 | 否(是模板) | 是(运行实例) |
| 生命周期 | 静态存在,构建后不变 | 动态,可启动/停止/删除 |
| 数量关系 | 一个镜像 | 可创建多个容器 |
| 类比 | 类 / 安装镜像 / 蓝图 | 对象 / 运行中的系统 / 房子 |
| 数据 | 镜像层数据永久保存 | 可写层数据在容器删除时丢失 |
最容易混淆的一点:容器删除后,容器可写层里的数据就全部丢失了。这就是为什么我们需要「数据卷」(见第 4 节)来持久化重要数据。
2.4 镜像的命名与标签
镜像名通常形如 nginx:1.25,格式为「仓库名:标签」:
- 仓库名:标识是哪个镜像,如 nginx、mysql;
- 标签(tag):标识版本,如 1.25、latest;
- 不写标签时默认 latest(但不建议生产环境依赖 latest,因为它会变)。
如果是私有或指定命名空间的镜像,形如 user/myapp:v1.0、registry.example.com/app/web:2.0(带仓库地址)。
三、端口映射:让外部访问到容器
3.1 问题:容器里的服务外部访问不到
容器运行在自己的网络命名空间里,有自己的 IP。但容器的 IP 是 Docker 分配的私有内部地址,宿主机的局域网/公网用户是访问不到的。要让外部访问容器里的服务,必须做端口映射。
3.2 用 -p 做端口映射
docker run -d --name web -p 8080:80 nginx:1.25
-p 8080:80 的含义是:宿主机的 8080 端口 → 容器的 80 端口。即访问 宿主机IP:8080 的流量,会被转发到容器的 80 端口上。
格式是 -p 宿主机端口:容器端口:
# 宿主机 9090 -> 容器 80
docker run -d --name web2 -p 9090:80 nginx:1.25
# 只指定容器端口(宿主机自动分配随机高位端口)
docker run -d --name web3 -p 80 nginx:1.25
# 指定 IP + 端口(只在本机某 IP 上暴露)
docker run -d --name web4 -p 127.0.0.1:8080:80 nginx:1.25
3.3 端口映射是怎么工作的
Docker 的端口映射借助宿主机的 iptables / firewalld 规则实现。当你用 -p 8080:80 时,Docker 在宿主机上添加了一条 NAT 规则:把发往宿主机 8080 端口的包,DNAT(目的地址转换)转发到容器的 80 端口。
外部访问 宿主机:8080
|
v
宿主机 iptables NAT
| DNAT 到容器
v
容器 80 端口 -> nginx
用 docker port <容器名> 可以查看某个容器的端口映射情况。如果宿主机开了防火墙,要确保对应端口放行(或用 firewalld 允许),否则外部仍访问不到。
3.4 端口冲突与注意点
- 同一宿主机的宿主机端口不能重复(8080 被一个容器占用后,另一个容器不能再用 8080);
- 容器端口可以相同(不同容器内部都用 80 没问题),只要宿主机端口不冲突;
- 生产环境要把端口规划好,或用反向代理统一入口,避免每个容器都暴露一个端口。
四、数据卷:容器重启数据不丢
4.1 容器文件系统的「易失性」问题
容器可写层的生命周期和容器绑定:容器删除,可写层里的数据随之消失。想象一下,如果一个数据库跑在容器里,直接把数据写在容器可写层,那么一旦容器被删(或重建),数据就全没了——这是灾难性的。
解决办法就是数据卷(Volume)。
4.2 什么是数据卷
数据卷是独立于容器生命周期的一块存储空间,由 Docker 管理,挂载(mount)进容器使用。卷里的数据在容器删除后仍然保留,可以再挂到新容器上。
用 -v 挂载数据卷:
# 把命名卷 mydata 挂载到容器的 /data 目录
docker run -d --name app -v mydata:/data someimage
# 把宿主机目录 /home/user/data 挂载到容器的 /data(绑定挂载)
docker run -d --name app -v /home/user/data:/data someimage
4.3 三种数据持久化方式
Docker 提供三种数据存储方式,用途不同:
| 方式 | 挂载格式 | 说明 | 适用场景 |
|---|---|---|---|
| 命名卷(named volume) | 卷名:/容器路径 | Docker 管理,位置在 /var/lib/docker/volumes/ | 推荐用于正式数据,如数据库 |
| 绑定挂载(bind mount) | 宿主机绝对路径:/容器路径 | 直接映射宿主机路径 | 开发时映射源码、配置文件 |
| tmpfs 挂载 | --tmpfs /容器路径 | 数据存内存,不落盘 | 临时数据、敏感缓存 |
4.4 为什么要用卷而不是直接把数据写在容器里
- 持久化:容器删了数据还在;
- 共享:多个容器可以挂同一个卷,数据互通;
- 备份迁移:卷可以整体备份、复制、迁移;
- 性能:数据库等高频写入场景,把数据放到卷(尤其绑定宿主机磁盘)通常比写在容器可写层更合适。
五、Docker 与虚拟机的本质区别
5.1 共享内核 vs 独立内核
要理解容器,必须分清它和虚拟机的本质差别。两者都用于「隔离」和「打包运行环境」,但隔离的层次完全不一样:
- 虚拟机(VM):通过 Hypervisor(如 KVM、VirtualBox)虚拟化出一整套硬件,每个 VM 里跑一个完整的操作系统,拥有自己独立的内核。
- 容器(Container):共享宿主机的操作系统内核,只隔离用户空间(进程、文件系统、网络、PID 等 namespace),并通过 cgroups 限制资源。
虚拟机(每个 VM 独立内核) 容器(共享宿主内核)
+----------+ +----------+ +-----+ +-----+
| App | | App | | App | | App |
| Guest OS | | Guest OS | | libs| | libs|
| 内核 | | 内核 | +--+--+ +--+--+
+----+-----+ +----+-----+ |共享内核|
| Hypervisor | +--+--+
+-----+------+ +--+----+
| | 宿主机内核 |
宿主机硬件 +---------+
5.2 对比表
| 特性 | 虚拟机(VM) | 容器(Container) |
|---|---|---|
| 内核 | 每个 VM 独立内核 | 共享宿主机内核 |
| 启动速度 | 分钟级 | 秒级 |
| 资源占用 | 大(整套 Guest OS) | 小(只有应用及依赖) |
| 隔离强度 | 强(硬件级) | 相对弱(进程级) |
| 镜像体积 | GB 级 | MB 到数百 MB |
| 单机密度 | 一台几十个 | 一台成百上千个 |
| 适用 | 强隔离、不同内核需求 | 微服务、CI/CD、快速伸缩 |
5.3 两者常常配合使用
生产实践里两者并非「非此即彼」,而是常常搭配:在一台虚拟机(提供强隔离)里跑多个容器(提供高密度)。K8s 集群的 node 节点,就是虚拟机或物理机上再跑容器。虚拟机的隔离 + 容器的密度,两者结合才是云原生的常态。
5.4 各有什么短板
- 虚拟机的短板:重、慢、资源浪费(每个 VM 一套系统)。
- 容器的短板:共享内核意味着不能跑需要不同内核的应用(如不能在 Linux 上直接跑 Windows);隔离相对弱,容器逃逸风险是安全关注点。
六、Docker 生态全景:Engine / CLI / Compose / Hub / Desktop
6.1 Docker Engine 与 docker CLI
Docker Engine 是 Docker 的核心守护进程 dockerd,配合底层的 containerd、runc 等,负责真正地管理镜像、容器、网络、卷。它监听来自客户端的请求。
docker CLI 是用户与之交互的命令行工具。装完 Docker 你会得到:
- dockerd:守护进程(systemd 服务);
- docker:命令行客户端;
- containerd:底层容器运行时;
- docker compose:多容器编排插件(新版随 Docker 安装)。
6.2 Docker Hub 与镜像仓库
Docker Hub 是 Docker 官方的公共镜像仓库,全球最大的容器镜像社区,可理解为「容器界的 GitHub / 应用商店」:
- docker pull nginx 拉取公共镜像;
- 注册后可 docker push 上传自己的镜像;
- 企业内部可搭建私有仓库(如 Harbor、Registry)。
中国大陆直接访问 Docker Hub 可能很慢,常用解法是配置国内镜像加速器(阿里云、DaoCloud 等)。
6.3 Docker Compose
单条 docker run 只能管理单个容器。真实应用往往是多个容器协作(Web + 数据库 + 缓存)。Docker Compose 用一份 YAML 文件把这些容器、网络、卷一次性定义,docker compose up 一键拉起。
6.4 Docker Desktop
Docker Desktop 是面向 macOS/Windows 的图形化 Docker 发行版,自带图形界面和内置 K8s,适合本机开发。
需注意它的授权:2024 年后授权放宽,个人以及员工少于 250 人、年营收低于 1000 万美元的公司可免费使用(Docker Personal 订阅);超过阈值商用需购买订阅。
对服务器运维而言,本系列以 Linux 上的 Docker Engine 为主,Docker Desktop 是开发机便利工具,了解即可。
6.5 生态全景图
用户 / 开发者 / 运维
| docker CLI
v
+-------------------------+
| Docker Engine | 管理镜像/容器/网络/卷
+--------+----------------+
|
+------+------+----------+-------------+
v v v v
镜像 容器 网络 卷
(Image) (Container) (Network) (Volume)
| | | |
+------+------+----------+------+------+
v v
镜像仓库 编排工具
(Hub/Registry) (Compose / Swarm / K8s)
七、Docker 能做什么:典型应用场景
7.1 环境标准化与可移植
一份镜像,处处运行。开发、测试、生产用同一个镜像,消除「本地能跑、线上挂」的经典问题。
7.2 微服务架构
把单体应用拆成多个小服务,每个服务打包成独立容器,独立部署、独立伸缩、独立更新。这是 K8s 流行的基石。
7.3 CI/CD 流水线
持续集成/持续交付里,Docker 提供一致的构建与测试环境:每次提交都基于相同镜像构建、跑测试,结果可复现。GitLab CI、Jenkins、GitHub Actions 都深度依赖容器。
7.4 快速部署与弹性伸缩
容器秒级启动,配合编排工具可快速扩缩容,应对流量波动。
7.5 与 Ansible、数据库运维的衔接
- 与 Ansible:用 Ansible 模块批量安装 Docker、启动容器、管理 Compose 服务,实现「基础设施即代码 + 应用编排」联动;
- 与数据库:MySQL/Redis/PostgreSQL 都有官方镜像,用容器跑数据库非常普遍,但要注重数据持久化(卷)与性能——第 4 篇深入讲。
八、学 Docker 的价值与前置基础
8.1 需要的基础
Linux 命令行、systemd 服务管理、简单 YAML 语法。这些在你已完成的中级 Ansible、Shell 篇里已经打好底。
九、总结
- Docker 解决的痛点是环境不一致,办法是「把应用和完整运行环境一起打包成镜像」;
- 镜像是只读、分层的模板;容器是镜像的可写运行实例;镜像分层 + 可写层是理解二者的关键;
- 端口映射(-p 宿主机端口:容器端口)让外部能访问容器内的服务;
- 数据卷让容器数据不随容器删除而丢失,是持久化的关键;
- 容器共享宿主机内核,与「独立内核」的虚拟机有本质区别,二者常配合使用;
- Docker 生态包括 Engine、CLI、Hub、Compose、Desktop,生产实践几乎必用 Compose;
参考资料
- Docker 官方文档(Get started):https://docs.docker.com/get-started/
- Docker 官方「镜像与容器」概念说明:https://docs.docker.com/get-started/docker-concepts/
- Docker Engine 安装(RHEL):https://docs.docker.com/engine/install/rhel/
- Docker Engine 安装(Ubuntu):https://docs.docker.com/engine/install/ubuntu/
- 阿里云开源镜像站 docker-ce:https://developer.aliyun.com/mirror/docker-ce
- Red Hat 官方:RHEL 中未提供 docker 包的说明:https://access.redhat.com/solutions/3696691
- Docker Desktop 许可协议:https://docs.docker.com/subscription/desktop-license/
