7、Kubernetes的Ingress&Network&Scheduler

一、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 工作流程

  1. 先部署 Ingress Controller 实体(前端 Nginx Pod);
  2. 再创建 Ingress 规则资源;
  3. Controller 与 apiserver 交互,动态 Watch 集群中的 Ingress 规则,解析后生成 Nginx 配置;
  4. 配置写入 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 四部分组成

  1. 独立命名空间 ingress-nginx;
  2. ConfigMap:存放控制器通用配置变量;
  3. RBAC:ServiceAccount、ClusterRole、Role、RoleBinding、ClusterRoleBinding;
  4. ingress‑nginx‑controller Deployment(把 Ingress 规则转化为 Nginx 配置)。

部署后 ingress-nginx-controller Service 为 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:默认创建 docker0 Linux 网桥,主机与容器通过一对虚拟接口 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 的完整流程

  1. 客户端:组装创建 Pod JSON 请求发给 kube‑apiserver。
  2. kube‑apiserver :①认证(证书 / SA token)→ ②授权 → ③准入控制(Mutating/Validating 插件)→ ④字段合法性校验 → ⑤通过后写入 etcd;Pod 状态 Pending,spec.nodeName=""。
  3. etcd:持久化存储 Pod 对象。
  4. kube‑scheduler :List‑Watch 感知 Pending Pod → ①过滤 Filter (资源不足、污点不匹配、亲和规则不满足、节点 cordon 等剔除)→ ②无可选节点则尝试抢占 低优先级 Pod 腾资源 → ③打分 Score 选最优节点 → ④内存临时预留资源防并发冲突 → ⑤调用 apiserver Binding 子资源接口发起绑定。
  5. kube‑apiserver :原子更新 Pod,填充 spec.nodeName=目标节点,写回 etcd(Pod 仍 Pending)。
  6. 目标节点 kubelet:Watch 感知 Pod 绑定本机 → 拉取配置 → 准备存储卷(CSI/PVC/emptyDir)→ 调用 CNI 准备网络 → 调用容器运行时创建启动容器。
  7. 容器运行时 containerd/docker:拉镜像、创建沙箱、启动业务容器。
  8. 状态回写 :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 为例:

  1. kubectl 提交 Deployment 给 apiserver;
  2. apiserver 认证授权准入后把 Deployment 存入 etcd(此时无 Pod);
  3. kube‑controller‑manager 内 Deployment 控制器 List‑Watch 到新 Deployment → 对比 replicas 期望数与现有 Pod 数 → 不足则调用 apiserver 创建新 Pod(Pending、spec.nodeName="");
  4. scheduler 过滤、打分、绑定;
  5. apiserver 写入 nodeName;
  6. kubelet 准备存储 / 网络,运行时拉镜像启动;
  7. 状态回写 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

思维导图

相关推荐
码农客栈1 小时前
mt7601u移植
linux·运维·服务器
2601_949847751 小时前
io-ts 跨端三方库仓颉适配全流程
linux·运维·ubuntu
打工仔折腾 AI13 小时前
在 Ubuntu ARM64 部署 Q1 V3.0 MuJoCo 模型:加载、单步推理与执行器响应解析
linux·运维·人工智能·python·深度学习·ubuntu·性能优化
yyuuuzz13 小时前
跨境站点日志时区混乱的排查记录
运维·服务器·网络·云计算·aws·1024程序员节
‎ദ്ദിᵔ.˛.ᵔ₎13 小时前
关于Linux 线程局部存储的认识
linux·运维
GlobalInfo13 小时前
全球及中国风电叶片检测机器人行业研究报告(2026版):市场现状、行业前景与占有率分析
运维·网络·人工智能·机器人
隔窗听雨眠15 小时前
KingbaseES平替全链路实践:从迁移评估到可持续运维
运维
skywalk816315 小时前
登到192.168.1.5那台机器,看看今天白天,大约从早晨到晚上,都卡住了。看看因为什么卡住,为什么卡住而没有杀死那个导致卡死的进程,为什么
运维·系统·freebsd
运维行者_15 小时前
网络监控工具怎么选?从设备监控到智能运维的能力清单
运维·服务器·开发语言·网络·人工智能·支持向量机·php