Kubernetes Ingress|CNI 网络模型|Calico 网络策略|Pod 调度器完整实战教程
摘要:Service 实现四层 TCP/UDP 负载均衡,而 Ingress 是 K8s 的七层 HTTP/HTTPS 网关,实现域名路由、路径路由、HTTPS 证书、限流、跨域、灰度金丝雀;本文接着讲解容器网络模型 CNM/CNI、Calico IPIP/VXLAN 隧道、NetworkPolicy 网络防火墙;最后深度剖析 kube‑scheduler 调度器完整工作流程、nodeName/nodeSelector/ 亲和性调度,附带全套可复制 YAML 与实验,适合云原生运维入门学习。
目录
- Ingress 七层网关详解(ingress‑nginx 控制器)
- Ingress 多种实战案例:域名虚拟主机、路径路由、重写、TLS HTTPS、限流、跨域、金丝雀灰度
- 容器网络基础:CNM 与 CNI 网络模型
- 跨主机 CNI 插件对比:Flannel / Calico / Weave / Macvlan
- Calico 深度:IPIP、VXLAN 隧道模式对比,配置切换
- NetworkPolicy 网络策略(Pod 防火墙)完整实验
- K8s Pod 调度器 kube‑scheduler 工作原理
- 调度约束实操:nodeName、nodeSelector
- 排坑总结
- 实验环境清理
一、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 工作流程
- 部署 ingress‑nginx 控制器(DaemonSet/Deployment,真正的 Nginx 服务)
- 编写并创建 Ingress YAML 资源(定义路由规则,相当于写 Nginx 的 conf 配置片段)
- ingress‑nginx 控制器监听 K8s APIServer,获取 Ingress、Service、Endpoint 变更
- 将 Ingress 规则转换为 Nginx 配置,写入容器内
/etc/nginx/nginx.conf - 执行 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 版本强制必须写)
- Prefix :前缀匹配,按
/分段匹配前缀,/foo匹配/foo、/foo/bar - Exact:严格完全匹配 URL 路径,区分大小写
- 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
- 创建自签名证书 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 都兼容),插件化。 两类插件:
- CNI Plugin:配置网卡、veth pair、网桥、隧道
- 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 概念
- Underlay:直接使用底层物理网络,无报文封装,性能高。BGP/host‑gw/macvlan 属于 Underlay。
- 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)
Always:全部跨节点流量走隧道封装(公有云推荐)Never:关闭隧道,BGP 发布 Pod 网段路由,Underlay 直连,要求节点二层互通,私有机房性能最优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 流量。
核心概念
-
podSelector:选择本命名空间哪些 Pod 应用这条防火墙规则 -
policyTypes:Ingress入站、Egress出站,可以同时写
yaml
ingress.from
:入站流量来源;支持三类匹配
podSelector:同命名空间 Pod 标签namespaceSelector:其他命名空间标签ipBlock:IP 网段 CIDR
egress.to:出站流量目标地址
NetworkPolicy 是白名单机制 :一旦启用 Ingress,没有被规则允许的流量全部拒绝。规则是叠加关系,多条规则满足任意一条即放行。
重要限制
- 不能直接拒绝,只能写白名单允许;没有黑名单语法。
- 无法针对 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
实验要点:
- 空
podSelector: {}代表当前命名空间全部 Pod- 一旦 policyTypes 开启 Ingress,默认全部拒绝,必须写 from 白名单才能通信
实验完整操作参考原文档,创建多 ns、多 Pod,测试访问连通性。
三、Kube‑Scheduler Pod 调度器深度原理
kube‑scheduler:K8s 默认调度器,负责把Pending 状态未绑定 nodeName 的 Pod 挑选合适节点运行 。 调度器只做选择节点,不会启动容器,真正启动容器是对应节点 kubelet。
3.1 Pod 完整创建链路(Deployment 方式)
- kubectl 提交 Deployment → apiserver 认证授权准入校验 → 存入 etcd
- kube‑controller‑manager 的 Deployment 控制器 watch 资源变化,计算需要多少 Pod,调用 apiserver创建 Pod 对象 ,此时 Pod
spec.nodeName="",状态 Pending。 - kube‑scheduler watch 发现 Pending Pod
- 阶段 1:Predicate 过滤(断言):把不满足条件的节点全部剔除
- 阶段 2:Priority 打分,剩余可用节点计算分数,分数最高优先;分数相同随机选一个节点
- 调度器发送 Binding 请求给 apiserver,设置 Pod 的
spec.nodeName=节点名,写入 etcd。Pod 依旧 Pending。 - 目标节点的 kubelet watch 到 Pod 绑定到本机:
- 调用 CSI 准备存储卷
- 调用 CNI 插件配置 Pod 网络
- 调用 containerd 拉取镜像,创建启动容器
- kubelet 上报 Pod 状态 Running 回写 etcd。
3.2 Predicate 过滤规则(过滤掉不合格节点)
PodFitsResources:节点 CPU 内存资源是否满足 Pod requests 请求PodToleratesNodeTaints:Pod 容忍度是否匹配节点污点 TaintMatchNodeSelector: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 亲和 / 反亲和、拓扑分布约束,属于进阶内容。
常见排坑点
- Pod 一直 Pending:看
kubectl describe pod xxx事件,大概率 Predicate 过滤后无可用节点;资源不足、nodeSelector 标签不匹配、节点污点。 - NetworkPolicy 配置完不生效:确认 CNI 插件是 Calico,flannel 不支持网络策略。
- Ingress 访问 404:检查 Ingress 的 pathType,Service 后端 Selector、Endpoints 是否存在。
- Ingress rewrite‑target 不生效:必须开启注解
nginx.ingress.kubernetes.io/use‑regex: "true"。 - 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