【Kubernetes从入门到精通】第17篇:Ingress——HTTP流量的“总管家“
上一篇【第16篇】Service的负载均衡原理——kube-proxy到底干了什么
下一篇【第18篇】Ingress Controller选型和实战——Nginx Ingress完全指南
摘要
Service不错——ClusterIP让你内部Pod互相找到,NodePort对外开了个后门,LoadBalancer更是直接挂上了云厂商的LB。但你有没有发现一个尴尬的问题:一个公网LB一个月几百块,你有3个服务就得买3个LB,10个服务就得买10个——这谁顶得住?而且Service只管四层(TCP/UDP),HTTP Header里那些花活(域名路由、路径匹配、Cookie粘滞、Header改写)它一概不关心。
这就是Ingress出场的原因——它是K8s原生的七层HTTP路由入口。一个Ingress Controller对应一个LB,通过域名和路径把流量分发给不同的后端Service。本文先把Ingress和Service的关系理清楚,再逐字段拆解Ingress YAML,最后演示TLS证书管理。
一、Ingress是什么——“HTTP反向代理入口”
1.1 Service解决不了的三个问题
【Service的局限——为什么要Ingress】
问题1:每个公网服务要一个LB = 穷死
用 LoadBalancer Service: 用 Ingress:
┌──────┐ ┌──────┐ ┌──────┐ ┌─────────────────────────┐
│ LB-1 │ │ LB-2 │ │ LB-3 │ │ 一个 LB (省钱!) │
│$100/月│ │$100/月│ │$100/月│ │ │
└──┬───┘ └──┬───┘ └──┬───┘ │ api.example.com → API │
│ │ │ │ web.example.com → Front │
▼ ▼ ▼ │ admin.example.com→Admin │
┌──────┐┌──────┐┌──────┐ └─────────────────────────┘
│API ││Front ││Admin │
└──────┘└──────┘└──────┘
10个服务 = 10个LB = ¥1000/月 😱 10个服务 = 1个LB = ¥100/月 😎
问题2:域名路由 Service不行
问题3:URL路径路由 Service不行
/api/* → API Service, /web/* → Frontend Service
要点:Service工作在OSI第四层(传输层),只管IP和端口。Ingress工作在第七层(应用层),能看HTTP的Host头、URL路径、Cookie等。打个比方:Service是邮局的"按地址送信",Ingress是公司的"前台接待员"——看你是来面试的、送快递的还是谈合作的,把你引到不同的办公室。
1.2 Ingress ≠ Ingress Controller
这是很多人学Ingress时踩的第一个坑——Ingress只是"规则",Ingress Controller才是真正转发流量的"发动机"。
【Ingress 和 Ingress Controller 的关系】
你写的 Ingress 资源: 实际干活的是 Ingress Controller:
┌─────────────────────────┐ ┌─────────────────────────┐
│ apiVersion: networking │ │ Nginx Ingress Controller│
│ .k8s.io/v1 │ │ (一个运行的Pod) │
│ kind: Ingress │ ──监听──▶ │ │
│ │ │ 监听Ingress资源变化 │
│ spec: │ │ → 生成 nginx.conf │
│ rules: │ │ → reload nginx │
│ - host: api.ex.com │ │ → 按规则转发HTTP流量 │
│ paths: │ │ │
│ - path: /users │ │ 类比: │
│ backend: ... │ │ Ingress = nginx.conf │
└─────────────────────────┘ │ Ingress Controller │
│ = nginx 进程 │
└─────────────────────────┘
Ingress 只是配置文件——自己不干活!
跟Service类似:Service也是"配置",真正转发的是kube-proxy
要点:K8s默认不安装任何Ingress Controller——你装了Nginx Ingress、Traefik、Contour等任一款Controller后,Ingress资源才能生效。这个设计很像Java的接口和实现:Ingress是接口标准,各家Controller是具体实现。
二、Ingress YAML——完整拆解
一个完整的Ingress资源长这样:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
namespace: default
annotations: # 各种功能开关(不同Controller不同)
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx # ★ 指定用哪个 Ingress Controller
tls: # ★ TLS配置
- hosts:
- api.example.com
- web.example.com
secretName: example-tls # TLS证书存在这个Secret里
rules: # ★ 路由规则——核心!
- host: api.example.com # 域名匹配
http:
paths:
- path: /users # 路径前缀匹配
pathType: Prefix # Prefix(前缀)或 Exact(精确)
backend:
service:
name: users-service # 转发到哪个Service
port:
number: 8080
- path: /orders
pathType: Prefix
backend:
service:
name: orders-service
port:
number: 8080
- host: web.example.com # 另一个域名
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
defaultBackend: # ★ 默认后端——匹配不到任何规则时用
resource:
apiGroup: k8s.example.com
kind: StorageBucket
name: static-assets
2.1 ingressClassName——“谁来执行这些规则?”
spec:
ingressClassName: nginx # 告诉K8s:"这个Ingress交给Nginx Ingress Controller处理"
如果你集群里装了多个Ingress Controller(比如同时有Nginx和Traefik),这个字段确保Ingress只被指定的Controller处理。K8s 1.18+版本强烈推荐设置这个字段。
2.2 host和path——“根据什么路由?”
【Ingress路由决策流程】
HTTP请求: GET http://api.example.com/users/123
│
▼
┌─────────────────────────────────────────────┐
│ Ingress Controller │
│ │
│ Step 1: 匹配 host │
│ "Host头是 api.example.com 吗?" │
│ 遍历所有rules,找到 host 匹配的 │
│ │ │
│ ▼ │
│ Step 2: 匹配 path │
│ "URL路径是 /users/123" │
│ pathType是Prefix:/users能匹配 /users/123 │
│ │ │
│ ▼ │
│ Step 3: 转发到 backend │
│ 转发到 users-service:8080 │
└─────────────────────────────────────────────┘
2.3 pathType——前缀还是精确?
| pathType | 含义 | 示例 | /users能匹配的请求 |
|---|---|---|---|
| Prefix | 路径前缀匹配 | path: /users |
/users、/users/、/users/123、/users/123/orders |
| Exact | 精确匹配 | path: /users |
仅 /users |
| ImplementationSpecific | 由Controller决定 | — | 取决于具体Controller的实现 |
# Prefix vs Exact 的区别
paths:
- path: /api
pathType: Prefix # /api、/api/、/api/users 都能匹配
backend: ...
- path: /health
pathType: Exact # 只有 /health 能匹配,/health/check 不行
backend: ...
2.4 defaultBackend——“如果都没匹配到…”
# 所有规则都没匹配上时的兜底处理
spec:
defaultBackend:
service:
name: 404-handler # 返回404页面
port:
number: 80
rules:
- host: api.example.com
# ...
要点:
defaultBackend不是必选项,但我建议都配上——至少指向一个返回404的服务。否则没匹配到的请求可能会被路由到随机后端,或者返回Ingress Controller自己的默认页面,用户体验极差。
三、基于域名的路由——“一个入口,多个服务”
【域名路由示意】
user1: api.example.com/users ─┐
user2: api.example.com/orders ──┤
│
▼
┌─────────────────┐
│ Ingress Controller│
│ (Nginx/Traefik) │
│ :80/:443 │
└──┬──────┬──────┬──┘
│ │ │
host匹配 │ │ │
┌──────────────┘ │ └──────────────┐
▼ ▼ ▼
api.example.com web.example.com admin.example.com
│ │ │
┌────────┴────────┐ ┌──────┴──────┐ ┌──────┴──────┐
│ /users │ /orders│ │ / │ │ / │
▼ ▼ │ ▼ │ ▼ │
┌──────┐ ┌────────┐ │ ┌──────────┐ │ ┌──────────┐ │
│users │ │orders │ │ │frontend │ │ │admin │ │
│svc │ │svc │ │ │svc │ │ │panel svc │ │
└──────┘ └────────┘ │ └──────────┘ │ └──────────┘ │
└────────────────┘ └────────────────┘
# 域名+路径双层路由
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-domain-ingress
spec:
ingressClassName: nginx
rules:
# 第一个域名:api.example.com
- host: api.example.com
http:
paths:
- path: /users
pathType: Prefix
backend:
service:
name: users-service
port:
number: 8080
- path: /orders
pathType: Prefix
backend:
service:
name: orders-service
port:
number: 8080
- path: /products
pathType: Prefix
backend:
service:
name: products-service
port:
number: 8080
# 第二个域名:web.example.com
- host: web.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
# 第三个域名:admin.example.com
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 8080
四、TLS配置——让Ingress终结HTTPS
Ingress Controller是TLS终结的最佳位置——客户端到Ingress是HTTPS,Ingress到后端Pod是HTTP。这样后端Pod不用管证书的事,省心又安全。
【TLS 终结——Ingress处理HTTPS,后端Pod只管HTTP】
客户端 Ingress Controller 后端Pod
────── ────────────────── ──────
https://api.example.com/users ┌────────────────┐ ┌────┐
──────────────────────────────► │ 解密TLS │ http://10.244 │ │
加密传输 │ 检查Host/Path │ ─────────────► │ │
│ 路由到后端 │ 明文传输 │ │
│ (K8s内部网络安全) │ └────┘
└────────────────┘
4.1 手动配置TLS证书
# Step 1: 用OpenSSL生成自签名证书(仅限测试!)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout tls.key -out tls.crt \
-subj "/CN=api.example.com/O=MyOrg"
# Step 2: 创建TLS Secret
kubectl create secret tls example-tls \
--cert=tls.crt \
--key=tls.key \
-n default
# Step 3: 在Ingress中引用
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress-tls
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
- web.example.com # 一个Secret可以服务多个域名
secretName: example-tls # 刚才创建的Secret
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
4.2 用cert-manager自动管理证书——“再也不用记续期时间”
cert-manager是K8s生态中管理TLS证书的事实标准。它自动从Let’s Encrypt(免费)等CA申请证书、自动续期。
# 安装cert-manager(Helm方式)
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set installCRDs=true
# 创建Issuer(证书颁发者配置)
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-prod
namespace: default
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: nginx
---
# Ingress——只需加一个Annotation,cert-manager自动帮你拿证书
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress-tls-auto
annotations:
cert-manager.io/issuer: "letsencrypt-prod" # ← 就这一行!
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls-secret # cert-manager自动创建这个Secret
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
要点:cert-manager注册免费TLS证书需要域名有真实DNS解析(Let’s Encrypt会验证域名所有权)。本地测试用自签名证书就够了,但生产环境强烈建议用cert-manager + Let’s Encrypt——免费、自动续期、不用半夜爬起来更新过期证书。
五、rewrite-target——URL路径改写
这是Ingress最常见的玩法——外部路径和内部路径不一样:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rewrite-ingress
annotations:
# 关键:重写目标路径
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
# 外部: /api/users → 内部: /users
# 正则 (.*) 捕获组,$2 代表第二个捕获组
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: api-service
port:
number: 8080
【URL 重写示意】
外部请求 内部转发
───────── ────────
/api/users ──rewrite──► /users
/api/users/123 ──rewrite──► /users/123
/api/orders ──rewrite──► /orders
/health ──不匹配──► /health(走其他规则或defaultBackend)
注解说明:
nginx.ingress.kubernetes.io/rewrite-target: /$2
path: /api(/|$)(.*)
正则解释:
/api — 匹配 "/api"
(/|$) — $1: 匹配 "/" 或 结尾
(.*) — $2: 匹配剩余所有字符
rewrite到: /$2 = 去掉 /api 前缀
六、同一个Ingress管理多个服务——完整示例
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: main-ingress
annotations:
cert-manager.io/issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- "*.example.com"
secretName: wildcard-tls
defaultBackend:
service:
name: default-backend
port:
number: 80
rules:
# 用户API
- host: api.example.com
http:
paths:
- path: /v1/users
pathType: Prefix
backend:
service:
name: users-v1-service
port:
number: 8080
- path: /v2/users
pathType: Prefix
backend:
service:
name: users-v2-service # v2灰度版
port:
number: 8080
# PC Web前端
- host: www.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-frontend-service
port:
number: 80
# 移动端API(不同的域名)
- host: m.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mobile-api-service
port:
number: 8080
# 管理后台
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 8080
# 部署并验证
kubectl apply -f main-ingress.yaml
kubectl get ingress
# NAME CLASS HOSTS ADDRESS PORTS
# main-ingress nginx api.example.com,www.example.com 10.0.1.100 80, 443
# m.example.com,admin.example.com
# 测试路由
curl -H "Host: api.example.com" http://10.0.1.100/v1/users
curl -H "Host: www.example.com" http://10.0.1.100/
curl -H "Host: admin.example.com" http://10.0.1.100/
本篇小结
Ingress是K8s七层路由的标准入口——它让你用一个LB管理N个服务,通过域名和路径精准分发HTTP流量:
- Ingress是规则,Controller是引擎:Ingress资源只是"配置文件",真正干活的是Nginx Ingress/Traefik等Controller
- 域名+路径双层路由:
host和path组合决定流量去向,Prefix/Exact两种匹配模式各有用处 - TLS终结:Ingress处理HTTPS→HTTP转换,cert-manager免费自动管理证书,告别手动续期
- pathType和rewrite:控制路径匹配粒度和改写规则,是Ingress日常使用率最高的功能
下一篇,咱们深入Ingress Controller的世界——Nginx Ingress怎么工作、常用Annotations大全、金丝雀发布怎么配、Traefik有什么不一样的玩法。
上一篇【第16篇】Service的负载均衡原理——kube-proxy到底干了什么
下一篇【第18篇】Ingress Controller选型和实战——Nginx Ingress完全指南
更多推荐

所有评论(0)