Qingular

Ingress 与 Gateway API

·CKAk8s练习

CKA Domain 3 — Kubernetes Ingress 控制器配置与 Gateway API 概念

← 返回 CKA 练习目录

概述

Ingress 是 Kubernetes 中管理外部访问集群服务的 API 对象,提供基于 HTTP/HTTPS 的路由规则。Gateway API 是新一代的 API 网关标准,旨在替代 Ingress,提供更强大的路由能力和更清晰的职责分离。


一、Ingress

Ingress 控制器 vs Ingress 资源

  • Ingress 控制器:实际运行的反向代理/负载均衡器(如 nginx-ingress、traefik、HAProxy)
  • Ingress 资源:定义路由规则的 YAML 声明

只有安装了 Ingress 控制器后,Ingress 资源才能生效。

安装 Ingress 控制器

# NGINX Ingress Controller (minikube)
minikube addons enable ingress

# NGINX Ingress Controller (k8s 集群)
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.4/deploy/static/provider/cloud/deploy.yaml

基础 Ingress YAML

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
spec:
  ingressClassName: nginx    # K8s v1.18+,指定 Ingress 控制器
  rules:
    - host: myapp.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-service
                port:
                  number: 80

pathType

类型说明
Prefix基于 URL 前缀匹配(如 /api 匹配 /api/users
Exact精确 URL 匹配
ImplementationSpecific由 Ingress 控制器自定义匹配逻辑
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-type-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: example.com
      http:
        paths:
          # 精确匹配
          - path: /exact-match
            pathType: Exact
            backend:
              service:
                name: exact-svc
                port:
                  number: 80
          # 前缀匹配
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-svc
                port:
                  number: 8080

多主机名路由

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: multi-host-ingress
spec:
  ingressClassName: nginx
  rules:
    - host: app1.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app1-svc
                port:
                  number: 80
    - host: app2.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app2-svc
                port:
                  number: 80

Ingress 注解

注解用于配置 Ingress 控制器的特定行为:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: annotated-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /    # URL 重写
    nginx.ingress.kubernetes.io/ssl-redirect: "true" # SSL 重定向
    nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
    nginx.ingress.kubernetes.io/limit-rps: "10"      # 速率限制
spec:
  ingressClassName: nginx
  rules:
    - host: myapp.example.com
      http:
        paths:
          - path: /old-path
            pathType: Prefix
            backend:
              service:
                name: my-service
                port:
                  number: 80

常用注解列表

注解说明
nginx.ingress.kubernetes.io/rewrite-targetURL 重写目标
nginx.ingress.kubernetes.io/ssl-redirectHTTP 自动跳转 HTTPS
nginx.ingress.kubernetes.io/cors-enabled启用 CORS
nginx.ingress.kubernetes.io/limit-rps每秒请求数限制
nginx.ingress.kubernetes.io/whitelist-source-rangeIP 白名单

TLS/SSL 配置

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-ingress
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - secure.example.com
      secretName: tls-secret   # 使用 kubectl create secret tls 创建
  rules:
    - host: secure.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: secure-svc
                port:
                  number: 443
# 创建 TLS Secret
kubectl create secret tls tls-secret --cert=path/to/tls.crt --key=path/to/tls.key

常用命令

# 创建 Ingress
kubectl create ingress my-ingress --rule="example.com/=my-service:80"

# 查看 Ingress
kubectl get ingress
kubectl get ingress -o wide
kubectl describe ingress my-ingress

# 编辑 Ingress
kubectl edit ingress my-ingress

二、Gateway API

概述

Gateway API 是 Kubernetes 的一个扩展 API,旨在大幅改进 Ingress 的功能。它引入了一种新的服务网络模型,其关键特性包括:

  • 面向角色的设计:区分基础设施提供商、集群管理员和应用开发者
  • 可移植性:跨不同实现的标准 API
  • 表达能力更强:支持 HTTP 头匹配、权重路由、流量分割等

核心资源

GatewayClass  →  集群范围的网关类定义
    ↓
Gateway       →  网关实例(类似 Ingress 控制器实例)
    ↓
HTTPRoute     →  路由规则(类似 Ingress 规则)

Gateway 示例

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: example-gateway-class
spec:
  controllerName: example.io/gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
spec:
  gatewayClassName: example-gateway-class
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: All
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-http-route
spec:
  parentRefs:
    - name: my-gateway
  hostnames:
    - example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: api-svc
          port: 8080
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: web-svc
          port: 80

Gateway API 特性

# 流量分割(Traffic Splitting / Canary)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: traffic-split
spec:
  parentRefs:
    - name: my-gateway
  rules:
    - backendRefs:
        - name: stable-svc
          port: 80
          weight: 90
        - name: canary-svc
          port: 80
          weight: 10

Ingress vs Gateway API 对比

特性IngressGateway API
标准规范Kubernetes 核心 API扩展 API (CRD)
角色分离单一资源GatewayClass / Gateway / Route 三层
协议支持HTTP/HTTPSHTTP、HTTPS、TCP、UDP、TLS
流量分割依赖注解原生支持(权重路由)
头匹配依赖注解原生支持
跨命名空间默认不支持原生支持
成熟度GA(稳定)Beta(v1.0+)


🧪 完整操作实例:配置基于路径的 Ingress 路由

场景描述

创建两个 Deployment(app1 和 app2),通过 Ingress 按路径前缀(/app1 和 /app2)将流量路由到不同的后端 Service。

前置条件

  • 集群已安装 NGINX Ingress Controller(或 minikube 已启用 ingress addon)
  • kubectl 已配置好集群访问
  • 测试机器上可修改 /etc/hosts 或使用 curl --resolve

操作步骤

Step 1: 创建 app1 Deployment 及其 Service

# 创建 app1 Deployment(模拟前端应用)
kubectl create deployment app1 --image=nginx:1.25 --replicas=2
# 预期输出:deployment.apps/app1 created

# 自定义 app1 的首页内容,便于区分
kubectl exec deployment/app1 -- sh -c 'echo "<h1>App 1</h1>" > /usr/share/nginx/html/index.html'
# 预期输出:无报错

# 暴露 app1 为 ClusterIP Service
kubectl expose deployment app1 --name=app1-svc --port=80 --target-port=80
# 预期输出:service/app1-svc exposed

Step 2: 创建 app2 Deployment 及其 Service

# 创建 app2 Deployment(模拟后端 API 服务)
kubectl create deployment app2 --image=nginx:1.25 --replicas=1
# 预期输出:deployment.apps/app2 created

# 自定义 app2 的首页内容
kubectl exec deployment/app2 -- sh -c 'echo "<h1>App 2</h1>" > /usr/share/nginx/html/index.html'
# 预期输出:无报错

# 暴露 app2 为 ClusterIP Service
kubectl expose deployment app2 --name=app2-svc --port=80 --target-port=80
# 预期输出:service/app2-svc exposed

# 确认 Service 已创建
kubectl get svc app1-svc app2-svc
# NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
# app1-svc    ClusterIP   10.96.100.1     <none>        80/TCP    1m
# app2-svc    ClusterIP   10.96.100.2     <none>        80/TCP    1m

Step 3: 创建 Ingress 资源

cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-based-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: myapp.example.com
      http:
        paths:
          - path: /app1
            pathType: Prefix
            backend:
              service:
                name: app1-svc
                port:
                  number: 80
          - path: /app2
            pathType: Prefix
            backend:
              service:
                name: app2-svc
                port:
                  number: 80
EOF
# 预期输出:ingress.networking.k8s.io/path-based-ingress created

kubectl get ingress path-based-ingress
# NAME                CLASS   HOSTS              ADDRESS        PORTS   AGE
# path-based-ingress  nginx   myapp.example.com  localhost      80      10s

Step 4: 配置本地域名解析

# 获取 Ingress 控制器暴露的 IP
# 如果是 minikube:
minikube ip
# 假设输出:192.168.49.2

# 如果是 kind 或其他集群,获取 Ingress 控制器 Pod 所在节点 IP:
kubectl get pods -n ingress-nginx -o wide

# 添加 hosts 记录(Linux/macOS 需要 sudo):
# echo "192.168.49.2  myapp.example.com" | sudo tee -a /etc/hosts

# 对于 minikube,也可以使用 minikube tunnel(另开终端):
# minikube tunnel

# 或者使用 curl --resolve 避免修改 hosts
INGRESS_IP=$(kubectl get ingress path-based-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "Ingress IP: $INGRESS_IP"
# 如果 IP 为空,minikube 可能需要 minikube tunnel

Step 5: 验证路径路由

# 使用 curl 测试 /app1 路径
curl -H "Host: myapp.example.com" http://localhost/app1
# 或如果已有 Ingress IP:
curl --resolve myapp.example.com:80:$INGRESS_IP http://myapp.example.com/app1
# 预期输出:<h1>App 1</h1>(rewrite-target 将 /app1 重写为 /)

# 测试 /app2 路径
curl --resolve myapp.example.com:80:$INGRESS_IP http://myapp.example.com/app2
# 预期输出:<h1>App 2</h1>

# 测试根路径(应返回 404 因为未定义根路径路由)
curl --resolve myapp.example.com:80:$INGRESS_IP http://myapp.example.com/
# 预期输出:nginx 404 Not Found

Step 6: 对比 Gateway API 格式(附加)

# 查看 Gateway API 等效配置(需安装 Gateway API CRD)
cat <<EOF
# Gateway API 等效的 HTTPRoute 配置:
# apiVersion: gateway.networking.k8s.io/v1
# kind: HTTPRoute
# metadata:
#   name: app-routes
# spec:
#   parentRefs:
#     - name: my-gateway
#   hostnames:
#     - "myapp.example.com"
#   rules:
#     - matches:
#         - path:
#             type: PathPrefix
#             value: /app1
#       backendRefs:
#         - name: app1-svc
#           port: 80
#     - matches:
#         - path:
#             type: PathPrefix
#             value: /app2
#       backendRefs:
#         - name: app2-svc
#           port: 80
EOF

验证结果

# 查看 Ingress 详情
kubectl describe ingress path-based-ingress
# Rules:
# Host              Path  Backends
# ----              ----  --------
# myapp.example.com
#                   /app1   app1-svc:80 (10.244.1.5:80,10.244.2.7:80)
#                   /app2   app2-svc:80 (10.244.3.9:80)

# 查看 Ingress 控制器日志(确认请求路由)
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller --tail=50 | grep -i "myapp.example.com"

# 清理资源
kubectl delete ingress path-based-ingress
kubectl delete deployment app1 app2
kubectl delete svc app1-svc app2-svc

考试提示