K8s Ingress核心实战指南

K8s Ingress核心实战指南

Ingress 是 Kubernetes 中用于管理集群外部访问集群内部服务的 API 对象,它提供了基于 HTTP 和 HTTPS 的七层路由能力。本文将详细介绍如何在基于 kubeadm搭建的裸金属(Bare-metal)集群中部署和使用 Ingress。

核心概念​

Ingress 由两大核心组件构成:

Ingress 资源 (Resource):一个 Kubernetes API 对象,用于定义路由规则。它本身不具备流量转发能力,仅是一份规则声明。例如,声明将域名 webapp.example.com 的 /api 路径流量转发至 api-service。

Ingress 控制器 (Controller):一个实际运行在集群中的程序(通常为 Pod),它持续监听 Ingress 资源的变化,并根据这些规则来配置一个真正的代理服务器(如 NGINX、Traefik),从而执行流量的转发。

因此,标准操作流程是:先部署 Ingress Controller,再创建 Ingress 资源来定义路由规则。

第一步:安装 Ingress Controller​

本文以社区最活跃的 NGINX Ingress Controller 为例。

1. 应用安装清单​

官方提供了针对裸金属环境的部署清单,它会通过 NodePort 的方式暴露 Ingress Controller 服务。

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.1/deploy/static/provider/baremetal/deploy.yaml

注意:v1.10.1 是编写此笔记时的较新版本。建议在部署前访问 官方 GitHub Release 页面 以获取最新或特定版本的 deploy.yaml 文件。

2. 验证安装​

该命令会在 ingress-nginx 命名空间中创建所需资源。通过以下命令检查 Controller Pod 是否正常运行:

kubectl get pods -n ingress-nginx

预期会看到名为 ingress-nginx-controller-xxxxx 的 Pod 处于 Running 状态。

3. 查看暴露端口​

检查 Ingress Controller 的 Service 以获取其对外暴露的 NodePort。

kubectl get svc -n ingress-nginx

输出结果类似如下:

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEingress-nginx-controller NodePort 10.106.51.189 80:32080/TCP,443:32443/TCP 5m

这表明,集群中任何一个 Node 节点的 IP 加上端口 32080 (HTTP) 或 32443 (HTTPS) 即可访问到 Ingress Controller。

第二步:创建并暴露一个简单服务​

在配置路由规则前,我们先部署一个示例应用。

1. 准备示例应用与服务​

创建一个 demo-app.yaml 文件,内容如下:

apiVersion: apps/v1kind: Deploymentmetadata: name: my-webappspec: replicas: 2 selector: matchLabels: app: webapp template: metadata: labels: app: webapp spec: containers: - name: webapp image: nginx:1.19-alpine # 使用 Nginx 镜像作为示例 ports: - containerPort: 80---apiVersion: v1kind: Servicemetadata: name: my-webapp-svcspec: selector: app: webapp ports: - protocol: TCP port: 80 # Service 端口 targetPort: 80 # Pod 端口

部署该应用:

kubectl apply -f demo-app.yaml

2. 创建 Ingress 规则​

创建 my-ingress.yaml 文件,定义将特定域名和路径的流量转发到上述服务。

apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: my-webapp-ingressspec: # 指定该 Ingress 由哪个 Controller 处理,名称需与 Controller Class 匹配 ingressClassName: nginx rules: - host: "webapp.example.com" # 定义用于访问的域名 http: paths: - path: "/" # 匹配根路径 pathType: Prefix # 路径匹配类型,Prefix 表示前缀匹配 backend: service: name: my-webapp-svc # 目标 Service 名称 port: number: 80 # 目标 Service 端口

应用该规则:

kubectl apply -f my-ingress.yaml

3. 测试访问​

为了使域名 webapp.example.com 指向我们的集群,需要在访问端配置 DNS 解析或修改本地 hosts 文件。

修改 hosts 文件 (推荐用于测试)

在本地机器的 hosts 文件(如 Linux/macOS 的 /etc/hosts)中添加一条记录:

webapp.example.com

替换为集群中任意节点的 IP 地址。

发起访问(带 NodePort)

使用 curl 命令或浏览器访问,注意 URL 中需包含第一步获取的 NodePort:

# 假设 HTTP 的 NodePort 是 32080curl http://webapp.example.com:32080

如果一切正常,您将看到 Nginx 的欢迎页面,证明 Ingress 已成功将流量转发至 my-webapp-svc。

解惑:NodePort 与路径路由的关系​

一个常见疑问是:既然 Ingress 能够基于域名和路径进行七层路由,为什么访问时还需要带上 NodePort 端口?

答案在于流量的两个阶段:

从集群外部 到 Ingress Controller:Ingress Controller 本身是运行在集群内的 Pod。在没有云厂商负载均衡器(LoadBalancer)的裸金属环境中,我们需要通过 NodePort 方式将 Controller 服务暴露给外部,以便流量能进入集群。这个 NodePort(如 32080)是 Ingress Controller 的入口端口,而非最终应用的端口。

从 Ingress Controller 到 最终服务:一旦流量通过 NodeIP:NodePort 到达 Ingress Controller,Controller 的智能路由功能便开始工作。它会解析请求的 Host 头(webapp.example.com)和路径(/),匹配已创建的 Ingress 规则,然后在集群内部将流量转发到目标 Service(my-webapp-svc)的 80 端口。

可以把这个过程类比为进入一栋办公楼:

K8s 概念办公楼类比Node IP办公楼的街道地址NodePort (e.g., :32080)办公楼的特定入口(如员工通道)门牌号Ingress Controller站在入口处的智能前台Ingress 规则前台手里的访客登记表Host/Path您告知前台:“我要找 Example 公司,访问他们的 / 部门”Service & Port前台查表后,指引您去 8 楼的 WebApp 办公室

生产环境架构​

在生产环境中,为隐藏 NodePort 并使用标准的 80/443 端口,通常会在 Kubernetes 集群前部署一个外部负载均衡器(如 HAProxy、F5 或云厂商的 LB)。

外部 LB 配置:监听 80/443 端口,并将流量转发至后端所有 K8s 节点的 NodePort(如 192.168.1.101:32080, 192.168.1.102:32080...)。

最终流量路径为:用户 → 外部 LB (80/443) → K8s 节点:NodePort → Ingress Controller → 目标服务。

进阶:配置多路径路由​

Ingress 的核心优势之一是能够基于同一域名,根据不同路径将流量分发到不同服务。

场景示例​

假设我们有两个服务:

frontend-svc: 提供 Web UI,通过根路径 / 访问。

backend-api-svc: 提供数据 API,通过 /api 前缀访问。

Ingress YAML 配置​

可以修改 Ingress 资源,在 paths 数组中定义多条规则:

apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: multi-path-ingressspec: ingressClassName: nginx rules: - host: "webapp.example.com" http: paths: # 规则一:将根路径及其子路径转发到前端服务 - path: / pathType: Prefix backend: service: name: frontend-svc # 指向前端服务 port: number: 80 # 规则二:将 /api/ 开头的路径转发到后端 API 服务 - path: /api pathType: Prefix backend: service: name: backend-api-svc # 指向后端 API 服务 port: number: 8080 # 假设 API 服务端口为 8080

关键点​

paths 数组:允许在同一个 host 下定义多个路径规则。

匹配优先级:Ingress Controller 通常优先匹配最长、最精确的路径。因此,对 webapp.example.com/api/users 的请求会由 path: /api 规则处理,而不是 path: /。

pathType:

Prefix (前缀匹配): path 的值被视为前缀,如 path: /api 会匹配 /api, /api/ 和 /api/v1/users 等。

Exact (精确匹配): URL 路径必须与 path 的值完全相同。

路由结果​

用户访问的 URLIngress 匹配的路径最终转发到的服务http://webapp.example.com//frontend-svchttp://webapp.example.com/about.html/frontend-svchttp://webapp.example.com/api/v1/login/apibackend-api-svchttp://webapp.example.com/api/status/apibackend-api-svc

通过这种方式,仅需暴露 Ingress Controller 的单一入口,即可灵活管理集群内所有需要对外暴露的 HTTP 服务。