在云原生时代,Docker 已成为容器化部署的事实标准。无论你是开发、运维还是架构师,理解 Docker 的核心概念与底层机制,都是迈向 Kubernetes 与容器编排的第一步。本文将从环境搭建、架构原理到常用命令,为你构建一个完整的 Docker 知识框架。
一、环境准备与基础配置
在开始容器之旅前,我们需要先准备好 Docker 运行环境。以下操作基于 Ubuntu/Debian 系统,使用 apt 包管理器进行安装与配置。
1. 安装与卸载
安装 Docker 非常简单,只需几条命令即可完成。卸载时也需要彻底清理,避免残留文件影响后续使用。
sudo apt install docker.io
sudo apt-get purge docker.io
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
2. 自定义镜像加速
由于网络原因,直接从 Docker Hub 拉取镜像可能较慢。我们可以通过配置镜像加速器来提升下载速度。Linux 与 macOS 的配置文件位置不同,但格式一致。
{
"registry-mirrors": [
"https://hub.xdark.top",
"https://hub.littlediary.cn",
"https://dockerpull.org",
"https://hub.crdz.gq",
"https://docker.1panel.live",
"https://docker.unsee.tech",
"https://docker.udayun.com",
"https://docker.kejilion.pro",
"https://registry.dockermirror.com",
"https://docker.rainbond.cc",
"https://hub.geekery.cn",
"https://docker.1panelproxy.com",
"https://docker.linkedbus.com",
"https://docker.nastool.de"
]
}
配置完成后,需要重新加载守护进程使配置生效。
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo launchctl daemon-reload
sudo launchctl restart docker
3. 免 sudo 使用 Docker
默认情况下,执行 Docker 命令需要 sudo 权限。将当前用户加入 docker 组,可以免去每次输入 sudo 的麻烦。
sudo groupadd docker # 创建 docker 组(如果不存在)
sudo usermod -aG docker $USER
macOS 用户使用 Docker Desktop 则无需此操作,登录桌面应用后即可直接使用命令行工具。
docker run hello-world
二、镜像与容器:核心关系解析
镜像是模板,容器是实例。这是理解 Docker 的最关键概念。镜像定义了应用及其运行环境,容器则是镜像运行时的实体。你可以从同一个镜像创建多个互不干扰的容器。
docker run -it ubuntu bash # 用 ubuntu 镜像运行一个容器
docker run -it ubuntu bash # 再运行一个,还是独立的容器
⚠️ 值得注意的是:删除容器不会影响镜像;但删除镜像后,已创建的容器仍可运行(因为容器已有自己的可写层),只是无法再基于该镜像创建新容器。
镜像 (Image) ---> 容器 (Container)
只读层 + 可写层
模板 + 实例
三、Docker 的价值与边界
1. 解决了什么问题?
- ✅ 环境一致性:彻底解决“在我机器上能跑”的经典问题,开发、测试、生产环境完全统一。
- ✅ 资源隔离与限制:通过 cgroups 为每个容器分配 CPU、内存等资源,避免资源争抢。
- ✅ 快速扩展与弹性伸缩:容器秒级启动,配合 Kubernetes 等编排工具可实现自动扩缩容。
2. Docker 的局限
Docker 是容器化技术,遵循单一职责原则:一个容器只运行一个主进程。将多个进程塞进一个容器会带来诸多弊端,例如更新某个进程的镜像时其他进程被迫重启,一个进程崩溃可能导致整个容器挂掉。容器 = 应用 + 依赖执行环境,而非轻量虚拟机。
3. Docker 与虚拟机的区别
虚拟机需要为每个应用运行完整的 Guest OS,资源占用大、启动慢;而 Docker 容器共享宿主机内核,仅隔离应用环境,因此占用小、启动快、部署灵活。
传统虚拟机 (VM)
┌───────────────────────────────┐
│ 物理硬件 (Hardware) │
├───────────────────────────────┤
│ 主机操作系统 (Host OS)│
├───────────────────────────────┤
│ Hypervisor (虚拟机管理器) │
├───────────────┬───────────────┤
│ Guest OS │ Guest OS │ (每个虚拟机都有完整的操作系统)
│ Libraries │ Libraries │
│ App1 │ App2 │
└───────────────┴───────────────┘
Docker (容器)
┌───────────────────────────────┐
│ 物理硬件 (Hardware) │
├───────────────────────────────┤
│ 主机操作系统 (Host OS)│
├───────────────────────────────┤
│ Docker Engine │
├───────────────┬───────────────┤
│ Libraries │ Libraries │ (共享同一个内核,无需重复OS)
│ App1 │ App2 │
└───────────────┴───────────────┘
四、架构与底层原理
1. 基本架构
Docker 采用 C/S 架构,由客户端、守护进程、镜像、容器和仓库组成。下图展示了各组件之间的关系:
┌──────────────────────────┐
│ Docker Registry (注册中心) │
│ Docker Hub / 私有仓库 │
└───────────▲──────────────┘
│ pull/push 镜像
│
┌────────────────────────────┴───────────────────────────┐
│ Docker Host (主机) │
│ │
│ ┌───────────────┐ ┌─────────────────────────┐ │
│ │ Docker Client │─────▶│ Docker Daemon (守护进程) │ │
│ │ (CLI / API) │◀─────│ 接收命令,管理容器/镜像 │ │
│ └───────────────┘ └─────────────────────────┘ │
│ │ │
│ │ run/start/stop │
│ ▼ │
│ ┌────────────────┐ ┌─────────────────────┐ │
│ │ Image (镜像) │───▶ │ Container (容器) │ │
│ │ 只读模板 │ │ 镜像运行的实例,带状态 │ │
│ └────────────────┘ └─────────────────────┘ │
│ │
└────────────────────────────────────────────────────────┘
- 客户端 (Client):通过命令行或 SDK 与守护进程通信。
- 主机 (Host):运行守护进程和容器的物理或虚拟机器。
- 注册中心 (Registry):保存镜像的仓库,如 Docker Hub。
2. rootfs 与 Linux Namespace
rootfs 是容器启动时内部进程可见的根文件系统,包含 /dev、/proc、/bin 等目录及运行所需配置。
Namespace 是 Linux 内核提供的隔离机制,将进程置于独立的“虚拟环境”中。主要类型包括:
- PID Namespace:隔离进程号,容器内进程 PID 从 1 开始。
- NET Namespace:隔离网络协议栈,容器拥有独立 IP 和端口。
- IPC Namespace:隔离进程间通信。
- UTS Namespace:隔离主机名和域名。
- MNT Namespace:隔离文件系统挂载点。
- USER Namespace:隔离用户和用户组 ID,增强安全性。
我们可以通过实验直观感受 Namespace 的隔离效果:
docker pull ubuntu:22.04
#启动ubuntu容器
docker run -it --privileged ubuntu:22.04 /bin/bash
#-it:交互式终端。
#--privileged:允许容器访问更多 Linux 功能,比如命名空间。
#/bin/bash:进入 bash
# 这个时候命令行会变成:root@<container_id>:/#
#安装命令包
apt update
apt install -y util-linux
#然后就可以运行命令
lsns -p <PID>
#退出容器
exit
#直接退出之后,虽然镜像在,但是容器即这个实例没了,之前操作也没有了(默认是不删除的),所以最好保存一下(哪怕只是重命名好记一点)
docker run -it --name myubuntu --privileged ubuntu:22.04 /bin/bash
#以后启动:
docker start -ai myubuntu
# 重命名
docker rename quirky_sammet myubuntu
# 以后可以用:
docker start -ai myubuntu
#在其他终端还想连这个docker
docker exec -it myubuntu /bin/bash
lsns
# pid=1的命名空间
lsns -p 1
#查看符号连接
ls -l /proc/1/ns
ls -l /proc/$$/ns
# $$代表当前shell的pid
#获取容器内主进程id
docker inspect -f '{{.State.Pid}}' <容器ID或名字>
# 查看它命名空间
ls -l /proc/12345/ns
nsenter --target 12345 --pid --uts --net --mount
# (1)查看容器进程(宿主机 vs 容器)
# 宿主机看容器进程:
ps -ef | grep <容器名>
# 容器内看进程(PID 从 1 开始):
docker exec -it <容器> ps -ef
# (2) 网络隔离
# 查看容器网络接口:
docker exec -it <容器> ip addr
# 对比宿主机的:
ip addr
# (3) 挂载点隔离
# 容器里:
mount | head
# 宿主机:
mount | head
# 容器和宿主机看到的文件系统不同。
# (4) UTS 隔离(主机名)
# 宿主机:
hostname
# 容器:
docker exec -it <容器> hostname
# 不同容器有不同 hostname。
# (5) 用户隔离
# 容器里默认 root 其实是 容器内部的 root,和宿主机 root 不一样。
# 可以在容器里 id 查看:
docker exec -it <容器> id
3. cgroups:资源控制的核心
cgroups(Control Groups)是 Linux 内核的资源管理机制,将进程分组并限制其资源使用。主要子系统包括:
- cpu 子系统:限制 CPU 使用率,支持 CFS 配额(cpu.cfs_quota_us / cpu.cfs_period_us)和实时调度(cpu.rt_runtime_us / cpu.rt_period_us)。
- cpuset 子系统:绑定 CPU 核心和 NUMA 内存节点。
- cpuacct 子系统:统计 CPU 使用情况。
- memory 子系统:限制内存使用量,可设置 OOM 控制。
- blkio 子系统:控制块设备 I/O 带宽和 IOPS。
- devices 子系统:控制设备访问权限。
- freezer 子系统:挂起/恢复进程组。
- net_cls / net_prio 子系统:网络流量分类与优先级控制。
以下为各子系统的配置示例:
# 限制某个容器只能用50%cpu
# 创建一个cgroup
# 注意到在这么深的文件夹内新建,因为这是内核挂载的cgroup虚拟文件系统
mkdir /sys/fs/cgroup/cpu/mygroup
# 限制周期100ms
echo 100000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_period_us
# 限制配额50ms -> 50%
echo 50000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us
# 把进程 12345 加入这个 cgroup
echo 12345 > /sys/fs/cgroup/cpu/mygroup/cgroup.procs
mkdir /sys/fs/cgroup/cpuset/myset
echo 0-1 > /sys/fs/cgroup/cpuset/myset/cpuset.cpus
echo 0 > /sys/fs/cgroup/cpuset/myset/cpuset.mems
echo 12345 > /sys/fs/cgroup/cpuset/myset/cgroup.procs
cat /sys/fs/cgroup/cpuacct/mygroup/cpuacct.usage
cat /sys/fs/cgroup/cpuacct/mygroup/cpuacct.stat
mkdir /sys/fs/cgroup/memory/mygroup
echo 200M > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes
echo 12345 > /sys/fs/cgroup/memory/mygroup/cgroup.procs
echo "8:0 1048576" > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device
echo "c 1:3 rwm" > /sys/fs/cgroup/devices/mygroup/devices.allow
echo FROZEN > /sys/fs/cgroup/freezer/mygroup/freezer.state
echo 0x10001 > /sys/fs/cgroup/net_cls/mygroup/net_cls.classid
echo "eth0 5" > /sys/fs/cgroup/net_prio/mygroup/net_prio.ifpriomap
下表总结了各子系统的主要功能:
| 子系统 | 功能 | 例子/应用场景 |
|---|---|---|
| cpu | 限制 CPU 使用率 | 限制容器只能用 50% CPU |
| cpuset | 绑定 CPU/内存节点 | 数据库绑核 |
| cpuacct | 统计 CPU 使用 | 监控/计费 |
| memory | 限制内存 | 防止 OOM |
| blkio | 限制磁盘 IO | 防止容器拖慢磁盘 |
| devices | 控制设备访问 | 禁止容器访问宿主硬盘 |
| freezer | 挂起/恢复进程 | docker pause |
| net_cls | 打标签,配合 tc 做流量控制 | QoS |
| net_prio | 设置网络优先级 | 关键服务优先 |
五、常用命令速查
掌握以下命令,你就能熟练操作 Docker 了。建议收藏本文,随时查阅。
1. 环境信息
docker info
docker version
2. 系统日志
docker events : 从服务器获取实时事件
# OPTIONS说明:
# -f :根据条件过滤事件;
# --since :从指定的时间戳后显示所有事件;
# --until :流水时间显示到指定的时间为止;
# //第一个终端执行
# docker events
# //第二个终端操作容器
# docker start/stop/restart
# //查看第一个终端输出
# 获取容器日志
docker logs
# 查看指定镜像的创建历史
docker history
3. 容器生命周期
# 创建一个新容器但是不启动
docker create
# 创建一个新的容器并运行一个命令
docker run
#启动一个或多个已经被停止的容器
docker start
# 停止一个运行中的容器(发送信号给主进程,可能造成数据未保存)
docker stop
# 重启容器
docker restart
# 杀掉一个运行中的容器(容器马上退出,可能造成数据没保存)
docker kill
# 删除一个或多个容器。
docker rm
# 暂停容器中所有的进程。
docker pause
# 恢复容器中所有的进程
docker unpause
4. 运维操作
# 在运行的容器中执行命令
docker exec
# 列出容器
docker ps
# 获取容器/镜像的元数据
docker inspect
# 查看容器中运行的进程信息
docker top
# 连接到正在运行中的容器
docker attach
# 阻塞运行直到容器停止,然后打印出它的退出代码
docker wait
# 将文件系统作为一个tar归档文件导出到STDOUT
docker export
# 用于容器和主机之间的数据拷贝
docker cp
# 检查容器里面文件结构的更改
docker diff
# 重命名
docker rename
# 查看状态
docker stats
# docker update 命令用于 动态修改已经运行的容器的资源限制,不需要重新创建容器
docker update
5. 镜像管理
# 命令用于使用 Dockerfile 创建镜像
docker build
# 列出本地镜像
docker images
# 删除本地一个或多个镜像
docker rmi
# 标记本地镜像,将其归入某一仓库
docker tag
# 将指定镜像保存成 tar 归档文件
docker save
# 导入使用 docker save 命令导出的镜像
docker load
# 从归档文件中创建镜像
docker import
# 从容器创建一个新的镜像
docker commit
6. 镜像仓库
#登陆/登出到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub
docker login/logout
# 从镜像仓库中拉取或者更新指定镜像
docker pull
# 将本地的镜像上传到镜像仓库,要先登陆到镜像仓库
docker push
# 从Docker Hub查找镜像
docker search
结语
Docker 以轻量级容器化技术解决了环境一致性与资源隔离问题,是微服务和 Kubernetes 的基石。理解镜像与容器的关系、Namespace 与 cgroups 的底层机制,能帮助你更高效地进行容器化部署与容器编排。希望本文能为你构建扎实的 Docker 知识体系,在云原生之路上走得更远。
[AFFILIATE_SLOT_1] [AFFILIATE_SLOT_2]
浙公网安备 33010602011771号