Kubernetes Ingress 从零到一:为你的微服务打造统一的流量大门
在 Kubernetes 的世界里,我们通过 Service 将一组 Pod 暴露为一个网络服务。然而,Service 的 ClusterIP 类型仅在集群内部可访问,NodePort 和 LoadBalancer 类型虽然能提供外部访问,但在管理多个服务、SSL/TLS 终结、基于域名的虚拟主机等复杂场景下显得力不从心。这时,我们就需要 Ingress 来扮演集群“统一流量入口”的角色。
一、什么是 Ingress?为什么需要它?
简单来说,Ingress 是 Kubernetes 中管理外部访问集群内部服务的 API 对象。它本身并不直接处理流量,而是通过一组你定义的规则(路由规则),将 HTTP/HTTPS 流量路由到集群内部相应的 Service。
你可以把 Ingress 想象成集群的“智能门卫”或“流量调度中心”。它的核心价值在于:
- 统一入口:为多个后端服务提供一个单一的访问端点(IP 或域名),无需为每个服务都分配外部 IP。
- 基于规则的路由:可以根据请求的 主机名(Host) 和 URL 路径(Path) 将流量分发到不同的后端服务。
- 负载均衡:在多个后端 Pod 实例间自动分配流量。
- SSL/TLS 终结:在 Ingress 层面统一处理 HTTPS 加密和解密,减轻后端服务的负担。
- 成本效益:相比为每个服务使用
LoadBalancer类型(在云平台上通常会产生额外费用),一个 Ingress 可以代理数十上百个服务,成本更低。
重要概念区分:
- Ingress: 一组路由规则的集合,是 Kubernetes 的一种资源类型(
kind: Ingress)。 - Ingress Controller: 负责实际读取并执行 Ingress 规则的 Pod。它是流量的真正处理者。常见的实现有 Nginx Ingress Controller、Traefik、HAProxy Ingress 等。你必须先部署一个 Ingress Controller,Ingress 资源才能生效。
二、Ingress 的工作原理
下图清晰地展示了 Ingress 的工作流程:
外部用户
|
v (发起请求: https://shop.example.com/api/orders)
|
[ Ingress Controller (运行在Pod中) ]
| (读取 Ingress 规则)
| (匹配规则: Host=shop.example.com, Path=/api/orders -> Service: order-service)
|
v (负载均衡)
[ Service: order-service ]
|
v (服务发现)
[ Pods: order-app-xxxx ] [ Pods: order-app-yyyy ]
- 用户访问
https://shop.example.com/api/orders。 - DNS 将该域名解析到 Ingress Controller 服务的外部 IP(可能是
LoadBalancer或NodePort类型)。 - 请求到达 Ingress Controller Pod。
- Ingress Controller 查询集群中所有的 Ingress 资源,根据定义的规则进行匹配。
- 匹配到规则:主机头(Host)为
shop.example.com且路径前缀为/api/orders的请求,应转发到名为order-service的 Kubernetes Service。 - Ingress Controller 将请求代理到
order-service。order-service再通过其负载均衡机制,将请求最终转发到某个健康的order-appPod 上。
三、实战:部署 Nginx Ingress Controller 并配置规则
接下来,我们通过一个完整的例子,部署最流行的 Nginx Ingress Controller,并为其配置路由规则。
步骤 1:部署 Nginx Ingress Controller
我们使用官方维护的 Helm Chart 进行部署,这是最简便的方式。
首先,添加 Helm 仓库并更新:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
然后,在 ingress-nginx 命名空间中安装:
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.service.type=LoadBalancer # 根据你的环境调整,例如 Minikube 可以用 NodePort
安装完成后,查看 Ingress Controller 的 Service,获取外部访问地址:
kubectl get svc -n ingress-nginx
输出类似如下,EXTERNAL-IP 就是入口地址(如果是 pending,在云平台需要等待片刻;本地环境如 Minikube 会用 NodePort)。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.96.100.10 192.168.1.100 80:32456/TCP,443:31445/TCP 5m
步骤 2:部署示例后端应用
我们创建两个简单的 Web 应用来模拟不同的服务。
应用 A (frontend-app):
# frontend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-app
spec:
replicas: 2
selector:
matchLabels:
app: frontend-app
template:
metadata:
labels:
app: frontend-app
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
---
# frontend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
selector:
app: frontend-app
ports:
- protocol: TCP
port: 80
targetPort: 80
应用 B (backend-api):
# backend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-api
spec:
replicas: 2
selector:
matchLabels:
app: backend-api
template:
metadata:
labels:
app: backend-api
spec:
containers:
- name: http-echo
image: hashicorp/http-echo
args: ["-text=Hello from Backend API!"]
ports:
- containerPort: 5678
---
# backend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
selector:
app: backend-api
ports:
- protocol: TCP
port: 80
targetPort: 5678
应用配置:
kubectl apply -f frontend-deployment.yaml -f frontend-service.yaml
kubectl apply -f backend-deployment.yaml -f backend-service.yaml
步骤 3:创建 Ingress 资源定义规则
现在,我们来编写 Ingress 规则,实现:
- 访问
myapp.example.com/或myapp.example.com/web时,路由到frontend-service。 - 访问
myapp.example.com/api时,路由到backend-service。
# example-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
# 可选注解:指定使用的Ingress Controller类型,如果集群有多个的话
kubernetes.io/ingress.class: "nginx"
# 可选注解:重写路径,将 /api 前缀去掉后再转发给后端
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.example.com # 你的域名,本地测试可以配置hosts文件指向Ingress IP
http:
paths:
- path: /web
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- path: /api
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 80
- path: /
pathType: Prefix # 默认路径,放在最后
backend:
service:
name: frontend-service
port:
number: 80
应用 Ingress 规则:
kubectl apply -f example-ingress.yaml
步骤 4:测试验证
由于我们没有真实的 myapp.example.com 域名,可以通过修改本地 hosts 文件(/etc/hosts 或 C:\Windows\System32\drivers\etc\hosts)进行测试。
将 Ingress Controller 的外部 IP 映射到我们的域名:
# 将 192.168.1.100 替换为你的实际 EXTERNAL-IP
192.168.1.100 myapp.example.com
然后使用 curl 命令测试:
- 测试根路径和/web路径(应返回Nginx默认页面):
curl http://myapp.example.com/ curl http://myapp.example.com/web - 测试/api路径(应返回后端API信息):
curl http://myapp.example.com/api # 预期输出:Hello from Backend API!
你也可以在浏览器中访问 http://myapp.example.com/api 查看结果。
四、进阶配置:HTTPS 与 TLS 证书
生产环境必须使用 HTTPS。Ingress 可以很方便地配置 TLS 证书。
1. 准备 TLS 证书
假设你已有一个域名 myapp.example.com 的 TLS 证书(tls.crt)和私钥(tls.key)。
2. 创建 Kubernetes Secret 存储证书
kubectl create secret tls myapp-tls-secret \
--cert=tls.crt \
--key=tls.key
3. 更新 Ingress 规则,指定 TLS 配置
修改之前的 example-ingress.yaml,在 spec 部分添加 tls 字段:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls: # TLS配置部分
- hosts:
- myapp.example.com
secretName: myapp-tls-secret # 指向存储证书的Secret
rules:
- host: myapp.example.com
http:
paths:
... # 后面的paths规则与之前相同
应用更新后,Ingress Controller 就会在 443 端口上启用 HTTPS,并自动将 HTTP 请求重定向到 HTTPS。
五、总结与最佳实践
通过本文,你已经掌握了 Kubernetes Ingress 的核心概念和部署流程。总结一下关键点:
- 先 Controller,后规则: 确保 Ingress Controller 已成功运行,再创建 Ingress 资源。
- 路径顺序: 在定义多个
path时,更具体的路径应放在前面,通用路径(如/)放在最后,避免被意外覆盖。 - 注解(Annotations)是利器: 不同的 Ingress Controller 支持丰富的注解来实现高级功能(如限流、认证、CORS、重写等),请查阅对应 Controller 的文档。
- 生产环境务必使用 HTTPS: 利用
tls配置和 Secret 管理证书。对于自动证书管理,可以集成 Cert-Manager 来自动签发 Let‘s Encrypt 证书。 - 监控与日志: 为 Ingress Controller 配置日志收集和监控(如 Prometheus Metrics),这对于排查流量问题至关重要。
Ingress 作为 Kubernetes 集群流量的“总闸门”,是微服务架构中不可或缺的一环。熟练掌握其配置与管理,能极大地提升应用的可访问性、安全性与可维护性。现在,就去为你集群中的应用配置一个统一的访问入口吧!