Ingress

一、作用

Ingress 是管理从集群外部访问集群内部服务的 HTTP 和 HTTPS 路由规则的 API 对象

你可以把它想象成集群的智能路由网关入口管理员。在 Ingress 出现之前,我们通常使用 LoadBalancer 或 NodePort 类型的 Service 来暴露服务,但这两种方式都有其局限性,而 Ingress 就是为了解决这些问题而生的。

Ingress 的核心作用:

1、提供外部可访问的 URL
  • 为内部服务提供一个统一的外部访问地址,如 https://api.example.com

2、基于域名或路径的路由
  • 基于主机名(域名):将 user-service.example.com 的流量路由到用户服务,将 order-service.example.com 的流量路由到订单服务。
  • 基于路径:将 example.com/user 的流量路由到用户服务,将 example.com/order 的流量路由到订单服务。
3、负载均衡
  • 在多个 Pod 副本之间分配流量。

4、终止 SSL/TLS
  • 在 Ingress 层面处理 HTTPS 加密和解密,减轻后端服务的负担。你只需要在 Ingress 上配置证书,后端服务仍然可以使用 HTTP。

5、虚拟主机托管

  • 在单个 IP 地址上通过不同的域名提供多个服务。

与 LoadBalancer 和 NodePort 的对比

特性NodePortLoadBalancerIngress
工作原理在每个节点上开放一个端口云厂商创建外部负载均衡器一个 Ingress Controller 根据 Ingress 规则路由 HTTP/HTTPS 流量
暴露层级L4 (传输层)L4 (传输层)L7 (应用层)
路由能力无,流量直接转发到 Service无,流量直接转发到 Service有,基于域名和路径
SSL 终止需要在 Pod 内处理需要在 Pod 内处理可在 Ingress 层面统一处理
成本高(云负载均衡器通常收费)低(自建)或 中等(使用云厂商的 Ingress Controller)
适用场景测试、开发、简单应用需要直接 TCP/UDP 负载均衡的生产环境暴露 HTTP/HTTPS 服务的标准生产环境方案

二、Ingress 的核心组件

要理解 Ingress,必须区分两个概念:

Ingress Controller(控制器)

  • 是什么:一个具体的、正在运行的 Pod,它负责读取和处理 Ingress 规则,并充当反向代理和负载均衡器(类似于 Nginx、Traefik、HAProxy)。
  • 作用:它是实际干活的组件。你必须先部署一个 Ingress Controller,Ingress 资源才能生效。
  • 常见实现

Ingress Resource(资源)

  • 是什么:一个 Kubernetes API 资源对象(一个 YAML 文件),它定义了具体的路由规则。
  • 作用:它告诉 Ingress Controller 应该如何路由流量。你通过 kubectl apply -f ingress.yaml 来创建它。

关系:你部署 Controller,然后创建 Resource 规则。Controller 会持续监听这些 Resource 的变化,并动态更新自己的配置。

三、案例演示

我们以最流行的 Nginx Ingress Controller 为例,演示一个完整的场景。

场景描述

我们有两个后端服务:

  • user-service:处理用户信息,我们希望通过 my-app.com/user 来访问。
  • order-service:处理订单信息,我们希望通过 my-app.com/order 来访问。

同时,我们希望通过 HTTPS 访问。

步骤 1:部署 Ingress Controller

首先,你需要安装 Ingress Controller。这里我们使用官方的 Nginx Ingress Controller。

# 使用官方 Manifest 部署(适用于实验环境)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml

注意:在生产环境中,请参考官方文档进行更详细的配置。

部署成功后,你可以查看 Ingress Controller 的 Pod 和 Service(通常是 LoadBalancer 类型):

kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

步骤 2:部署后端服务

创建两个简单的 Deployments 和 Services。

user-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: nginx:alpine # 用一个简单镜像模拟
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

order-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
      - name: order-service
        image: nginx:alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

应用它们:

kubectl apply -f user-service.yaml
kubectl apply -f order-service.yaml

步骤 3:创建 Ingress 资源规则

现在,创建最重要的 Ingress 资源,定义路由规则。

ingress-rule.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    # 注解非常重要,用于指定特定控制器的行为
    kubernetes.io/ingress.class: "nginx" # 指定使用 nginx ingress controller
    nginx.ingress.kubernetes.io/rewrite-target: / # 重要:重写路径,后面会解释
spec:
  tls: # TLS 配置部分,用于 HTTPS
  - hosts:
      - my-app.com
    secretName: my-app-tls-secret # 指向一个包含 TLS 证书的 Secret
  rules:
  - host: my-app.com # 配置的域名
    http:
      paths:
      - path: /user
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 80
      - path: /order
        pathType: Prefix
        backend:
          service:
            name: order-service
            port:
              number: 80

应用这个 Ingress 规则:

kubectl apply -f ingress-rule.yaml
关于路径重写 (rewrite-target)

这是一个非常关键的注解。在我们的例子中:

  • 用户访问 my-app.com/user/profile
  • Ingress Controller 收到请求后,需要将流量发送到 user-service 服务。
  • 但是,user-service 服务本身可能监听在 /profile 路径上。
  • 如果不做重写,Ingress 会把 /user/profile 这个完整的路径传递给后端服务,而后端服务可能没有 /user/profile 这个路由。
  • nginx.ingress.kubernetes.io/rewrite-target: / 的作用是:将匹配到的路径(如 /user)去掉,然后将剩余的路径(如 /profile)传递给后端服务。
  • 所以,后端服务收到的请求路径就是 /profile

步骤 4:测试

由于我们通常没有真实的域名和证书,可以通过修改本地 hosts 文件(C:\Windows\System32\drivers\etc\hosts 或 /etc/hosts)来进行测试。

1、获取 Ingress Controller 的外部 IP
kubectl get svc -n ingress-nginx

找到 ingress-nginx-controller 服务,并复制其 EXTERNAL-IP。如果是 localhost 或 minikube ip,则使用那个地址。假设 IP 是 192.168.49.2

2、修改 hosts 文件,添加一行
192.168.49.2 my-app.com
# 当用户或应用程序尝试访问my-app.com时,系统会直接将其解析为192.168.49.2,而不是去查询DNS服务器。

3、进行访问
  • 访问 http://my-app.com/user (会看到 Nginx 默认页面,这证明请求被成功路由到了 user-service 的 Pod)。

  • 访问 http://my-app.com/order (请求被成功路由到了 order-service)。

步骤 5:配置 HTTPS

要配置 HTTPS,你需要一个 TLS 证书。在测试环境中,可以创建一个自签名的证书。

1、生成自签名证书和私钥
# 生成证书和私钥
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \    
  -keyout tls.key \
  -out tls.crt \
  -subj "/CN=my-app.com/O=my-app"

# 验证证书内容
openssl x509 -in tls.crt -text -noout

# 验证私钥
openssl rsa -in tls.key -check

2、在 Kubernetes 中创建 TLS Secret
kubectl create secret tls my-app-tls-secret \
  --key tls.key \
  --cert tls.crt

这个 Secret 的名字 my-app-tls-secret 必须与 Ingress YAML 中 tls.secretName 字段一致。

3、再次测试

现在你可以通过 https://my-app.com/user 来访问你的服务了。(浏览器会提示不安全,因为证书是自签名的,但连接已经是加密的)。

总结

Ingress 是 Kubernetes 中暴露 HTTP/HTTPS 服务的事实标准。它通过分离 Controller(实现) 和 Resource(规则),提供了一个灵活、强大且成本效益高的集群入口管理方案。核心优势在于其七层路由能力集中的 SSL/TLS 管理

使用Secret管理HTTPS证书

openssl req -x509 -nodes-days 365 \
-newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=test.com"
kubectl -n default create secret tls nginx-test-tls --key=tls.key --cert=tls.crt
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-https-test
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:
  - host: https-test.com
    http:
      paths:
      - backend:
          serviceName: nginx-svc
          servicePort: 80
  tls:
  - secretName: nginx-test-tls

更多推荐