背景与问题
在日常运维工作中,经常遇到开发团队反馈 Service 无法访问、POD 无法启动、Pod 之间通信异常等问题。这些问题的根因往往不在应用层,而在于 Kubernetes 核心工作流的理解偏差。本文从一线运维视角出发,系统讲解从 Deployment 到 Service 的完整数据流,剖析每个环节的工作原理、常见故障点以及排障方法。
本文基于 Kubernetes 1.29 版本编写,操作系统环境为 CentOS Stream 9 或 Ubuntu 24.04 LTS,容器运行时为 containerd 1.7.x。所有命令和配置均经过实际环境验证。
一、Kubernetes 核心资源对象解析
1.1 Workload 与 WorkloadResources 的区分
Kubernetes 将资源对象分为 Workload 和 WorkloadResources 两大类别。Workload 是运行应用的工作负载,WorkloadResources 则是支持工作负载运行的其他资源。
Workload 资源包括 Deployment、StatefulSet、DaemonSet、Job、CronJob 等。这些资源负责管理 Pod 的创建、调度和生命周期。
WorkloadResources 包括 Service、ConfigMap、Secret、PersistentVolumeClaim、ServiceAccount 等。这些资源为 Pod 提供网络、存储、配置等支撑能力。
理解这个分类是理解 K8s 工作流的基础。很多新手混淆了这两类资源的作用域,导致配置错误。
1.2 Deployment 的本质与作用
Deployment 是 Kubernetes 最常用的 Workload 资源,其核心职责是管理 ReplicaSet,而 ReplicaSet 才是真正管理 Pod 的资源。
Deployment 的主要功能包括:
第一,声明式更新。通过 spec.replicas 和 spec.template 定义期望状态,Kubernetes 控制器会自动将实际状态调整为期望状态。
第二,版本管理。每次 Deployment 更新都会创建一个新的 ReplicaSet,保留了版本回滚的能力。
第三,并行滚动更新。通过 strategy.rollingUpdate 参数控制更新过程中的最大不可用 Pod 数量和最大 Surplus Pod 数量。
查看一个标准 Deployment 的 YAML 定义:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: default labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 1 maxSurge: 1 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.27-alpine ports: - containerPort: 80 resources: limits: memory: "256Mi" cpu: "500m" requests: memory: "128Mi" cpu: "100m" livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 5
这个 YAML 包含了 Deployment 的核心配置:副本数、标签选择器、更新策略、容器配置、健康检查。
1.3 ReplicaSet 的控制循环机制
ReplicaSet 是 Kubernetes 控制器的核心实现,其工作原理基于经典的控制循环。
控制循环包含四个组件:观测器(Observers)、解释器(Interpreters)、分析器(Analyzers)、执行器(Effectors)。
在 ReplicaSet 控制器中:
观测器负责监听 Pod 资源的变化,包括 Pod 创建、删除、状态变更。
解释器将观测到的实际状态与期望状态进行对比。期望状态来自 ReplicaSet 的 spec.replicas 字段,实际状态是当前运行的 Pod 数量。
分析器根据对比结果决定是否需要采取行动。如果实际 Pod 数小于期望数量,需要创建新 Pod;如果大于期望数量,需要删除多余 Pod。
执行器通过 API Server 创建或删除 Pod 资源。
这个控制循环是 Kubernetes 自愈能力的基础。当某个节点上的 Pod 异常退出时,ReplicaSet 控制器会自动检测到 Pod 数量减少,然后创建新的 Pod 来补充。
1.4 Pod 的调度流程详解
Pod 的调度分为两个阶段:控制平面阶段的调度决策,和节点阶段的容器启动。
1.4.1 控制平面调度
控制平面的调度器(kube-scheduler)负责为每个未调度的 Pod 选择最佳节点。调度决策基于以下因素:
节点亲和性(NodeAffinity):根据节点的标签选择符合条件的节点。
Pod 亲和性与反亲和性(PodAffinity、PodAntiAffinity):控制 Pod 之间的部署关系,例如将同一个应用的 Pod 分散到不同节点。
污点与容忍(Taints、Tolerations):节点可以通过污点拒绝特定 Pod,Pod 通过容忍来接受带有污点的节点。
资源请求与限制(Requests、Limits):调度器会检查节点的可用资源,确保 Pod 的资源请求能够得到满足。
优先级与抢占(Priority、Preemption):高优先级的 Pod 可以抢占低优先级 Pod 的资源。
查看调度器配置:
# 查看调度器配置 kubectl get configmap kube-scheduler-config -n kube-system -o yaml # 查看 Pod 的调度结果 kubectl describe pod| grep -A 10 "Events:" # 查看节点的可用资源 kubectl describe node | grep -A 5 "Allocated resources"
1.4.2 节点阶段容器启动
调度决策完成后,节点上的 kubelet 负责容器的实际启动。kubelet 通过 CRI(Container Runtime Interface)与容器运行时交互。
容器启动流程:
首先,kubelet 通过 CRI API 调用容器运行时,拉取容器镜像。
然后,容器运行时创建容器的文件系统、网络、存储等命名空间。
接着,kubelet 配置容器的资源限制和环境变量。
最后,启动容器内的主进程,并持续监控其状态。
1.5 Service 的网络抽象
Service 是 Kubernetes 网络模型的核心抽象,它为一组 Pod 提供稳定的 IP 地址和 DNS 名称。
1.5.1 Service 的四种类型
ClusterIP:集群内部访问,仅在集群内部可达,默认类型。
NodePort:通过节点端口访问,每个节点都会开放一个相同的端口,范围 30000-32767。
LoadBalancer:通过云厂商的负载均衡器访问,需要云厂商支持。
ExternalName:通过 CNAME 记录将 Service 映射到外部域名。
apiVersion: v1 kind: Service metadata: name: nginx-service namespace: default spec: type: ClusterIP selector: app: nginx ports: - name: http protocol: TCP port: 80 targetPort: 80
1.5.2 kube-proxy 与服务发现
Kubernetes 不直接实现 Service 的网络转发,而是通过每个节点上的 kube-proxy 组件实现。
kube-proxy 有三种工作模式:
iptables 模式:kube-proxy 通过 iptables 规则实现负载均衡。适用于节点数量不多的场景。
IPVS 模式:kube-proxy 通过 IPVS(IP Virtual Server)实现负载均衡。适用于大规模集群,性能更好。
nftables 模式:新一代模式,逐步替代 iptables。
查看 kube-proxy 的工作模式:
# 查看 kube-proxy 模式 kubectl get configmap kube-proxy-config -n kube-system -o yaml | grep mode # 在节点上查看 iptables 规则 sudo iptables -t nat -L KUBE-SERVICES -n -v | head -20 # 查看 IPVS 规则 sudo ipvsadm -L -n | grep KUBE
二、从 Deployment 到 Service 的完整数据流
2.1 工作流的完整路径
从 Deployment 到 Service 的完整数据流包含以下步骤:
第一步,用户通过 kubectl 或 API 创建 Deployment 资源。
第二步,Deployment 控制器创建 ReplicaSet 资源。
第三步,ReplicaSet 控制器根据 spec 创建 Pod 资源。
第四步,调度器为每个未调度的 Pod 选择节点。
第五步,节点上的 kubelet 创建和启动容器。
第六步,用户创建 Service 资源,通过 selector 关联到 Pod。
第七步,kube-proxy 配置网络规则,实现服务访问。
2.2 实际工作流演示
2.2.1 创建 Deployment
# 创建 Deployment kubectl apply -f deployment.yaml # 查看 Deployment 状态 kubectl get deployment nginx-deployment kubectl describe deployment nginx-deployment # 查看 ReplicaSet kubectl get replicaset kubectl get rs -l app=nginx # 查看 Pod kubectl get pod -l app=nginx kubectl get pods -o wide -l app=nginx
Deployment 创建后,ReplicaSet 控制器会立即创建对应的 ReplicaSet。然后 ReplicaSet 控制器会创建 Pod 对象。调度器为每个 Pod 选择节点后,kubelet 在对应节点上启动容器。
2.2.2 创建 Service
# 创建 Service kubectl apply -f service.yaml # 查看 Service kubectl get svc nginx-service kubectl describe svc nginx-service # 查看 Endpoint kubectl get endpoints nginx-service kubectl describe endpoints nginx-service
Service 创建后,kube-proxy 会自动配置相应的网络规则。Endpoint 控制器会根据 selector 自动创建 Endpoint 对象,关联到匹配的 Pod。
2.3 核心配置项详解
2.3.1 Selector 的作用机制
Selector 是连接 Deployment、ReplicaSet、Pod、Service 的关键纽带。
Deployment 的 selector 用于标识它管理的 ReplicaSet。
ReplicaSet 的 selector 必须匹配其模板中的 Pod 标签。
Service 的 selector 用于发现和关联后端 Pod。
这三个 selector 的关系必须一致,否则会导致工作流断裂。
常见错误案例:
# Deployment 的 selector selector: matchLabels: app: nginx # 但是 Pod 模板的标签是 template: metadata: labels: app: nginx-web # 标签不一致,导致无法管理 # Service 的 selector selector: app: nginx-proxy # 与 Pod 标签不匹配,导致无法关联
2.3.2 端口配置的关键点
Service 的端口配置有几个关键参数:
port:Service 暴露的端口,其他 Pod 访问 Service 时使用这个端口。
targetPort:后端 Pod 监听端口,流量转发到这个端口。
nodePort:节点端口,外部访问时使用。
protocol:协议类型,TCP 或 UDP。
ports: - name: http protocol: TCP port: 80 # Service 端口 targetPort: 8080 # 容器端口,如果省略则默认等于 port nodePort: 30080 # 节点端口,仅 NodePort 类型需要指定
三、滚动更新与回滚机制
3.1 滚动更新原理
滚动更新是 Deployment 的默认更新策略,它通过逐步替换旧版 Pod 来实现零停机部署。
3.1.1 滚动更新参数
maxUnavailable:更新过程中允许不可用的最大 Pod 数量。可以是绝对值或百分比。
maxSurge:更新过程中允许超过期望副本数的最大 Pod 数量。可以是绝对值或百分比。
这两个参数配合使用,实现更新过程中的服务连续性。
示例配置:
spec: strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 25% # 最多25%的 Pod 不可用 maxSurge: 25% # 最多25%的 Pod 超出期望数量
3.1.2 滚动更新过程
滚动更新的实际过程:
假设 replicas=3,maxUnavailable=1,maxSurge=1。
初始状态:3 个旧版 Pod 正常运行。
第一步:创建一个新版 Pod,总数变为 4。
第二步:等待新版 Pod Ready 后,删除一个旧版 Pod,总数变为 3。
第三步:再创建一个新版 Pod,总数变为 4。
第四步:等待新版 Pod Ready 后,再删除一个旧版 Pod。
重复以上步骤,直到所有 Pod 都更新为新版。
查看滚动更新状态:
# 查看更新历史 kubectl rollout history deployment/nginx-deployment # 查看特定版本的详情 kubectl rollout history deployment/nginx-deployment --revision=2 # 查看当前滚动状态 kubectl rollout status deployment/nginx-deployment # 查看 Deployment 事件 kubectl describe deployment nginx-deployment | grep -A 10 "Events:"
3.2 回滚操作
当滚动更新出现问题时,可以快速回滚到之前的版本。
# 回滚到上一个版本 kubectl rollout undo deployment/nginx-deployment # 回滚到指定版本 kubectl rollout undo deployment/nginx-deployment --to-revision=2 # 验证回滚状态 kubectl rollout status deployment/nginx-deployment kubectl get pods -l app=nginx
回滚的本质是创建一个新的 ReplicaSet,其配置与指定版本的 ReplicaSet 相同。
3.3 暂停与恢复更新
对于复杂的更新场景,可以暂停滚动更新,分步进行。
# 暂停更新 kubectl rollout pause deployment/nginx-deployment # 执行部分更新 kubectl set image deployment/nginx-deployment nginx=nginx:1.28-alpine # 恢复更新 kubectl rollout resume deployment/nginx-deployment
四、网络通信机制
4.1 容器间通信
同一节点上的容器通过 CNI(Container Network Interface)插件配置的网桥进行通信。
Kubernetes 使用 Pause 容器作为 Pod 的基础设施容器,所有业务容器共享 Pause 容器的网络命名空间。
查看节点网络配置:
# 在节点上查看网桥 ip link show type bridge # 查看 cni0 网桥 ip addr show cni0 # 查看路由表 ip route
4.2 Pod 间通信
不同节点上的 Pod 通过 overlay 网络进行通信。常用的 CNI 插件包括 Flannel、Calico、Cilium 等。
Flannel 使用 VXLAN 封装数据包,通过 UDP 发送到目标节点。
Calico 使用 BGP 协议直接路由数据包,性能更好。
Cilium 基于 eBPF 实现,提供更精细的网络控制和观测能力。
4.3 Service 访问原理
当一个 Pod 访问 Service 时,流量经过以下路径:
第一步,Pod 通过 DNS 解析 Service 名称得到 ClusterIP。
第二步,Pod 将请求发送到 ClusterIP。
第三步,kube-proxy 拦截请求,根据 iptables 或 IPVS 规则将目标 IP 替换为后端 Pod 的真实 IP。
第四步,请求被路由到后端 Pod。
查看 DNS 解析:
# 进入测试 Pod kubectl run -it --rm debug --image=busybox:1.36 -- sh # 查询 DNS nslookup kubernetes.default nslookup nginx-service.default.svc.cluster.local # 测试 Service 访问 wget -qO- http://nginx-service:80
五、常见故障与排障
5.1 Pod 无法启动
5.1.1 镜像拉取失败
这是最常见的 Pod 启动失败原因。
排查步骤:
# 查看 Pod 状态 kubectl get pod-o wide # 查看详细事件 kubectl describe pod | grep -A 20 "Events:" # 常见错误信息: # ErrImagePull:镜像拉取失败 # ImagePullBackOff:多次拉取失败后进入回退状态 # InvalidImageName:镜像名称格式错误
解决方案:
# 检查镜像是否存在 docker pull# 使用私有镜像仓库 kubectl create secret docker-registry regcred --docker-server= --docker-username= --docker-password= --docker-email= # 在 Pod 中引用 secret spec: imagePullSecrets: - name: regcred
5.1.2 资源不足
节点资源不足会导致 Pod 无法调度或启动。
排查方法:
# 查看节点状态 kubectl describe node# 查看资源分配 kubectl describe node | grep -A 5 "Allocated resources" # 查看 Pod 的资源请求 kubectl get pod -o jsonpath='{.spec.containers[*].resources}'
5.1.3 调度失败
# 查看 Pod 事件中的调度错误 kubectl describe pod| grep -A 5 "Events:" # 常见错误: # FailedScheduling:调度失败 # 0/3 nodes are available: 1 node(s) had taint {node.kubernetes.io/not-ready:...} # 0/3 nodes are available: 1 node(s) didn't match Pod's node affinity/selector
5.2 Service 无法访问
5.2.1 Endpoint 为空
# 查看 Service 和 Endpoint kubectl get svc nginx-service kubectl get endpoints nginx-service # 如果 Endpoint 为空,检查 selector 是否匹配 kubectl get pods -l app=nginx kubectl describe svc nginx-service | grep Selector
常见原因:Deployment 的 selector 与 Service 的 selector 不匹配。
5.2.2 kube-proxy 异常
# 检查 kube-proxy 日志 kubectl logs -n kube-system -l k8s-app=kube-proxy # 检查 kube-proxy 配置 kubectl get configmap kube-proxy-config -n kube-system -o yaml # 重启 kube-proxy(谨慎操作) kubectl rollout restart daemonset kube-proxy -n kube-system
5.2.3 DNS 解析问题
# 检查 CoreDNS 是否正常运行 kubectl get pod -n kube-system -l k8s-app=kube-dns # 测试 DNS 解析 kubectl exec -it-- nslookup nginx-service # 检查 /etc/resolv.conf 配置 kubectl exec -it -- cat /etc/resolv.conf
5.3 网络连接问题
5.3.1 跨节点通信故障
# 在源节点上测试 ping# 追踪路由 traceroute # 检查 CNI 插件状态 ip link show | grep cni cat /etc/cni/net.d/10-flannel.conflist
5.3.2 网络策略问题
# 检查是否配置了 NetworkPolicy kubectl get networkpolicy -o yaml # 示例:允许特定命名空间的流量 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-frontend spec: podSelector: matchLabels: app: backend policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: name: frontend ports: - protocol: TCP port: 80
5.4 滚动更新异常
5.4.1 更新卡住
# 查看 Deployment 状态 kubectl get deployment nginx-deployment # 查看 ReplicaSet 状态 kubectl get rs -l app=nginx # 检查不可用的 Pod kubectl get pod -l app=nginx | grep -v Running # 强制回滚 kubectl rollout undo deployment/nginx-deployment
5.4.2 Pod 无法 Ready
# 检查探针配置 kubectl describe pod| grep -A 10 "Conditions:" # 测试健康检查端点 kubectl exec -it -- curl -k http://localhost:80/healthz # 检查探针日志 kubectl describe pod | grep -A 5 "Liveness" | grep -A 5 "Reason:"
六、最佳实践
6.1 资源配额与限制
为每个容器设置合理的资源请求和限制:
spec: containers: - name: nginx resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "500m"
建议的做法:
requests 设置为实际平均使用量,确保调度器能够做出正确决策。
limits 设置为峰值上限,防止单个容器耗尽节点资源。
内存 limits 应该与 requests 相近,避免内存碎片化。
6.2 健康检查配置
合理配置探针,避免过早或过晚检测到故障:
spec: containers: - name: nginx livenessProbe: httpGet: path: /healthz port: 80 initialDelaySeconds: 15 # 等待容器启动完成 periodSeconds: 10 # 每10秒检查一次 failureThreshold: 3 # 连续3次失败才重启 readinessProbe: httpGet: path: /ready port: 80 initialDelaySeconds: 5 periodSeconds: 5 failureThreshold: 1 # 一次失败即移除
initialDelaySeconds 需要根据应用启动时间调整。过短会导致启动过程中被杀死,过长会导致故障发现延迟。
6.3 标签管理策略
建立统一的标签管理规范:
metadata: labels: app.kubernetes.io/name: nginx # 应用名称 app.kubernetes.io/instance: nginx-prod # 实例名称 app.kubernetes.io/version: "1.27" # 版本号 app.kubernetes.io/component: webserver # 组件类型 app.kubernetes.io/part-of: frontend # 所属应用 app.kubernetes.io/managed-by: kubectl # 管理工具
使用标签进行环境隔离、版本管理、团队划分。
6.4 部署策略选择
根据业务需求选择合适的部署策略:
金丝雀发布:逐步将流量切换到新版本,降低发布风险。
spec: strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 maxSurge: 10%
蓝绿部署:通过两个完全相同的环境实现瞬时切换。
滚动更新:适用于无状态服务,默认策略。
6.5 日志与监控
配置集群级日志收集:
# 使用 Fluentd 收集日志 apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd-logging namespace: kube-system spec: selector: matchLabels: k8s-app: fluentd-logging template: spec: containers: - name: fluentd image: fluentd:v1.16 volumeMounts: - name: varlog mountPath: /var/log - name: containers mountPath: /var/lib/docker/containers volumes: - name: varlog hostPath: path: /var/log - name: containers hostPath: path: /var/lib/docker/containers
七、性能与扩展
7.1 调度器性能调优
大规模集群中,调度器可能成为瓶颈:
# kube-scheduler 配置 apiVersion: kubescheduler.config.k8s.io/v1beta3 kind: KubeSchedulerConfiguration profiles: - schedulerName: default-scheduler percentageOfNodesToScore: 50 # 减少扫描节点数量 podInitialBackoffSeconds: 10 podMaxBackoffSeconds: 20
7.2 kube-proxy 性能优化
IPVS 模式相比 iptables 有更好的性能:
# 查看当前模式 kubectl get configmap kube-proxy-config -n kube-system -o yaml | grep mode # 切换到 IPVS 模式 kubectl edit configmap kube-proxy-config -n kube-system
7.3 水平自动扩缩容
使用 HPA 实现自动扩缩容:
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: nginx-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx-deployment minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80
八、安全配置
8.1 RBAC 权限控制
最小权限原则:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: pod-reader namespace: default rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: pod-reader-binding subjects: - kind: ServiceAccount name: default namespace: default roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io
8.2 Pod 安全策略
使用 Pod Security Standards:
apiVersion: v1 kind: Namespace metadata: name: production labels: pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/warn: restricted
总结
从 Deployment 到 Service 的工作流是 Kubernetes 最核心的运维主线。理解 Deployment 的声明式更新机制、ReplicaSet 的控制循环、Pod 的调度与启动过程、Service 的网络抽象,是解决日常问题的理论基础。
实际排障中,应该按照数据流顺序逐层排查:先看资源状态是否达到期望,再看调度是否成功,然后看容器是否正常启动,最后看网络是否连通。每个环节都有对应的 kubectl 命令和节点工具可以使用。
配置层面,资源限制要合理、健康检查要准确、标签管理要规范,这些最佳实践能够显著减少生产环境中的故障发生概率。
全部0条评论
快来发表一下你的评论吧 !