最近开始往 Linux 运维后面继续学,Docker 和 Kubernetes 这两个词基本绕不开。

但如果之前只学过:

Linux 命令
进程
服务
网络
磁盘

突然看到下面这一堆东西,很容易懵:

Docker
Container
Image
Dockerfile
Registry
Volume
Kubernetes
K8s
Pod
Node
Deployment
Service
Ingress
ConfigMap
Secret

我一开始最大的疑问其实很简单:

Docker 到底是干什么的?

K8s 又是干什么的?

都已经有 Docker 了,为什么还要 Kubernetes?

Pod 为什么不直接叫 Container?

Kubernetes 是不是就是“批量管理 Docker”?

后来把整个过程串起来以后,我发现它没有想象中那么玄乎。

先记住一句话:

Docker 主要解决“应用怎么打包并以容器方式运行”;Kubernetes 主要解决“容器多起来以后,怎么在多台机器上统一管理”。

这篇不急着背 YAML,也不准备一上来安装一个复杂集群。

先把最基础的关系理顺。


一、先从一个很现实的问题说起

假设我写了一个 Web 项目。

在我电脑上运行:

Python 3.12
Nginx
Redis
某几个 Python 依赖包
某个特定版本的系统库

我的电脑上:

运行正常。

然后把代码发到服务器。

服务器说:

Python 版本不一样;
依赖缺少;
配置路径不同;
系统库版本不同;
环境变量没配;

最后出现一句程序员很熟悉的话:

“可是我电脑上明明能跑。”

这里的问题并不只是代码。

一个应用真正运行起来,需要的是:

代码
+
运行时
+
依赖
+
系统库
+
配置

如果只把代码拷走,环境还得重新搭。

Docker 最重要的价值之一,就是把这件事变得更加标准化。


二、Docker 到底是什么?

先不用管特别严格的定义。

我现在更喜欢把 Docker 理解成:

一套用来构建、分发和运行容器化应用的工具和平台。

比如原本部署一个 Nginx:

服务器
↓
安装软件源
↓
安装 Nginx
↓
检查版本
↓
修改配置
↓
解决依赖
↓
启动

使用现成 Docker 镜像后,可以变成:

docker run -d -p 8080:80 nginx

然后:

Nginx Container

就跑起来了。

当然,真实生产环境没有这么简单。

但这个例子已经能说明 Docker 为什么让人觉得方便:

我不再只把“程序代码”交给你,而是把运行这个程序所需要的一整套用户空间环境一起打包。


三、容器和虚拟机到底有什么区别?

这也是学习 Docker 绕不开的问题。

假设一台物理服务器上需要运行三套应用。

虚拟机的思路

大致可以理解成:

        物理服务器
             │
        Hypervisor
      ┌──────┼──────┐
      ↓      ↓      ↓
     VM1    VM2    VM3
      │      │      │
   Guest   Guest   Guest
     OS      OS      OS
      │      │      │
    App1   App2   App3

每台虚拟机都有自己的 Guest OS。

容器的思路

容器更像:

         Linux Host
             │
         Linux Kernel
             │
      Container Runtime
      ┌──────┼──────┐
      ↓      ↓      ↓
    App1    App2    App3
  Container Container Container

这些 Linux 容器共享宿主机内核,但拥有彼此隔离的进程、文件系统视图、网络环境、主机名和资源限制。

因此容器通常比完整虚拟机更轻量,创建和启动也更快。


四、所以容器就是“轻量虚拟机”吗?

这个说法方便入门,但并不完全准确。

虚拟机主要做的是:

虚拟出一套硬件环境,再运行完整 Guest OS。

容器主要做的是:

隔离进程及其运行环境,共享宿主机内核。

所以 VM 和 Container 虽然都可以达到“隔离不同应用”的效果,但底层思路不一样。


五、Docker 最重要的三个词:Image、Container、Registry

如果刚开始学,我觉得先把这三个搞懂,比背一堆 Docker 命令重要得多。

1. Image:镜像是什么?

Docker Image:

可以理解为创建 Container 的只读模板。

例如:

nginx:latest
redis:7
mysql:8
ubuntu:24.04

一个镜像里可能包含:

应用程序
运行时
系统库
依赖
默认配置
启动命令

可以把 Image 想成:

已经准备好的应用运行模板。

2. Container:容器是什么?

Container:

Image 真正运行起来后的实例。

关系很像:

Image
  │
  ├── Container 1
  ├── Container 2
  └── Container 3

一个 Nginx Image 可以启动很多个 Nginx Container。

比如:

docker run nginx

本质上是:

找到 nginx Image
↓
根据 Image 创建 Container
↓
运行 Container

3. Registry 又是什么?

Image 做出来以后,总得有地方存。

这个地方就是:

Registry
镜像仓库

最常听到:

Docker Hub

企业内部也经常会建设自己的 Registry。

所以一条很典型的流程是:

开发者
  │
  ↓
制作 Image
  │
  ↓
Push 到 Registry
  │
  ↓
服务器 Pull Image
  │
  ↓
启动 Container

六、Dockerfile 又是什么?

现在出现另一个问题:

Image 从哪里来?

当然可以直接从别人那里 Pull。

但如果是自己的应用,就需要自己构建镜像。

Dockerfile 可以理解成:

告诉 Docker“这个镜像应该怎么制作”的构建说明。

例如一个非常简单的 Python Dockerfile:

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY . .

CMD ["python", "app.py"]

不用一上来背语法。

现在只看意思:

FROM
→ 我从哪个基础镜像开始?

WORKDIR
→ 容器里的工作目录在哪里?

COPY
→ 把哪些文件放进镜像?

RUN
→ 构建镜像时执行什么?

CMD
→ 容器启动以后运行什么?

然后:

docker build -t myapp:1.0 .

得到:

myapp:1.0 Image

再:

docker run myapp:1.0

得到 Container。

于是关系就完整了:

Dockerfile
    ↓
docker build
    ↓
  Image
    ↓
docker run
    ↓
Container

这条线一定要先记住。


七、Docker 的基本工作流

可以把 Docker 的入门流程压缩成:

写应用
  ↓
Dockerfile
  ↓
docker build
  ↓
Image
  ↓
docker push
  ↓
Registry
  ↓
docker pull
  ↓
docker run
  ↓
Container

理解这张图以后,Docker 的大量命令其实都只是围绕这几个对象操作。


八、为什么容器删掉以后,数据可能也没了?

Container 默认不是设计成“永久保存所有数据”的。

比如启动 MySQL,如果关键数据库数据完全依赖容器自身的可写层,一旦容器删除或重新创建,就会带来数据管理问题。

所以 Docker 还有一个非常重要的概念:

Volume

Volume 用来:

把需要持久保存的数据放到 Container 生命周期之外。

可以理解成:

Container
    │
    ↓
 Volume
    │
    ↓
持久数据

容器可以删除、重建、升级,但 Volume 还在。


九、Docker 为什么还要讲 Network?

因为真实应用通常不是一个 Container。

例如:

Nginx
  ↓
Java Application
  ↓
Redis
  ↓
MySQL

它们可能分别运行在多个容器里,需要互相通信。

比如:

docker run -p 8080:80 nginx

这里 8080 是宿主机端口,80 是 Container 内 Nginx 监听端口。

于是:

访问 Host:8080
        ↓
映射
        ↓
Container:80

后面继续学 Docker Network 时,会遇到:

bridge
host
none
自定义 bridge
端口映射

十、学到这里 Docker 大概就有轮廓了

到目前为止,可以得到:

Dockerfile
负责描述怎么构建镜像

Image
应用运行模板

Container
运行中的镜像实例

Registry
存镜像

Volume
保存持久数据

Network
让容器互相通信以及与外部通信

这其实已经是 Docker 最重要的一层基础概念。


十一、既然 Docker 已经这么方便了,为什么还需要 Kubernetes?

这才是我一开始最困惑的问题。

假设目前只有一台服务器:

Server01
│
├── Nginx Container
├── Java Container
├── Redis Container
└── MySQL Container

Docker 很舒服。

问题来了。

公司业务扩大,现在变成:

100 台服务器
500 个 Container

这时候会冒出来一堆问题。

1. Container 到底放在哪台服务器?

Node01:CPU 90%
Node02:内存快满
Node03:非常空闲

我要启动一个需要 4GB RAM 的 Container,应该放哪?

2. Container 挂了怎么办?

要求 Web 应用必须一直有 3 个实例。

原来:

Container1
Container2
Container3

突然 Container2 挂了。

谁来发现?谁再启动一个?

3. 服务器挂了怎么办?

如果 Node01 直接宕机,上面的很多应用都没了。

谁负责把这些应用重新安排到其他机器?

4. 业务突然变多怎么办?

平时 3 个实例
高峰 50 个实例
低谷再缩回 5 个

谁来扩缩容?

5. 升级怎么办?

从:

myapp:v1

升级到:

myapp:v2

希望逐步上线、发现问题能回滚、尽量不中断服务。

如果这些都手工做,会越来越难。


十二、于是 Kubernetes 出场了

Kubernetes 简称:

K8s

“Kubernetes”中间有 8 个字母,因此常缩写成 K8s。

我现在最简单的理解是:

Kubernetes 是一个用来管理容器化应用的集群编排系统。

Docker 更像:

我要把这个 Container 跑起来。

Kubernetes 更像:

我有几十台服务器。

这个应用必须保持 3 份。
那个应用至少 5 份。
这个应用最多用 1GB 内存。
A 挂了要自动补。
服务器挂了要把应用重新调度。
升级时一批一批替换。
对外还要有一个稳定地址。

K8s 帮你维护这些事情。


十三、K8s 最重要的思想:Desired State

这是 Kubernetes 我觉得最值得先理解的东西。

假设我告诉 K8s:

我希望 nginx 永远保持 3 个副本。

这叫:

Desired State
期望状态

现在实际:

3 个 Pod

那么:

Desired = 3
Actual  = 3

没问题。

突然挂了一个:

Desired = 3
Actual  = 2

Kubernetes 发现不一致,于是再创建一个 Pod。

最终又回到:

Desired = 3
Actual  = 3

所以 K8s 很多机制都可以理解为:

不断观察实际状态,然后努力把实际状态拉回用户声明的期望状态。


十四、K8s 里为什么不是直接管理 Container,而是 Pod?

这是学习 Kubernetes 第一个很重要的词:

Pod

Kubernetes 中:

Pod 是运行一个或多个 Container 的基本工作单元。

最常见:

一个 Pod
  │
  └── 一个 Container

例如:

nginx Pod
   │
   └── nginx Container

一个 Pod 也可以放多个需要紧密协作的 Container。

例如:

Pod
├── Main App Container
└── Sidecar Container

它们可以共享网络和部分存储。

初学阶段先记:

大多数最简单的 Pod 里只有一个主要 Container。


十五、Node 又是什么?

Node:

Kubernetes 集群里真正运行 Pod 的机器。

它可能是物理服务器,也可能是虚拟机。

例如:

Kubernetes Cluster
│
├── Node01
│    ├── Pod A
│    └── Pod B
│
├── Node02
│    ├── Pod C
│    └── Pod D
│
└── Node03
     └── Pod E

所以:

Cluster
  ↓
Node
  ↓
Pod
  ↓
Container

这是 K8s 初学最值得先记下来的层次。


十六、Cluster 又是什么?

Cluster 就是整个 Kubernetes 集群。

通常包括:

Control Plane
+
Worker Nodes

可以简单理解:

         Kubernetes Cluster
                 │
       ┌─────────┴─────────┐
       ↓                   ↓
 Control Plane        Worker Nodes
       │              │    │    │
    管理集群          Pod  Pod  Pod

十七、Control Plane 是干什么的?

先不要被这些名字吓到:

kube-apiserver
etcd
kube-scheduler
kube-controller-manager

只理解职责就够了。

kube-apiserver

可以理解成 Kubernetes 的统一 API 入口。

你执行:

kubectl get pods

大致就是:

kubectl
   ↓
Kubernetes API
   ↓
kube-apiserver

etcd

可以简单理解为:

保存 Kubernetes 集群状态的重要键值数据库。

例如有哪些 Node、有哪些 Deployment、希望有几个副本等。

kube-scheduler

Scheduler 负责:

给还没安排机器的 Pod 找一个合适 Node。

初学阶段可以记成:

K8s 的“分配座位的人”。

kube-controller-manager

Controller 可以理解为:

不断检查现实和目标有没有偏差。

例如希望 3 个 Pod,实际只剩 2 个,就推动系统补回 3 个。


十八、Worker Node 上最重要的是谁?

其中一个非常重要的组件叫:

kubelet

可以把 kubelet 理解成:

每台 Node 上负责确保 Pod 按要求运行的执行者。

它会和 Container Runtime 配合,让 Container 真正跑起来。


十九、这里顺便纠正一个很常见的理解

很多人说:

Kubernetes 就是用来管理 Docker 的。

拿来入门可以理解,但现在不够准确。

Kubernetes 真正依赖的是:

Container Runtime

常见:

containerd
CRI-O

也可以通过合适方式与 Docker Engine 配合。

所以更准确应该说:

Kubernetes 编排的是容器化工作负载,并通过容器运行时真正运行 Container。

Docker 和 Kubernetes 有关系,但不是:

K8s
↓
必须依赖 Docker

二十、Deployment 又是什么?

如果只创建一个 Pod,Pod 本身并不是你应该长期手工维护的业务抽象。

实际部署无状态应用,更常见的是:

Deployment

例如我告诉 Deployment:

nginx
副本数 = 3

它会帮你维持:

Deployment
    │
    ↓
ReplicaSet
    │
    ├── Pod1
    ├── Pod2
    └── Pod3

所以 Deployment 可以理解成:

“我要这个应用按照什么状态长期运行”的声明。


二十一、为什么大家喜欢 YAML?

K8s 特别强调声明式管理。

例如:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3

它的意思并不是:

请执行三次创建 Pod 命令。

而是:

我声明:这个 nginx Deployment 的期望状态是 3 个副本。

至于现在需要创建几个、哪个 Node 运行、其中一个挂了怎么办,K8s 自己去协调。


二十二、Pod IP 会变,那别人到底怎么访问它?

Pod 不应该被当成永久固定机器来使用。

Pod 可能:

被删除
重新创建
迁移到其他 Node
IP 改变

如果前端直接写死 Pod IP,很容易失效。

于是出现:

Service

Service:

给一组动态变化的 Pod 提供一个相对稳定的访问入口。

例如:

             Service
          nginx-service
               │
       ┌───────┼───────┐
       ↓       ↓       ↓
     Pod1    Pod2    Pod3

Pod 可以不断变化,Service 给客户端提供稳定访问方式。

所以客户端不用关心现在 nginx 有几个 Pod、IP 是多少、哪个刚刚被重建。


二十三、Deployment 和 Service 怎么区分?

这两个特别容易混。

我现在是这样记:

Deployment
管“后面应该跑几个应用实例”

Service
管“别人怎么稳定找到这些实例”

例如:

Deployment
   ↓
保证 3 个 nginx Pod

Service
   ↓
为这 3 个 Pod 提供统一访问入口

二十四、ConfigMap 和 Secret 又是什么?

应用总有配置。

例如:

数据库地址
日志级别
应用模式
Nginx 配置

不希望每次改配置都重新 Build Image。

于是 Kubernetes 有:

ConfigMap

用于保存一般配置。

敏感配置,例如数据库密码、Token,则常使用:

Secret

不过要注意:

Secret 这个名字不代表“放进去以后就绝对安全”。

生产环境仍需要考虑权限、etcd 加密、RBAC 和密钥管理等问题。


二十五、K8s 的 Volume 又是干什么的?

和 Docker 类似,Container 本身不应该被当作永久数据存储。

K8s 中会继续遇到:

Volume
PersistentVolume
PersistentVolumeClaim
StorageClass

初学阶段不用一次学完。

先理解:

Pod
可能消失

业务数据
不能跟着一起消失

因此计算生命周期和持久数据生命周期需要分离。


二十六、到这里,把 Docker 和 K8s 放在一起看

终于可以画完整一点了。

开发者
  │
  ↓
Dockerfile
  │
  ↓
Build
  │
  ↓
Image
  │
  ↓
Registry
  │
  ↓
Kubernetes Cluster
  │
  ↓
Deployment
  │
  ↓
Pod
  │
  ↓
Container Runtime
  │
  ↓
Container

外部访问:

User
 ↓
Service / Ingress / Gateway
 ↓
Pod
 ↓
Container
 ↓
Application

数据:

Pod / Container
      ↓
   Volume
      ↓
持久化存储

到这里,Docker 和 K8s 的关系已经没有那么乱了。


二十七、Docker 和 K8s 到底是什么关系?

可以用一句话:

Docker 更靠近“如何制作和运行一个容器化应用”,Kubernetes 更靠近“如何在集群中管理大量容器化应用”。

例如:

Docker:
把 Nginx 跑成一个 Container。

K8s:
我要 100 台服务器上合理运行 500 个应用实例,
其中 nginx 永远至少 10 个,
挂了自动补,
升级滚动进行,
还要有稳定入口。

这是两个层次的问题。


二十八、Docker Compose 又是什么?

假设一个项目需要:

Web
Redis
MySQL

自己分别执行多个 docker run 比较麻烦。

Compose 可以通过一个 YAML 描述多个 Container。

例如:

services:
  web:
    image: myapp

  redis:
    image: redis

  mysql:
    image: mysql

然后统一:

docker compose up -d

可以先这样理解:

单个 Container
→ Docker

一台机器上多个相关 Container
→ Docker Compose 很方便

跨多台机器的大规模容器编排
→ Kubernetes

这个理解不是绝对边界,但非常适合入门。


二十九、那为什么不直接从 K8s 开始学?

理论上当然可以。

但我不建议。

因为 Kubernetes 会默认你已经知道:

Container 是什么
Image 是什么
Registry 是什么
Port 是什么
Volume 是什么
Linux 进程是什么
网络大概怎么通信

如果 Docker 都完全没接触,直接看到 Pod、Deployment、Service、PVC、ConfigMap、Ingress,很容易变成背 YAML。

所以学习顺序我更建议:

Linux
 ↓
Docker
 ↓
Docker Compose
 ↓
Kubernetes

三十、一个非常简单的 Docker 实验

后面真正学的时候,可以从 Nginx 开始。

先确认 Docker:

docker version

拉镜像:

docker pull nginx

查看:

docker images

启动:

docker run -d --name my-nginx -p 8080:80 nginx

查看 Container:

docker ps

测试:

curl http://127.0.0.1:8080

进入 Container:

docker exec -it my-nginx /bin/sh

查看日志:

docker logs my-nginx

停止:

docker stop my-nginx

删除:

docker rm my-nginx

这个小实验真正做一遍,下面这几个词就活了:

Image
Container
Port Mapping
Logs
Exec

三十一、同一个 Nginx 放到 K8s 是什么思路?

Docker:

docker run -d -p 8080:80 nginx

你告诉 Docker:

给我运行一个 Nginx Container。

Kubernetes:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3

你告诉 K8s:

我要一个 nginx 应用,并且长期保持 3 个副本。

这就是思想上的差别。

Docker 命令更像:

“做这件事情。”

Kubernetes 声明更像:

“我最终希望系统保持成这个样子。”

三十二、K8s 是不是特别难?

说实话,它确实比 Docker 复杂很多。

因为 Kubernetes 真正要解决的是分布式系统问题。

后面会遇到:

容器
网络
存储
负载均衡
调度
服务发现
证书
高可用
权限
监控
日志
自动扩容
发布

所以感觉复杂很正常。

但刚开始完全没必要第一天就搭三 Master 高可用集群,第二天研究 CNI,第三天研究 Operator。

先把:

Pod
Deployment
Service
Node
Cluster

这五个概念搞懂,已经够学很久。


三十三、Docker / K8s 初学最常见的几个误区

误区 1:Container 就是一台虚拟机

不完全对。

Container 主要隔离进程及其用户空间环境,并共享宿主机内核。

误区 2:Image 就是运行中的 Container

错误。

Image
= 模板

Container
= 运行实例

误区 3:删除 Container 就等于删除 Image

不是。

Container 和 Image 是两个对象。

误区 4:有 Docker 就不需要 K8s

小规模环境当然可以完全不用 K8s。

Kubernetes 主要在多节点、大量工作负载、自动恢复、滚动升级、扩缩容和服务发现等问题开始复杂时体现价值。

误区 5:Kubernetes 就是管理 Docker

不够准确。

Kubernetes 管理的是容器化工作负载,它通过 Container Runtime 运行容器,并不要求底层必须直接使用 Docker Engine。

误区 6:Pod 就是 Container

也不完全是。

一个 Pod

可以包含一个或多个 Container。

误区 7:Pod 挂了以后 IP 不会变

Pod 本身应该被认为是相对临时的计算实例。

稳定访问通常应通过 Service 等机制。


三十四、如果从运维角度继续学,我建议这样走

第一阶段:Docker 基础

先会:

docker pull
docker images
docker run
docker ps
docker exec
docker logs
docker stop
docker rm

然后搞懂:

Image
Container
Dockerfile
Registry
Volume
Network

第二阶段:自己做一个 Image

学:

Dockerfile
docker build
docker tag
docker push

真正把一个自己的 Web 项目做成 Image。

第三阶段:Docker Compose

部署:

Nginx
+
Application
+
Redis
+
MySQL

开始理解多 Container 应用。

第四阶段:Kubernetes 基础

先搞懂:

Cluster
Node
Pod
Deployment
Service
Namespace
ConfigMap
Secret

第五阶段:真正部署应用

用 K8s 部署 Nginx,然后:

1 个 Pod
↓
3 个 Pod
↓
删除一个看自动恢复
↓
修改 Image 做滚动升级
↓
Service 访问

做到这一步,Kubernetes 的核心思想会比看十篇理论文章更清楚。

第六阶段:再碰网络和存储

继续:

CNI
Service
CoreDNS
Ingress / Gateway
PV
PVC
StorageClass

如果本身学过数通,这一阶段会开始非常有意思。

你会发现:

Pod IP
Service IP
路由
NAT
VXLAN
BGP
负载均衡

很多东西都能和原来的网络知识连接起来。


三十五、最后用一个公司的比喻再记一次

Dockerfile

员工培训手册和岗位说明

告诉你这个“员工模板”怎么制造。

Image

标准员工模板

Container

真正上班的员工

Image 运行起来以后才是 Container。

Registry

人才库

统一存放 Image。

Volume

公司档案柜

员工离职了,重要资料不能跟着消失。

Node

一间办公室

里面可以安排多个 Pod。

Pod

一个实际工作小组

通常一个主要员工,也可能带辅助员工。

Deployment

公司规定:
客服岗位必须一直保持 10 个小组。

少一个自动补。

Service

公司的统一客服电话

后面的员工可以换,但客户永远打同一个号码。

Kubernetes

整家公司的运营调度中心

它关心:

员工够不够?
谁挂了?
哪个办公室还有位置?
要不要扩招?
新版本怎么换班?
谁对外提供服务?

这样一想,很多词就不再是孤立的了。


写在最后

刚开始看到 Docker 和 Kubernetes 的时候,我会觉得:

这已经不是 Linux 了,
好像突然进入了另一套世界。

但真正开始拆以后会发现,它们其实和 Linux 运维联系得非常紧。

Docker 后面依然绕不开:

进程
文件系统
网络
端口
磁盘
权限
日志

Kubernetes 后面依然绕不开:

Linux
Container
网络
存储
调度
负载均衡
DNS
证书
监控

所以前面学过的 Linux 并没有白学。

反而是从这里开始,那些零散的知识会慢慢被串起来。

现在如果只要求记住最基础的一层,我觉得记住下面这些就够了:

Docker
负责构建、分发和运行容器化应用。

Image
是 Container 的模板。

Container
是 Image 的运行实例。

Dockerfile
描述 Image 怎么构建。

Registry
存放 Image。

Volume
负责把重要数据从 Container 生命周期中独立出来。

Kubernetes
负责在集群中编排和管理容器化工作负载。

Node
是运行工作负载的机器。

Pod
是 Kubernetes 的基本工作单元。

Deployment
维护应用期望副本和发布状态。

Service
给动态 Pod 提供稳定访问入口。

下一步真正值得做的,不是继续背二十个 Kubernetes 名词。

而是亲手:

安装 Docker
↓
Pull 一个 Nginx Image
↓
Run 一个 Container
↓
看端口
↓
看日志
↓
进入 Container
↓
再自己写一次 Dockerfile

把 Docker 这一层真正摸到以后,再去看 Kubernetes,会舒服很多。

更多推荐