Day 58 / 共 68 天 · 阶段 11 部署

Kubernetes 基础:集装箱的码头调度中心

昨天(Day 57)你学会了把 Agent 打成一个集装箱(Docker 镜像)。可线上要抗流量,得同时跑几十个一样的箱子,还要它们挂了自动重启、升级时不停机——手动管这么多箱子会累死人。今天认识 Kubernetes(简称 K8s):集装箱的「码头调度中心」,用 Pod / Deployment / Service 三个核心概念自动编排一大群容器。零基础不用深钻,今天目标是看懂轮廓、能讲清这三个词、看得懂一份最小 YAML;明天(Day 59)学怎么用 CI/CD 把「改代码 → 打镜像 → 上 K8s」这条流水线自动化。

📍 你在阶段 11(部署 D57-61)的位置
D57 Docker D58 K8s 基础 D59 CI/CD&IaC D60 云上部署 D61 AI 网关
💡 用一个类比兜住今天(今天全程沿用「集装箱码头」的世界观) 管理一堆容器 = 运营一个繁忙的集装箱码头K8s = 码头的自动调度中心(总控室);Pod = 码头上一个能落地干活的最小箱位(通常就装一个容器);Deployment = 一张下给调度中心的「订单」(我要一直保证有 3 个这样的箱子在跑,坏了立刻补);Service = 码头门口那个固定的收货地址/前台(不管里面箱子怎么增减换新,外面永远认这一个地址);kubectl = 你对调度中心下命令的对讲机。K8s 最迷人的地方:你只说「我想要什么状态」,它自己想办法一直维持——像一个不知疲倦的码头主管。
L01

为什么要编排:一个箱子好管,一百个就乱了

🤔 痛点用户多了,一个容器扛不住,你手动 docker run 起 10 个。结果:半夜有个容器崩了没人管、升级得手动一个个停再起(中间服务中断)、流量该发给哪个箱子还得自己配……人肉运维彻底忙不过来。
💡 本质容器编排(orchestration) = 用一个大脑自动管理成百上千个容器:自动重启挂掉的、自动多起几个扛流量、升级时逐个替换不停机、自动分配流量。K8s 就是业界最主流的这个「大脑」。你从「一个个手动搬箱子的工人」升级成「给调度中心下订单的主管」。
手动管容器 vs 交给 K8s 调度中心 😵 人肉运维 崩了要半夜爬起来重启 升级得手动停再起 扩容一个个 docker run 🤖 K8s 自动编排 崩了自动重启 / 自愈 滚动升级不停机 改个数字就扩缩容
图注:K8s 的核心是「声明式」——你声明想要的状态,它负责一直维持,出偏差自动纠。
👶 我一定要学 K8s 吗?好难的样子。作为转行者,你现在不需要会「搭 K8s 集群」,只需要「看得懂、会用别人搭好的」。因为云厂商都提供托管 K8s(明天/后天会讲),你多数时候只写几行 YAML 声明「我要跑什么、几份」。今天的目标就是把 Pod/Deployment/Service 这三个词讲明白——面试问到能答上,就够了。
L02

Pod:码头上最小的一个箱位

🤔 痛点Docker 里最小单位是「容器」,可 K8s 里到处说「Pod」,这俩啥关系?
💡 本质Pod 是 K8s 调度的最小单位,里面通常就装一个容器(偶尔几个紧密配合的容器共处一个 Pod)。K8s 不直接管容器,而是管 Pod。就像码头不按「单件货」调度,而按「一个箱位」调度——箱位里一般放一个集装箱。可以先粗略理解成:一个 Pod ≈ 一个正在跑的容器。
👶 为什么不直接管容器,要多套一层 Pod?因为有时候两个容器必须「同生共死、共享网络」——比如主程序容器 + 一个帮它收集日志的小容器(边车/sidecar)。把它俩放同一个 Pod,K8s 就把它们当一个整体调度、放到同一台机器上。90% 的场景一个 Pod 就一个容器,你先这么记,遇到 sidecar 再深究。
📝 举个例子:Pod 是「会飘的」 Pod 有个重要特性:随时可能被销毁重建(节点故障、升级、扩缩容)。重建后 IP 会变。所以你不能直接把某个 Pod 的 IP 记下来去访问它——这正是下面要讲 Service 的原因:需要一个「不变的门牌号」挡在飘忽的 Pod 前面。
L03

Deployment:一张「保证有 N 份在跑」的订单

🤔 痛点Pod 会崩、会飘。我想要「永远有 3 个我的 Agent 在跑,崩一个立刻补一个,升级时别停机」——总不能自己盯着手动补吧?
💡 本质Deployment = 你下给 K8s 的一张订单:「给我一直保持 N 个一模一样的 Pod 在跑」。K8s 会不停地对比「现在有几个」和「你要几个」,少了自动补、多了自动删、你改镜像版本它就滚动替换。这就是 K8s 的灵魂——声明式:你说想要的结果,它负责达成并维持。像给码头主管下单:「这条线永远配 3 个箱子,坏了你自己补,别来烦我。」
Deployment:声明 replicas=3,K8s 自动维持 Deployment 订单 replicas: 3(我要 3 份) Pod ✅ Pod ✅ Pod ✖ 崩了 → 自动补一个
图注:崩一个,K8s 立刻拉起新的补齐到 3 个——「自愈」。想扩容?把 3 改成 10 就行。
📝 举个例子:扩容和升级有多简单 流量涨了要扩容:kubectl scale deployment my-agent --replicas=10(从 3 变 10);
发新版本:把 Deployment 里的镜像从 my-agent:v1 改成 :v2,K8s 自动滚动升级(先起一个新版、确认健康、再干掉一个旧版,逐个替换,全程服务不中断)。这就是「声明式」的爽点:你改数字/版本,脏活它全包。
L04

Service:一个永远不变的收货地址

🤔 痛点Pod 会飘、IP 会变、数量会增减。前端/别的服务想调用你的 Agent,总不能每次去查「现在哪几个 Pod 活着、IP 多少」吧?太折腾。
💡 本质Service = 挡在一堆飘忽 Pod 前面的一个「固定门牌号 + 自动分流」。外面只认这一个稳定地址,Service 自动把请求分发给背后当前活着的 Pod(负载均衡)。Pod 换了、多了、少了,外面无感。就像码头前台:货找前台一个地址就行,前台自己知道现在哪个箱位能收货,你不用管里面怎么倒腾。
Service:稳定入口,自动把流量分给活着的 Pod 用户/前端 Service 前台 固定地址 + 分流 Pod A Pod B Pod C
图注:Service 靠「标签(label)」认领它该管哪些 Pod——谁贴了 app=my-agent 的标签,它就把流量分给谁。

👶 小白:那外面的真实用户,怎么从公网访问到 Service?

👨‍🏫 老师:Service 有几种类型。集群内部互相调用用 ClusterIP(只在集群里可见);要暴露到公网,常用 LoadBalancer(云厂商给你分一个公网负载均衡),或者用 Ingress(更高级的入口,能按域名/路径分流、配 HTTPS)。这一层再往上,就是我们 Day 61 要讲的「AI 网关」——在入口统一做限流、鉴权、多模型路由、token 计量。今天你只要知道「Service = 稳定入口」这个概念就够,别被这些类型名吓到。

L05

一份最小 YAML:把三者串起来看

🤔 痛点Pod、Deployment、Service 各自懂了,可它们在真实文件里长啥样、怎么拼一起?
💡 本质K8s 里你不写代码,而是写 YAML 声明文件(还记得 Day 57 的 compose 也是 YAML 吗)——「我想要什么」写清楚,交给 K8s。下面一个 Deployment + 一个 Service,就能把昨天打的 my-agent:v1 镜像跑成 3 份、对外提供稳定访问。读的时候对照右边注释,抓住关键几行就行。
# deploy.yaml —— 上半段是 Deployment(订单),下半段是 Service(前台)
apiVersion: apps/v1
kind: Deployment              # 这是一张「Deployment 订单」
metadata:
  name: my-agent             # 订单名字
spec:
  replicas: 3                # ★ 我要一直保持 3 个 Pod 在跑
  selector:
    matchLabels: { app: my-agent }   # 这张订单管理「贴了 app=my-agent 标签」的 Pod
  template:                  # 下面是「每个 Pod 长啥样」的模板
    metadata:
      labels: { app: my-agent }      # 给 Pod 贴标签(Service 靠它认领)
    spec:
      containers:
      - name: agent
        image: my-agent:v1   # ★ 用昨天打的镜像(换成 :v2 就是升级)
        ports:
        - containerPort: 8000
        env:
        - name: LLM_API_KEY  # 密钥用环境变量注入(真项目从 Secret 取,不写明文)
          value: "sk-xxx"
---                          # YAML 里用 --- 分隔两个对象
apiVersion: v1
kind: Service                # 这是「Service 前台」
metadata:
  name: my-agent-svc
spec:
  selector: { app: my-agent }        # ★ 把流量分给贴了这个标签的所有 Pod
  ports:
  - port: 80                 # 前台对外的端口
    targetPort: 8000         # 转发到 Pod 里容器的 8000(对应 Day57 的服务端口)
带 ★ 的三行是重点:replicas(要几份)、image(跑哪个镜像)、selector/labels(Service 靠标签认领 Pod)。其余字段用时查文档,别背。密钥在真实项目里用 K8s 的 Secret 存,不像这里写明文——概念先记住即可。
L06

kubectl:对调度中心喊话的对讲机

🤔 痛点YAML 写好了,怎么让它生效?线上出问题了,怎么查是哪个 Pod、看它的日志?
💡 本质kubectl(读作 "kube control")是你和 K8s 对话的命令行工具——所有「应用配置、看状态、查日志、扩缩容」都靠它。就一把对讲机,记住五六个高频命令就能应付日常。
kubectl apply -f deploy.yaml    # 应用上一讲的 YAML:让 K8s 照单执行(最常用)
kubectl get pods                # 看现在有哪些 Pod、是否 Running(数箱子)
kubectl get deploy,svc          # 看 Deployment 和 Service 的状态
kubectl logs my-agent-xxxx      # 看某个 Pod 的日志(对应 Day55 可观测!)
kubectl describe pod my-agent-xxxx   # Pod 起不来时,看详细事件排查原因
kubectl scale deploy my-agent --replicas=10   # 扩容到 10 份
kubectl rollout undo deploy my-agent          # 新版本有问题?一键回滚到上一版
命令大白话什么时候用
apply -f照这份 YAML 去做部署 / 更新配置
get pods数一数箱子、看死活日常巡检
logs看某箱子的日志排查报错
scale改份数扩容 / 缩容
rollout undo回退上一版发版翻车急救
📝 举个例子:一次典型的线上排查 用户说服务 502。你 kubectl get pods 发现有个 Pod 状态是 CrashLoopBackOff(反复崩溃重启)→ kubectl logs 看它日志,发现是漏了环境变量导致启动就报错 → 补上 Secret 重新 applyK8s 的自愈救了大局(其他 2 个 Pod 还在扛),你从容修复,不用半夜手忙脚乱。
L07

今日小结 + 动手 10 分钟

🧠 今天你应该能回答

  • 为什么需要容器编排?K8s 靠什么理念工作?(声明式:你说想要的状态,它维持)
  • Pod 是什么?为什么 Pod 会「飘」、IP 会变?
  • Deployment 解决什么?replicas 是啥?扩容和滚动升级怎么做?
  • Service 为什么必要?它怎么找到该管哪些 Pod?(靠标签 label)
  • 一份最小 YAML 里最关键的三行是什么?
  • kubectl 的 apply / get pods / logs / scale / rollout undo 各干嘛?

✋ 动手 10 分钟:读懂并「讲出」一份 YAML

不用真装 K8s(集群较重)。今天的动手是「读」和「讲」——这才是转行阶段真正要练的:

# 1) 把上面 L05 的 deploy.yaml 抄下来,逐行对着注释,用大白话讲给自己听:
#    「这张订单要 3 个 Pod,跑 my-agent:v1 镜像,Service 靠 app=my-agent 标签
#     把 80 端口的流量分给这 3 个 Pod 的 8000 端口。」

# 2) 想真上手体验的(可选):本地装一个迷你 K8s,如 minikube 或 kind
minikube start                     # 本地起一个单节点迷你集群
kubectl apply -f deploy.yaml       # 部署上去
kubectl get pods                   # 看 3 个 Pod 是否都 Running
kubectl scale deploy my-agent --replicas=5   # 试试扩容,再 get pods 看变化
minikube stop                      # 玩完关掉

面试自测:合上笔记,用「集装箱码头」的比喻,把 Pod / Deployment / Service 三个词一口气讲清楚。讲得出,今天就过关了。

明日预告 · Day 59:现在你会写 Dockerfile、会写 K8s YAML 了,可每次改完代码都要手动「打镜像 → 推仓库 → apply 到 K8s」,又慢又容易出错。明天学 CI/CD & IaC:用 GitHub Actions 把「提交代码 → 自动测试 → 自动打镜像 → 自动部署」串成一条流水线;再用 Terraform 把「云上要建哪些资源」也写成代码。让机器替你干重复的部署活。
← Day 57 · Docker 打包 Day 59 · CI/CD & IaC →