Kubernetes Ingress|CNI 网络模型|Calico 网络策略|Pod 调度器完整实战教程

Kubernetes Ingress|CNI 网络模型|Calico 网络策略|Pod 调度器完整实战教程

摘要:Service 实现四层 TCP/UDP 负载均衡,而 Ingress 是 K8s 的七层 HTTP/HTTPS 网关,实现域名路由、路径路由、HTTPS 证书、限流、跨域、灰度金丝雀;本文接着讲解容器网络模型 CNM/CNI、Calico IPIP/VXLAN 隧道、NetworkPolicy 网络防火墙;最后深度剖析 kube‑scheduler 调度器完整工作流程、nodeName/nodeSelector/ 亲和性调度,附带全套可复制 YAML 与实验,适合云原生运维入门学习。

目录

  1. Ingress 七层网关详解(ingress‑nginx 控制器)
  2. Ingress 多种实战案例:域名虚拟主机、路径路由、重写、TLS HTTPS、限流、跨域、金丝雀灰度
  3. 容器网络基础:CNM 与 CNI 网络模型
  4. 跨主机 CNI 插件对比:Flannel / Calico / Weave / Macvlan
  5. Calico 深度:IPIP、VXLAN 隧道模式对比,配置切换
  6. NetworkPolicy 网络策略(Pod 防火墙)完整实验
  7. K8s Pod 调度器 kube‑scheduler 工作原理
  8. 调度约束实操:nodeName、nodeSelector
  9. 排坑总结
  10. 实验环境清理

一、Kubernetes Ingress 七层网关

Service 是四层负载均衡,只能处理 TCP/UDP,不能解析 HTTP 协议的 Host 域名、URL 路径。Ingress 是七层 HTTP/HTTPS 网关,用来对外暴露 Web 业务,实现域名路由、路径分流、SSL 证书、限流、跨域、灰度发布。
⚠️重要知识点:Ingress 资源本身只是一堆规则描述 ,不会真正处理流量。必须部署 Ingress‑Nginx 控制器(真正运行 Nginx 的 Pod),控制器监听 APIServer,读取 Ingress 规则,自动生成 Nginx 配置,reload 生效。

1.1 ingress‑nginx 工作流程

  1. 部署 ingress‑nginx 控制器(DaemonSet/Deployment,真正的 Nginx 服务)
  2. 编写并创建 Ingress YAML 资源(定义路由规则,相当于写 Nginx 的 conf 配置片段)
  3. ingress‑nginx 控制器监听 K8s APIServer,获取 Ingress、Service、Endpoint 变更
  4. 将 Ingress 规则转换为 Nginx 配置,写入容器内/etc/nginx/nginx.conf
  5. 执行 nginx‑s reload,加载新配置,七层流量正式生效

Ingress 只负责 HTTP/HTTPS;TCP/UDP 业务对外暴露,仍然使用 NodePort、LoadBalancer 类型 Service。

1.2 部署 ingress‑nginx 控制器

前提:集群部署 MetalLB,提供 LoadBalancer 类型 IP。

yaml 复制代码
# 下载离线包
wget https://lbc.cloud/class/course-materials/softwares/stage03/ingress-nginx-controller-v1.11.2.tar.gz
tar -xf ingress-nginx-controller-v1.11.2.tar.gz
# 替换镜像地址为内网镜像仓库
sed -ir 's#@sha256.*##;s/registry.k8s.io/hub.lbc.cloud/' ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
# 部署全套资源:ns、configmap、rbac、deployment、service、admission webhook
kubectl apply -f ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml

查看部署完成资源:

yaml 复制代码
kubectl get all -n ingress-nginx

关键点:ingress‑nginx‑controller Service 类型为LoadBalancer,分配外部访问 VIP,客户端访问这个 IP 进入七层 Nginx 网关。

1.3 Ingress 核心字段说明

IngressClass

集群可以部署多套不同 Ingress 控制器,使用ingressClassName指定由哪个控制器处理该 Ingress 规则。 可以设置集群默认 IngressClass,注解:ingressclass.kubernetes.io/is-default-class: "true",Ingress 不写ingressClassName自动使用默认。

pathType 路径类型(v1 版本强制必须写)

  1. Prefix :前缀匹配,按/分段匹配前缀,/foo匹配/foo、/foo/bar
  2. Exact:严格完全匹配 URL 路径,区分大小写
  3. ImplementationSpecific :交给 ingress‑nginx 自定义正则匹配,配合use‑regex注解

资源示例:defaultBackend 默认后端

所有不匹配任何 host/path 的流量,全部转发给 defaultBackend 指定 Service

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  defaultBackend:
    service:
      name: testsvc
      port:
        number: 80

1.4 全套 Ingress 实战实验

准备两套测试业务 webapp01、webapp02

yaml 复制代码
# webapp01
kubectl create deployment webapp01 --image=hub.lbc.cloud/library/httpd --replicas=2
kubectl exec -it $(kubectl get pods -l app=webapp01 -o name|head -1|cut -d/ -f2) -- bash -c "echo hello webapp01 > htdocs/index.html"
kubectl expose deployment webapp01 --port=80

# webapp02
kubectl create deployment webapp02 --image=hub.lbc.cloud/library/httpd --replicas=2
kubectl exec -it $(kubectl get pods -l app=webapp02 -o name|head -1|cut -d/ -f2) -- bash -c "echo hello webapp02 > htdocs/index.html; mkdir -p htdocs/games; echo game page > htdocs/games/index.html"
kubectl expose deployment webapp02 --port=80

案例 1:多域名虚拟主机(不同域名转发不同服务)

webapp01.lbc.cloud → webapp01 服务;webapp02.lbc.cloud → webapp02 服务

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-host-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: webapp01.lbc.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp01
            port:
              number: 80
  - host: webapp02.lbc.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp02
            port:
              number: 80
kubectl apply -f multi-host-ingress.yaml
# 本地hosts解析,ingress‑nginx的LoadBalancerVIP为10.1.8.40
echo "10.1.8.40 webapp01.lbc.cloud webapp02.lbc.cloud" >> /etc/hosts
curl webapp01.lbc.cloud
curl webapp02.lbc.cloud

案例 2:同一域名,不同路径转发不同服务

www.lbc.cloud/访问 webapp01;www.lbc.cloud/games访问 webapp02

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-path-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: www.lbc.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp01
            port:
              number: 80
      - path: /games
        pathType: Prefix
        backend:
          service:
            name: webapp02
            port:
              number: 80

案例 3:路径重写(rewrite‑target)

访问www.lbc.cloud/webapp01/xxx,后端剥离/webapp01前缀,转发为/xxx

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-trimming-ingress
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  ingressClassName: nginx
  rules:
  - host: www.lbc.cloud
    http:
      paths:
      - path: /webapp01/(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: webapp01
            port:
              number: 80

案例 4:TLS HTTPS,80 强制跳转 443

  1. 创建自签名证书 Secret
yaml 复制代码
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.lbc.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

Ingress 配置 TLS + 强制 https 跳转

yaml 复制代码
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.lbc.cloud
    secretName: www-tls
  rules:
  - host: www.lbc.cloud
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: webapp01
            port:
              number: 80

测试访问:

yaml 复制代码
curl -Lk http://www.lbc.cloud
curl -Lk https://www.lbc.cloud

常用 annotations 注解速查表

表格

注解 功能
nginx.ingress.kubernetes.io/rewrite-target: /$1 路径重写,剥离 URL 前缀
nginx.ingress.kubernetes.io/force-ssl-redirect: "true" http 强制跳转 https
nginx.ingress.kubernetes.io/enable‑cors: "true" 开启跨域(前后端分离)
nginx.ingress.kubernetes.io/whitelist‑source‑range: "10.1.8.0/24" IP 白名单,内网后台限制访问源
nginx.ingress.kubernetes.io/limit‑rps: "20" 单 IP 每秒请求限流防刷
nginx.ingress.kubernetes.io/canary: "true" canary‑weight: "10" 金丝雀权重灰度发布
nginx.ingress.kubernetes.io/x‑forwarded‑for: "true" 透传真实客户端 IP 给后端 Pod

⚠️注意:Ingress 只是 Nginx 配置模板,真正负载均衡逻辑全部运行在 ingress‑nginx 控制器 Pod 内部。


二、Kubernetes 容器网络

2.1 容器网络两大模型 CNM vs CNI

CNM(Docker libnetwork 模型)

Docker 原生网络模型,libnetwork实现。

  • 组件:Sandbox(network namespace)、Endpoint(veth‑pair)、Network(bridge 网桥)
  • 绑定 dockerd 守护进程,Docker 专属;k8s 不使用 CNM。
  • driver:bridge、overlay、macvlan 等。

CNI(Container Network Interface)

CNI 是谷歌 + CoreOS 制定通用容器网络标准,Kubernetes 强制使用 CNI。

不绑定特定容器运行时(containerd/docker 都兼容),插件化。 两类插件:

  1. CNI Plugin:配置网卡、veth pair、网桥、隧道
  2. IPAM Plugin:IP 地址管理,分配 / 回收 Pod IP 地址

流程:kubelet 创建 Pod 网络命名空间,调用 CNI 插件配置网络,分配 IP,完成 veth pair 对接。

对比 CNM(Docker) CNI (K8s 标准)
开发方 Docker Google+CoreOS
依赖守护进程 dockerd 无守护进程,二进制插件直接调用
适配对象 docker k8s、containerd,通用
k8s 使用 不使用 强制使用

2.2 主流 CNI 插件对比

CNI 插件 模式 是否隧道 支持 NetworkPolicy 适用场景
Flannel host‑gw(Underlay)/VXLAN(Overlay) VXLAN 封装,host‑gw 无封装 ❌不支持网络策略 简单集群,不需要 Pod 防火墙
Calico BGP(Underlay)/IPIP/VXLAN(Overlay) IPIP/VXLAN 封装;BGP 无隧道 ✅完整支持 NetworkPolicy 生产首选,支持 Pod 防火墙策略
WeaveNet UDP Overlay 隧道 UDP 封装 ✅支持 小规模测试,部署简单
Macvlan Underlay 二层直连物理网络 无隧道封装 视配套插件而定 Pod 需要局域网独立物理 IP,追求极低延迟

Underlay vs Overlay 概念

  1. Underlay:直接使用底层物理网络,无报文封装,性能高。BGP/host‑gw/macvlan 属于 Underlay。
  2. Overlay:隧道封装,原始 Pod 数据包外层再套一层宿主机 IP 头;VXLAN、IPIP、UDP 隧道。公有云环境最常用,底层网络不用感知 Pod 网段,但是有封包解包 CPU 开销。

2.3 Calico 深度详解

Calico 支持三种工作模式:BGP、IPIP、VXLAN。

IPIP 隧道

  • 三层隧道,协议号 4;虚拟网卡tunl0
  • 封装:外层节点 IP 头 + 内层 Pod 完整 IP 包

⚠️很多公有云安全组拦截IP 协议号 4,公有云环境 IPIP 无法工作。

VXLAN 隧道

  • 二层 UDP 隧道,默认 UDP 端口 4789;虚拟网卡vxlan.calico
  • 封装完整二层以太网帧,支持广播组播;公有云普遍放行 UDP,兼容性好。

缺点:包头更大,MTU 需要调小。

IPPool 三个模式(ipipMode /vxlanMode)

  1. Always:全部跨节点流量走隧道封装(公有云推荐)
  2. Never:关闭隧道,BGP 发布 Pod 网段路由,Underlay 直连,要求节点二层互通,私有机房性能最优
  3. CrossSubnet:混合模式:同子网节点直接 BGP;跨子网节点自动启用隧道封装。

查看当前 Calico 隧道模式:

yaml 复制代码
kubectl get ippool default-ipv4-ippool -o yaml
# 查看宿主机路由,dev tunl0代表IPIP隧道
ip route

修改 IPPool(生产低峰操作,先备份)

yaml 复制代码
kubectl get ippool default-ipv4-ippool -o yaml > ippool.yaml
kubectl edit ippool default-ipv4-ippool
# 修改 ipipMode: Never / Always
# 可选重启calico‑node
kubectl rollout restart daemonset calico-node -n kube-system

2.4 NetworkPolicy(Pod 防火墙)

NetworkPolicy 是 K8s 的 Pod 级别防火墙,只有 CNI 插件支持才生效,Calico 原生支持。 默认集群全部 Pod 之间互通;NetworkPolicy 可以限制 Pod 入站 Ingress、出站 Egress 流量。

核心概念

  1. podSelector:选择本命名空间哪些 Pod 应用这条防火墙规则

  2. policyTypes:Ingress入站、Egress出站,可以同时写

yaml 复制代码
ingress.from

:入站流量来源;支持三类匹配

  • podSelector:同命名空间 Pod 标签
  • namespaceSelector:其他命名空间标签
  • ipBlock:IP 网段 CIDR
  1. egress.to:出站流量目标地址

NetworkPolicy 是白名单机制 :一旦启用 Ingress,没有被规则允许的流量全部拒绝。规则是叠加关系,多条规则满足任意一条即放行。

重要限制

  1. 不能直接拒绝,只能写白名单允许;没有黑名单语法。
  2. 无法针对 Node 节点做策略;无法阻塞localhost本地回环访问 Pod。

实验示例

示例:只允许同 ns 标签run:test访问run:web1的 80 端口
yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-test-access-web1
  namespace: web
spec:
  podSelector:
    matchLabels:
      run: web1
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          run: test
    ports:
    - protocol: TCP
      port: 80
示例:拒绝命名空间内所有 Pod 全部入站流量(默认拒绝所有)
yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: web
spec:
  podSelector: {}
  policyTypes:
  - Ingress

实验要点:

  1. 空podSelector: {}代表当前命名空间全部 Pod
  2. 一旦 policyTypes 开启 Ingress,默认全部拒绝,必须写 from 白名单才能通信
    实验完整操作参考原文档,创建多 ns、多 Pod,测试访问连通性。

三、Kube‑Scheduler Pod 调度器深度原理

kube‑scheduler:K8s 默认调度器,负责把Pending 状态未绑定 nodeName 的 Pod 挑选合适节点运行 。 调度器只做选择节点,不会启动容器,真正启动容器是对应节点 kubelet。

3.1 Pod 完整创建链路(Deployment 方式)

  1. kubectl 提交 Deployment → apiserver 认证授权准入校验 → 存入 etcd
  2. kube‑controller‑manager 的 Deployment 控制器 watch 资源变化,计算需要多少 Pod,调用 apiserver创建 Pod 对象 ,此时 Pod spec.nodeName="",状态 Pending。
  3. kube‑scheduler watch 发现 Pending Pod
    • 阶段 1:Predicate 过滤(断言):把不满足条件的节点全部剔除
    • 阶段 2:Priority 打分,剩余可用节点计算分数,分数最高优先;分数相同随机选一个节点
  4. 调度器发送 Binding 请求给 apiserver,设置 Pod 的spec.nodeName=节点名,写入 etcd。Pod 依旧 Pending。
  5. 目标节点的 kubelet watch 到 Pod 绑定到本机:
    • 调用 CSI 准备存储卷
    • 调用 CNI 插件配置 Pod 网络
    • 调用 containerd 拉取镜像,创建启动容器
  6. kubelet 上报 Pod 状态 Running 回写 etcd。

3.2 Predicate 过滤规则(过滤掉不合格节点)

  • PodFitsResources:节点 CPU 内存资源是否满足 Pod requests 请求
  • PodToleratesNodeTaints:Pod 容忍度是否匹配节点污点 Taint
  • MatchNodeSelector:Pod nodeSelector 标签匹配节点标签
  • PodFitsHostPorts:节点是否有空闲主机端口
  • NoDiskConflict:卷冲突检查

过滤完成,如果没有任何可用节点,Pod 一直保持 Pending。

3.3 Priority 打分规则(给合格节点算分数,择优)

  • LeastRequestedPriority:优先选择资源剩余多的节点(默认)
  • BalancedResourceAllocation:均衡 CPU 内存资源分配
  • NodeAffinityPriority:节点亲和性打分
  • TaintTolerationPriority:污点容忍打分
  • ImageLocalityPriority:优先选本地已有镜像的节点
  • EvenPodsSpreadPriority:Pod 拓扑分布,打散 Pod 到不同节点 / 机房,提高可用性

3.4 手动控制 Pod 调度位置三种方式

1)nodeName(最高优先级,直接指定节点名称,绕过调度器)

直接写死节点名字,kube‑scheduler 完全跳过过滤打分,直接强制绑定。风险:节点宕机 Pod 不会自动调度。

yaml 复制代码
spec:
  nodeName: worker32.lbc.cloud
  containers:
  - name: nginx
    image: hub.lbc.cloud/library/nginx

2)nodeSelector(标签匹配,简单硬约束)

给节点打标签,Pod 模板写 nodeSelector,调度器过滤,节点必须拥有对应标签,Pod 才能调度上去。

yaml 复制代码
# 给节点打标签
kubectl label node worker31.lbc.cloud disktype=ssd

Pod 模板:

yaml 复制代码
spec:
  nodeSelector:
    disktype: ssd
  containers:
  - name: nginx
    image: hub.lbc.cloud/library/nginx

⚠️注意:后续如果删除节点标签,已经运行的 Pod 不会迁移;只有新建 Pod 才受影响。
高级调度还有:节点亲和性、Pod 亲和 / 反亲和、拓扑分布约束,属于进阶内容。

常见排坑点

  1. Pod 一直 Pending:看kubectl describe pod xxx事件,大概率 Predicate 过滤后无可用节点;资源不足、nodeSelector 标签不匹配、节点污点。
  2. NetworkPolicy 配置完不生效:确认 CNI 插件是 Calico,flannel 不支持网络策略。
  3. Ingress 访问 404:检查 Ingress 的 pathType,Service 后端 Selector、Endpoints 是否存在。
  4. Ingress rewrite‑target 不生效:必须开启注解nginx.ingress.kubernetes.io/use‑regex: "true"。
  5. Calico IPIP 不通:公有云安全组拦截 IP 协议号 4,切换 VXLAN 模式。

环境清理

yaml 复制代码
kubectl delete ns ingress web lbc scheduler
kubectl delete -f ingress-nginx-controller-v1.11.2/deploy/static/provider/cloud/deploy.yaml
相关推荐
启博网络1 小时前
下一代防火墙是什么意思?下一代防火墙可以抵御哪些网络攻击?
网络·防火墙
FPGA信号处理2 小时前
【人工神经网络】第一讲:竞争网络与自组织特征映射:从胜者为王到保序映射
网络
吴声子夜歌2 小时前
Kubernetes权威指南——Kubernetes安装配置指南(网络配置)
网络·容器·kubernetes
考拉讲支付3 小时前
延迟分账 / 核销分账的技术实现方案:服务完成后再分钱,到底怎么设计?
大数据·运维·人工智能·微信小程序·小程序·系统架构
闲云野鹤在人间3 小时前
Kubernetes Pod Scheduler 详解
云原生·容器·kubernetes
硅基造物主3 小时前
STM32 从 0 到 1 做智能家居(十二):USART2 分时复用 —— ESP-12F + MQTT
网络·stm32·mqtt·智能家居·esp-12f
我不会起名字3223 小时前
TCP 三次握手为什么是三次:丢包、重传与初始序列号
网络·tcp·原理·握手
ADAI_Bowen3 小时前
写文章 - 知乎
大数据·运维·人工智能
Yang96113 小时前
鼎讯信通DXA-3S光纤熔接机:光缆教学中的技术精粹解析
网络