一、Kubernetes Ingress
1.1 Ingress 介绍
- Ingress 为 Service 提供外部可访问的 URL、7 层负载均衡、SSL/TLS 终止、基于名称的虚拟主机等能力。
- Ingress 只是 K8s 资源对象(相当于 Nginx 配置) ;真正处理流量的是 Ingress 控制器(相当于前端 Nginx 实体),控制器不随集群自动启动,需单独部署。
- Ingress 只处理 HTTP/HTTPS;其他协议对外暴露仍需 NodePort / LoadBalancer 类型 Service。
- 官方维护:AWS、GCE、Nginx Ingress 控制器;本次实验使用 ingress‑nginx。
1.2 ingress‑nginx 工作流程
- 先部署 Ingress Controller 实体(前端 Nginx Pod);
- 再创建 Ingress 规则资源;
- Controller 与 apiserver 交互,动态 Watch 集群中的 Ingress 规则,解析后生成 Nginx 配置;
- 配置写入 Controller Pod 的
/etc/nginx/nginx.conf,然后 reload Nginx。
本质:7 层 HTTP/HTTPS 反向代理。部署前提:已具备外部流量入口(实验用 MetalLB LoadBalancer)。
1.3 部署 ingress‑nginx
# 下载解压
wget https://laoma.cloud/.../ingress-nginx-controller-v1.11.2.tar.gz
tar -xf ingress-nginx-controller-v1.11.2.tar.gz
# 查看镜像并替换私有仓库地址、去掉 sha256 摘要
grep image: ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml | uniq
sed -ir 's#@sha256.*##;s/registry.k8s.io/hub.laoma.cloud/' \
ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
# 部署
kubectl apply -f ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
kubectl get all -n ingress-nginx
deploy.yaml 四部分组成
- 独立命名空间
ingress-nginx; - ConfigMap:存放控制器通用配置变量;
- RBAC:ServiceAccount、ClusterRole、Role、RoleBinding、ClusterRoleBinding;
- ingress‑nginx‑controller Deployment(把 Ingress 规则转化为 Nginx 配置)。
部署后
ingress-nginx-controllerService 为 LoadBalancer 类型,暴露 80、443;另有两个 Job(admission‑create /admission‑patch)完成证书准入配置。
1.4 Ingress 规则核心结构
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myingress
spec:
ingressClassName: nginx # 指定由哪个控制器实现
defaultBackend: # 无 rule 时的兜底后端
service:
name: testsvc
port:
number: 80
tls: # TLS 证书绑定
- hosts: [www.laoma.cloud]
secretName: www-tls
rules:
- host: www.laoma.cloud # 虚拟主机名,默认 *
http:
paths:
- path: / # 路径
pathType: Prefix # 路径匹配类型
backend:
service:
name: www
port:
number: 80
IngressClass
- 不同控制器实现不同 Ingress;每个 Ingress 通过
ingressClassName引用 IngressClass 资源。 - 注解
ingressclass.kubernetes.io/is-default-class: "true"可标记默认类;未写ingressClassName的 Ingress 自动使用默认类。
路径匹配类型 pathType
表格
| 类型 | 规则 |
|---|---|
Prefix |
按 / 分隔的路径元素逐个前缀匹配,区分大小写;/ 匹配所有路径;/aaa/bbb 匹配 /aaa/bbb/ccc,但不匹配 /aaa/bbbxyz |
Exact |
精确匹配 URL 路径,区分大小写;/foo 不匹配 /foo/ |
ImplementationSpecific |
匹配方式由控制器实现决定(ingress‑nginx 正则场景使用) |
多重匹配优先级 :匹配路径最长者优先;长度相同则 Exact 优先于 Prefix。
主机名匹配
- 精确匹配:HTTP
Host头与host完全一致; - 通配符:
*.foo.com只覆盖一个 DNS 标签 ,匹配bar.foo.com,不匹配baz.bar.foo.com、也不匹配foo.com。
1.5 规则实践(实验环境)
# 两个站点,各 2 副本 httpd
kubectl create deployment webapp01 --image=hub.laoma.cloud/library/httpd --replicas=2
kubectl create deployment webapp02 --image=hub.laoma.cloud/library/httpd --replicas=2
# 分别写主页、webapp02 准备 games/index.html
kubectl expose deployment webapp01 --port=80 --target-port=80
kubectl expose deployment webapp02 --port=80 --target-port=80
① 多域名虚拟主机(多 host 路由)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-host-ingress
spec:
ingressClassName: nginx
rules:
- host: webapp01.laoma.cloud
http:
paths:
- path: /
pathType: Prefix
backend: {service: {name: webapp01, port: {number: 80}}}
- host: webapp02.laoma.cloud
http:
paths:
- path: /
pathType: Prefix
backend: {service: {name: webapp02, port: {number: 80}}}
kubectl apply -f multi-host-ingress.yaml
kubectl describe ingress multi-host-ingress
# 客户端 hosts 解析到 LB IP,直接用域名 80 端口访问(不带端口号)
echo '10.1.8.40 webapp01.laoma.cloud' >> /etc/hosts
echo '10.1.8.40 webapp02.laoma.cloud' >> /etc/hosts
curl webapp01.laoma.cloud
② 同一域名多路径路由(path 分流)
spec:
ingressClassName: nginx
rules:
- host: www.laoma.cloud
http:
paths:
- path: /
pathType: Prefix
backend: {service: {name: webapp01, port: {number: 80}}}
- path: /games
pathType: Prefix
backend: {service: {name: webapp02, port: {number: 80}}}
curl www.laoma.cloud # → webapp01
curl www.laoma.cloud/games/ # → webapp02
③ 路径重写 / 裁剪(等价 Nginx proxy_pass /)
场景:前端访问 /api/xxx,后端只识别 /xxx,剥离前缀。
metadata:
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: www.laoma.cloud
http:
paths:
- path: /webapp01/(.*)
pathType: ImplementationSpecific
backend: {service: {name: webapp01, port: {number: 80}}}
- path: /webapp02/(.*)
pathType: ImplementationSpecific
backend: {service: {name: webapp02, port: {number: 80}}}
④ TLS 证书 + 强制 HTTPS
# 生成自签证书并创建 TLS Secret
openssl genrsa -out www.key 2048
openssl req -new -key www.key -out www.csr \
-subj "/C=CN/ST=JS/L=NJ/O=LM/OU=DEVOPS/CN=www.laoma.cloud/emailAddress=webadmin@laoma.cloud"
openssl x509 -req -days 3650 -in www.csr -signkey www.key -out www.crt
kubectl create secret tls www-tls --cert=./www.crt --key=./www.key
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts: [www.laoma.cloud]
secretName: www-tls
rules:
- host: www.laoma.cloud
http:
paths:
- path: /
pathType: Prefix
backend: {service: {name: webapp01, port: {number: 80}}}
# -L 跟随 301/302/307/308 重定向,-k 跳过证书校验
curl -Lk http://www.laoma.cloud/
curl -k https://www.laoma.cloud/
⑤ 后端 HTTPS 透传(Ingress 不解密)
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
rules:
- host: www.laoma.cloud
http:
paths:
- path: /
pathType: Prefix
backend: {service: {name: www, port: {number: 443}}}
1.6 生产高频注解速查表
表格
| 注解 | 作用 |
|---|---|
nginx.ingress.kubernetes.io/force-ssl-redirect: "true" |
80 强制跳转 HTTPS |
nginx.ingress.kubernetes.io/rewrite-target: /$1 |
路径重写、裁剪路由前缀 |
nginx.ingress.kubernetes.io/use-regex: "true" |
开启路径正则匹配 |
nginx.ingress.kubernetes.io/whitelist-source-range: "10.1.8.0/24" |
IP 白名单 |
nginx.ingress.kubernetes.io/limit-connections: "50" |
单 IP 最大并发连接数 |
nginx.ingress.kubernetes.io/limit-rps: "20" |
单 IP 每秒请求数(防 CC) |
nginx.ingress.kubernetes.io/proxy-connect-timeout: "10" |
后端连接超时(秒) |
nginx.ingress.kubernetes.io/proxy-read-timeout: "60" |
读超时,解决接口超时断开 |
nginx.ingress.kubernetes.io/proxy-send-timeout: "60" |
发送超时 |
nginx.ingress.kubernetes.io/enable-cors: "true" |
开启跨域 |
nginx.ingress.kubernetes.io/cors-allow-origin: "*" |
允许跨域来源 |
nginx.ingress.kubernetes.io/cors-allow-methods: "GET,POST,PUT,DELETE,OPTIONS" |
允许跨域方法 |
nginx.ingress.kubernetes.io/x-forwarded-for: "true" |
后端获取真实客户端 IP |
nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "10.0.0.0/8" |
真实 IP 来源网段 |
nginx.ingress.kubernetes.io/proxy-cache: "true" |
开启静态资源缓存 |
nginx.ingress.kubernetes.io/proxy-cache-valid: "200 302 10m" |
缓存有效期 |
nginx.ingress.kubernetes.io/canary: "true" |
标记灰度 Ingress |
nginx.ingress.kubernetes.io/canary-weight: "10" |
灰度权重 10% |
nginx.ingress.kubernetes.io/custom-http-errors: "404,500,502,503" |
自定义后端错误页 |
# 环境清理
kubectl delete ns ingress
二、Kubernetes Network 网络基础
2.1 单主机网络
- Docker:默认创建
docker0Linux 网桥,主机与容器通过一对虚拟接口 veth pair 连通;外部主机访问容器需端口映射。 - Containerd:与 Docker 类似,创建容器时在主机和容器内分别创建虚拟接口互通。
- 虚拟接口转发在内核中完成数据包复制,转发效率高,无需经过外部物理网络设备。
2.2 跨主机网络方案对比
表格
| CNI 方案 | 网络模型 | 是否隧道封装 | 支持 NetworkPolicy | 适用场景 |
|---|---|---|---|---|
| Flannel | host‑gw(Underlay)、VXLAN(Overlay) | VXLAN 封装;host‑gw 无封装 | ❌ | 简单、无访问控制需求;中小型集群 |
| Calico | BGP(Underlay)、IPIP/VXLAN(Overlay) | IPIP/VXLAN 封装;BGP 无封装 | ✅ 原生支持 | 需要网络策略;自建机房 / 公有云通用 |
| Weave Net | UDP 隧道 Overlay | UDP 封装 | ✅ | 测试环境、小规模;部署简单无需 etcd |
| Macvlan | Underlay(二层直连物理网络) | 无封装 | 取决于配套 CNI | Pod 需要占用局域网独立 IP、低延迟业务 |
Underlay 与 Overlay
- Underlay:直接使用底层物理网络转发 Pod 流量,无隧道封装,性能优于 Overlay。
- Overlay:在宿主机网络之上构建虚拟隧道,数据包封装进 UDP 传输;有封装开销,但能更好利用已有网络、避免物理交换机 MAC 表耗尽。
各方案要点
- Flannel :
host‑gw节点加静态路由、无封装、性能高,但要求底层网络能转发 Pod 网段;VXLAN跨节点报文封装 UDP,仅要求主机 IP 互通,公有云通用;不提供 NetworkPolicy。 - Calico :
BGP节点间交换 Pod 路由、无封装、性能最优(前提网络允许 BGP);IPIP/VXLAN不支持 BGP 时启用隧道封装;最大亮点:原生支持 NetworkPolicy。 - Weave:节点间 UDP 隧道,内置 DNS、支持 NetworkPolicy、可加密;隧道封装持续占 CPU,大规模性能弱于 Flannel/Calico。
- Macvlan:物理网卡上虚拟多张独立网卡,Pod 拥有独立 MAC 直连二层局域网;性能极高,但父网卡不能桥接、同宿主机 Macvlan 子接口不能直接互通、网络规划复杂。
2.3 网络模型标准:CNM 与 CNI
CNM(Docker 提出,libnetwork)
三类组件:
- Sandbox:容器网络栈(interface、路由表、DNS),标准实现为 Linux Network Namespace;
- Endpoint:把 Sandbox 接入 Network,典型实现 veth pair;一个 Endpoint 只属于一个 Network 和一个 Sandbox;
- Network:一组可直接通信的 Endpoint,实现可为 Linux Bridge、VLAN。
CNI(Google + CoreOS 联合制定,K8s 使用)
- 两个概念:容器(独立 Linux 网络命名空间)、网络(拥有唯一 IP 的互联实体)。
- 两类插件:CNI Plugin 负责配置容器网络;IPAM Plugin 负责分配容器 IP 地址。
CNM vs CNI 对比
表格
| 特点 | CNM | CNI |
|---|---|---|
| 标准 | Libnetwork | CNI |
| 最小单元 | 容器 | Pod |
| 守护进程依赖 | 依赖 dockerd | 不依赖任何守护进程 |
| 跨主机通信 | 依赖外部 KV 数据库 | 使用本身 KV 数据库 |
| 灵活度 | 被 Docker 绑定 | 插件可随意替换 |
三、Calico 网络
3.1 Calico 优势
- 支持 BGP 模式(Underlay):节点间 BGP 交换路由,无隧道封装,原生 IP 转发,性能最优;
- 支持 IPIP / VXLAN 模式(Overlay):底层不支持 BGP 时启用隧道,适配公有云;
- 原生支持 NetworkPolicy(Pod 防火墙策略)。
3.2 IPIP 与 VXLAN 隧道对比
表格
| 项目 | IPIP | VXLAN |
|---|---|---|
| 隧道类型 | 三层 IP 隧道 | 二层 UDP 隧道 |
| 传输载体 | IP 协议号 4 | UDP 端口 4789 |
| 虚拟网卡 | tunl0 |
vxlan.calico |
| 是否带二层 MAC | ❌ 不带 | ✅ 完整二层帧 |
| 包头开销 | 较小 | 更大(MTU 要更小) |
| 公有云兼容性 | 很多公有云封禁协议号 4,直接不通 | UDP 端口一般放行,兼容性更好 |
| 广播 / 组播 | 不支持 | 支持 |
| Calico 配置 | ipipMode: Always,vxlanMode: Never |
ipipMode: Never,vxlanMode: Always |
| 适用场景 | 私有机房、底层允许 IPIP 协议 | 公有云、底层不允许 IPIP |
3.3 隧道模式取值(ipipMode /vxlanMode 一致)
表格
| 取值 | 行为 |
|---|---|
Always |
所有跨节点 Pod 流量全部封装隧道包,路由下一跳指向隧道网卡;节点只需三层可达 |
Never |
不封装隧道,靠 BGP 同步 Pod 网段路由,下一跳指向物理网卡;要求节点同子网 L2 互通 |
CrossSubnet |
混合:同子网通信不封装(BGP 原生),跨子网自动启用隧道封装 |
无论是否开启 IPIP,Calico 都会运行 BGP 进程同步 Pod 网段;隧道开关只决定数据包是否封装。
模式选择
Never:无封装、性能优、抓包可见原生 Pod IP;Always:节点跨子网无法二层互通、公有云部署、不想依赖底层 BGP;CrossSubnet:企业机房多子网,同网段直连路由、跨网段走隧道。
3.4 查看与修改工作模式
查看模式
# 方法1:查看 IPPool 资源(Calico 控制隧道模式的核心资源)
kubectl get ippool -o yaml | egrep 'ipip|vxlan'
# ipipMode: Always
# vxlanMode: Never
# 方法2:查看宿主机路由表
ip route | grep '/26 via'
# 10.224.19.0/26 via 10.1.8.31 dev tunl0 proto bird onlink
# dev tunl0 → IPIP 隧道模式
# dev ens32(物理网卡)→ BGP 原生路由模式
修改模式
# 步骤1:备份原 IPPool
kubectl get ippool default-ipv4-ippool -o yaml > ippool-backup.yaml
# 步骤2:编辑 default-ipv4-ippool,修改 ipipMode
kubectl edit ippool default-ipv4-ippool
# spec:
# cidr: 10.224.0.0/16
# ipipMode: Never
# 配置 30~60 秒自动生效;长期不生效可重启 calico-node
kubectl rollout restart daemonset calico-node -n kube-system
# 步骤3:验证路由表已切到物理网卡
ip route | grep '/26'
⚠️ 修改 IPPool 会立刻改变集群跨节点转发行为,生产需业务低峰操作并提前备份。
四、NetworkPolicy 网络策略
4.1 基本概念
- 默认状态:集群外部可访问集群内部、内部可访问外部、各 namespace 之间无隔离。
- NetworkPolicy 在 IP / 端口层控制流量,是以应用为中心的白名单结构;必须使用支持 NetworkPolicy 的网络插件(如 Calico)。
- 策略适用于一端或两端为 Pod 的连接;策略之间叠加(相加),评估顺序不影响结果。
- 要允许源 Pod 访问目的 Pod:源 Egress 策略与目的 Ingress 策略都要放行,任一不允许即连接失败。
4.2 隔离模型
- 入口隔离(Ingress) :默认非隔离(所有入站允许);一旦有策略选中该 Pod 且
policyTypes含Ingress,入口被隔离,只允许策略ingress列表放行的连接(节点本身到 Pod 的连接始终允许)。 - 出口隔离(Egress) :默认非隔离;
policyTypes含Egress后只允许策略egress列表放行的连接。
4.3 规约字段
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector: # 选中策略作用的 Pod;空 {} 选择 ns 下全部 Pod
matchLabels:
role: db
policyTypes: # Ingress 控制外部访问内部;Egress 控制 Pod 访问外部
- Ingress
- Egress
ingress: # 入站白名单;from 与 ports 同时匹配
- from:
- ipBlock: # IP 网段
cidr: 172.17.0.0/16
except: [172.17.1.0/24]
- namespaceSelector: # 按 namespace 标签选来源
matchLabels:
project: myproject
- podSelector: # 同 ns 内按 Pod 标签选来源
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress: # 出站白名单;to 与 ports 同时匹配
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
from /to 四种选择器
表格
| 选择器 | 作用 |
|---|---|
podSelector |
同一 namespace 内按标签选 Pod |
namespaceSelector |
按 namespace 标签选择某命名空间全部 Pod |
namespaceSelector + podSelector |
指定 namespace 内的指定 Pod |
ipBlock |
指定 IP CIDR 范围(cidr + except 排除子网);主要用于集群外部 IP |
from数组内多个元素是 OR 关系(满足任一即可);同一规则内from与ports是 AND 关系。
4.4 实验环境
kubectl create ns web
kubens web
# web1、web2、test 三个 nginx Pod + 两个 NodePort Service
kubectl run web1 --image=hub.laoma.cloud/library/nginx
kubectl exec -it web1 -- bash -c 'echo Hello web1 > /usr/share/nginx/html/index.html'
kubectl run web2 --image=hub.laoma.cloud/library/nginx
kubectl exec -it web2 -- bash -c 'echo Hello web2 > /usr/share/nginx/html/index.html'
kubectl expose pod web1 --port=80 --target-port=80 --type=NodePort
kubectl expose pod web2 --port=80 --target-port=80 --type=NodePort
kubectl run test --image=hub.laoma.cloud/library/nginx
# 跨 ns 测试 Pod
kubectl create ns laoma
kubectl run test -n laoma --image=hub.laoma.cloud/library/nginx
# 默认全部互通:同 ns、跨 ns、Service ClusterIP、NodePort 外部节点都能访问
4.5 实验场景汇总
① 按 Pod 标签限定(同 ns 内 run=test → run=web1:80)
spec:
podSelector: {matchLabels: {run: web1}}
policyTypes: [Ingress]
ingress:
- from:
- podSelector: {matchLabels: {run: test}}
ports: [{protocol: TCP, port: 80}]
- 同 ns 的
test可访问 web1;跨 ns Pod 不可访问 ;把 test 标签改成run=web2后同 ns 也无法访问。
② 允许同 ns 全部 Pod 访问 web1(podSelector: {} 空选择器)
ingress:
- from:
- podSelector: {}
ports: [{protocol: TCP, port: 80}]
同 ns 所有 Pod 可访问,跨 ns 仍被拒绝。
③ 按 namespace 标签限定
ingress:
- from:
- namespaceSelector: {matchLabels: {project: myproject}}
ports: [{protocol: TCP, port: 80}]
# 给 laoma 命名空间打标签后,其中 Pod 才可访问 web1
kubectl label namespaces laoma project=myproject
namespaceSelector: {} 允许所有 namespace 的 Pod 访问。
④ 按 IP 网段限定(ipBlock)
ingress:
- from:
- ipBlock:
cidr: 10.1.8.0/24
except: [10.1.8.128/26]
ports: [{protocol: TCP, port: 80}]
放行 10.1.8.0/24 但排除 10.1.8.128/26;集群内 Pod 来源 IP 经 kube‑proxy 改写,可能不按预期匹配。 放行全部、排除部分:cidr: 0.0.0.0/0 + except: [10.1.8.0/26]。
⑤ 不设 ports:放行所有端口
ingress:
- from:
- podSelector: {matchLabels: {run: test}}
- 匹配条件 Pod 可 ping 通 PodIP;但 Service 只开放 80 端口,ping Service ClusterIP 仍然不通。
⑥ 端口范围
ports:
- protocol: TCP
port: 32000
endPort: 32768
⑦ 多条件 OR 组合
ingress:
- from:
- ipBlock: {cidr: 10.1.1.0/24}
- namespaceSelector: {matchLabels: {project: myproject}}
- podSelector: {matchLabels: {run: test}}
ports: [{protocol: TCP, port: 80}]
4.6 默认策略(兜底白名单)
表格
| 策略 | YAML 要点 | 效果 |
|---|---|---|
| 默认允许所有入站 | podSelector: {} + policyTypes: [Ingress] + ingress: [{}] |
放行全部入站 |
| 默认拒绝所有入站 | podSelector: {} + policyTypes: [Ingress],无 ingress 规则 |
未被其他策略选中的 Pod 也被隔离 |
| 默认允许所有出站 | policyTypes: [Egress] + egress: [{}] |
放行全部出站 |
| 默认拒绝所有出站 | policyTypes: [Egress],无 egress 规则 |
未选中 Pod 禁止出站 |
| 默认拒绝全部 | policyTypes: [Ingress, Egress],无规则 |
入站出站全部拒绝 |
4.7 NetworkPolicy 无法完成的工作
-
节点特定策略、基于名字的策略;
-
适用于所有 namespace / Pod 的全局默认策略;
-
显式拒绝策略:模型默认拒绝,只支持添加允许规则;
-
无法阻塞 localhost 回路、无法禁止来自所在节点的访问。
环境清理
kubectl delete ns web laoma
五、Kubernetes Pod Scheduler 调度
5.1 调度概念
- 调度 = 把 Pod 放置到合适节点的过程;kube‑scheduler 是默认调度器,通过 List‑Watch 发现未绑定节点的 Pending Pod,挑选最优节点运行。
- 调度器只负责选节点,不启动容器。
5.2 直接创建 Pod 的完整流程
- 客户端:组装创建 Pod JSON 请求发给 kube‑apiserver。
- kube‑apiserver :①认证(证书 / SA token)→ ②授权 → ③准入控制(Mutating/Validating 插件)→ ④字段合法性校验 → ⑤通过后写入 etcd;Pod 状态
Pending,spec.nodeName=""。 - etcd:持久化存储 Pod 对象。
- kube‑scheduler :List‑Watch 感知 Pending Pod → ①过滤 Filter (资源不足、污点不匹配、亲和规则不满足、节点 cordon 等剔除)→ ②无可选节点则尝试抢占 低优先级 Pod 腾资源 → ③打分 Score 选最优节点 → ④内存临时预留资源防并发冲突 → ⑤调用 apiserver Binding 子资源接口发起绑定。
- kube‑apiserver :原子更新 Pod,填充
spec.nodeName=目标节点,写回 etcd(Pod 仍 Pending)。 - 目标节点 kubelet:Watch 感知 Pod 绑定本机 → 拉取配置 → 准备存储卷(CSI/PVC/emptyDir)→ 调用 CNI 准备网络 → 调用容器运行时创建启动容器。
- 容器运行时 containerd/docker:拉镜像、创建沙箱、启动业务容器。
- 状态回写 :kubelet 检测容器正常 → 上报 apiserver → Pod 状态更新为
Running存入 etcd。
精简流程
Client → apiserver(认证/授权/准入) → etcd(Pending) → scheduler(过滤→抢占→打分→绑定)
→ apiserver 写入 nodeName → kubelet(CSI 存储 + CNI 网络) → 容器运行时启动 → 状态回写 Running
5.3 通过控制器创建 Pod 的流程
Client → kube-apiserver → etcd → kube-controller-manager → kube-scheduler → kubelet → containerd
以 Deployment 为例:
- kubectl 提交 Deployment 给 apiserver;
- apiserver 认证授权准入后把 Deployment 存入 etcd(此时无 Pod);
- kube‑controller‑manager 内 Deployment 控制器 List‑Watch 到新 Deployment → 对比
replicas期望数与现有 Pod 数 → 不足则调用 apiserver 创建新 Pod(Pending、spec.nodeName=""); - scheduler 过滤、打分、绑定;
- apiserver 写入 nodeName;
- kubelet 准备存储 / 网络,运行时拉镜像启动;
- 状态回写 Running。
controller‑manager 职责:持续协调期望状态与实际状态;Deployment/StatefulSet/DaemonSet 等控制器都运行在这里;控制器只创建 / 删除 Pod,不参与调度、不启动容器。
5.4 调度两阶段:过滤 + 打分
① 过滤(断言 Predicates):剔除不满足条件的节点
表格
| 过滤器 | 作用 |
|---|---|
PodFitsHostPorts |
节点端口是否满足 Pod 请求端口 |
PodFitsHost |
Pod 是否通过主机名指定节点 |
PodFitsResources |
节点空闲 CPU / 内存能否满足 requests |
MatchNodeSelector |
节点标签是否匹配 nodeSelector |
NoVolumeZoneConflict |
卷的故障区域限制是否冲突 |
NoDiskConflict |
请求卷与已挂载卷是否冲突 |
MaxCSIVolumeCount |
CSI 附加卷数量是否超限 |
PodToleratesNodeTaints |
Pod toleration 能否容忍节点 taint |
CheckVolumeBinding |
PVC 卷绑定是否满足 |
过滤后列表为空 = Pod 不可调度。
② 打分(优先级 Priorities):从可用节点选最优
表格
| 打分策略 | 作用 |
|---|---|
SelectorSpreadPriority |
同服务 / 状态集 / 副本集 Pod 跨节点分散 |
InterPodAffinityPriority |
Pod 间亲和 / 反亲和 |
LeastRequestedPriority |
优先资源请求少的节点(均衡负载) |
MostRequestedPriority |
优先资源占用多的节点(尽量少用节点) |
RequestedToCapacityRatioPriority |
基于 requests / 容量比评分 |
BalancedResourceAllocation |
优先 CPU / 内存使用均衡的节点 |
NodePreferAvoidPodsPriority |
按节点注解 preferAvoidPods 暗示分散 |
NodeAffinityPriority |
节点亲和 PreferredDuringSchedulingIgnoredDuringExecution 偏好 |
TaintTolerationPriority |
按不可容忍污点数量调整等级 |
ImageLocalityPriority |
优先本地已有镜像的节点 |
ServiceSpreadingPriority |
同 Service Pod 分散到不同节点,提升故障弹性 |
EqualPriority |
所有节点等权 |
EvenPodsSpreadPriority |
Pod 拓扑分布约束 |
得分最高节点运行;平分时 scheduler 随机选取一个。
5.5 控制 Pod 运行位置(四种方式)
① nodeName(最简单、优先级最高,通常不推荐)
spec:
nodeName: worker32.laoma.cloud
containers:
- image: hub.laoma.cloud/library/nginx
name: nginx
限制:指定节点不存在 Pod 不会运行甚至被自动删除;节点资源不足调度失败(OOM/Out of CPU);云环境节点名不可预测不稳定。
② nodeSelector(推荐形式,标签键值对)
# 先给节点打标签
kubectl label node worker31.laoma.cloud disktype=ssd
kubectl get node -L disktype
spec:
nodeSelector:
disktype: ssd
containers:
- image: hub.laoma.cloud/library/nginx
name: nginx
-
Pod 只能运行在包含全部指定标签的节点上;
-
删除节点标签不会触发 Deployment 重新部署;删除 Deployment 的
nodeSelector才会自动触发重调度;移除节点标签
kubectl label node worker31.laoma.cloud disktype-
移除 Deployment 的 nodeSelector 触发重调度
kubectl patch deployment webapp --type json
-p '[{"op":"remove","path":"/spec/template/spec/nodeSelector"}]'
文档提及但未展开:亲和性与反亲和性、Pod 拓扑分布约束。
# 环境清理
kubectl delete deployments.apps webapp
kubectl delete ns scheduler
思维导图
