Pod
Pod 是 K8s 的最小调度单位,里面可以有一个或多个容器,这些容器共享网络、存储等资源。
Pod 里的容器共享什么
| 资源 | 是否共享 | 说明 |
|---|---|---|
| 网络 namespace | 共享 | 同一个 Pod 内容器共用 IP、端口空间,可以用 localhost 通信 |
| UTS namespace | 共享 | 主机名相同 |
| IPC namespace | 共享 | 可以用共享内存、信号量 |
| 存储卷 Volume | 可共享 | 多个容器可以挂同一个 volume |
| PID namespace | 默认不共享 | 设置 shareProcessNamespace: true 才共享 |
| MNT namespace | 默认不共享 | 每个容器有自己的 rootfs |
所以同一个 Pod 里:
- 容器之间可以用
localhost访问 - 端口不能冲突
- 主机名一样
- 文件系统默认各自独立
- 可以通过 volume 共享数据
通常一个 Pod 里放几个容器?
大多数情况:一个 Pod 一个主容器。
多容器常见于:
- sidecar:日志收集、代理
- init container:启动前初始化
- adapter:格式转换
它们生命周期和调度绑定在一起。
设计时,多个容器是否放在一个Pod内的关键考虑因素
| 维度 | 适合同 Pod 的信号 | 应该拆开的信号 |
|---|---|---|
| 网络 | 必须用 localhost 通信,共享端口空间 |
通过 Service、API、消息队列通信即可 |
| 存储 | 必须共享同一个 volume,低延迟读写同一批文件 | 用 PVC、对象存储、数据库交换数据即可 |
| 生命周期 | 一起创建、一起删除,生命周期基本一致 | 一个长期运行,一个按任务创建销毁 |
| 调度 | 必须调度到同一节点 | 可以分散到不同节点 |
| 安全隔离 | 两者可信程度相同,安全要求一致 | 一个跑不可信代码,需要强隔离 |
| 扩缩容 | 副本数和扩缩容节奏一致 | 一个要扩,一个不用扩,或比例不同 |
| 资源边界 | 可以共享同一套资源限制和 QoS | 需要独立 CPU/内存 limits、独立 QoS |
| 失败影响 | 一个挂掉可以接受影响另一个 | 一个崩溃不应影响另一个 |
Node
节点(Node)就是 K8s 集群里的一台工作机器(虚拟机or物理机),Pod 最终跑在节点上。
节点一般可以根据职责分为两类------控制节点和工作节点
工作负载
Deployment
Deployment 是 K8s 里最常用的工作负载控制器,用来管理无状态 Pod 的副本
StatefulSet
StatefulSet 是专门用来管理有状态Pod的工作负载控制器
StatefulSet 和 Deployment 的核心区别
| 维度 | Deployment | StatefulSet |
|---|---|---|
| Pod 身份 | 随机名字,可互换 | 固定名字,如 web-0、web-1 |
| 网络标识 | 通常用 Service 负载均衡 | 每个 Pod 有稳定 DNS |
| 存储 | 通常无状态,共享存储可选 | 每个 Pod 独立 PVC |
| 启动顺序 | 并行启动 | 默认按顺序启动 |
| 扩缩顺序 | 随意 | 有序扩缩 |
| 更新顺序 | 滚动更新,任意替换 | 默认逆序更新 |
| 适用 | 无状态、可水平扩展 | 有状态、需要稳定标识和存储 |
Deployment + 普通 Service的K8s内部请求链路
客户端
-> DNS: web.default.svc.cluster.local
-> 得到 ClusterIP: 10.96.0.10
-> 向 ClusterIP 发请求
-> 节点内核按 kube-proxy 规则 DNAT
-> 转发到任意一个 Ready Pod(如 web-7d8f9c-abcde)
特点:
- Pod 名字随机,客户端不关心连的是哪个
- Service 做负载均衡
- Pod 挂了、扩缩容,EndpointSlice 更新,规则自动变
StatefulSet + Headless Service的K8s内部请求链路
客户端
-> DNS: web.default.svc.cluster.local
-> 得到所有 Pod IP 列表:[10.244.0.5, 10.244.0.6, 10.244.0.7]
-> 客户端自己选一个 Pod IP
-> 直连 Pod
特点:
- 没有 ClusterIP
- 不经过 kube-proxy VIP 转发
- 负载均衡由客户端自己做
- 适合 gRPC 客户端自己维护连接池
客户端(集群内部的其他Pod)如何知道DNS的Key(FQDN)的?------通过配置文件提前配置
有状态的Pod是不是就一定不能用Deployemnt?------不一定,如果不考虑可用性,Pod是单实例的话,那用Deployment也可以。核心决定性因素在于------Pod 挂掉重建后,能不能还以原来的身份,挂回原来分配给它的那个卷。单副本情况下不需要做多副本的区分,所以可以
Service------把IP:Port路由到具体的Pod
Service(服务) 是 Kubernetes 中用于为 Pod 提供稳定网络访问入口和负载均衡的核心组件,它抽象了 Pod 的网络访问方式,使得外部客户端或其他 Pod 可以通过 Service 访问后端 Pod,而无需关心 Pod 的具体 IP 地址或生命周期。Service本身也只是规则,真正处理流量的是kube-proxy。负责K8s的四层路由
Service的所有类型
K8s 里 Service 的 spec.type 官方只有 4 种:
| 类型 | 作用 | 外部能否访问 | 典型场景 |
|---|---|---|---|
ClusterIP |
分配一个集群内部虚拟 IP | 不能,默认仅集群内 | 集群内服务互访,默认类型 |
NodePort |
在ClusterIP的基础上在每个节点上开一个端口 | 能,节点IP:端口 |
测试、简单暴露、无云 LB |
LoadBalancer |
向云/基础设施申请外部负载均衡器 | 能,外部LB IP:端口 |
生产环境暴露服务 |
ExternalName |
用 DNS CNAME 指向外部域名 | 不代理流量,只做 DNS 映射 | 集群内访问外部服务 |
另外还有两个容易混淆的概念:
- Headless Service :不是独立类型,而是
ClusterIP: None的特殊 ClusterIP。 - ExternalIPs :
spec.externalIPs字段,不是 Service 类型。 - Ingress:不是 Service 类型,是七层入口,通常后端再接 Service。
ClusterIP
ClusterIP 是 K8s 给 Service 分配的一个集群内部虚拟 IP ,用来在集群内稳定地访问一组 Pod。
查看机器中的所有Service和其ClusterIP
root@knowledgeskilltest:/home/zn# kubectl get services --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8d
dynamic-test-runtime dynamic-test-admission-projector ClusterIP 10.96.211.7 <none> 9443/TCP 6d1h
dynamic-test-runtime dynamic-test-run ClusterIP None <none> <none> 6d1h
dynamic-test dynamic-test-api ClusterIP 10.96.65.96 <none> 8010/TCP 6d18h
dynamic-test dynamic-test-gateway ClusterIP 10.96.4.159 <none> 9444/TCP 6d18h
dynamic-test dynamic-test-projector ClusterIP 10.96.122.184 <none> 8443/TCP 6d18h
dynamic-test minio ClusterIP 10.96.225.52 <none> 9000/TCP,9001/TCP 6d19h
dynamic-test mock-event-sink ClusterIP 10.96.170.115 <none> 8443/TCP 6d18h
dynamic-test mock-model-provider ClusterIP 10.96.252.70 <none> 8443/TCP 6d18h
dynamic-test mysql ClusterIP 10.96.3.129 <none> 3306/TCP 6d19h
dynamic-test registry ClusterIP 10.96.250.62 <none> 5000/TCP 6d1h
dynamic-test skillhub-mock ClusterIP 10.96.4.147 <none> 8443/TCP 6d18h
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 8d
opensandbox-dynamic-test opensandbox-ingress-gateway ClusterIP 10.96.184.95 <none> 80/TCP 7d
opensandbox-dynamic-test opensandbox-server ClusterIP 10.96.152.62 <none> 8443/TCP 6d23h
可以看到dynamic-test-run 这个Service其ClusterIP为None,这种Service 就是前文提到的Headless Service
查看机器中的所有Pod
root@knowledgeskilltest:/home/zn# kubectl get pods -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
dynamic-test-runtime dynamic-test-admission-projector-7b967f54d8-vjs6j 1/1 Running 0 5d20h 10.244.0.165 dynamic-test-control-plane <none> <none>
dynamic-test-runtime dynamic-test-admission-projector-7b967f54d8-x286g 1/1 Running 0 5d20h 10.244.0.164 dynamic-test-control-plane <none> <none>
dynamic-test-runtime dynamic-test-run-0 1/1 Running 0 43h 10.244.0.18 dynamic-test-control-plane <none> <none>
dynamic-test-runtime dynamic-test-run-1 1/1 Running 0 42h 10.244.0.22 dynamic-test-control-plane <none> <none>
dynamic-test-runtime dynamic-test-run-2 1/1 Running 0 42h 10.244.0.21 dynamic-test-control-plane <none> <none>
dynamic-test-runtime dynamic-test-runtime-reaper-7dbcddcb78-bzn9q 1/1 Running 0 5d20h 10.244.0.167 dynamic-test-control-plane <none> <none>
dynamic-test-runtime dynamic-test-runtime-reaper-7dbcddcb78-kwlx5 1/1 Running 0 5d20h 10.244.0.163 dynamic-test-control-plane <none> <none>
dynamic-test dynamic-test-api-556d6cbbbb-8949c 1/1 Running 0 23h 10.244.0.36 dynamic-test-control-plane <none> <none>
dynamic-test dynamic-test-assistant-96bfc89bd-4252m 1/1 Running 0 7d16h 10.244.0.123 dynamic-test-control-plane <none> <none>
dynamic-test dynamic-test-image-74f65fdc7d-8f6xd 1/1 Running 0 47h 10.244.0.238 dynamic-test-control-plane <none> <none>
dynamic-test dynamic-test-migration-8bgfk 0/1 Completed 0 7d17h 10.244.0.59 dynamic-test-control-plane <none> <none>
dynamic-test dynamic-test-model-gateway-747dc9c58f-r5bps 1/1 Running 0 43h 10.244.0.6 dynamic-test-control-plane <none> <none>
dynamic-test dynamic-test-projector-6d5684d6f9-67wpj 1/1 Running 0 7d16h 10.244.0.118 dynamic-test-control-plane <none> <none>
dynamic-test dynamic-test-projector-6d5684d6f9-sbvjw 1/1 Running 0 7d16h 10.244.0.119 dynamic-test-control-plane <none> <none>
dynamic-test dynamic-test-registry-d66678795-8spdp 1/1 Running 0 7d 10.244.0.135 dynamic-test-control-plane <none> <none>
dynamic-test dynamic-test-relay-5c74788d86-x6drs 1/1 Running 0 7d16h 10.244.0.121 dynamic-test-control-plane <none> <none>
dynamic-test minio-59c78bffbd-kqqbp 1/1 Running 0 7d17h 10.244.0.41 dynamic-test-control-plane <none> <none>
dynamic-test mock-event-sink-7c966d5f7c-gzcmh 1/1 Running 0 7d16h 10.244.0.107 dynamic-test-control-plane <none> <none>
dynamic-test mock-model-provider-857bd94db8-8cq2h 1/1 Running 0 44h 10.244.0.250 dynamic-test-control-plane <none> <none>
dynamic-test mysql-6fcfccb8f8-92mld 1/1 Running 0 7d17h 10.244.0.37 dynamic-test-control-plane <none> <none>
dynamic-test skillhub-mock-5d785786c9-kz4bn 1/1 Running 0 7d16h 10.244.0.114 dynamic-test-control-plane <none> <none>
ingress-nginx ingress-nginx-controller-b6b495bc9-rrnrs 1/1 Running 0 4m22s 10.244.0.44 dynamic-test-control-plane <none> <none>
kube-system coredns-559f6c778d-4wdfq 1/1 Running 0 9d 10.244.0.3 dynamic-test-control-plane <none> <none>
kube-system coredns-559f6c778d-mzqb8 1/1 Running 0 9d 10.244.0.4 dynamic-test-control-plane <none> <none>
kube-system etcd-dynamic-test-control-plane 1/1 Running 0 9d 172.18.0.2 dynamic-test-control-plane <none> <none>
kube-system kindnet-kkmdv 1/1 Running 0 9d 172.18.0.2 dynamic-test-control-plane <none> <none>
kube-system kube-apiserver-dynamic-test-control-plane 1/1 Running 0 9d 172.18.0.2 dynamic-test-control-plane <none> <none>
kube-system kube-controller-manager-dynamic-test-control-plane 1/1 Running 0 9d 172.18.0.2 dynamic-test-control-plane <none> <none>
kube-system kube-proxy-vhnbx 1/1 Running 0 9d 172.18.0.2 dynamic-test-control-plane <none> <none>
kube-system kube-scheduler-dynamic-test-control-plane 1/1 Running 0 9d 172.18.0.2 dynamic-test-control-plane <none> <none>
local-path-storage local-path-provisioner-75f7fc7dc5-lh46q 1/1 Running 0 9d 10.244.0.2 dynamic-test-control-plane <none> <none>
opensandbox-dynamic-test opensandbox-controller-manager-5d44fcc5f7-r7gvp 1/1 Running 0 2d 10.244.0.186 dynamic-test-control-plane <none> <none>
opensandbox-dynamic-test opensandbox-ingress-gateway-656fb874c-sf8tv 1/1 Running 0 2d 10.244.0.187 dynamic-test-control-plane <none> <none>
opensandbox-dynamic-test opensandbox-server-7b497b4b5c-nzm7s 2/2 Running 0 46h 10.244.0.244 dynamic-test-control-plane <none> <none>
name为coredns开头的,就是负责将FQDN转化为IP的组件
- 对于普通Service,其会将FQDN解析为ClusterIP
- 对于Headless Service,其会将FQDN解析为后端Pod IP列表
- StatefulSet 工作负载下的POD,会有稳定的POD名,也会有稳定的FQDN,coreDNS能将其转化为单个Pod 的IP
neme为kube-proxy开头的,就是负责将ClusterIP/NodePort流量转发到具体Pod的组件
NodePort
在每个节点 上开放同一个端口 ,把这个端口收到的流量,转发到 Service 后面的 Pod。一个端口对应一个Service
注意启用了NodePort后,整个Service一般依旧会有一个ClusterIP------NodePort负责对外,ClusterIP负责对内
LoadBalancer
本质上是 NodePort 的上一层封装 :在 NodePort 基础上,再向云厂商或基础设施申请一个独立的负载均衡器 IP。刚需公网IP
Q:LB怎么知道过来请求到底要访问哪个NodePort?
A:一个云 LB 可以为多个端口创建一个监听器,每个监听器分别映射到对应的后端------一个IP不同,但是Port相同的IP:Port列表。
K8s 原生 LoadBalancer 的语义是"一个 Service 一个 LB"------所以一个LoadBalancer虽然可以对应多个NodePort,但是其后端都是同一组Pod。也就是说不存在只使用一个公网IP+LoadBalancer就完成多个Service的暴露的情况。或者说K8s原生中,没有LB这个对象,有的只是LoadBalancer这种Service类型,因此也就没有LB-Service的一对多关系。
但是云厂商天生就需要对LB和公网IP做管理,因此实现一套这样的逻辑成本相对低------而且用户也有需求。
所以其实在云上,完全可以用 一个公网 IP + 一个负载均衡器(LB),不用 Ingress,就对外提供多个服务。限制就是必须依靠不同的端口来区分不同的服务。
Ingress------把HTTP 请求(域名、路径)路由到Service
Ingress 是 K8s 里的一种 API 对象,用来定义"外部 HTTP/HTTPS 流量怎么进入集群、路由到哪些 Service"。它本身只是规则,真正处理流量的是 Ingress Controller(一组以DaemonSet工作负载形式部署的Pod)。负责K8s的七层路由
root@knowledgeskilltest:/home/zn# kubectl get pods -A -o wide | grep ingress
ingress-nginx ingress-nginx-controller-b6b495bc9-rrnrs 1/1 Running 0 7m21s 10.244.0.44 dynamic-test-control-plane <none> <none>
这个筛选出来的Pod就是ingress Controller实例,它里面通常跑着 ingress-nginx 的 controller 逻辑和 Nginx 进程。真正直接承接外部 HTTP/HTTPS 请求、按 Ingress 规则转发的,就是这个 Pod 里的 Nginx。
Ingress Controller的Service一般是前文中提到的LoadBalancer或者NodePort,通过IP(一般LB是公网,NodePort是内网)提供一个4层入口,然后Ingress Controller内部的nginx再解析 Host/Path,将请求根据Ingress规则反向代理到到后端 Service 对应的 Pod(四层)
外部流量路径
外部用户
-> DNS 解析到入口 IP
-> 四层入口:云 LB / Service type=LoadBalancer / NodePort
-> Ingress Controller Pod
└── TCP 承载到达(四层)
└── Nginx / Traefik / Envoy 解析 HTTP(七层)
-> 根据 Ingress 规则选择后端
-> 通过 TCP 连接发往后端 Pod IP:Port(四层)
Service / Endpoint 提供服务发现,可能不经过 ClusterIP
-> 业务应用解析 HTTP,处理业务(七层)