K8s 简单介绍
容器与云原生

K8s 简单介绍

JACIN··18 分钟阅读

k8s 是什么?#

K8s 不是用来取代 Docker 的,它是用来管理 Docker 的。

Kubernetes (容器编排): 它的核心能力是**“管理”和“调度”。你不需要告诉它“怎么做”,你只需要告诉它“我想要什么状态”(比如:我要服务一直活着,且要有 3 个分身)。K8s 会想尽办法去维持**这个状态。

Docker (容器引擎): 它的核心能力是**“打包”“运行”**。你给它一个指令,它就帮你起一个容器。它只管当前这一刻,不管未来。

  • 自愈能力 (Self-healing):
    • 容器挂了?重启它。
    • 节点挂了?迁移它。
    • 健康检查不通过?杀掉重建。
    • K8s 就像一个永不睡觉的运维人员。
  • 弹性伸缩 (Scaling):
    • 白天流量大,自动开 10 个实例。
    • 晚上流量小,自动缩回 2 个实例省钱。
  • 解耦与抽象 (Abstraction):
    • 这是 K8s 最难学但也最强大的地方。它把“网络”、“存储”、“配置”都变成了独立的资源对象(Service, PVC, Secret)。
    • 好处: 开发人员只管写代码,不用关心底层 IP 是多少,也不用把密码写死在代码里。
名词对应 Docker 概念人话解释典型用途
Namespace(无)文件夹/隔离区分离开发、测试、生产环境
Pod容器 (紧密版)豌豆荚 (最小调度单位)运行你的代码
Deploymentdocker run包工头 (管无状态应用)Web 服务、API
StatefulSet(无)宠物饲养员 (管数据库)MySQL, Redis
Service-p 端口映射内线总机 (固定 IP)让服务之间能找到彼此
IngressNginx 反代对外大门 (域名管理)给外网用户访问
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 里的 ragapiprod 里的 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: 能管域名、路径 (/api vs /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)。

整个过程是这样的:

  1. 摘除流量: K8s 先把这个旧 Pod 从 Service(前台)的名单里划掉。新的请求再也不会进来了。
  2. 发送信号 (SIGTERM): K8s 告诉容器:“我要杀你了,给你 30秒(默认值)的时间收拾行李。”
  3. 容器处理 (关键点):
    • 你的程序收到 SIGTERM 信号后,应该立刻停止接受新任务
    • 但是!要继续处理手里没干完的活(比如把当前的数据库事务提交了,把当前的 WebSocket 消息发完)。
  4. 强制击杀 (SIGKILL):
    • 如果 30秒 到了,容器还没把自己关掉(比如还在处理一个超大的长连接),K8s 就会失去耐心,直接强制杀掉
    • 这时候,长连接就真的断了。

评论

还没有评论,来发第一个吧