Contents hide

概述

什么是 Ingress?

Ingress 是 Kubernetes 中用于管理外部访问集群内服务的 API 对象。它提供了 HTTP 和 HTTPS 路由、负载均衡、SSL/TLS 终止等功能。

核心概念

  • Ingress Controller:实际处理流量的组件,负责实现 Ingress 规范
  • Ingress 资源:定义路由规则的 Kubernetes 资源对象
  • IngressClass:用于指定使用哪个 Ingress Controller

为什么需要 Ingress?

  • 统一入口管理:避免为每个 Service 使用 NodePort 或 LoadBalancer
  • 成本优化:一个 LoadBalancer 可以服务多个应用
  • 灵活路由:基于域名、路径的路由规则
  • SSL/TLS 管理:集中管理证书

架构设计原则

1. 集中式 Controller + 分布式 Ingress 资源

核心思想

  • 集群级部署一个或多个 Ingress Controller(高可用)
  • 各业务命名空间独立管理自己的 Ingress 资源
  • Controller 统一处理所有命名空间的 Ingress

2. IngressClass 作用域

集群作用域(Cluster-scoped)

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx

特点

  • 集群内所有命名空间可用
  • 适合共享的 Ingress Controller
  • 生产环境推荐使用

命名空间作用域(Namespace-scoped)

特点

  • 仅在该命名空间内可用
  • 适合多租户或特殊隔离场景
  • 一般不建议使用

Ingress Controller 选型

主流 Controller 对比

Controller维护者特点适用场景
Ingress-NGINXKubernetes 社区最流行,基于 Nginx,功能丰富通用场景,推荐
TraefikTraefik Labs配置简单,自动证书微服务架构
Istio GatewayIstio 社区服务网格集成服务网格环境
KongKong Inc.API 网关功能API 管理场景

推荐:Ingress-NGINX

优势

  • Kubernetes 官方维护,社区活跃
  • 功能完善,文档齐全
  • 性能优秀,生产验证
  • 支持丰富的注解(annotations)

企业级架构方案

标准架构图

┌─────────────────────────────────────────────────────────┐
外部流量入口
│              (LoadBalancer / NodePort)                   │
└──────────────────────┬──────────────────────────────────┘

┌──────────────────────▼──────────────────────────────────┐
Ingress Controller (集群级)                      │
│  ┌──────────────────────────────────────────────────┐  │
│  │  Namespace: ingress-nginx                        │  │
│  │  - Deployment: ingress-nginx-controller (3副本)   │  │
│  │  - Service: LoadBalancer                         │  │
│  │  - IngressClass: nginx (集群作用域)              │  │
│  └──────────────────────────────────────────────────┘  │
└──────────────────────┬──────────────────────────────────┘
监听所有命名空间
        ┌──────────────┼──────────────┐
        │              │              │
┌───────▼──────┐ ┌─────▼──────┐ ┌─────▼──────┐
a-api       │ │  b-api     │ │  c-api
namespace   │ │  namespace │ │  namespace
│              │ │            │ │            │
Ingress     │ │  Ingress   │ │  Ingress
Service     │ │  Service   │ │  Service
Deployment  │ │  Deployment│ │  Deployment
└──────────────┘ └────────────┘ └────────────┘

高可用部署

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  replicas: 3  <em># 多副本高可用</em>
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  template:
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app.kubernetes.io/name
                  operator: In
                  values:
                  - ingress-nginx
              topologyKey: kubernetes.io/hostname

多 Controller 场景(可选)

如果需要内外网隔离:

- ingress-nginx-internal (内网IngressClass: nginx-internal)
- ingress-nginx-external (外网IngressClass: nginx-external)

Ingress-NGINX 工作原理

1. 核心架构组件

┌─────────────────────────────────────────┐
Ingress Controller Pod
│  ┌───────────────────────────────────┐  │
│  │  Ingress Controller (Go程序)       │  │
│  │  - 监听 Kubernetes API Server      │  │
│  │  - 生成 Nginx 配置                 │  │
│  │  - 管理 Nginx 进程                 │  │
│  └───────────────────────────────────┘  │
│  ┌───────────────────────────────────┐  │
│  │  Nginx (C程序)                     │  │
│  │  - 实际处理 HTTP/HTTPS 流量        │  │
│  │  - 读取生成的配置文件              │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘

2. 工作流程

阶段 1:Controller 启动和初始化

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  template:
    spec:
      containers:
      - name: controller
        args:
        - /nginx-ingress-controller
        - --watch-ingress-without-class=true  <em># 监听所有 Ingress</em>
        - --ingress-class=nginx               <em># 只处理指定 class  Ingress</em>
        - --configmap=ingress-nginx-controller  <em># 全局配置</em>

启动步骤

  1. 连接 Kubernetes API Server
  2. 创建必要的 RBAC 权限(ClusterRole/ClusterRoleBinding)
  3. 初始化 Informer 监听机制

阶段 2:监听机制(Informer Pattern)

Controller 使用 Kubernetes 的 Informer 机制实现事件驱动监听:

关键特性

  • 集群级权限:通过 ClusterRole 读取所有命名空间的资源
  • 事件驱动:资源变化时立即触发,无需轮询
  • 本地缓存:减少 API Server 压力

监听资源类型

  • Ingress 资源(所有命名空间)
  • Service 资源(相关命名空间)
  • Endpoints 资源(相关命名空间)
  • Secret 资源(TLS 证书)

阶段 3:Ingress 资源发现和过滤

当在任何命名空间创建 Ingress 时:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: a-api-ingress
  namespace: a-api
spec:
  ingressClassName: nginx  <em># 关键指定使用 nginx IngressClass</em>
  rules:
  - host: a-api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: a-api-service
            port:
              number: 80

Controller 处理逻辑

  1. IngressClass 匹配检查
    • 检查 spec.ingressClassName 是否匹配
    • 如果不匹配,忽略该 Ingress
  2. 资源验证
    • 验证 Ingress 规则的有效性
    • 检查引用的 Service 是否存在
  3. 规则解析
    • 解析 host、path 规则
    • 获取后端 Service 信息
  4. 缓存更新
    • 更新内部 Ingress 缓存
    • 触发配置重新生成

阶段 4:Nginx 配置生成

Controller 将 Ingress 规则转换为 Nginx 配置:

生成的配置示例

<em># /etc/nginx/nginx.conf</em>

<em># 从 a-api 命名空间</em>
upstream upstream_balancer_a {
    least_conn;
    server 10.244.1.5:8080 max_fails=0 fail_timeout=0;
    server 10.244.1.6:8080 max_fails=0 fail_timeout=0;
}

server {
    listen 80;
    server_name a-api.example.com;
    
    location / {
        proxy_pass http://upstream_balancer_a;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

<em># 从 b-api 命名空间</em>
upstream upstream_balancer_b {
    least_conn;
    server 10.244.2.3:8080 max_fails=0 fail_timeout=0;
}

server {
    listen 80;
    server_name b-api.example.com;
    
    location / {
        proxy_pass http://upstream_balancer_b;
    }
}

配置生成过程

  1. 遍历所有匹配的 Ingress 资源
  2. 解析每个 Ingress 的规则(host、path)
  3. 获取对应的 Service 和 Endpoints
  4. 生成 upstream 配置(负载均衡)
  5. 生成 server 块(路由规则)
  6. 写入配置文件
  7. 验证配置语法
  8. 重载 Nginx(nginx -s reload

阶段 5:Service 和 Endpoints 发现

Controller 同时监听 Service 和 Endpoints 变化:

Endpoints 更新流程

  1. Pod 启动/停止 → Endpoints 变化
  2. Controller 监听到变化
  3. 更新对应的 upstream 配置
  4. 重载 Nginx

关键点

  • Endpoints 变化时自动更新负载均衡配置
  • 无需手动干预,实现自动服务发现

3. 跨命名空间访问原理

RBAC 配置

<em># ClusterRole - 集群级权限</em>
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ingress-nginx
rules:
- apiGroups: [""]
  resources: ["services", "endpoints", "secrets", "nodes", "pods"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses/status"]
  verbs: ["update"]
- apiGroups: ["networking.k8s.io"]
  resources: ["ingressclasses"]
  verbs: ["get", "list", "watch"]
---
<em># ClusterRoleBinding - 绑定到所有命名空间</em>
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: ingress-nginx
subjects:
- kind: ServiceAccount
  name: ingress-nginx
  namespace: ingress-nginx

权限说明

  • ClusterRole 提供集群级权限,可访问所有命名空间
  • ClusterRoleBinding 将权限绑定到 Controller 的 ServiceAccount
  • Controller 因此可以读取所有命名空间的 Ingress、Service、Endpoints

4. IngressClass 匹配机制

IngressClass 定义

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx

匹配逻辑

Controller 启动时指定要处理的 IngressClass:

--ingress-class=nginx

匹配规则

  1. Ingress 明确指定 ingressClassName: nginx → 匹配
  2. Ingress 未指定,但 nginx 是默认 IngressClass → 匹配
  3. 其他情况 → 不匹配,忽略

5. 完整数据流

用户创建 Ingress (a-api 命名空间)

Kubernetes API Server

Ingress Controller Informer 监听到事件

Controller 验证 IngressClass 匹配

Controller 读取对应的 Service (a-api 命名空间)

Controller 读取 Service  Endpoints

Controller 生成 Nginx 配置包含 upstream

Controller 写入 /etc/nginx/nginx.conf

Controller 执行 nginx -s reload

Nginx 开始处理流量

流量NginxServicePod

实施步骤

步骤 1:部署 Ingress Controller

使用 Helm 部署(推荐)

<em># 添加 Helm 仓库</em>
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

<em># 安装 Ingress Controller</em>
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace \
  --set controller.replicaCount=3 \
  --set controller.service.type=LoadBalancer

使用官方 YAML 部署

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

验证部署

<em># 检查 Controller 状态</em>
kubectl get pods -n ingress-nginx

<em># 检查 IngressClass</em>
kubectl get ingressclass

<em># 检查 Service</em>
kubectl get svc -n ingress-nginx

步骤 2:创建 IngressClass(如未自动创建)

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: nginx
spec:
  controller: k8s.io/ingress-nginx

步骤 3:在各命名空间创建 Ingress 资源

a-api 命名空间示例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: a-api-ingress
  namespace: a-api
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - a-api.example.com
    secretName: a-api-tls
  rules:
  - host: a-api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: a-api-service
            port:
              number: 80

b-api 命名空间示例

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

步骤 4:配置 TLS 证书(可选)

<em># 创建 TLS Secret</em>
apiVersion: v1
kind: Secret
metadata:
  name: a-api-tls
  namespace: a-api
type: kubernetes.io/tls
data:
  tls.crt: <base64-encoded-cert>
  tls.key: <base64-encoded-key>

步骤 5:验证配置

<em># 检查 Ingress 状态</em>
kubectl get ingress -A

<em># 查看 Ingress 详情</em>
kubectl describe ingress a-api-ingress -n a-api

<em># 测试访问</em>
curl -H "Host: a-api.example.com" http://<ingress-ip>/

最佳实践

✅ 推荐做法

1. 单一 Ingress Controller

  • 一个集群部署一个 Ingress Controller(多副本高可用)
  • 所有命名空间共享同一个 Controller
  • 节省资源,便于管理

2. IngressClass 集群作用域

  • 使用集群作用域的 IngressClass
  • 所有命名空间可以引用
  • 统一管理,避免混乱

3. 命名空间隔离

  • 每个业务命名空间管理自己的 Ingress 资源
  • 通过 RBAC 限制权限
  • 实现职责分离

4. 域名规划

方案 A:子域名

a-api.example.com
b-api.example.com
c-api.example.com

方案 B:路径路由

example.com/a-api
example.com/b-api
example.com/c-api

5. RBAC 控制

<em># 限制命名空间只能管理自己的 Ingress</em>
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ingress-manager
  namespace: a-api
rules:
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ingress-manager
  namespace: a-api
subjects:
- kind: ServiceAccount
  name: app-deployer
  namespace: a-api
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ingress-manager

6. 监控告警

  • 监控 Ingress Controller 的 Pod 状态
  • 监控 Nginx 错误日志
  • 监控 Ingress 资源状态
  • 设置告警规则

7. 资源限制

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-nginx-controller
spec:
  template:
    spec:
      containers:
      - name: controller
        resources:
          requests:
            cpu: 100m
            memory: 90Mi
          limits:
            cpu: 1000m
            memory: 512Mi

8. 配置优化

<em># ConfigMap 配置</em>
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
data:
  <em># 工作进程数</em>
  worker-processes: "4"
  <em># 最大连接数</em>
  max-worker-connections: "16384"
  <em># 启用 gzip</em>
  enable-gzip: "true"
  <em># 日志格式</em>
  log-format-upstream: |
    $remote_addr - $remote_user [$time_local] "$request" 
    $status $body_bytes_sent "$http_referer" 
    "$http_user_agent" $request_length $request_time 
    [$proxy_upstream_name] [$proxy_alternative_upstream_name] 
    $upstream_addr $upstream_response_length 
    $upstream_response_time $upstream_status 
    $req_id

❌ 不推荐做法

  1. 每个命名空间部署独立的 Controller
    • 资源浪费
    • 管理复杂
    • 成本增加
  2. 使用命名空间作用域的 IngressClass
    • 除非有特殊隔离需求
    • 一般场景不推荐
  3. 在 Ingress 中硬编码 IP
    • 使用 Service 名称
    • 利用服务发现
  4. 忽略 TLS 配置
    • 生产环境必须启用 HTTPS
    • 使用 Let’s Encrypt 自动证书

常见问题与解决方案

Q1: Controller 无法发现其他命名空间的 Ingress?

原因

  • RBAC 权限不足
  • IngressClass 不匹配

解决方案

<em># 检查 RBAC</em>
kubectl get clusterrole ingress-nginx -o yaml
kubectl get clusterrolebinding ingress-nginx -o yaml

<em># 检查 IngressClass</em>
kubectl get ingressclass
kubectl describe ingress <ingress-name> -n <namespace>

Q2: 如何实现蓝绿部署?

使用 Ingress 注解:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"  <em># 10% 流量</em>
spec:
  ingressClassName: nginx
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service-v2  <em># 新版本</em>
            port:
              number: 80

Q3: 如何配置限流?

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/limit-rps: "100"
    nginx.ingress.kubernetes.io/limit-connections: "10"
spec:
  ingressClassName: nginx
  <em># ...</em>

Q4: 如何实现跨命名空间服务访问?

Ingress 可以引用其他命名空间的 Service(需要特殊配置):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cross-ns-ingress
  namespace: a-api
  annotations:
    nginx.ingress.kubernetes.io/upstream-vhost: "b-api-service.b-api.svc.cluster.local"
spec:
  ingressClassName: nginx
  rules:
  - host: a-api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: b-api-service
            namespace: b-api  <em># 跨命名空间</em>
            port:
              number: 80

注意:需要 Controller 有跨命名空间访问权限。

Q5: 如何查看 Nginx 配置?

<em># 进入 Controller Pod</em>
kubectl exec -it -n ingress-nginx <controller-pod> -- /bin/sh

<em># 查看生成的配置</em>
cat /etc/nginx/nginx.conf

<em># 查看特定 upstream</em>
grep -A 10 "upstream_balancer" /etc/nginx/nginx.conf

GitOps 集成

目录结构

ic2-deploy-config/
├── ingress-controller/          # Ingress Controller 配置
│   ├── base/
│   │   ├── ingressclass.yaml
│   │   ├── deployment.yaml
│   │   └── kustomization.yaml
│   └── overlays/
│       ├── production/
│       └── staging/
├── apps/
│   ├── backend/
│   │   ├── a-api/
│   │   │   ├── base/
│   │   │   │   └── ingress.yaml  # 业务 Ingress
│   │   │   └── overlays/
│   │   └── b-api/
│   └── ...
└── argocd-bootstrap/
    └── ingress-controller/
        └── application.yaml

ArgoCD Application 示例

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: ingress-controller
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/ic2-deploy-config
    targetRevision: main
    path: ingress-controller/overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: ingress-nginx
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true

业务 Ingress 管理

每个业务应用在自己的目录下管理 Ingress:

<em># apps/backend/a-api/base/ingress.yaml</em>
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: a-api-ingress
  namespace: a-api
spec:
  ingressClassName: nginx
  rules:
  - host: a-api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: a-api-service
            port:
              number: 80

环境差异化配置

<em># apps/backend/a-api/overlays/production/ingress-patch.yaml</em>
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: a-api-ingress
  namespace: a-api
spec:
  rules:
  - host: a-api.prod.example.com  <em># 生产环境域名</em>
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: a-api-service
            port:
              number: 80

总结

核心要点

  1. 一个集群级 Ingress Controller 处理所有命名空间的 Ingress
    • 通过 ClusterRole 获得集群级权限
    • 使用 Informer 监听所有命名空间
    • IngressClass 过滤匹配的 Ingress
  2. IngressClass 使用集群作用域
    • 所有命名空间共享
    • 统一管理,避免混乱
  3. 各命名空间独立管理 Ingress 资源
    • 职责分离
    • 通过 RBAC 控制权限
  4. GitOps 实践
    • Controller 配置放在基础设施仓库
    • 业务 Ingress 随应用代码管理
    • 使用 ArgoCD/Flux 自动化部署

架构优势

  • ✅ 资源高效:一个 Controller 服务所有应用
  • ✅ 管理简单:统一入口,集中管理
  • ✅ 成本优化:减少 LoadBalancer 数量
  • ✅ 灵活扩展:支持多 Controller 场景
  • ✅ 生产就绪:高可用、监控、告警

参考资源