2. Kubernetes基础回顾

在深入跨云多集群架构之前,我们必须先夯实单集群内的核心对象模型与通信原理。Kubernetes 之所以能够成为分布式系统的“操作系统”,其根本在于它用一套声明式 API 将基础设施的复杂性抽象为若干可组合、可观测、可移植的对象。本章将聚焦于 Pod、Service、Deployment、Ingress 与 Namespace 这五个最核心的对象,剖析它们各自的职责边界、协作关系以及在实际生产环境中的设计要点。理解这些基础对象在单集群内的行为模式,是后续理解多集群服务网格、联邦调度和跨云故障域隔离的基石。

Kubernetes 核心对象协作关系与集群架构 Kubernetes Cluster (单集群边界) 控制平面 (Control Plane) kube-apiserver etcd (状态存储) kube-scheduler kube-controller-manager (声明式API + 调谐循环) Namespace: production Deployment (无状态应用) 期望状态: replicas=3 滚动更新策略 Pod 模板 (spec.template) ReplicaSet Pod 实例组 (工作负载节点) Pod A IP: 10.244.1.10 容器: c1, c2 Pod B IP: 10.244.1.11 容器: c1 Pod C IP: 10.244.1.12 容器: c1 Service (ClusterIP) 虚拟IP: 10.96.0.10 → 选择器: app=web Ingress (7层路由) 域名 → Service:80 管理/调谐 选择器 转发 外部用户流量 存储状态 控制面组件 工作负载控制器 Pod实例 服务发现 入口路由

上图展示了单集群内核心对象的静态拓扑与动态协作关系。控制平面通过 API Server 暴露声明式接口,Deployment 作为工作负载的“期望状态”声明者,通过 ReplicaSet 间接管理 Pod 的生命周期。Service 作为一层稳定的虚拟 IP 抽象,屏蔽了后端 Pod IP 的易变性,而 Ingress 则在 L7 层将外部域名流量路由至对应的 Service。Namespace 则从逻辑上划分了资源边界,使得同一集群可以服务于多个团队或环境。下面我们将逐一拆解这些对象的设计哲学与实战要点。

2.1 Pod:最小调度单元与容器共享模型

核心原理:为什么 Pod 是原子单位?

Pod 是 Kubernetes 中可创建和部署的最小单元,它代表集群中运行的单个进程实例。但 Pod 并非简单的容器封装,其核心价值在于调度原子性与资源共享模型。一个 Pod 内的多个容器共享同一个网络命名空间(Network Namespace)、IPC 命名空间以及可选的共享存储卷(Volume)。这意味着 Pod 内的容器可以通过 localhost 直接通信,且它们对外的 IP 地址是唯一的。这种设计使得“紧密耦合的辅助进程”(如日志收集 sidecar、流量代理 sidecar)可以与主应用容器打包部署,共享生命周期。

操作流程:Pod 的创建与调度过程

  1. 提交:用户通过 kubectl apply -f pod.yaml 向 API Server 提交 Pod 定义。
  2. 存储:API Server 将 Pod 对象写入 etcd,并返回确认信息。
  3. 调度:kube-scheduler 通过 watch 机制发现未绑定的 Pod,根据资源请求(requests/limits)、节点亲和性、污点容忍度等策略,选出最优节点并更新 Pod 的 nodeName 字段。
  4. 运行:目标节点上的 kubelet 监听到 Pod 绑定信息,调用容器运行时(如 containerd)拉取镜像并启动容器。
  5. 探针:kubelet 根据 livenessProbe 和 readinessProbe 定期检查容器健康状态,并将状态上报至 API Server。

案例拆解:多容器 Pod 的适用场景

假设我们有一个 Web 应用需要实时收集访问日志并推送至 Kafka。若将日志收集逻辑写入主应用代码,会耦合业务与基础设施逻辑。更优的方案是采用 Sidecar 模式:主容器运行 Nginx 服务,Sidecar 容器运行 Filebeat。两者共享一个名为 log-volume 的 emptyDir 卷,Nginx 将日志写入该卷,Filebeat 读取并转发。这种模式下,Pod 的 IP 是唯一的,Service 只需负载均衡到该 Pod 即可,无需关心内部有几个容器。

关键配置示例(Pod 网络共享验证):
apiVersion: v1
kind: Pod
metadata:
  name: web-with-sidecar
spec:
  containers:
  - name: nginx
    image: nginx:1.25
    ports:
    - containerPort: 80
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/nginx
  - name: filebeat
    image: elastic/filebeat:8.11.0
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/nginx
      readOnly: true
  volumes:
  - name: log-volume
    emptyDir: {}
常见误区:不要将多个功能独立的进程强行放入同一 Pod。Pod 的扩容单位是整体,如果 A 容器需要扩容而 B 容器不需要,则不应放在同一 Pod 内。此外,Pod 是临时资源,其 IP 会随重建而变化,因此不应直接通过 Pod IP 进行外部通信。

2.2 Deployment:声明式应用管理引擎

核心原理:调谐循环与期望状态

Deployment 是 Kubernetes 中最常用的工作负载控制器,它通过 控制器模式(Controller Pattern) 不断将当前状态(Actual State)调谐至期望状态(Desired State)。Deployment 本身不直接管理 Pod,而是通过管理 ReplicaSet 来实现 Pod 的副本数控制与版本更新。这种间接层级提供了回滚和版本追溯的能力:每次变更都会生成一个新的 ReplicaSet,旧版本 ReplicaSet 被保留但缩容至 0,以便快速回滚。

操作流程:滚动更新与回滚

步骤操作kubectl 命令效果
1创建 Deploymentkubectl create deployment web --image=nginx:1.25生成 ReplicaSet 与 1 个 Pod
2更新镜像版本kubectl set image deployment/web web=nginx:1.26触发滚动更新,新 RS 创建,旧 RS 缩容
3查看更新状态kubectl rollout status deployment/web显示更新进度直至完成
4回滚到上一版本kubectl rollout undo deployment/web旧 RS 重新扩容,新 RS 缩容至 0

实战场景:多集群环境下的版本策略

在跨云多集群场景中,Deployment 的清单文件(YAML)通常作为应用发布单元被 GitOps 工具(如 ArgoCD)同步至多个集群。此时需注意 replicas 字段的差异化处理:例如生产集群 A 需要 10 个副本,灾备集群 B 仅需 2 个副本。建议将副本数通过 Kustomize 的 patches 或 Helm 的 values.yaml 进行覆盖,而非直接修改基础 YAML,以保证基础配置的一致性。

经验提醒:设置 spec.minReadySeconds 可以避免新 Pod 刚启动尚未就绪就被计入可用状态,从而减少滚动更新期间的流量损失。同时,务必配置 resources.requests,否则调度器无法准确计算节点资源余量,可能导致 Pod 调度失败或节点过载。

2.3 Service:稳定的服务发现与负载均衡抽象

核心原理:虚拟 IP 与 Endpoint 管理

由于 Pod 是易失的,其 IP 不可依赖,Service 提供了一种稳定的访问入口。Service 通过标签选择器(Selector)动态关联一组 Pod,并维护一个 Endpoint 列表(或 EndpointSlice)。当 Pod 变化时,Service 的 Endpoint 自动更新。Service 的 ClusterIP 是虚拟 IP,仅在集群内部可达。kube-proxy 组件负责将发往 ClusterIP 的流量转发至后端 Pod,实现四层负载均衡。

类型对比与选择

Service 类型访问范围典型场景实现方式
ClusterIP集群内部内部微服务调用kube-proxy iptables/IPVS
NodePort集群外部(节点 IP+端口)临时调试、无 LB 环境节点端口映射
LoadBalancer集群外部(云 LB)云环境对外暴露服务云控制器调用云 API
ExternalName集群外部(DNS CNAME)访问集群外数据库DNS 解析

案例拆解:跨云场景下的服务发现痛点

假设我们在 AWS 与 GCP 各有一个集群,且需要互相调用服务。若直接使用各自的 ClusterIP,则无法跨集群通信。此时有两种常见方案:其一,使用 LoadBalancer 类型将服务暴露至公网,但需自行处理 TLS 与鉴权;其二,使用 多集群 Service(MCS) 或服务网格(如 Istio)的跨集群负载均衡能力。在基础回顾阶段,我们需明确:单集群的 Service 无法解决跨集群发现问题,这将在后续章节详细展开。

风险提示:不要将 Service 的 clusterIP 设置为固定值(除非使用 headless service 或无头服务)。ClusterIP 的分配范围由 API Server 的 --service-cluster-ip-range 决定,手动指定容易冲突。对于不需要负载均衡的客户端直连场景,应使用 clusterIP: None 的 Headless Service,配合 StatefulSet 使用。

2.4 Ingress:七层路由与统一入口

核心原理:从四层到七层的跃迁

Service 工作在 L4(传输层),只能基于 IP 和端口转发。而 Ingress 工作在 L7(应用层),能够基于 HTTP 路径、域名、请求头等属性进行路由。Ingress 本身只是一个规则集合,真正执行转发的是 Ingress Controller(如 Nginx Ingress、Traefik、AWS ALB Ingress Controller)。Ingress 资源定义了“外部流量如何到达集群内 Service”的规则,而 Controller 负责将这些规则转化为实际的反向代理配置。

配置示例与路径匹配规则

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /v1(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: api-v1-service
            port:
              number: 80
      - path: /v2(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: api-v2-service
            port:
              number: 80

实战场景:多集群入口的统一管理

在多集群架构中,Ingress 的挑战在于 DNS 解析与流量分发。通常我们会部署一个全局负载均衡器(如 AWS Route53、GCP Cloud DNS 或外部 DNS + 负载均衡器),将域名解析到多个集群的 Ingress Controller 入口 IP。此时,Ingress 的配置需要保持同步,且需考虑会话保持(Session Affinity)策略。建议将 Ingress 资源放入独立的 Namespace,并通过 GitOps 统一管理,避免各集群配置漂移。

经验提醒:Ingress Controller 本身通常以 Deployment + LoadBalancer Service 方式部署。在跨云场景中,注意不同云厂商的 LoadBalancer 注解(Annotation)差异,例如 AWS 的 service.beta.kubernetes.io/aws-load-balancer-type: nlb 与 GCP 的 networking.gke.io/load-balancer-type: Internal。建议使用 ingressClassName 字段指定 Controller,而非依赖默认类。

2.5 Namespace:多租户隔离与资源配额

核心原理:逻辑隔离而非安全隔离

Namespace 是 Kubernetes 用于实现多租户资源划分的逻辑边界。它不提供网络隔离(默认情况下),也不提供安全隔离(需配合 NetworkPolicy 与 RBAC)。Namespace 的主要作用是:资源对象的归属管理、资源配额(ResourceQuota) 的分配以及 策略(LimitRange) 的设定。例如,我们可以为 production 和 development 两个团队分别创建 Namespace,并设置不同的 CPU/内存配额。

操作流程:创建与切换

  1. 创建 Namespace:kubectl create namespace dev
  2. 在指定 Namespace 下创建资源:kubectl apply -f app.yaml -n dev
  3. 切换默认上下文:kubectl config set-context --current --namespace=dev
  4. 查看配额:kubectl describe resourcequota -n dev

案例拆解:多集群中的命名空间策略

在跨云多集群管理中,我们通常会在每个集群中创建相同的 Namespace 集合(如 prod、staging、shared),以保证应用部署的一致性。但需注意,Namespace 的删除是级联的,会删除其下所有资源。在多集群场景下,误删 Namespace 可能导致多个集群的配置丢失。建议为关键 Namespace 开启 kubectl apply --prune 的防护,或使用 Velero 等备份工具定期备份 Namespace 下的资源清单。

常见误区:不要将 Namespace 作为安全边界。默认情况下,Pod 可以访问其他 Namespace 中的 Service(通过全限定域名 service.namespace.svc.cluster.local)。若需隔离,必须配合 NetworkPolicy 定义允许的入站/出站规则。此外,系统创建的 kube-system、kube-public、kube-node-lease 不应被删除或修改。

2.6 集群架构总结与多集群扩展思考

回顾本章,单集群的架构可以概括为:控制平面(大脑) + 工作节点(四肢) + 声明式对象模型(语言)。Pod 是运行载体,Deployment 是管理载体,Service 是通信载体,Ingress 是入口载体,Namespace 是组织载体。这五个对象构成了绝大多数无状态应用部署的最小闭环。

当我们迈向跨云多集群时,上述对象的概念依然适用,但引入了新的维度:集群间服务发现、全局负载均衡、配置同步以及故障域隔离。例如,在多集群中,Deployment 的副本数可能需要根据集群的实时容量进行动态调整;Service 的 ClusterIP 无法跨集群访问,需要借助 MCS 或服务网格;Ingress 的 DNS 解析需要指向多个集群的入口。理解单集群的协作机制,是理解这些扩展方案的前提。

本章核心要点速查表:
对象层级核心职责常见故障点
Pod计算运行容器,共享网络/存储镜像拉取失败、探针配置不当
Deployment工作负载声明式更新、回滚、扩缩容资源请求未设置、更新策略过激
Service网络稳定虚拟 IP,负载均衡选择器不匹配、端口命名错误
Ingress入口L7 路由,域名分发Controller 未部署、注解拼写错误
Namespace组织资源隔离与配额误删级联、配额耗尽