在云原生时代,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]