Docker学习笔记(一):容器基础、生态与安装实践
Docker
容器生态系统
容器技术
容器技术是轻量级操作系统级虚拟化技术,核心解决 “环境不一致” 与 “资源低效” 问题,让应用及依赖在任意环境一致运行,是云原生时代的核心基础设施。
核心本质:与传统虚拟机(VM)的关键差异
容器共享宿主机内核,仅隔离进程、网络等资源;VM 需模拟完整硬件与 OS,二者对比如下:
维度 | 容器 | 传统 VM |
---|---|---|
虚拟化层级 | 操作系统级(共享内核) | 硬件级(Hypervisor) |
启动时间 | 秒级 | 分钟级 |
资源开销 | 极低(MB 级镜像) | 较高(GB 级镜像) |
隔离强度 | 进程级(较弱) | 完全隔离(较强) |
三大核心组件
-
容器镜像:只读二进制 “模板”,包含应用、运行时、依赖(如
nginx:1.23
),可版本化,一个镜像可生成多个容器; -
容器引擎
:管理镜像与容器的工具,主流有:
- Docker(生态完善,适合开发 / 小型场景);
- containerd(轻量,K8s 默认运行时);
- Podman(无守护进程,更安全);
-
编排工具:管理大规模容器的 “大脑”,以Kubernetes(K8s)为标准,支持:
- 扩缩容、滚动更新、故障自愈;
- 服务发现(Service)、资源隔离(Namespace)、数据持久化(PV/PVC)。
核心优势与典型场景
优势
- 环境一致:消除 “开发 / 测试 / 生产环境差异”;
- 轻量高效:秒级启动,单服务器可运行数百容器;
- 弹性伸缩:结合 K8s 自动适配流量变化;
- 适配 DevOps:加速 “代码 - 镜像 - 部署” 迭代。
场景
- 微服务部署:拆分服务独立打包、运维;
- CI/CD 流程:代码提交后自动构建镜像、部署;
- 开发环境标准化:团队统一镜像,快速搭建环境;
- 多云 / 混合云:镜像跨云厂商兼容,避免锁定。
关键挑战与趋势
- 挑战:共享内核导致安全风险(需镜像扫描、最小权限控制);容器数据临时(需 PV/PVC 持久化);
- 趋势:Serverless 容器(免运维集群,按需付费);边缘容器(边缘设备 + 云协同);多架构支持(x86/ARM 通用镜像)。
总结
容器技术以 “轻量、一致、高效” 为核心,通过 “镜像 - 引擎 - 编排” 生态,支撑微服务、DevOps 等场景,是企业通向云原生的关键工具,掌握 Docker 与 K8s 是核心技能。
容器生态系统
对于容器这种平台级技术,相关知识、软件和解决方案往往错综复杂,容易陷入 “知识迷宫”,不知道该从哪儿学起。解决办法很简单 —— 就像去陌生城市旅游时,我们不会一落地就扎进小巷,而是先看地图:先搞清楚城市的整体位置和轮廓,再了解它分哪几个区,主要交通干道是什么。学习容器技术也一样,我们需要先 “从天上鸟瞰”,弄明白三件事:
- 容器生态里有哪些不同层次的技术?
- 这些技术之间是怎么配合的?
- 哪些是必须掌握的核心技术,哪些是辅助工具?
先建立整体认知,后续学习才能 “有的放矢”,分清重点和优先级,不会越学越乱。接下来我会结合自己的学习经验,梳理一条清晰的容器学习路线,带大家一步步探索容器生态。而且学习新技术最关键的是 “及时反馈”,所以我们很快就会动手搭建实验环境,跑起第一个容器,亲身感受容器到底是什么。
千里之行始于足下,咱们就从 “看懂容器生态地图” 开始吧!
鸟瞰容器生态:先搞懂核心框架
一提到容器,几乎所有人都会先想到 Docker。确实,是 Docker 把容器技术从 “技术圈小众工具” 变成了主流,但大家要知道:Docker 只是容器生态的 “基石”,真正支撑容器技术落地、健康发展的,是围绕它构建的完整生态系统。
如果把容器生态比作一座城市,那它可以清晰地分成三大 “功能区”:核心技术、平台技术和支持技术。今天我们先聚焦最基础的 “核心技术区”—— 也就是让容器能在电脑上跑起来的那些关键技术。
容器核心技术:支撑容器运行的 “基础设施”
容器核心技术的作用很明确:让容器能在主机操作系统(host OS)上正常启动、运行。具体又能分成 6 类,咱们一个个讲清楚:
容器规范:让不同容器 “能互通” 的 “通用语言”
容器不只有 Docker,还有 CoreOS 的 rkt、红帽的 Podman、containerd 等。如果每种容器都按自己的规则来,不同工具创建的容器就无法兼容,生态就乱了。
为了解决这个问题,Docker、CoreOS、Google 等公司联合成立了Open Container Initiative(OCI,开放容器倡议),核心任务就是制定 “开放的容器规范”。目前 OCI 主要发布了两个关键规范:
- runtime spec(运行时规范):定义容器怎么启动、运行、停止;
- image format spec(镜像格式规范):定义容器镜像的统一格式。
有了这两个规范,不管是 Docker、Podman 还是 rkt 创建的容器,都能在符合 OCI 标准的环境里运行 —— 就像大家都讲普通话,不同地区的人能顺畅沟通一样,保证了容器的 “可移植性”。
容器 Runtime:容器的 “运行舞台”
Runtime(运行时)是容器真正 “跑起来” 的地方,它需要和操作系统内核深度配合,为容器提供独立的运行环境。
如果用 Java 来类比就很好理解:Java 程序好比 “容器”,JVM(Java 虚拟机)好比 “Runtime”——Java 程序必须在 JVM 里才能运行,容器也必须在 Runtime 里才能启动。
目前主流的容器 Runtime 有 3 种:
- lxc:Linux 上的 “老牌 Runtime”,Docker 早期就是用它来运行容器的;
- runc:Docker 自己开发的 Runtime,完全符合 OCI 规范,现在是 Docker 的默认 Runtime;
- rkt:CoreOS 开发的 Runtime,同样符合 OCI 规范,所以能直接运行 Docker 创建的容器。
容器管理工具:用户操作容器的 “遥控器”
光有 Runtime 还不够,普通人没法直接和 Runtime 交互,得有个 “中间工具” 帮我们管理容器 —— 这就是容器管理工具。它对内和 Runtime 对接,对外给用户提供操作界面(比如命令行 CLI),就像我们用 “电视遥控器” 操作电视,而不用直接拆电视一样。
对应不同的 Runtime,有不同的管理工具:
- lxc 的管理工具是lxd;
- runc 的管理工具是Docker Engine(也就是我们常说的 “Docker”),它包含后台的守护进程(daemon)和命令行工具(CLI),平时用的
docker run
、docker build
等命令,就是通过 Docker Engine 发给 Runtime 的; - rkt 的管理工具是rkt cli,用法和 Docker CLI 类似,也是通过命令操作容器。
容器定义工具:给容器 “画图纸”
要创建容器,得先定义 “容器里有什么”“怎么配置”—— 这就需要容器定义工具,它能把容器的内容、属性固化下来,方便保存、共享和重复创建。
最常见的就是 Docker 的一套工具:
- Docker Image(镜像):相当于容器的 “模板”,Runtime 就是根据镜像来创建容器实例的;
- Dockerfile:一个包含多条命令的文本文件,我们通过编写 Dockerfile,就能一步步构建出 Docker 镜像。
另外,CoreOS 的 rkt 也有类似工具,叫ACI(App Container Image),作用和 Docker Image 一样,是 rkt 容器的 “模板格式”。
Registry:容器镜像的 “仓库”
容器是从镜像创建的,那么多镜像总不能散着放 ——Registry 就是专门存放镜像的 “仓库”,相当于镜像的 “云存储”。
常用的 Registry 分两种:
- 公共 Registry:所有人都能用,比如 Docker 官方的Docker Hub(https://hub.docker.com),上面有几十万现成的镜像(比如 Nginx、MySQL),拿过来就能用;还有Quay.io(https://quay.io/),也是常用的公共镜像仓库;
- 私有 Registry:企业或团队自己搭建的 “内部仓库”,用 Docker 官方提供的Docker Registry工具就能搭建,适合存放敏感的业务镜像(比如公司自己开发的应用镜像)。
容器 OS:专门跑容器的 “精简系统”
其实只要有容器 Runtime,大部分 Linux、macOS、Windows 系统都能运行容器。但为了让容器跑得更高效,就有了 “容器 OS”—— 专门为运行容器设计的操作系统。
和普通操作系统比,容器 OS 有三个特点:体积更小(去掉了很多用不上的组件)、启动更快、运行容器的效率更高。目前主流的容器 OS 有CoreOS、Atomic和Ubuntu Core,常用来搭建专门的容器服务器。
docker的安装
准备一台虚拟机
-
镜像选择:CentOS-Stream-8-20240603.0-x86_64-dvd1.iso
-
最小化安装
虚拟机模板:
1.配置基础yum源
2.关闭selinux
3.清除密钥信息
4.清除Machine ID
5.设置密码
下面就开始配置环境:
[root@localhost ~]# hostnamectl set-hostname docker
[root@localhost ~]# nmcli connection modify ens160 ipv4.method manual ipv4.addresses 192.168.108.30/24 ipv4.gateway 192.168.108.2 ipv4.dns 192.168.108.2 autoconnect yes
[root@localhost ~]# nmcli con up ens160
开始安装
# 卸载旧版本
[root@docker ~]# yum remove docker-ce# 安装必要工具
[root@docker ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 vim
[root@docker ~]# dnf install -y bash-completion
[root@docker ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
Adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@docker ~]# yum makecache
Docker CE Stable - x86_64 63 kB/s | 66 kB 00:01
CentOS Stream 8 - BaseOS 6.5 kB/s | 3.9 kB 00:00
CentOS Stream 8 - AppStream 9.2 kB/s | 4.4 kB 00:00
Metadata cache created.
allinone部署
# 安装软件
[root@docker ~]# yum install -y docker-ce# 配置服务
[root@docker ~]# systemctl enable docker.service --now
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.# 查看docker版本
[root@docker ~]# docker --version
Docker version 26.1.3, build b72abbb
配置镜像加速器
华为云
[root@docker ~]# vi /etc/docker/daemon.json
{"registry-mirrors": [ "https://faf9c955231a47648fa3dad688d6db6c.mirror.swr.myhuaweicloud.com" ]
}#重启容器引擎
[root@docker ~]# systemctl restart docker
[root@docker ~]# docker info
运行第一个容器
环境就绪,马上运行第一个容器,执行命令:
[root@docker ~]# docker run hello-world
Unable to find image 'hello-world:latest' locally # 本地找helloworld镜像没找到
latest: Pulling from library/hello-world #去华为云镜像站下载
17eec7bbc9d7: Pull complete
Digest: sha256:a0dfb02aac212703bfcb339d77d47ec32c8706ff250850ecc0e19c8737b18567
Status: Downloaded newer image for hello-world:latest #hello-world镜像下载成功Hello from Docker! # 通过hello-world镜像产生了容器
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 theexecutable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client, which sent itto your terminal.To try something more ambitious, you can run an Ubuntu container with:$ docker run -it ubuntu bashShare images, automate workflows, and more with a free Docker ID:https://hub.docker.com/For more examples and ideas, visit:https://docs.docker.com/get-started/
其过程可以简单的描述为:
-
从本地查找hello-wrold镜像,没找到。
-
从 Docker Hub 下载hello-world镜像。
-
启动hello-world容器。
运行第二个容器
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 1b44b5a3e06a 3 weeks ago 10.1kB
[root@docker ~]# docker run -d -p 80:80 httpd
Unable to find image 'httpd:latest' locally
latest: Pulling from library/httpd
396b1da7636e: Pull complete
40712a21826a: Pull complete
4f4fb700ef54: Pull complete
d2b1a5ae8cd3: Pull complete
7e8bbac53823: Pull complete
779ccd583397: Pull complete
Digest: sha256:3198c1839e1a875f8b83803083758a7635f1ae999f0601f30f2f3b8ce2ac99e3
Status: Downloaded newer image for httpd:latest
ad2ae941e339aba37f22e1c57cdd3651529b9c41f84d840843dcb6658ed31685
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 1b44b5a3e06a 3 weeks ago 10.1kB
httpd latest 199e3a035264 3 weeks ago 117MB
其过程可以简单的描述为:
-
从 Docker Hub 下载 httpd 镜像。镜像中已经安装好了 Apache HTTP Server。
-
启动 httpd 容器,并将容器的 80 端口映射到 host 的 80 端口。
可以通过浏览器验证容器是否正常工作。在浏览器中输入 http://[your host IP]
[root@docker ~]# curl 192.168.108.30
<html><body><h1>It works!</h1></body></html>
# 可以访问容器的 http 服务,容器运行成功,拥有了一个 WEB 服务器。
docker C/S分离部署
首先准备两个虚拟机,分别为docker_client和docker_server
server端
ip 192.168.108.30
安装软件
[root@docker_server ~]# hostnamectl set-hostname docker_server
[root@docker_server ~]# nmcli connection modify ens160 ipv4.method manual ipv4.addresses 192.168.108.30/24 ipv4.gateway 192.168.108.2 ipv4.dns 192.168.108.2 autoconnect yes
[root@docker_server ~]# yum remove docker-ce[root@docker_server ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 vim [root@docker_server ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
Adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@docker_server ~]# yum makecache
Docker CE Stable - x86_64 53 kB/s | 66 kB 00:01
CentOS Stream 8 - BaseOS 5.8 kB/s | 3.9 kB 00:00
CentOS Stream 8 - AppStream 8.2 kB/s | 4.4 kB 00:00
Metadata cache created.
[root@docker_server ~]# yum install -y docker-ce-cli
[root@docker_server ~]# dnf install -y bash-completion
[root@docker_server ~]# systemctl enable docker.service --now
[root@docker_server ~]# vi /etc/docker/daemon.json
{"registry-mirrors": [ "https://faf9c955231a47648fa3dad688d6db6c.mirror.swr.myhuaweicloud.com" ]
}
[root@docker_server ~]# systemctl restart docker
配置服务
[root@docker_server ~]# vim /usr/lib/systemd/system/docker.service
# 在ExecStart参数中最后添加 -H tcp://0.0.0.0:2375,docker默认监听2375
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
-H tcp://0.0.0.0:2375
[root@docker_server ~]# systemctl daemon-reload
[root@docker_server ~]# systemctl retart docker.service
[root@docker_server ~]# systemctl stop firewalld
[root@docker_server ~]# systemctl disable firewalld
验证
[root@docker_server ~]# yum install lsof
[root@docker_server ~]# lsof -i :2375
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dockerd 12672 root 3u IPv6 52967 0t0 TCP *:docker (LISTEN)
client端
ip 192.168.108.31
[root@docker_client ~]# nmcli connection modify ens160 ipv4.method manual ipv4.addresses 192.168.108.31/24 ipv4.gateway 192.168.108.2 ipv4.dns 192.168.108.2 autoconnect yes
只安装docker客户端
[root@docker_client ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 vim
[root@docker_client ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@docker_client ~]# yum makecache
[root@docker_client ~]# yum install -y docker-ce-cli
验证
#client直接执行报错,没有装服务端
[root@docker_client ~]# docker run hello-world
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See 'docker run --help'.[root@docker_client ~]# docker -H 192.168.108.30 run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
17eec7bbc9d7: Pull complete
Digest: sha256:a0dfb02aac212703bfcb339d77d47ec32c8706ff250850ecc0e19c8737b18567
Status: Downloaded newer image for hello-world:latestHello 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 theexecutable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client, which sent itto your terminal.To try something more ambitious, you can run an Ubuntu container with:$ docker run -it ubuntu bashShare images, automate workflows, and more with a free Docker ID:https://hub.docker.com/For more examples and ideas, visit:https://docs.docker.com/get-started/[root@docker_client ~]# docker -H 192.168.108.30 images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 1b44b5a3e06a 3 weeks ago 10.1kB
[root@docker_server ~]# docker -H 192.168.108.30 images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 1b44b5a3e06a 3 weeks ago 10.1kB
说明:client只做管理,image和container存储在server端。
容器架构
容器发展三问
学习新技术最怕 “一头扎进去”,尤其是容器这种涉及历史、原理、实操的技术。我习惯用 “3W 框架”(What 是什么、Why 为什么用、How 怎么实现)梳理逻辑,再结合容器的发展历史和与虚拟机的对比,把整个知识体系串起来。下面就是我整理的 “容器 3W 笔记”,从基础到核心,一步步讲透。
先看容器发展史:不是突然出现,而是迭代了 40 年
很多人以为容器是 Docker 之后才有的,其实它的 “隔离思想” 早在上世纪 70 年代就有了。我梳理了关键节点,能帮大家理解 “容器为什么是现在这样”:
-
1979 年:Unix V7 引入
chroot
—— 最早的 “隔离雏形”,能把进程限制在指定目录(比如让某个程序只能看到/home/app
),但缺点很明显:root 用户能轻易突破隔离,没有安全机制。 -
1982 年:
chroot
加入 BSD 系统,隔离思想开始普及,但核心问题没解决。 -
2000 年:FreeBSD Jail 出现 —— 第一次实现 “更安全的隔离”,能把系统分成多个独立 “小系统”,还能分配独立 IP,相当于容器的 “早期版本”。
-
2001 年:Linux VServer 发布 —— 基于 Linux 内核做了操作系统级虚拟化,支持在一个 Linux 系统上跑多个不同发行版(比如在 CentOS 上跑 Ubuntu),进一步完善隔离能力。
-
2004 年:Solaris Containers 推出 —— 用 “资源控制” 和 “区域(zone)” 实现隔离,能限制进程的 CPU、内存使用,这是 “资源限制” 思想的重要一步。
-
2006 年:Google 推出 Process Containers—— 后来改名叫
cgroups
(控制组),专门用来限制、统计进程的资源(CPU、内存、IO 等),最终合并到 Linux 2.6.24 内核 —— 这成了现在容器技术的核心基石之一。 -
2008 年:LXC(Linux Containers)发布 —— 第一个成熟的 Linux 容器管理器,结合了
cgroups
(资源限制)和Namespace
(环境隔离),能真正跑起 “独立容器”,但操作复杂,没普及。 -
2013 年:Docker 诞生 —— 改变一切的关键!在 LXC 基础上优化了 “用户体验”:用简单命令(比如
docker run
)就能启动容器,还引入了 “镜像” 和 “仓库”,让容器能轻松打包、共享。后来 Docker 用自己的libcontainer
替换了 LXC,更灵活。 -
2014 年
:两个重要事件:
- Google 开源 LMCTFY(容器工具),但后来和 Docker 合作,把核心功能合并到
libcontainer
,自己不再维护; - CoreOS 发布 rkt—— 另一个容器工具,和 Docker 竞争,也推动了容器规范的统一。
- Google 开源 LMCTFY(容器工具),但后来和 Docker 合作,把核心功能合并到
简单说:容器是 “隔离思想 + 资源限制” 迭代 40 年的结果,Docker 的功劳是把复杂技术 “平民化”,让普通人也能轻松用起来。
What:容器到底是什么?先和虚拟机掰扯清楚
很多人第一次接触容器,都会问 “和虚拟机有啥区别?”—— 搞懂这个,就懂了容器的核心。
容器的定义:轻量级的 “软件集装箱”
我给容器的定义是:一种把应用和依赖 “打包成标准单元” 的技术,这个单元里包含了应用本身、需要的库、配置文件,而且能在任何支持容器的环境(开发机、服务器、云平台)里 “原样运行”,不用改配置。
比如你在自己电脑上用 Docker 打包了一个 “Python Flask 应用 + Python 3.9 + 依赖库” 的容器,拿到公司服务器上,直接跑命令就能启动,不会出现 “我这能跑,你那跑不了” 的问题。
容器 vs 虚拟机:核心差异在 “隔离粒度”
两者都是为了 “隔离应用”,但方式完全不同,我用表格对比最清楚:
对比维度 | 容器(Container) | 虚拟机(VM) |
---|---|---|
隔离层级 | 操作系统级(共享宿主机内核) | 硬件级(模拟独立硬件 + 完整 OS) |
启动时间 | 秒级(比如docker run 1 秒启动) | 分钟级(要加载完整操作系统) |
体积大小 | 轻量(MB 级,比如 Nginx 容器才 20 多 MB) | 庞大(GB 级,比如一个 CentOS 虚拟机要 10GB+) |
资源开销 | 极低(只占应用自身资源) | 较高(要预留 OS 运行资源) |
运行密度 | 一台服务器能跑上千个容器 | 一台服务器最多跑几十个虚拟机 |
隔离强度 | 进程级隔离(较弱,共享内核) | 完全隔离(较强,内核独立) |
举个直观的例子:如果把服务器比作 “一栋楼”,虚拟机就是 “一个个独立房间”(每个房间有自己的水电、家具),容器就是 “一个个标准集装箱”(放在楼里,共享楼的水电,但每个集装箱里的东西独立)—— 集装箱显然更省空间、搬起来更快。
Why:为什么非要用容器?解决了开发运维的 “千古难题”
容器不是 “花架子”,它解决的是软件开发和运维的 “核心痛点”—— 环境不一致。
痛点:开发运维的 “矩阵噩梦”
现在的软件架构越来越复杂:一个应用可能依赖 MySQL、Redis、MQ,而且要部署到 “开发机→测试机→生产服务器→云平台” 多个环境。这就形成了一个 “N×M 矩阵”:
- N 个服务(应用、MySQL、Redis…)
- M 个环境(开发、测试、生产…)
开发人员要为每个环境调配置(比如开发机用本地 MySQL,测试机用服务器 MySQL),运维人员要为每个服务搭环境(比如给 Python 应用装 3.9,给 Java 应用装 JDK 11)—— 两边都累,还容易出问题(比如开发机没问题,测试机报 “缺少某个库”)。
容器的解法:“软件集装箱” 思想
容器的灵感来自 “运输业的集装箱”—— 不管里面装的是钢琴还是汽车,只要装进标准集装箱,就能用卡车、轮船、火车随便运,不用拆包重装。
Docker 把这个思想用到软件上,实现了 “一次打包,到处运行”,对应到开发运维就是:
- 开发人员:“Build Once, Run Anywhere”—— 只需要把应用和依赖打包成一个容器,不管部署到哪,都是同一个环境。
- 运维人员:“Configure Once, Run Anything”—— 只需要在服务器上装 Docker,就能运行任何容器,不用再为每个应用搭环境。
我再用 “集装箱 vs 容器” 的对应关系,帮大家理解:
特性 | 运输业集装箱 | 软件容器(Docker) |
---|---|---|
打包对象 | 钢琴、汽车等任何货物 | 应用、依赖库、配置等任何软件 |
兼容性 | 标准尺寸,能装卡车 / 轮船 / 火车 | 标准格式,能跑开发机 / 服务器 / 云平台 |
隔离性 | 密封打包,货物不互相挤压 | 进程隔离,应用不互相干扰 |
效率 | 不用拆包,直接搬运 | 不用改配置,直接运行 |
分工 | 货主管装货,承运方管运输 | 开发管打包,运维管运行 |
所以,容器的核心价值是:消除环境差异,让开发和运维各司其职,提高效率。
How:容器是怎么工作的?先搞懂 Docker 核心
容器的实现依赖 Linux 内核的Namespace
(隔离)和cgroups
(资源限制),但对普通人来说,不用深钻内核,先搞懂 Docker 的核心组件就行 ——Docker 是目前最主流的容器工具,掌握它就掌握了容器的 80%。
Docker 的三大核心概念:镜像、容器、仓库
这三个是 Docker 的 “三驾马车”,缺一不可:
- 镜像(Image):容器的 “模板”,只读的。比如 “Ubuntu 22.04 镜像”“Nginx 镜像”,里面包含了操作系统或应用的所有文件。你可以把它理解成 “安装包”—— 安装包不能直接用,要装成软件(容器)才能用。
- 容器(Container):镜像的 “运行实例”。从镜像创建容器,就像从安装包安装软件 —— 一个镜像可以创建多个容器(比如用 Nginx 镜像创建 10 个 Nginx 容器,每个都是独立的)。
- 仓库(Registry):存放镜像的 “云盘”。比如 Docker Hub(公共仓库,有上百万个免费镜像),企业会搭私有仓库(比如 Harbor)存自己的业务镜像。你可以从仓库 “拉取”(
docker pull
)镜像,也可以把自己的镜像 “推送”(docker push
)到仓库。
Docker 的工作流程:以 “启动 Nginx 容器” 为例
我用一个实际操作,带你看 Docker 组件怎么配合:
- 你在终端敲命令:
docker run nginx
(启动一个 Nginx 容器); - Docker 客户端(就是你敲的
docker
命令)把请求发给 Docker 守护进程(dockerd
,后台运行的 “大脑”); - 守护进程检查本地有没有nginx镜像:
- 如果没有,就去 Docker Hub(默认仓库)拉取
nginx
镜像到本地; - 如果有,直接用本地镜像;
- 如果没有,就去 Docker Hub(默认仓库)拉取
- 守护进程基于
nginx
镜像创建容器,分配独立的网络(比如默认的 bridge 网络),用cgroups
限制资源(比如默认不限 CPU / 内存); - 容器启动,运行 Nginx 服务,守护进程把容器 ID、状态返回给客户端,你在终端就能看到结果;
- 你再敲
docker ps
,就能看到这个运行中的 Nginx 容器。
总结:容器的核心逻辑就 3 句话
- 历史上:容器是 “隔离 + 资源限制” 迭代 40 年的结果,Docker 让它平民化;
- 本质上:容器是 “软件集装箱”,把应用和依赖打包成标准单元,解决环境不一致;
- 用起来:Docker 的 “镜像→容器→仓库” 是核心,先学这三个概念,再动手跑命令,就能入门。
Docker架构详解
要搞懂 Docker,不能只停留在 “用命令跑容器” 的表面,得先理清它的架构逻辑 —— 就像拆一台机器,先知道每个零件是啥、负责啥,才能明白整体怎么转。下面我结合自己的学习和实操经验,把 Docker 架构拆成 “核心组件”“工作流程”“关键实操” 三部分,把逻辑捋顺。
Docker 核心架构:Client/Server 模式是基础
Docker 本质是C/S(客户端 - 服务器)架构:我们平时敲的docker
命令是 “客户端”,真正负责创建容器、管理镜像的是 “服务器”(Docker 守护进程)。客户端和服务器可以在同一台机器上,也能通过网络远程通信(比如用另一台电脑管理服务器上的 Docker)。
整个 Docker 系统由 7 个关键部分组成,我按 “用户交互→后台运行→数据存储” 的逻辑排了序,这样更好理解:
组件名称 | 我的理解与核心作用 | 举个例子 |
---|---|---|
1. Docker 客户端(Client) | 用户和 Docker 交互的 “入口”,通过命令行(CLI)发送请求(比如docker run ),再转交给服务器。 | 我们敲的docker ps “查看容器”、docker build “构建镜像”,都是客户端在发指令。 |
2. REST API | 客户端和服务器之间的 “通信语言”—— 客户端的命令会先转成 API 请求,服务器通过 API 接收并处理。 | 哪怕不用docker 命令,直接调用 API(比如用 Python 的requests 库),也能控制 Docker。 |
3. Docker 守护进程(Daemon) | Docker 的 “大脑”,后台常驻运行(进程名dockerd ),负责处理所有请求:创建容器、管理镜像、配置网络等。 | 执行systemctl start docker ,就是启动这个守护进程;它一停,所有 Docker 操作都用不了。 |
4. 容器(Container) | 镜像的 “可运行实例”—— 镜像相当于 “模板”,容器就是用模板造出来的 “成品”,能启动、停止、删除。 | 用nginx 镜像启动的nginx 容器,就是一个能提供 Web 服务的独立实例。 |
5. 镜像(Image) | 只读的 “容器模板”,包含运行应用所需的所有东西:操作系统、依赖、代码、配置(比如ubuntu:22.04 镜像)。 | 你可以把它理解成 “安装包”,容器就是 “安装后的软件”。 |
6. 镜像仓库(Registry) | 存放镜像的 “仓库”,分公共和私有 —— 相当于镜像的 “云盘”,需要时下载(pull ),做好了上传(push )。 | Docker Hub 是公共仓库(有nginx 、mysql 等现成镜像);企业常用 Harbor 搭私有仓库存业务镜像。 |
7. 服务(Services) | 用于集群场景,能跨多台 Docker 服务器管理容器(比如指定 “同时运行 3 个 nginx 容器”,自动负载均衡)。 | 在 Docker Swarm(Docker 自带的集群工具)里,用docker service create 创建服务,实现容器扩缩容。 |
其中,最核心的 5 个组件是:Client(客户端)、Daemon(服务器)、Image(镜像)、Registry(仓库)、Container(容器)—— 搞懂这 5 个,就掌握了 Docker 的 90% 基础。
Docker 的核心组件包括:
-
Docker 客户端 - Client
-
Docker 服务器 - Docker daemon
-
Docker 镜像 - Image
-
Registry
-
Docker 容器 - Container
Docker 架构如下图所示:
Docker 内部怎么工作?一步拆透请求流程
我们以 “用docker run nginx
启动一个 nginx 容器” 为例,看看从敲命令到容器运行,Docker 内部是怎么配合的:
- 用户发指令:在终端敲
docker run nginx
,客户端(Client)先解析这个命令,转成 REST API 请求,发给本地或远程的 Docker 守护进程(Daemon)。 - Daemon 检查镜像:Daemon 收到请求后,先查本地有没有
nginx
镜像 —— 如果没有,就去默认的 Registry(Docker Hub)下载镜像(相当于 “从仓库拿模板”)。 - 存储镜像:下载好的镜像,会通过 “镜像管理驱动(Graph driver)” 以分层的方式存在本地(比如用 Overlay2 文件系统),方便后续复用。
- 创建容器环境:Daemon 调用 “网络驱动(Network driver)”,给容器分配独立的网络(比如默认的 bridge 网络),保证容器能联网;如果需要存储,还会通过 “存储驱动” 挂载卷(Volume)。
- 启动容器:最后,Daemon 通过 “执行驱动(Exec driver)” 调用
runc
(Docker 默认的容器运行时),基于nginx
镜像创建容器实例,并执行nginx
的启动命令 —— 此时容器就跑起来了。 - 返回结果:Daemon 把容器的 ID、状态等信息通过 API 返回给客户端,客户端再显示在终端上(比如 “容器启动成功,ID 是 abc123”)。
关键实操:从客户端到服务器的 “动手验证”
光懂理论不够,得动手看才真切。下面是我平时验证 Docker 架构的几个常用操作,大家可以跟着试:
认识 Docker 客户端:常用命令有哪些?
客户端的核心是docker
命令,输入docker
就能看到所有子命令,我把最常用的整理成了表格,刚学的时候记这几个就够:
常用命令 | 作用 | 示例 |
---|---|---|
docker run | 创建并启动容器 | docker run -d --name nginx nginx (后台启动 nginx 容器) |
docker ps | 查看运行中的容器 | docker ps -a (查看所有容器,包括停止的) |
docker images | 查看本地镜像 | docker images (列出所有本地镜像) |
docker build | 用 Dockerfile 构建镜像 | docker build -t my-app:1.0 . (当前目录构建镜像,标签 1.0) |
docker pull/push | 下载 / 上传镜像到仓库 | docker pull nginx:1.25 (下载 nginx 1.25 版本) |
docker exec | 进入运行中的容器执行命令 | docker exec -it nginx /bin/bash (进入 nginx 容器的命令行) |
查看 Docker 服务器:守护进程跑起来了吗?
Docker 服务器就是dockerd
进程,用下面的命令能看到它的状态:
# 查看Docker守护进程状态
systemctl status docker.service
如果看到 “Active: active (running)”,说明守护进程在运行;如果没跑,用systemctl start docker
启动。
配置远程访问:让客户端控制远程服务器的 Docker
默认情况下,客户端只能控制本地的 Docker。如果想在 A 电脑控制 B 电脑的 Docker(比如开发机控制服务器),需要给 B 电脑的 Docker 守护进程配置 TCP 监听:
# 1. 编辑Docker服务配置文件
vim /usr/lib/systemd/system/docker.service# 2. 找到ExecStart行,末尾加 -H tcp://0.0.0.0:2375(允许所有IP访问,2375是默认端口)
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375# 3. 重启Docker服务,让配置生效
systemctl daemon-reload
systemctl restart docker# 4. 关闭防火墙(测试环境用,生产环境建议用防火墙限制IP)
systemctl stop firewalld
systemctl disable firewalld
配置好后,在 A 电脑上用-H
指定远程服务器 IP,就能控制 B 电脑的 Docker 了:
# 比如查看远程服务器的Docker信息(B电脑IP是192.168.108.30)
docker -H tcp://192.168.108.30:2375 info
总结:Docker 架构的核心逻辑
其实 Docker 架构没那么复杂,记住三个关键点就行:
- C/S 模式是骨架:客户端发命令,服务器做实事,API 是中间的 “翻译官”;
- 镜像和容器是核心:镜像管 “打包”(环境一致),容器管 “运行”(独立实例),仓库管 “存储”(复用和共享);
- 守护进程是中枢:所有操作最终都靠 Daemon 协调,从下载镜像到创建容器,全是它在调度。
我眼中的 Docker:用 “集装箱思维” 改变 IT 效率的工具
如果让我用一句话总结 Docker,那一定是:它把运输业的 “集装箱逻辑” 搬进了软件世界—— 集装箱让货物能跨卡车、轮船、火车无缝运输,Docker 则让软件能跨开发机、测试服、生产云无缝运行,核心都是 “标准化” 和 “无差别适配”。
Docker 的核心逻辑:软件也能 “装集装箱”
Docker 的设计哲学特别好懂,我常拿它和真实集装箱类比:
- 真实集装箱里装的是 “货物”(钢琴、汽车、家电),Docker 容器里装的是 “软件 + 依赖”(比如 Web 服务 + Java 环境、数据库 + 配置文件);
- 真实集装箱不管里面装啥,只要符合标准尺寸,就能用任何交通工具运;Docker 不管容器里跑啥软件,只要打包成镜像,就能在任何装了 Docker 的环境里跑;
- 真实集装箱能快速装卸、堆叠,Docker 容器能秒级启动、批量创建 —— 本质都是 “标准化带来的效率提升”。
就像我在服务器上执行docker images
看到的那样,一个httpd
(Apache)镜像才 148MB,拉下来就能启动容器提供 Web 服务,不用像以前那样手动装系统、配环境、改配置,省了太多时间。
Docker 最香的地方:让 “哪里都能跑” 和 “随便折腾” 成为可能
Docker 彻底改变了开发和运维的工作方式,我总结了两个最直观的好处:
跨环境无缝流转:从开发到生产 “零修改”
开发人员在自己笔记本上把 “应用 + 依赖” 打包成镜像,上传到仓库(比如 Docker Hub 或私有 Harbor);测试人员直接从仓库拉镜像,在测试机上启动容器做测试;最后运维把同一个镜像部署到生产环境 —— 全程不用改一行配置,因为 “镜像里的环境是固定的”。
以前最头疼的 “开发环境能跑,生产环境报错”,现在用 Docker 基本不会出现了。
降低学习和试错成本:不用怕 “搞坏环境”
这一点对新手尤其友好:
- 如果你是运维,想研究 HAProxy 负载均衡,不用手动装依赖、改配置文件,直接敲
docker run haproxy
,容器启动就能上手实战,删了容器也不会影响主机环境; - 如果你是开发,想学 Django 写 Python Web,直接
docker run django
启动容器,在里面随便装包、改代码,哪怕把容器搞崩了,重新启动一个新的就行,主机的 Python 环境永远是干净的。
Docker Hub 上几乎有所有常用软件的镜像(Nginx、MySQL、Redis、Elasticsearch……),相当于一个 “软件宝库”,需要什么直接拿,不用从零开始搭。
最后想说:Docker 真的提升了 IT 人的 “幸福指数”
毫不夸张地说,Docker 把我从 “重复配环境” 的繁琐工作里解放了出来 —— 以前搭一个测试用的 MySQL,要装系统、改权限、调参数,至少半小时;现在docker run -d -p 3306:3306 mysql
,10 秒就能启动一个可用的 MySQL 容器。
它就像打开了一个 “潘多拉盒子”,但里面装的是 “效率工具”:不仅降低了新技术的学习门槛(新手能快速上手复杂软件),还让团队协作更顺畅(开发和运维对 “环境” 的认知统一了)。
对我来说,Docker 不只是一个工具,更是一种 “简化复杂问题” 的思维 —— 用标准化解决不一致,用隔离性降低试错成本,这也是它能成为容器技术标杆的核心原因。
错”,现在用 Docker 基本不会出现了。
降低学习和试错成本:不用怕 “搞坏环境”
这一点对新手尤其友好:
- 如果你是运维,想研究 HAProxy 负载均衡,不用手动装依赖、改配置文件,直接敲
docker run haproxy
,容器启动就能上手实战,删了容器也不会影响主机环境; - 如果你是开发,想学 Django 写 Python Web,直接
docker run django
启动容器,在里面随便装包、改代码,哪怕把容器搞崩了,重新启动一个新的就行,主机的 Python 环境永远是干净的。
Docker Hub 上几乎有所有常用软件的镜像(Nginx、MySQL、Redis、Elasticsearch……),相当于一个 “软件宝库”,需要什么直接拿,不用从零开始搭。
最后想说:Docker 真的提升了 IT 人的 “幸福指数”
毫不夸张地说,Docker 把我从 “重复配环境” 的繁琐工作里解放了出来 —— 以前搭一个测试用的 MySQL,要装系统、改权限、调参数,至少半小时;现在docker run -d -p 3306:3306 mysql
,10 秒就能启动一个可用的 MySQL 容器。
它就像打开了一个 “潘多拉盒子”,但里面装的是 “效率工具”:不仅降低了新技术的学习门槛(新手能快速上手复杂软件),还让团队协作更顺畅(开发和运维对 “环境” 的认知统一了)。
对我来说,Docker 不只是一个工具,更是一种 “简化复杂问题” 的思维 —— 用标准化解决不一致,用隔离性降低试错成本,这也是它能成为容器技术标杆的核心原因。