ingress-nginx在TKE上部署的最佳实践
Nginx Ingress 有多种部署方式,本文将介绍 Nginx Ingress 在 TKE 上的一些部署方案,这几种方案的原理、各自优缺点以及一些选型和使用上的建议。
Nginx Ingress 简介
Nginx Ingress 是 Kubernetes Ingress 的一种实现。它通过 watch Kubernetes 集群的 Ingress 资源,将 Ingress 规则转换成 Nginx 的配置,让 Nginx 进行7层的流量转发。如下图所示:
Nginx Ingress 有以下两种实现方式,本文重点对 Kubernetes 开源社区的实现进行介绍:
部署方案选型建议
对 Nginx Ingress 在 TKE 上部署的三种方案进行比较,本文向您提出以下选型建议:
Deployment + LB
:较为简单通用,但在大规模和高并发场景存在性能问题。如果对性能要求低,可以考虑使用此方案。Daemonset + HostNetwork + LB
:使用 hostNetwork 性能好,但需要手动维护 CLB 和 Nginx Ingress 节点,也无法实现自动扩缩容,不太建议用此方案。Deployment + LB 直通 Pod
:性能好,而且不需要手动维护 CLB,是理想解决方案。但在此方案中需要集群支持 VPC-CNI,如果已有集群本身用的 VPC-CNI 网络插件,或者用的 Global Router 网络插件并开启了 VPC-CNI 的支持(两种模式混用),建议使用此方案。
方案1: Deployment + LB
在 TKE 上部署 Nginx Ingress 最简单的方式是将 Nginx Ingress Controller 以 Deployment 的方式部署,并且为其创建 LoadBalancer 类型的 Service(自动创建负载均衡 CLB 或绑定已有 CLB),使 CLB 接收外部流量,再转发到 Nginx Ingress 内部。如下图所示:
当前 TKE 上 LoadBalancer 类型的 Service 默认实现是基于 NodePort,CLB 会绑定各节点的 NodePort 作为后端 rs,将流量转发到节点的 NodePort,然后节点上再通过 Iptables 或 IPVS 将请求路由到 Service 对应的后端 Pod,这里的 Pod 就是 Nginx Ingress Controller 的 Pod。后续如果有节点的增删,CLB 也会自动更新节点 NodePort 的绑定。
这是最简单的一种方式,可以直接通过下面命令安装:
kubectl create ns nginx-ingress
kubectl apply -f https://raw.githubusercontent.com/TencentCloudContainerTeam/manifest/master/nginx-ingress/nginx-ingress-deployment.yaml -n nginx-ingress
方案2:Daemonset + HostNetwork + LB
在方案1中,流量会经过一层 NodePort,会多一层转发。因此存在以下问题:
转发路径较长,流量到 NodePort 后会再经过 Kubernetes 内部 LB,通过 Iptables 或 IPVS 转发到 Nginx,会增加网络耗时。
经过 NodePort 必然发生 SNAT,如果流量过于集中则容易导致源端口耗尽或 conntrack 插入冲突导致丢包,引发部分流量异常。
每个节点的 NodePort 也充当一个负载均衡器,CLB 如果绑定大量节点的 NodePort,LB 的状态就分散在每个节点上,容易导致全局负载不均。
CLB 会对 NodePort 进行健康探测,探测包最终会被转发到 Nginx Ingress 的 Pod,如果 CLB 绑定的节点多,而 Nginx Ingress 的 Pod 少,会导致探测包对 Nginx Ingress 造成较大的压力。
在方案2中,提出以下解决方法: 让 Nginx Ingress 使用 hostNetwork,CLB 直接绑节点 IP + 端口(80,443),不用经过 NodePort。由于使用 hostNetwork,Nginx Ingress 的 pod 就不能被调度到同一节点,为避免端口监听冲突,可提前选取部分节点作为边缘节点,专门用于部署 Nginx Ingress,并为这些节点打上 label,然后 Nginx Ingress 以 DaemonSet 方式部署在这些节点上。架构如下图所示:
如需安装 Nginx Ingress,请执行以下步骤:
执行以下命令,将规划好的用于部署 Nginx Ingress 的节点打上 label(注意替换节点名称):
kubectl label node 10.0.0.3 nginx-ingress=true
执行以下命令,将 Nginx Ingress 部署在这些节点上:
kubectl create ns nginx-ingress
kubectl apply -f https://raw.githubusercontent.com/TencentCloudContainerTeam/manifest/master/nginx-ingress/nginx-ingress-daemonset-hostnetwork.yaml -n nginx-ingress
手动创建 CLB,及创建80和443端口的 TCP 监听器,分别绑定已部署 Nginx Ingress 节点的80和443端口。
方案3:Deployment + LB 直通 Pod
方案2相比方案1更有优势,但仍存在以下问题:
提高了手动维护 CLB 和 Nginx Ingress 节点的运维成本。
需要提前规划好 Nginx Ingress 的节点,增删 Nginx Ingress 节点时需要手动在 CLB 控制台绑定和解绑节点。
无法支持自动扩、缩容。
在方案3中,提出以下解决方法:
若网络模式是 VPC-CNI,且所有的 Pod 都使用弹性网卡,您可以使用 CLB 直接绑定弹性网卡的 Pod,即绕过 NodePort,不用手动管理 CLB且支持自动扩、缩容。如下图所示:
如果你的网络模式是 Global Router(大多集群都是这种模式),你可以为集群开启 VPC-CNI 的支持,即两种网络模式混用,在集群信息页可打开:
确保集群支持 VPC-CNI 之后,可以使用下面命令安装 Nginx Ingress:
kubectl create ns nginx-ingress
kubectl apply -f https://raw.githubusercontent.com/TencentCloudContainerTeam/manifest/master/nginx-ingress/nginx-ingress-deployment-eni.yaml -n nginx-ingress
常见问题
如何支持内网 Ingress ?
方案2:Daemonset + HostNetwork + LB
是手动管理 CLB,在自行创建 CLB 时可以选择用公网或内网。方案1:Deployment + LB
和 方案3:Deployment + LB 直通 Pod
默认创建公网 CLB。 如果要用内网,可以重新部署 YAML,给 nginx-ingress-controller 中的 Service 添加 key,例如 service.kubernetes.io/qcloud-loadbalancer-internal-subnetid
,value 为内网 CLB 创建的子网 id 的 annotation。请参考以下代码:
apiVersion: v1
kind: Service
metadata:
annotations:
service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-xxxxxx # value 替换为集群所在 vpc 的其中一个子网 id
labels:
app: nginx-ingress
component: controller
name: nginx-ingress-controller
如何复用已有 LB ?
方案1和方案3默认自动创建新的 CLB,Ingress 的流量入口地址取决于新创建 CLB 的 IP 地址。如果业务对入口地址有依赖,可以让 Nginx Ingress 绑定已有的 CLB。 操作方法为重新部署 YAML,给 nginx-ingress-controller 中的 Service 添加 key,例如 service.kubernetes.io/tke-existed-lbid
,value 为 CLB ID 的 annotation。请参考以下代码:
apiVersion: v1
kind: Service
metadata:
annotations:
service.kubernetes.io/tke-existed-lbid: lb-6swtxxxx # value 替换为 CLB 的 ID
labels:
app: nginx-ingress
component: controller
name: nginx-ingress-controller
Nginx Ingress 公网带宽有多大?
腾讯云账号有标准账户和传统账户两种类型:
注意:您可参考文档 区分腾讯云账户类型 来区分自己账号的类型。
标准账户类型: 指带宽上移到 CLB 或 IP 上管理。 当您的账号是标准账户类型时,Nginx Ingress 的带宽等于已购 CLB 的带宽,默认是 10Mbps(按量计费),可按需调整。
传统账户类型: 指带宽在云服务器(CVM)上管理。 当您的账号是传统账户类型时,Nginx Ingress 使用公网 CLB,Nginx Ingress 的公网带宽是 CLB 所绑定的 TKE 节点的带宽之和。如果使用
方案3:Deployment + LB 直通 Pod
,CLB 直通 Pod,即 CLB 直接绑定弹性网卡,那么此时 Nginx Ingress 的公网带宽是所有 Nginx Ingress Controller Pod 被调度到的节点上的带宽之和。
最后
以上部署的Ingress Nginx的Yaml文件都是腾讯云提供的,你也可以参考之前的文章通过Helm部署官方的chart,通过修改一定的配置,文章名:《ingress-nginx的安装使用》
参考资料
在 TKE 上部署 Nginx Ingress: https://cloud.tencent.com/document/product/457/47293
TKE Service 使用已有 CLB:https://cloud.tencent.com/document/product/457/45491
区分腾讯云账户类型:https://cloud.tencent.com/document/product/684/39903