外观
项目 1:Docker 核心架构剖析与环境安装
约 3745 字大约 12 分钟
DockerUbuntuDocker Engine虚拟化
2026-05-21
项目目标
欢迎来到《容器技术与应用》的第一课。在本节课中,我们将打破仅仅“敲命令安装软件”的表面学习方式,深入到操作系统的底层。我们将对比传统虚拟化与容器化的本质区别,剖析 Linux Namespace 和 Cgroups 隔离技术,最终在 Ubuntu 系统上完成 Docker Engine 的安装与配置。
通过本节课的“理论 -> 实践 -> 理论 -> 实践 -> 进阶任务”的穿插学习,你不仅能搭建起完美的实验环境,更能彻底搞懂你刚刚装进电脑里的到底是个什么“怪物”。
一、为什么我们需要 Docker?
在开始敲击任何代码之前,我们必须先弄清楚软件工程界长久以来的一个痛点。
1. 软件工程的百年难题:“在我的电脑上是好的啊!”
想象一下,你是一名开发人员,在自己的 Windows 电脑上花了一周时间写好了一个基于 Python 3.8、需要连接 MySQL 8.0 并且依赖各种特定版本 C++ 运行库的复杂系统。测试完美,你把代码打包交给了运维人员。 运维人员把代码放到公司的 Linux 服务器上运行,结果满屏报错:“找不到库”、“版本不兼容”、“端口被占用”……
这种现象在业界非常普遍。其核心原因在于:代码运行依赖于它所处的“环境”。 环境包含了操作系统版本、底层依赖库、环境变量配置文件等等。当开发环境、测试环境和生产环境不一致时,代码必然会崩溃。
2. 传统解法:沉重的虚拟机 (Virtual Machine)
为了解决“环境不一致”的问题,IT 行业早期发明了硬件级虚拟化技术(如 VMware、VirtualBox、KVM)。 虚拟机的逻辑很简单且暴力:既然环境不一致,那我就在服务器内部,用软件虚拟出一套完整的硬件(CPU、内存、硬盘),然后在上面安装一个完完整整的 Guest OS(访客操作系统),最后把应用程序放进去跑。
这种方式完美解决了环境隔离的问题,但带来了不可忽视的巨大代价:
- 资源浪费极高:哪怕你只想运行一个仅有 10MB 的网页服务器,你也必须先给它分配几个 GB 的内存来运行一个完整的 Linux 操作系统。
- 启动慢如蜗牛:每次启动应用,都必须经历一次完整的操作系统开机过程(几秒到几分钟不等)。
3. 革命性解法:轻灵的容器 (Container)
针对虚拟机的痛点,Google 等科技巨头开始大规模使用容器化(Containerization)技术。Docker 并不是容器的唯一实现,但它是目前最成功、最普及的。
容器的本质是“操作系统层面的虚拟化”。它放弃了模拟底层硬件,也不再安装 Guest OS。所有的容器都直接共享宿主机(Host OS)的内核。
既然共享了内核,那么不同的容器之间怎么保证不互相干扰呢?这得益于 Linux 内核提供的两大上古神器:
- Namespace(命名空间):负责“隔离”。它可以让每个容器以为自己拥有独立的进程树、网络接口、挂载点等。在容器 A 看来,自己是系统中唯一的程序,它根本看不见容器 B。
- Cgroups(控制组):负责“限制”。如果不加限制,一个死循环的容器可能会耗尽整个宿主机的 CPU。Cgroups 可以严格限制某个容器最多只能使用 20% 的 CPU 和 500MB 的内存。
正因为没有了冗余的 Guest OS 层,容器展现出了惊人的优势:
- 极致轻量:一个容器的体积通常只有几十 MB 甚至几 MB。
- 闪电启动:启动容器本质上只是启动一个被隔离的普通进程,耗时通常在毫秒级。
👇 你可以通过下方的交互式动画,亲自对比一下虚拟机(加载 Guest OS)与容器(共享内核)在启动速度和层级厚度上的夸张差异:
🚀 虚拟化 vs 容器化 启动对比
点击下方按钮,直观感受两者的层级结构与启动速度差异
传统虚拟机 (Virtual Machine)
服务器硬件 (Server)
宿主机操作系统 (Host OS)
Hypervisor (如 VMware/KVM)
访客操作系统 (Guest OS)
Bins/Libs (依赖库)
应用程序 A
VS
Docker 容器 (Container)
服务器硬件 (Server)
宿主机操作系统 (Host OS)
Docker Engine (容器引擎)
🚀 直接共享宿主机内核,无需 Guest OS!
Bins/Libs (依赖库)
应用程序 A
二、在 Ubuntu 上安装 Docker Engine
理解了容器为什么轻巧之后,我们开始在操作系统中真正部署它。Docker 官方推荐在 Linux 环境下运行(因为底层依赖 Linux Namespace),我们本次实验采用 Ubuntu 操作系统。
1. 准备基础环境与软件源
因为 Ubuntu 官方自带的软件源中,Docker 版本通常比较老旧,所以业界标准做法是添加 Docker 官方的源来安装最新的 Engine。
首先,更新本地软件列表并安装必要的依赖,让系统支持通过 HTTPS 获取软件仓库:
sudo apt update
sudo apt install -y ca-certificates curl gnupg lsb-release接下来是关键的软件源配置。为了确保你理解我们是在哪种操作系统上进行配置,请结合上下文,在下方的解锁框中输入该操作系统的英文名称以获取配置命令:
问题:根据上面的阅读,本次实验使用的操作系统名称是什么?(全小写,6个字母)
2. 开始安装核心组件
在添加了官方源之后,我们就可以执行安装命令了:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin💡 核心概念点拨:注意看上面的安装列表,你其实并不是只装了一个叫做 docker 的软件,你其实安装了一个组件集群:
docker-ce:Docker 引擎的核心守护进程(Daemon)。docker-ce-cli:平时我们在终端敲击docker run等命令时,使用的就是这个命令行客户端工具。containerd.io:这是真正负责调用 Linux Namespace 和 Cgroups 去创建和运行底层容器的“工业级容器运行时”。
安装完成后,输入以下命令检查版本以确认安装成功:
docker --version三、Docker 的 C/S 架构剖析
我们在第二步安装时提到了 docker-ce (守护进程) 和 docker-ce-cli (客户端)。这引出了 Docker 最核心的架构模式:C/S (Client-Server) 架构。
很多初学者误以为,当你在终端敲下 docker run 的时候,是这个终端命令自己去硬盘上找文件、创建网络、启动进程的。这是完全错误的!
真正的流程是:
- Client (客户端):你敲击的
docker命令只是一个极轻量级的“发号施令者”。它甚至不需要和你运行 Docker 的服务器在同一台机器上! - REST API:客户端会将你的命令翻译成基于 HTTP 协议的 REST API 请求,然后发送出去。
- Daemon (守护进程):运行在后台的
dockerd进程(Server 端)接收到这个 HTTP 请求。所有的脏活累活——包括下载镜像、分配 IP 地址、配置防火墙规则、调用 Linux 内核启动进程,全都是由守护进程来完成的。 - Registry (镜像仓库):如果守护进程发现本地没有你要求的运行环境(比如你想跑一个 Nginx,但本地没下载过),它会自动连接到云端的 Docker Hub(或其他镜像中心),将所需的“集装箱环境包(镜像)”下载到本地。
👇 通过下方这个交互式动画,你可以直观地看到这三大组件是如何协同工作的:
Docker 架构交互演示
点击组件查看详情,或使用下方按钮控制指令流向
💻
Docker Client
REST API
Docker Host
⚙️
Docker Daemon (dockerd)
💿
Images
📦
Containers
Pull
☁️
Docker Hub / Registry
Docker Client (客户端)
你敲击的命令行工具(如 docker run, docker pull)。它主要负责解析命令,通过 REST API 发送给 Docker Daemon。
四、配置守护进程与权限管理
既然我们知道了 Daemon 才是真正干活的大脑,现在我们需要对这个大脑进行两项至关重要的配置调优。
1. 确保 Daemon 服务已启动
在 Linux 系统中,后台服务通常由 systemd 来管理。如果 Docker Daemon 没启动,你敲击任何 docker 命令都会报错,因为“电话打不通”。
请在下方的解锁框中输入负责系统服务管理的命令名称来继续:
问题:根据上面的阅读,Linux 中负责管理系统服务的指令是什么?(全小写,9个字母)
服务正常运行时,status 输出中应看到高亮的 active (running)。
2. 配置 Registry Mirror (镜像加速器)
在架构原理中我们学到,Daemon 会去远端下载镜像。默认情况下,它会连接远在美国的官方 Docker Hub。受制于物理网络带宽,下载往往极慢甚至中断。 因此,我们需要告诉 Daemon:“以后别去国外下载了,去我指定的国内镜像节点下载。”
为此,我们要修改 Daemon 的配置文件 daemon.json。
# 创建配置目录
sudo mkdir -p /etc/docker
# 写入配置
sudo tee /etc/docker/daemon.json <<'EOF'
{
"registry-mirrors": [
"https://<此处替换为老师提供的镜像加速地址>"
]
}
EOF
# 修改了 Daemon 的大脑配置,必须重启服务才能生效
sudo systemctl restart docker
# 验证配置是否成功注入大脑
docker info | grep -A 5 "Registry Mirrors"3. 配置普通用户的免 sudo 权限
现在,如果你不用 root 账号,而是以普通用户身份直接输入 docker ps,系统会无情地报错:permission denied while trying to connect to the Docker daemon socket。
为什么会拒绝访问? 还记得我们说的 C/S 架构吗?普通用户运行的 Client 想要给 root 用户运行的 Daemon 发送指令。在同一台机器上,它们默认通过一个叫做 /var/run/docker.sock 的 UNIX 套接字文件通信。为了系统安全,这个文件的默认权限是仅限 root 访问。所以普通用户发不出请求。
如何优雅地解决? 我们不需要给普通用户提权,只需要把当前用户加入到与套接字文件同名的一个特殊用户组中即可。这个特殊的用户组名字和我们的容器技术名字一样,它叫 docker。请在下方的解锁框中输入该用户组的名称以获取操作命令:
问题:根据上面的阅读,免 sudo 需要加入的用户组叫什么名字?(全小写,6个字母)
(注意:加组后需要退出终端并重新登录,或者执行 newgrp docker 才能立即生效。)
4. 终极验证:Hello-World
一切准备妥当,让我们运行 Docker 界的第一个程序:
docker run hello-world当你敲下这条命令时,电脑后台正快速地完成 Client -> Daemon -> Registry -> Container 的完整闭环。 👇 亲自体验并学习这 5 个关键步骤到底是如何运作的:
docker run hello-world 执行内幕
1
发送请求
2
检查镜像
3
拉取镜像
4
运行容器
5
容器退出
💻 Client 终端
$ docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
⚙️ Docker Daemon
💿
本地镜像缓存
📦
容器实例
☁️ Docker Hub
library/hello-world
点击“下一步”或“自动播放”查看执行过程。
五、进阶任务 (Advanced Task):脱掉客户端的伪装,直面 UNIX Socket
在理论篇中,我们反复强调:docker 命令仅仅是一个 REST API 客户端,它并没有什么魔法。 为了彻底印证这个理论,进阶任务要求你完全不使用任何以 docker 开头的命令,直接利用 Linux 上的 HTTP 抓取工具 curl,向 Docker Daemon 发送原始请求。
我们要绕过 docker info,直接向 Daemon 的 UNIX Socket 发出查询系统信息的指令。
任务步骤指引:
- 定位目标:在前面的理论部分我们学过,Daemon 在本地监听的特殊通信文件路径为
/var/run/docker.sock。 - 确定接口:我们要查询系统信息,对应的 REST API 接口路径为
/info。 - 选择武器:既然要抛弃官方的客户端来发送原生的网络请求,我们就需要一个支持各种协议的网络数据传输神器。在 Linux 的世界里,这个神器的大名叫做
curl(卷曲)。 - 组装发射:通过该工具的
--unix-socket参数,我们可以强制它不要走公网,而是钻进本地的套接字文件里。
请结合上述流程指引,在下方输入我们选用的那把“网络传输神器”的英文名称,来解锁验证指令:
问题:上述指引中提到用于发送原生网络请求的命令行神器叫什么?(全小写,4个字母)
成功解锁并执行后,你将看到屏幕上输出了成堆的、极其复杂的 JSON 字符串。 这些乱码一样的 JSON,就是 Docker Daemon 返回的最原始数据。平时你敲击 docker info 看到的整洁排版,不过是官方的 docker 客户端程序帮你把这段 JSON 解析、美化后再显示出来的罢了!
通过这个任务,你应该顿悟:既然它只是标准的 HTTP API,那就意味着你可以用 Python 发送 requests.get(),用 Java 写后端系统,甚至用前端页面写 AJAX,来直接管理宿主机上的所有容器,而完全不需要借助官方的那个黑色终端!这也正是市面上各种容器管理面板(如 Portainer)能够实现的核心基础。
六、故障排查与验收标准
常见故障排查手册
| 现象 | 可能的原因 | 排查方案 |
|---|---|---|
docker: command not found | 软件源未正确添加,或安装步骤被中断。 | 重新执行 sudo apt update 和 sudo apt install docker-ce。 |
Cannot connect to the Docker daemon | 后台 dockerd 进程未启动,或异常崩溃。 | 执行 sudo systemctl status docker 查看报错日志,通常是因为配置文件(如 daemon.json 语法错误)导致无法启动。 |
permission denied | 当前普通用户不在 docker 用户组中,且未加 sudo。 | 执行 groups 查看当前用户所属组。如果刚加进去,必须彻底登出 SSH 并重新连接。 |
| 镜像下载极慢或超时 | 默认连接了国外的 Docker Hub 服务器被墙。 | 检查 /etc/docker/daemon.json 中的 registry-mirrors 地址是否可用,修改后必须 restart docker。 |
本课验收清单
完成本课的学习和实验后,你应当能够:
