第30篇 k8s之Ingress 基础:域名路由与 Ingress Controller

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.comwww.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 思维 !

相关推荐
Lumbrologist10 小时前
【零基础部署】Docker 部署 CrewAI 多 Agent 编排框架保姆级教程
运维·docker·容器
Dongwoo Jeong14 小时前
微服务架构(MSA)是如何诞生的?
微服务·云原生·架构
半旧夜夏14 小时前
【保姆级】微服务组件环境搭建(Docker Compose版)
java·linux·spring cloud·微服务·云原生·容器
阿里云云原生15 小时前
实战解析:如何用自然语言驱动混沌工程?Blade AI Agent 实现故障演练全链路自动化
云原生
张忠琳15 小时前
【kubernetes v1.21】(kubelet 1)Kubelet 核心架构与启动流程
云原生·架构·kubernetes·kubelet
宇明一不急17 小时前
k8s HPA storageclass configmap
云原生·容器·kubernetes
ZzzZZzzzZZZzzzz…19 小时前
Docker + K8s集群搭建实战:1 Master+2 Node,含Harbor私有仓库与软路由
docker·云原生·容器·kubernetes·容器编排·集群部署·cri-dockerd
xier_ran20 小时前
【infra之路】模块三:Kubernetes (下) — 阶段一毕业项目:在集群里跑 PyTorch 训练
pytorch·容器·kubernetes
Waay20 小时前
K8s新手实操|emptyDir卷超详细实战(附完整命令+核心理解)
云原生·容器·kubernetes