title: “K8s 系列 | 第 11 天:Ingress 与 Ingress Controller:外部流量接入全攻略”
tags:
– Kubernetes
– K8s系列
– DevOps
– Ingress
– 网络
– 负载均衡
– Nginx
第 11/30 天
引言
前几篇文章中,我们学习了 Service 的三种类型——ClusterIP、NodePort 和 LoadBalancer,它们分别解决了集群内部通信、节点端口暴露和云负载均衡的问题。然而在实际生产环境中,我们面对的是更复杂的场景:多个服务需要共用同一个公网入口、需要基于域名和路径做流量分发、需要 HTTPS 终止和 TLS 证书管理。
这时候,Ingress 就登场了。
Ingress 是 Kubernetes 中一个至关重要的 API 资源,它充当着集群的「交通指挥中心」——所有来自外部的请求首先到达 Ingress,然后由它根据规则路由到对应的后端 Service。从一个朴实的企业站到日活千万的电商平台,Ingress 是 K8s 网络栈中不可或缺的一环。
本文将带你从零掌握 Ingress 的核心机制,通过实战部署 Nginx Ingress Controller,并覆盖 HTTPS、路径重写、速率限制等生产场景配置。
核心概念
什么是 Ingress?
Ingress 是 Kubernetes 的一层 API 资源,定义了从集群外部到内部服务的 HTTP(S) 路由规则。它本质上是一个第 7 层(应用层)负载均衡器——这意味着它能理解 HTTP 请求的域名、路径、Header 等信息,并据此做出路由决策。
Ingress vs Service(NodePort / LoadBalancer)
| 特性 | NodePort | LoadBalancer | Ingress |
|---|---|---|---|
| 层级 | 第 4 层(传输层) | 第 4 层 | 第 7 层(应用层) |
| 域名路由 | ❌ | ❌ | ✅ |
| 路径路由 | ❌ | ❌ | ✅ |
| HTTPS 终止 | ❌(需额外组件) | ❌(需额外组件) | ✅ 内置 |
| 多服务共享端口 | ❌(每服务一个端口) | ❌(每服务一个 LB) | ✅(统一 80/443) |
| 成本 | 低(需节点端口) | 高(每个 LB 收费) | 低(共享 Ingress Controller) |
一句话总结:NodePort 和 LoadBalancer 让你「连得上」,Ingress 让你「连得对」。
Ingress Controller 的作用
Ingress 资源本身只是一个声明式规则——它描述了「什么域名/路径应该路由到哪个 Service」。真正执行这些规则的是 Ingress Controller ——一个运行在集群中的 Pod,负责监听 Ingress 资源的变化,并动态配置底层的反向代理(如 Nginx、Traefik、HAProxy 等)。
[Internet]
│
▼
┌─────────────────────┐
│ Ingress Controller │ ← 监听 Ingress 资源,动态配置反向代理
│ (e.g., Nginx) │
└────────┬────────────┘
│
┌────┴────┐
▼ ▼
┌──────┐ ┌──────┐
│Svc A │ │Svc B │
│:8080 │ │:3000 │
└──────┘ └──────┘
主流 Ingress Controller 选型
| 产品 | 特点 | 适用场景 |
|---|---|---|
| ingress-nginx | 社区最成熟,功能全面,性能稳定 | 通用首选,中小规模集群 |
| Traefik | 自动发现服务,支持多种协议,Dashboard 可视化 | 微服务 + Service Mesh 场景 |
| Kong | 插件生态丰富(认证、限流、日志) | API 网关需求强的企业 |
| HAProxy | 极致性能,内存占用低 | 高并发入口层(十万级 QPS) |
| ALB Ingress | AWS 原生 LB,直接走云网络 | AWS 全托管集群 |
| APISIX | 云原生 API 网关,低延迟 | 大规模微服务网关 |
对于大多数场景,ingress-nginx 是最稳妥的选择——它的社区最活跃、文档最完善、功能覆盖最全面。
实战步骤
1. 部署 Nginx Ingress Controller
使用官方 Helm Chart 部署是最推荐的方式:
# 添加 Helm 仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
# 部署到 ingress-nginx 命名空间
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx
--namespace ingress-nginx --create-namespace
--set controller.service.type=NodePort
--set controller.service.nodePorts.http=30080
--set controller.service.nodePorts.https=30443
如果你没有 Helm,也可以直接用 YAML 文件部署:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.1/deploy/static/provider/baremetal/deploy.yaml
验证部署状态:
kubectl get pod -n ingress-nginx -w
# 等待所有 Pod 处于 Running 状态
kubectl get svc -n ingress-nginx
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# ingress-nginx-controller NodePort 10.96.123.45 <none> 80:30080/TCP,443:30443/TCP
# ingress-nginx-controller-admission ClusterIP 10.96.67.89 <none> 443/TCP
2. 创建一个测试应用
我们先部署一个简单的 Web 应用来测试 Ingress 路由功能:
# web-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web-app-svc
namespace: default
spec:
selector:
app: web-app
ports:
- port: 80
targetPort: 80
# api-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-app
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: api-app
template:
metadata:
labels:
app: api-app
spec:
containers:
- name: api
image: hashicorp/http-echo:latest
args:
- "-text=Hello from API Service"
ports:
- containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
name: api-app-svc
namespace: default
spec:
selector:
app: api-app
ports:
- port: 80
targetPort: 5678
部署应用:
kubectl apply -f web-app.yaml
kubectl apply -f api-app.yaml
3. 创建 Ingress 规则——基于路径的路由
现在我们来创建第一个 Ingress 资源:根据请求路径 /web 和 /api 分别路由到不同的后端服务:
# ingress-path.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-based-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: / # 路径重写
spec:
ingressClassName: nginx
rules:
- host: k8s-demo.local
http:
paths:
- path: /web
pathType: Prefix
backend:
service:
name: web-app-svc
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-app-svc
port:
number: 80
kubectl apply -f ingress-path.yaml
验证 Ingress 状态:
kubectl get ingress
# NAME CLASS HOSTS ADDRESS PORTS AGE
# path-based-ingress nginx k8s-demo.local <ingress-ip> 80 10s
测试路由(假设 Ingress Controller 运行在 node-1 的 30080 端口):
# 测试 /web 路径 -> 应返回 Nginx 默认页面
curl -H "Host: k8s-demo.local" http://node-1-ip:30080/web
# 测试 /api 路径 -> 应返回 "Hello from API Service"
curl -H "Host: k8s-demo.local" http://node-1-ip:30080/api
4. 基于域名的路由
在同一集群中,你可能需要为不同的域名提供不同的服务。下面示范基于域名 app.example.com 和 api.example.com 的路由:
# ingress-host.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: host-based-ingress
namespace: default
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app-svc
port:
number: 80
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-app-svc
port:
number: 80
kubectl apply -f ingress-host.yaml
测试:
curl -H "Host: app.example.com" http://node-1-ip:30080/
# -> Nginx 默认页面
curl -H "Host: api.example.com" http://node-1-ip:30080/
# -> "Hello from API Service"
5. 配置 HTTPS(TLS 终止)
生产环境必不可少的一步——为 Ingress 配置证书,实现 HTTPS 访问。这里我们使用自签名证书做演示,生产环境请使用 Let’s Encrypt + cert-manager 自动签发。
# 生成自签名证书
openssl req -x509 -nodes -days 365 -newkey rsa:2048
-keyout tls.key -out tls.crt
-subj "/CN=k8s-demo.local/O=K8s Demo"
# 创建 Secret
kubectl create secret tls k8s-demo-tls
--cert=tls.crt --key=tls.key
-n default
# 验证
kubectl get secret k8s-demo-tls -n default
创建带 TLS 的 Ingress:
# ingress-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts:
- k8s-demo.local
secretName: k8s-demo-tls
rules:
- host: k8s-demo.local
http:
paths:
- path: /web
pathType: Prefix
backend:
service:
name: web-app-svc
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: api-app-svc
port:
number: 80
kubectl apply -f ingress-tls.yaml
# 测试 HTTPS
curl -k -H "Host: k8s-demo.local" https://node-1-ip:30443/web
# -k 表示忽略自签名证书警告
6. 高级配置:速率限制与白名单
Nginx Ingress Controller 提供了丰富的 Annotation 来控制流量行为:
# ingress-advanced.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: advanced-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
# 速率限制:每分钟 10 个请求
nginx.ingress.kubernetes.io/limit-rpm: "10"
# 请求体最大 10M
nginx.ingress.kubernetes.io/proxy-body-size: 10m
# 允许的源 IP(白名单)
nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8,192.168.0.0/16"
# 启用 CORS
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
# 连接超时
nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app-svc
port:
number: 80
常见问题
1. Ingress 创建后没有生效(404)
现象:创建 Ingress 后访问返回 404,或 kubectl get ingress 的 ADDRESS 字段为空。
排查步骤:
# 1. 确认 Ingress Controller Pod 是否运行
kubectl get pod -n ingress-nginx
# 2. 查看 Ingress Controller 日志
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx
# 3. 检查 Ingress 事件
kubectl describe ingress path-based-ingress
# 4. 确认 ingressClassName 是否正确匹配
kubectl get ingressclass
常见原因:
– Ingress Controller 未部署或启动中
– ingressClassName 不匹配(默认类名可能是 nginx 而非 nginx-ingress)
– Ingress 所在 Namespace 没有对应的后端 Service
2. 路径重写规则不生效
现象:/web 请求到达后端变成了 /web/index.html,而非预期的 /index.html。
解决方案:正确使用 rewrite-target annotation。当 path: /web 且 rewrite-target: / 时,请求路径中的 /web 前缀会被剥离:
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
如果需要更复杂的重写,可以用 use-regex + 正则捕获组:
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: example.com
http:
paths:
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
3. HTTPS 配置后证书不生效
现象:配置了 TLS Secret 后仍跳转到不安全的页面。
排查:
# 检查 Secret 是否存在且格式正确
kubectl describe secret k8s-demo-tls -n default
# 检查 Ingress 的 TLS 配置
kubectl get ingress tls-ingress -o yaml | grep -A 10 tls
# 强制 HTTP → HTTPS 重定向
# 添加 annotation:
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
4. 生产环境如何自动管理证书?
手动管理证书显然不可持续。最佳实践是使用 cert-manager + Let’s Encrypt 实现自动签发和续期:
# 安装 cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.0/cert-manager.yaml
# 创建 ClusterIssuer(全局证书签发者)
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- http01:
ingress:
class: nginx
EOF
# 在 Ingress 中添加 cert-manager annotation 即可自动签发
# cert-manager.io/cluster-issuer: "letsencrypt-prod"
总结
在本文中,我们深入探讨了 Ingress 的核心概念和在 Kubernetes 中管理外部流量的完整工作流:
| 知识点 | 要点 |
|---|---|
| Ingress 是什么 | 第 7 层路由规则,按域名/路径分发流量 |
| Ingress Controller | 真正执行路由规则的组件,ingress-nginx 是最主流的选择 |
| 路由方式 | 基于路径(Prefix/Exact)和基于域名(Host) |
| HTTPS 配置 | 通过 TLS Secret 实现 SSL 终止 |
| 高级功能 | 速率限制、CORS、白名单、路径重写 |
| 生产实践 | cert-manager 自动签发证书、Helm 部署管理 |
Ingress 让你的 K8s 集群拥有了一个「智能入口」——它不仅是流量路由的工具,更是安全策略、访问控制和流量治理的统一控制面。掌握 Ingress,意味着你已经从「能用 K8s 跑应用」进阶到了「能构建生产级入口架构」。
下期预告
第 12 天:NetworkPolicy:K8s 网络安全策略与微隔离
学习了 External → Cluster 的入口控制后,下一篇文章将转向集群内部的「微隔离」——NetworkPolicy 如何用声明式的方式定义 Pod 之间的网络访问规则,实现真正的零信任网络安全模型。
📚 系列目录(持续更新中)**
| 天数 | 标题 | 状态 |
|---|---|---|
| 第 1 天 | Kubernetes 是什么?核心概念与架构全景解析 | ✅ 已发布 |
| 第 2 天 | 手把手搭建你的第一个 K8s 集群(kubeadm 实战) | ✅ 已发布 |
| 第 3 天 | Pod 详解:K8s 最小的调度单元与生命周期管理 | ✅ 已发布 |
| 第 4 天 | Deployment 与 ReplicaSet:声明式应用管理 | ✅ 已发布 |
| 第 5 天 | Service 与网络基础:ClusterIP、NodePort、LoadBalancer 详解 | ✅ 已发布 |
| 第 6 天 | Namespace 与资源配额:多租户隔离基础 | ✅ 已发布 |
| 第 7 天 | ConfigMap 与 Secret:配置管理最佳实践 | ✅ 已发布 |
| 第 8 天 | Volume 与 PersistentVolume:存储抽象层的核心机制 | ✅ 已发布 |
| 第 9 天 | StorageClass 与动态存储供给实战 | ✅ 已发布 |
| 第 10 天 | StatefulSet:有状态应用的部署与管理 | ✅ 已发布 |
| 第 11 天 | Ingress 与 Ingress Controller:外部流量接入全攻略 | 📝 本文 |
| 第 12 天 | NetworkPolicy:K8s 网络安全策略与微隔离 | 🔜 即将发布 |
| 第 13 天 | Headless Service 与服务发现机制深度解析 | 🔜 即将发布 |
| 第 14 天 | CSI 存储插件与生产存储选型指南 | 🔜 即将发布 |
| 第 15 天 | 污点与容忍度:掌控 Pod 调度 | 🔜 即将发布 |
| 第 16 天 | Node Affinity 与 Pod Affinity:精细化调度策略实战 | 🔜 即将发布 |
| 第 17 天 | HPA 水平自动扩缩:基于 CPU/内存/自定义指标的弹性伸缩 | 🔜 即将发布 |
| 第 18 天 | VPA 与 Cluster Autoscaler:资源与集群层的自动扩缩 | 🔜 即将发布 |
| 第 19 天 | Job 与 CronJob:批处理与定时任务实战 | 🔜 即将发布 |
| 第 20 天 | PriorityClass 与抢占式调度机制 | 🔜 即将发布 |
| 第 21 天 | 资源配额与 LimitRange:多租户资源管控 | 🔜 即将发布 |
| 第 22 天 | 监控体系搭建:Prometheus + Grafana + Kube-state-metrics | 🔜 即将发布 |
| 第 23 天 | 日志收集实战:EFK/ELK 栈在 K8s 中部署 | 🔜 即将发布 |
| 第 24 天 | RBAC 权限控制:ServiceAccount、Role、ClusterRole 深度解析 | 🔜 即将发布 |
| 第 25 天 | Helm Charts:包管理器使用与 Chart 开发实战 | 🔜 即将发布 |
| 第 26 天 | 集群备份与恢复:etcd 快照 + Velero 方案 | 🔜 即将发布 |
| 第 27 天 | 滚动更新与回滚策略:实现零停机发布 | 🔜 即将发布 |
| 第 28 天 | 集群升级最佳实践:Control Plane 与 Node 升级步骤 | 🔜 即将发布 |
| 第 29 天 | 多集群管理:Federation / Cluster API / 多集群服务网格 | 🔜 即将发布 |
| 第 30 天 | K8s 生产环境踩坑实录:性能调优、故障排查与最佳实践 | 🔜 即将发布 |















暂无评论内容