部署多个Ingress Controller实现流量隔离

在单个集群中,除通过组件管理部署的默认Nginx Ingress Controller外,还可通过Helm应用安装多套独立的Controller,以便为不同业务或环境划分专属流量入口、通过独立的公私网SLB分离流量,或为特殊应用提供差异化的Controller配置与版本。与单个Controller管理公网和/或私网流量的模式不同,此方式能够实现彻底的故障与配置隔离。

重要

通过Helm应用安装的Controller与通过组件管理部署的Controller存在以下关键差异:

  • 产品化能力:组件管理Controller提供更多产品化能力,如灰度升级日志与监控集群巡检等。

  • 责任归属:Helm应用Controller需自行维护其生命周期,包括版本升级、配置变更、故障排查等。

工作原理

每个Controller通过唯一的IngressClass名称进行标识。创建Ingress资源时,可通过spec.ingressClassName字段声明由哪个Controller处理。仅与IngressClass名称匹配的Controller才会监听并应用对应的Ingress规则,形成流量隔离。

下图以公、私网隔离场景为例。

image

适用范围

集群版本为 1.22 及以上。

1.20及以下版本集群使用的组件版本已停止维护,详见【产品公告】关于停止维护Nginx Ingress Controller v1.2及以下版本的公告。如需升级集群,请参见手动升级集群

通过Helm应用部署新的Ingress Controller

  1. ACK集群列表页面,单击目标集群名称,在集群详情页左侧导航栏,选择应用 > Helm

  2. 单击创建,按照页面提示完成ack-ingress-nginx-v1的安装。

    关键配置如下,其余保持默认即可。

    配置项

    说明

    应用名

    名称需在集群范围内保持唯一。

    重要

    此名称将作为前缀生成Service资源,Service名为<应用名>-ack-ingress-nginx-v1-controller(私网LoadBalancer类型的Service格式为<应用名>-ack-ingress-nginx-v1-controller-internal)。总长度不可超过63个字符,否则资源会创建失败。

    Chart

    搜索并选择ack-ingress-nginx-v1。

    ack-ingress-nginx已停止维护。

    Chart 版本

    • 1.24及以上版本的集群:支持4.0.22及以上版本。

    • 1.22版本的集群:支持4.0.16及以上至4.0.22以下版本。

    Chart参数

    默认以  Deployment 形式部署一个 2 副本的 Nginx Ingress Controller。该 Controller 会自动创建一个公网 LoadBalancer 类型的Service,并绑定CLB实例作为流量入口。

    可参见ack-ingress-nginx-v1参数说明按需调整默认配置。

    本示例部署一个私网Controller,供后续步骤验证使用。部署时,需配置controller.service.external.enabled需设置为falsecontroller.service.internal.enabledtrue
    重要

    部署多套 Controller 时,需确保集群内controller.ingressClassResource.namecontroller.ingressClassResource.controllerValue的取值唯一,以避免IngressClass名称冲突。

    创建后,可在Helm页面查看新Controller信息。在基本信息区域,记录其命名空间等信息,在资源区域,记录其IngressClass名称、Service名称等信息,供后续验证使用。

验证流量隔离

下文模拟一个公私网分离场景来验证流量隔离:

  • 默认Controller:集群中已存在通过组件管理页面部署的Nginx ingress Controller,并绑定了公网负载均衡实例,负责暴露公网访问入口。

    如未配置,请参见创建并使用Nginx Ingress对外暴露服务
  • Controller:按前文创建的新Controller,绑定私网负载均衡实例,仅在VPC内提供服务。

下文部署一个示例应用,让其 Ingress 规则仅由新 Controller处理,以检验隔离是否生效。

1. 部署测试应用

  1. 创建nginx.yaml

    以下示例部署了一个Nginx应用及其Service。
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          run: nginx
      template:
        metadata:
          labels:
            run: nginx
        spec:
          containers:
          - image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
            imagePullPolicy: Always
            name: nginx
            ports:
            - containerPort: 80
              protocol: TCP
          restartPolicy: Always
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        run: nginx
      sessionAffinity: None
      type: NodePort
  2. 部署示例应用。

    kubectl apply -f nginx.yaml

2. 创建Ingress规则绑定新Controller

  1. 创建ingress.yaml

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: nginx
    spec:
      # 修改为此前配置的IngressClass名称(controller.ingressClassResource.name)
      ingressClassName: "<YOUR_INGRESS_CLASS>"
      rules:
      # 下方域名供临时测试用,生产环境中请替换为真实域名
      - host: foo.bar.com
        http:
          paths:
          - path: /
            backend:
              service: 
                name: nginx
                port:
                  number: 80
            pathType: ImplementationSpecific
  2. 创建Ingress规则。

    kubectl apply -f ingress.yaml

3. 测试访问

  1. 获取各ControllerSLB IP地址。

    • 默认公网ControllerSLB IP:

      PUBLIC_IP=$(kubectl get svc -n kube-system nginx-ingress-lb -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
      echo "Public Ingress IP: $PUBLIC_IP"
    • 新建私网ControllerSLB IP:

      # 将<YourNamespace>替换为新Controller的命名空间 (如default)
      # 将<YourChartName>替换为新Controller的应用名,即发布名称
      INTERNAL_IP=$(kubectl get svc -n <YourNamespace> <YourChartName>-ack-ingress-nginx-v1-controller-internal -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
      echo "Internal Ingress IP: $INTERNAL_IP"
  2. 通过私网Controller访问应用(预期成功)。

    登录VPC内终端,执行以下命令,如返回200,表明私网Controller已成功代理流量。

    # 替换为实际私网IP
    curl -o /dev/null -s -w "%{http_code}\n" -H "Host: foo.bar.com" http://$INTERNAL_IP
  3. 通过公网Controller访问应用(预期失败)。

    执行curl命令,如返回404 Not Found,表明公网Controller没有处理该Ingress规则,流量隔离生效。

    # 替换为实际公网IP
    curl -H "Host: foo.bar.com" http://$PUBLIC_IP

应用于生产环境

  • 资源规划:为保障高可用,关注组件Chart中的如下配置:

    • 配置多副本:controller.replicaCount

    • 设置合理的资源请求和限制:controller.resources.requestscontroller.resources.limits

    • 配置Pod反亲和性:在controller.affinity字段下添加podAntiAffinity规则,将Pod调度到不同节点

  • 监控告警:开启Metrics (controller.metrics.enabled: true) 和 ServiceMonitor (controller.metrics.serviceMonitor.enabled: true),将其接入Prometheus监控系统。重点关注请求延迟、错误率(HTTP 4xx/5xx)等指标,并配置告警规则

  • 性能优化:对于高性能、低延迟场景,建议在Service配置中使用NLB

    • 私网Service:controller.service.internal.loadBalancerClass: "alibabacloud.com/nlb"

    • 公网Service:controller.service.loadBalancerClass: "alibabacloud.com/nlb"

  • 版本维护:

附录:组件主要参数说明

参数

描述

controller.image.repository

Nginx Ingress Controller镜像地址。

controller.image.tag

Nginx Ingress Controller镜像版本

controller.ingressClassResource.name

IngressClass资源名称。集群范围内保持唯一,且不能为nginx(集群默认Ingress Controller的监听标识)。

controller.ingressClassResource.controllerValue

设置此Ingress ControllerController Class。集群范围内保持唯一,且不能为k8s.io/ingress-nginx(集群默认Ingress Controller的监听标识)。

controller.replicaCount

Ingress Controller Pod副本数。建议配置为2或以上以实现高可用。

controller.service.enabled

是否为Controller创建LoadBalancer类型(公网或私网)的Service以暴露服务。

controller.service.external.enabled

true则创建公网SLB Service,暴露公网访问入口。

controller.service.internal.enabled

true则创建私网SLB Service,仅在VPC内提供服务。

controller.kind

Ingress Controller的部署形态:DeploymentDaemonSet

controller.electionID

控制器副本间选主时使用的标识符。仅Leader可更新Ingress资源状态。

当在同一命名空间部署多套Ingress Controller时,此值需保持唯一。

controller.metrics.enabled

true则为Ingress Controller开启Prometheus Metrics监控指标接口。

controller.metrics.serviceMonitor.enabled

true则创建ServiceMonitor资源,以便Prometheus能够自动发现并采集指标。

建议在controller.metrics.enabledtrue时同步开启此项。

controller.service.loadBalancerClass

创建公网Service时使用的负载均衡实例类型。

  • "alibabacloud.com/clb"(默认):使用CLB

  • "alibabacloud.com/nlb":使用NLB

controller.service.internal.loadBalancerClass

创建私网Service时使用的负载均衡实例类型。

  • "alibabacloud.com/clb"(默认):使用CLB

  • "alibabacloud.com/nlb":使用NLB