IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。
在前两篇中,我们用 Service 解决了 Pod 的服务发现问题------ClusterIP 提供内部稳定入口,NodePort 和 LoadBalancer 暴露外部访问。但在实际生产环境中,你通常不会为每一个微服务都申请一个独立的云负载均衡器,费用高昂且难以统一管理。更常见的做法是:用一个统一的入口,根据域名 和URL 路径将流量分发到不同的后端服务。
举个例子:api.example.com 路由到 Flask 服务,www.example.com 路由到前端静态页面服务,admin.example.com 路由到后台管理系统。这种基于 HTTP/HTTPS 的七层路由能力,正是 Ingress 提供的核心功能。这一篇,我们就来拆解 Ingress 的架构,并在 Minikube 环境中实战配置贯穿案例的域名路由。
一、为什么 Service 不够用?
回顾第 28 篇,我们用 NodePort 类型的 Service 暴露了 Flask 应用,访问方式是 http://<节点IP>:30080。这在以下几个场景下会显得力不从心:
场景一:多服务共享同一端口。你有 3 个 Web 服务(前端、API、管理后台),都监听 80 端口。用 NodePort 的话,需要分别映射到 30080、30081、30082------不仅端口号不直观,而且每新增一个服务就要占用一个节点端口。
场景二:基于域名的路由 。你希望 api.example.com 和 www.example.com 访问不同的后端服务,但共享同一个入口 IP 和端口。Service 工作在四层(TCP/UDP),无法读取 HTTP 请求头中的 Host 信息,因此无法基于域名做路由决策。
场景三:TLS 终端。你希望统一管理 HTTPS 证书,在入口处完成 TLS 握手和证书卸载,而不是在每个 Pod 里各自配置 HTTPS。
Ingress 正是为解决这些问题而设计的------它工作在七层(HTTP/HTTPS),通过解析请求中的 Host 和 Path 信息,将流量智能路由到不同的 Service,同时统一管理 TLS 证书。
二、Ingress 与 Ingress Controller 的关系
很多初学者容易混淆 Ingress 和 Ingress Controller,把它们当成一回事。实际上,它们是两个完全不同的概念,遵循 K8s 经典的"API 对象 + 控制器"分离设计:
简单来说:Ingress 是"你想要什么路由规则",Ingress Controller 是"谁来执行这些规则"。这和 Deployment(你声明期望状态)与 Deployment Controller(控制器持续调和实际状态)的关系完全一致。
K8s 社区有多种 Ingress Controller 实现,选择哪一个取决于你的场景需求:
本系列以 NGINX Ingress Controller 为标准,因为它最贴近 K8s 原生生态,文档最丰富,也是生产环境中最常见的选择。
三、实战:在 Minikube 中部署 NGINX Ingress Controller
3.1 启用 Minikube Ingress 插件
Minikube 内置了 NGINX Ingress Controller,一条命令即可启用:
bash
minikube addons enable ingress
输出:
bash
🌟 The 'ingress' addon is enabled
验证 Ingress Controller Pod 是否运行:
bash
kubectl get pods -n ingress-nginx
输出:
bash
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-7c8b6f9d5f-abcde 1/1 Running 0 30s
这个 Pod 运行在 ingress-nginx 命名空间中。它是一个标准的 Nginx 反向代理实例,由 K8s 自动部署和管理。当你在集群中创建或修改 Ingress 资源时,Ingress Controller 会监听这些变化,自动更新 Nginx 配置文件并执行热重载。
3.2 部署示例应用:Flask 计数器
为贯穿案例创建 Deployment 和 Service。这一次,我们只需要 ClusterIP 类型的 Service 暴露 5000 端口,外部访问完全交给 Ingress 处理:
bash
apiVersion: apps/v1
kind: Deployment
metadata:
name: flask-app
spec:
replicas: 2
selector:
matchLabels:
app: flask-counter
template:
metadata:
labels:
app: flask-counter
spec:
containers:
- name: flask
image: flask-redis-counter:2.0
ports:
- containerPort: 5000
env:
- name: REDIS_HOST
value: redis-service
readinessProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 5
failureThreshold: 2
---
apiVersion: v1
kind: Service
metadata:
name: flask-service
spec:
type: ClusterIP
selector:
app: flask-counter
ports:
- port: 5000
targetPort: 5000
bash
kubectl apply -f flask-deployment.yaml
kubectl get svc flask-service
# NAME TYPE CLUSTER-IP PORT(S) AGE
# flask-service ClusterIP 10.96.200.80 5000/TCP 10s
flask-service 只是一个 ClusterIP Service,没有 NodePort、没有 LoadBalancer,外部无法直接访问。这很好------我们不需要让 Service 操心外部暴露,Ingress 会负责这一层。
3.3 创建 Ingress 资源:基于路径的路由
bash
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: flask-ingress
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /counter
pathType: Prefix
backend:
service:
name: flask-service
port:
number: 5000
关键字段解读:
-
ingressClassName: nginx:指定使用 NGINX Ingress Controller 来处理这个 Ingress。一个集群可以有多个 Ingress Controller,此字段确保规则被正确的控制器处理。 -
path: /counter:URL 路径前缀,匹配/counter、/counter/、/counter/anything。 -
pathType: Prefix:前缀匹配模式。Prefix表示以/counter开头的路径都会被路由到该 Service。另一种模式是Exact,精确匹配整个路径。 -
backend.service.name: flask-service:流量转发的目标 Service 名称。Ingress Controller 会查询该 Service 的 Endpoints,将请求转发到后端的 Pod IP。
bash
kubectl apply -f flask-ingress.yaml
kubectl get ingress
输出:
bash
NAME CLASS HOSTS ADDRESS PORTS AGE
flask-ingress nginx * 192.168.49.2 80 30s
ADDRESS 是 Ingress 的入口 IP(Minikube 节点的 IP)。HOSTS=* 表示当前没有配置域名规则,所有域名的 /counter 请求都会被路由到 flask-service。
3.4 验证路由
bash
curl http://192.168.49.2/counter
输出:
bash
Hello World! I have been seen 1 times.
如果你访问根路径 /,会得到 Nginx 的 404 页面------因为 Ingress 中只定义了 /counter 的路由规则,其他路径没有匹配的后端 Service。
小贴士 :Minikube 的 Ingress 可能会有一两分钟的初始化延迟,如果 curl 返回 Could not resolve host,稍等片刻再试。如果持续不通,执行 minikube addons list | grep ingress 确认插件确实已启用,然后 kubectl get pods -n ingress-nginx 确认 Controller Pod 处于 Running 状态。
四、实战:基于域名的路由
单路径路由是 Ingress 最基础的用法。更常见的场景是基于域名将请求分发到不同的后端服务。假设我们有三个服务:
-
counter.example.com→ Flask 计数器应用 -
api.example.com→ Flask API 应用(同一个镜像,不同的 Service) -
admin.example.com→ 后台管理应用(暂时用 Nginx 占位)
4.1 创建多个后端服务
bash
# 为演示创建第二个 Service,指向同一个 Deployment(实际中会是不同的应用)
kubectl expose deployment flask-app --name=api-service --port=5000 --target-port=5000
# 创建第三个 Service(后台管理占位)
kubectl create deployment admin --image=nginx:alpine
kubectl expose deployment admin --name=admin-service --port=80
4.2 创建多域名 Ingress
bash
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-domain-ingress
spec:
ingressClassName: nginx
rules:
- host: counter.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: flask-service
port:
number: 5000
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 5000
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 80
bash
kubectl apply -f multi-domain-ingress.yaml
4.3 在本地模拟域名访问
由于 example.com 是占位域名,我们需要在本地将域名解析到 Minikube 的 IP。使用 curl 的 -H 参数手动指定 Host 头:
bash
# 获取 Minikube IP
MINIKUBE_IP=$(minikube ip)
# 访问不同域名
curl -H "Host: counter.example.com" http://$MINIKUBE_IP
# Hello World! I have been seen 2 times.
curl -H "Host: api.example.com" http://$MINIKUBE_IP/health
# {"status":"ok"}
curl -H "Host: admin.example.com" http://$MINIKUBE_IP
# <!DOCTYPE html>...(Nginx 默认欢迎页)
同一个 IP 地址、同一个端口(80),仅凭 HTTP 请求头中的 Host 字段不同,就被路由到了三个完全不同的后端服务------这就是 Ingress 七层路由的核心能力。
关于域名和本机测试 :
example.com是 IANA 保留的示例域名,永远不会被注册。如果你希望在浏览器中测试,可以编辑/etc/hosts,添加192.168.49.2 counter.example.com api.example.com(将192.168.49.2替换为minikube ip的输出)。但请注意,浏览器会缓存 DNS 解析结果,修改 hosts 后可能需要重启浏览器或清除 DNS 缓存才能生效。对于本地快速验证,curl 的-H "Host:"参数是最干净的方式。
五、Ingress 与 Service 的对比
Ingress 并没有取代 Service,而是建立在 Service 之上 。Ingress 的 backend 字段指向的是 Service 名称,Service 仍然负责将流量负载均衡到具体的 Pod。Ingress 做的只是"根据 Host 和 Path,选择正确的 Service"。
六、命令速查表
七、本篇总结
-
Ingress 的定位:七层 HTTP/HTTPS 路由,根据 Host 和 Path 将外部流量分发到不同的 Service,弥补了 Service 在域名路由、TLS 终端、多服务共享端口方面的不足。
-
Ingress 与 Ingress Controller 的关系:Ingress 是定义路由规则的 API 对象,Ingress Controller 是实际执行转发的代理程序(如 NGINX、Traefik)。二者必须配套使用。
-
实战成果:在 Minikube 中部署了 NGINX Ingress Controller,通过基于路径和基于域名的两种方式将流量路由到贯穿案例的 Flask 应用。
-
Ingress 是建立在 Service 之上的,它选择正确的 Service,Service 负责将请求分发到 Pod。两者分工明确,不可相互替代。
通过本篇,你的 Flask 应用已经可以通过域名和路径被外部访问了。但到目前为止,流量都是明文 HTTP------生产环境必须用 HTTPS。下一篇------第 31 篇:Ingress 进阶:TLS、重写与认证,我们将为 Ingress 配置 TLS 证书、实现路径重写和基本认证,让外部访问真正达到生产级安全标准。
想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !