K8s 入门:Pod、Deployment、Service

把应用装进 Docker 只是第一步;当容器多到几十上百个,你就需要 Kubernetes 来统一调度。本文拆开它的三个核心对象——PodDeploymentService,帮你建立可落地的认知框架,而不是被一堆概念劝退。

一、为什么容器之后还要 Kubernetes

Docker 解决了”环境一致性”问题,我们在Docker 网络模式详解里聊过容器如何联网;但它没有回答:几百个容器该调度到哪台机器?某个挂了谁来拉起?流量怎么稳定地找到当前健康的实例?这就是 Kubernetes(常缩写为 K8s)要解决的编排(Orchestration)问题。

K8s 的价值可以浓缩成四件事:调度(把 Pod 放到资源合适的节点)、自愈(副本挂了自动补)、弹性(按需扩缩容)、服务发现(用稳定名字访问变动的实例)。理解这三件套,就理解了 K8s 八成的能力。

举个直观的例子:你声明”我要 3 个 nginx 副本”,调度器会扫描所有节点,挑出 CPU、内存余量足够的节点把 Pod 放上去;之后哪怕某个节点宕机,控制器也会把上面的 Pod 重新调度到健康节点。你只管”要什么”,不用管”放哪”。

二、Pod:Kubernetes 的最小调度单元

2.1 Pod 不是容器,是容器的”宿舍”

很多新手会把 Pod 和容器画等号,其实 Pod 是调度、网络、存储的最小单位。一个 Pod 可以包含一个或多个容器,它们共享同一个网络命名空间(localhost 互通)和存储卷。最常见的形态是”一个主容器 + 一个辅助容器(如日志收集 sidecar)”,但入门阶段可以先理解为”一个 Pod 跑一个容器”。

当确实需要多容器协作时,sidecar 模式非常常见:主容器跑业务,旁边挂一个轻量容器负责日志收集或网络代理,二者通过 localhost 直接通信、共享磁盘,部署却只用一个 Pod 描述,生命周期天然绑定。理解这一点,你就不会再纠结”这个进程到底该放哪个容器”。

2.2 写一个最小 Pod

# pod.yaml —— 一个 Pod 里跑一个 nginx 容器
apiVersion: v1
kind: Pod
metadata:
  name: nginx-demo
  labels:
    app: nginx
spec:
  containers:
    - name: nginx
      image: nginx:1.27
      ports:
        - containerPort: 80

注意 labels 这一行——它看似只是个标签,却是后面 Service 找到 Pod、Deployment 管理 Pod 的唯一依据。没有 label,K8s 的世界就乱了套。

三、Deployment:让副本与发布可控

3.1 ReplicaSet 与自愈

直接手捏 Pod 有个致命问题:Pod 被删就真没了。Production 里几乎不会直接创建 Pod,而是通过 Deployment 间接管理。Deployment 会维持你声明的副本数(replicas),某个 Pod 意外退出,控制器立刻拉起一个新的补上,这就是”自愈”。

3.2 滚动更新与回滚

Deployment 真正的杀手锏是滚动更新:你只改镜像版本,K8s 会逐个用新 Pod 替换旧 Pod,保证服务不中断;一旦新版本有问题,一条命令就能回滚到上一个稳定版本。下面是一份标准 Deployment 清单:

# deployment.yaml —— 维持 3 个副本并支持滚动更新
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80

默认滚动策略会保证”先起新、再下旧”,你还可以用 maxSurge 控制最多多起几个临时副本、用 maxUnavailable 控制最多允许几个旧副本同时离线,从而精确权衡发布速度与可用性。这比手写一堆重启脚本可靠得多。

发布与回滚都是一行命令的事:

# 滚动更新镜像
kubectl set image deployment/nginx-deploy nginx=nginx:1.28
# 观察发布状态
kubectl rollout status deployment/nginx-deploy
# 出问题一键回滚
kubectl rollout undo deployment/nginx-deploy

四、Service:给 Pod 一个稳定的访问入口

4.1 三种类型 ClusterIP / NodePort / LoadBalancer

Pod 随时可能被调度到不同节点、IP 也会变,直接用 Pod IP 访问是灾难。Service 就是一层稳定的虚拟访问入口:它用 label 选择器把请求转发到后端一组 Pod,对调用方屏蔽了 Pod 的生灭变动。三种常用类型对比如下:

类型访问范围典型用途
ClusterIP仅集群内部服务间调用、后端 API
NodePort节点 IP + 固定端口临时调试、裸金属暴露
LoadBalancer云厂商外部 IP生产对外服务

4.2 用 Service 串起前后端

# service.yaml —— 给 Deployment 暴露稳定入口
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  selector:
    app: nginx          # 匹配 Pod 的 label
  ports:
    - protocol: TCP
      port: 80          # Service 自身端口
      targetPort: 80    # 转发到 Pod 的端口
  type: ClusterIP

selector 里的 app: nginx 与前面 Deployment 的 label 严丝合缝,正是这一处把”动态 Pod 集合”和”稳定入口”绑定了起来。想要从集群外访问,把 type 改成 NodePortLoadBalancer 即可;生产环境更推荐用 Ingress(本质是增强版七层路由,和我们在Nginx 反向代理里讲的思路一脉相承)。

Service 背后依赖 kube-proxy 在节点上维护转发规则(早期用 iptables,新版本多用 IPVS),把虚拟 IP 的流量负载均衡到后端 Pod。对调用方来说,backend:8080 永远可用,至于后面是 3 个还是 30 个 Pod,完全无感。这一层”稳定的名字”,正是微服务能自由扩缩容的前提。

五、三者如何协作:一个 Spring Boot 应用的上线链路

把三件套串起来,就是一个真实的上线闭环。以我们写过的Spring Boot 3 升级服务为例:先在 CI(参考GitHub Actions 实战)里构建镜像并推送到镜像仓库,再用 Deployment 跑起多副本,最后用 Service 把流量导进去。

# 1) 构建镜像并推仓库(CI 用 GitHub Actions 自动化)
# 2) 按顺序提交清单
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
# 3) 验证
kubectl get pods -l app=nginx
kubectl get svc nginx-svc

你会发现整个交付物就是几份声明式 YAML:你想要什么状态,K8s 负责让现实逼近它。这种”声明式”思维,正是云原生区别于传统脚本运维的核心。

六、新手避坑清单

6.1 label 对不上,什么都连不通

Deployment 的 selector.matchLabels、Pod template 的 labels、Service 的 selector 三者必须一致。这是新手 80% 连不通的根源,排查时先 kubectl get pods --show-labels 核对。

6.2 别直接用 Pod,也别把数据库塞进 K8s

无状态服务(Web、API)最适合上 K8s;而自带持久化、有状态依赖的组件(MySQL、Redis 主节点)若非要上,也要用 StatefulSet + PV,而不是裸 Pod。新手期建议先把无状态服务跑顺,有状态组件先用托管服务或单独部署。真正落地时,配合命名空间(Namespace)做环境隔离、用 ResourceQuota 约束团队配额,才能把 K8s 从”能跑”变成”可控的生产平台”。

  • 资源限制:给容器设 requests/limits,否则一个 Pod 吃满节点内存会拖垮整台机器。
  • 健康检查:配好 liveness / readiness 探针,K8s 才知道何时重启、何时放流量。
  • 镜像标签:生产禁用 latest,固定版本才能保证回滚可预期。

七、总结

Pod 是最小调度单元,Deployment 负责副本数与滚动发布,Service 提供稳定访问入口——三者组合,就覆盖了从”跑起来”到”稳稳对外服务”的主路径。下一步可以深入 Ingress、ConfigMap、探针与健康检查,逐步把这套声明式能力用熟。你准备先把哪个服务搬上 K8s?欢迎在评论区聊聊你的迁移计划。

上一篇 技术债不是原罪:在速度与质量间做工程决策
下一篇 前端性能优化:Lighthouse 90+ 到首屏 1s