
k8s 是什么?#
K8s 不是用来取代 Docker 的,它是用来管理 Docker 的。
Kubernetes (容器编排): 它的核心能力是**“管理”和“调度”。你不需要告诉它“怎么做”,你只需要告诉它“我想要什么状态”(比如:我要服务一直活着,且要有 3 个分身)。K8s 会想尽办法去维持**这个状态。
Docker (容器引擎): 它的核心能力是**“打包”和“运行”**。你给它一个指令,它就帮你起一个容器。它只管当前这一刻,不管未来。
- 自愈能力 (Self-healing):
- 容器挂了?重启它。
- 节点挂了?迁移它。
- 健康检查不通过?杀掉重建。
- K8s 就像一个永不睡觉的运维人员。
- 弹性伸缩 (Scaling):
- 白天流量大,自动开 10 个实例。
- 晚上流量小,自动缩回 2 个实例省钱。
- 解耦与抽象 (Abstraction):
- 这是 K8s 最难学但也最强大的地方。它把“网络”、“存储”、“配置”都变成了独立的资源对象(Service, PVC, Secret)。
- 好处: 开发人员只管写代码,不用关心底层 IP 是多少,也不用把密码写死在代码里。
| 名词 | 对应 Docker 概念 | 人话解释 | 典型用途 |
|---|---|---|---|
| Namespace | (无) | 文件夹/隔离区 | 分离开发、测试、生产环境 |
| Pod | 容器 (紧密版) | 豌豆荚 (最小调度单位) | 运行你的代码 |
| Deployment | docker run | 包工头 (管无状态应用) | Web 服务、API |
| StatefulSet | (无) | 宠物饲养员 (管数据库) | MySQL, Redis |
| Service | -p 端口映射 | 内线总机 (固定 IP) | 让服务之间能找到彼此 |
| Ingress | Nginx 反代 | 对外大门 (域名管理) | 给外网用户访问 |
| ConfigMap/Secret | .env 文件 | 配置中心/保险柜 | 存配置、存密码 |
| PV/PVC | -v 挂载卷 | 硬盘/房卡 | 持久化存储数据 |
Pod 概念#
在 Docker 里,最小单位是 Container。在 K8s 里,最小单位是 Pod。
在 Docker Compose 里,-p 80:80 就完事了。但在 K8s 里,为了安全和灵活性,它设计了三层关卡。
同一个 Pod 里的所有容器,天然共享两样东西:
| 特性 | Docker Compose (Network) | K8s Pod (Inside) |
|---|---|---|
| 关系比喻 | 邻居 (住在同一个小区) | 连体婴 (共用一个身体) |
| IP 地址 | 每个容器都有独立 IP | 所有容器共用一个 IP |
| 通信方式 | 通过服务名 (DNS) | 通过 Localhost (127.0.0.1) |
| 端口冲突 | 不会冲突 (IP 不同) | 会冲突 (IP 相同) |
| 存储共享 | 需要单独配置 volume | 天然共享 (像读本地硬盘一样) |
A. 共享网络 (Network Namespace)#
- 同一个 Pod 里的容器,共用同一个 IP 地址。
- 它们之间互相访问,直接用
localhost就行! - 比喻: 就像夫妻。虽然是两个人(两个容器),但他们住在同一个地址(IP),互相说话不用打电话,直接喊一声(localhost)就行。(端口: 不能冲突! 如果
ragapi占用了 80 端口,Sidecar就绝对不能再用 80 端口了,因为 IP 是同一个。)
B. 共享存储 (Shared Storage)#
- Pod 可以挂载一个 Volume(数据卷),里面的所有容器都能读写这个卷。
- 比喻: 夫妻共用一个冰箱。
3. Pod 的生命周期:它是“牛”,不是“宠物”#
这是 Docker 用户思维转变的一个难点。
-
Docker 容器: 我们往往把它当宠物养。如果 MySQL 容器挂了,我们会尝试重启它,修好它,希望它的 IP 不变。
-
K8s Pod: 它是一次性的。
- Pod 随时可能死掉(被杀、节点宕机)。
- Pod 死后不会复活,K8s 会创建一个新的 Pod 来代替它。
- 重点: 新的 Pod 会有一个全新的 IP 地址。
- 这就是为什么我们必须要有 Service(前台)的原因——因为后端的 Pod(小李)一直在换人、换 IP,必须有个固定的前台号码。
-
Pod (不稳定的实体): 每次重启,IP 都会变(就像员工换了工位)。
-
Service : K8s 里的 DNS 机制(比如 CoreDNS)。
- 它记录着:
ragapi服务 -> 现在的 IP 是10.42.0.5。 - 如果 Pod 挂了重启,IP 变成
10.42.0.6,Service 会自动更新记录。 - 你的其他服务只要访问
http://ragapi,Service 就会自动把你导向最新的那个 IP。
- 它记录着:
Namespace(命名空间)#
在 Docker 里 docker ps,一下子列出所有容器,乱糟糟的。但在 K8s 里,它引入了 Namespace 来做隔离。“Docker 像是一个大通铺,所有容器挤在一起;K8s 的 Namespace 则是把大通铺变成了有隔断的套房,实现了多租户隔离。”
- Docker: 所有服务都在一起,没有文件夹的概念。
- K8s:
default: 这是你现在用的,像酒店的大堂。kube-system: 這是酒店的员工专用区(存放 K8s 自己的核心组件),客人(你)别随便进去瞎搞。- 实战用法: 你可以创建
dev(开发环境)、test(测试环境)、prod(生产环境)三个 Namespace。 - 神奇之处:
dev里的ragapi和prod里的ragapi就算名字一样,也互不干扰。就像 3 楼的 301 房间和 5 楼的 301 房间是两个世界。
Ingress(反向代理)#
Ingress 才是正门。
- 角色: 它其实就是一个反向代理(通常底层就是 Nginx 或 Traefik)。
- 功能: 它工作在七层(HTTP/HTTPS)。
- 客人说:“我要去
api.jacin.me” -> Ingress 指向ragapi服务。 - 客人说:“我要去
web.jacin.me” -> Ingress 指向前端服务。
- 客人说:“我要去
- 对比:
- Service (NodePort): 只能管 IP 和端口转发 (4层)。
- Ingress: 能管域名、路径 (
/apivs/static)、SSL 证书 (7层)。
PV&PVC(持久化存储)#
在 Docker 里,你直接 -v /host/data:/container/data 就完事了。
在 K8s 里,为了解耦,它把“硬盘”拆成了两部分:
- PV (Persistent Volume) —— 真实的房间:
- 这是运维人员(你)提前准备好的硬盘空间(比如 NFS、云硬盘)。
- 比喻:酒店里真实的客房。
- PVC (Persistent Volume Claim) —— 房卡/入住申请单:
- 这是开发人员(Pod)写的申请书:“我要 10G 的空间,读写模式。”
- 比喻:客人手里的入住凭证。
为什么要这么麻烦? 因为 Pod 是会飘的!今天在 A 机器,明天在 B 机器。 Pod 拿着 PVC (房卡),K8s 会保证无论 Pod 飘到哪,都能找到对应的 PV (房间) 并挂载上去。开发人员不需要知道底层硬盘是 NFS 还是 AWS EBS,只要有卡就行。
StatefulSet(有状态应用)#
Deployment,它适合管**“无状态应用”(比如你的 Python API,挂了重启就行,谁替谁都一样)。我们把这种应用叫“牛”**(Cattle)。
要部署 MySQL、Redis、MongoDB 这种数据库,它们需要固定的 ID,需要数据同步,不能随便乱杀。我们把这种应用叫**“宠物”**(Pet)。
滚动更新#
“滚动更新不是‘热迁移’,它只保证‘服务入口’不中断,不保证‘存量连接’不中断。”
对于短连接(REST API),K8s 的滚动更新是完美的零停机。 对于长连接(WebSocket),K8s 只能通过宽限期 (Grace Period) 尽量让连接自然结束,但最终的断线重连机制,依然依赖于健壮的客户端设计。这才是云原生架构的真相。
K8s: 它支持滚动更新 (Rolling Update)。
- 它会先偷偷启动一个新版本的容器,等新容器说“我准备好了”,K8s 才会把流量切过去,然后再关掉旧容器。
- 结果:用户对此完全无感,服务永远在线。
Docker Compose: 更新流程通常是:停止旧容器 ➡️ 删除旧容器 ➡️ 启动新容器。
- 在“停止”和“启动”中间的那几秒(甚至几十秒),用户访问就是
502 Bad Gateway。你的服务必然会中断。
注意:
k8s 它不能把一条正在进行的 TCP 长连接(比如 WebSocket、大文件下载、视频流)“瞬移”到另一个容器里。
- 短连接 (HTTP API): 用户发请求 -> 服务器 0.1秒处理完 -> 返回。这种完全没影响,K8s 会等这 0.1秒处理完再关容器。
- 长连接 (WebSocket/游戏/下载): 用户连着服务器 1 小时了。这时候你要更新服务,旧容器必须死,旧容器里的连接必然会断。物理定律不可违背。
K8s 杀 Pod 并不是直接“拔电源” (SIGKILL),而是先发一个“搬家通知” (SIGTERM)。
整个过程是这样的:
- 摘除流量: K8s 先把这个旧 Pod 从 Service(前台)的名单里划掉。新的请求再也不会进来了。
- 发送信号 (SIGTERM): K8s 告诉容器:“我要杀你了,给你 30秒(默认值)的时间收拾行李。”
- 容器处理 (关键点):
- 你的程序收到
SIGTERM信号后,应该立刻停止接受新任务。 - 但是!要继续处理手里没干完的活(比如把当前的数据库事务提交了,把当前的 WebSocket 消息发完)。
- 你的程序收到
- 强制击杀 (SIGKILL):
- 如果 30秒 到了,容器还没把自己关掉(比如还在处理一个超大的长连接),K8s 就会失去耐心,直接强制杀掉。
- 这时候,长连接就真的断了。
评论
还没有评论,来发第一个吧
