在Kubernetes集群中,Ingress对集群服务(Service)中外部可访问的API对象进行管理,提供七层负载均衡能力。Nginx Ingress Controller负责实现Ingress的功能,根据规则配置负载均衡并提供访问入口。在高负载场景下,CPU资源和网络连接数的不足会影响应用的性能。本文介绍如何通过部署Nginx Ingress Controller来支撑高负载应用。
前提条件
已确保ACK集群中的Nginx Ingress Controller组件运行正常。
已通过kubectl连接集群。具体操作,请参见通过kubectl连接Kubernetes集群。
部署说明
部署高负载场景下的Nginx Ingress Controller需要考虑以下三个方面。
硬件选型
在高并发场景下,Ingress对CPU资源和网络连接数占用都非常高,建议您选择增强型ECS实例,例如:
计算型实例:ecs.c6e.8xlarge(32 Core 64 GB,600万PPS)
网络型实例:ecs.g6e.8xlarge(32 Core 128 GB,600万PPS)
关于ECS实例规格的更多信息,请参见实例规格族。
K8s配置
设置Ingress Pod独占节点资源,添加污点和节点标签:
kubectl label nodes $node_name ingress-pod="yes" kubectl taint nodes $node_name ingress-pod="yes":NoExecute
设置CPU Policy为
static
。推荐调整ingress-controller service对应的SLB规格为超强型(slb.s3.large)。
推荐集群使用Terway网络插件及配置独占ENI。
Ingress配置
设置Ingress Pod为Guaranteed类型。
设置nginx-ingress-controller container的资源限制
requests
和limits
:30Core 40GiB。设置initContainer init-sysctl的资源限制
requests
和limits
:100m 70MiB。
调整Deployment Replicas数为新增节点数。
设置ConfigMap的
worker-processes
数为28(预留部分给系统使用)。调整ConfigMap的
keepalive
链接最大请求数。关闭日志访问记录。
步骤一:添加节点
选择指定集群,创建新的节点池并添加2台节点。
创建节点池需要配置的主要参数如下所示。具体操作,请参见创建节点池。
选择操作系统为Alibaba Cloud Linux3。
配置节点标签和污点(Taints)。
设置污点(Taints)为
ingress-pod
,值为yes
,Effect为NoExecute。设置节点标签为
ingress-pod
值为yes
。
选择CPU Policy为Static。
步骤二:配置Nginx Ingress Controller
执行kubectl edit deploy nginx-ingress-controller -n kube-system
命令打开Ingress Controller的配置文件,根据以下内容更新Ingress Controller的配置:
删除Pod反亲和性配置。
podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - ingress-nginx topologyKey: kubernetes.io/hostname
配置InitContainer的
requests
和limits
。resources: limits: cpu: 100m memory: 70Mi requests: cpu: 100m memory: 70Mi
修改nginx-ingress-controller container的
requests
和limits
都为30Core 40GiB。resources: limits: cpu: "30" memory: 40Gi requests: cpu: "30" memory: 40Gi
设置节点亲和性和容忍性。
nodeSelector: ingress-pod: "yes" tolerations: - effect: NoExecute key: ingress-pod operator: Equal value: "yes"
调整Replicas数为新增节点数。
关闭Metrics采集,修改启动参数,添加
--enable-metrics=false
。说明如果不需要获取Metrics信息,建议关闭Metrics采集。对于v1.9.3以上版本的Nginx Ingress Controller,您还可以通过配置启动参数
--exclude-socket-metrics
来排除相关的指标, 例如nginx_ingress_controller_ingress_upstream_latency_seconds
。这样做可以帮助减轻对系统性能的影响。containers: - args: - /nginx-ingress-controller - --configmap=$(POD_NAMESPACE)/nginx-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - --annotations-prefix=nginx.ingress.kubernetes.io - --publish-service=$(POD_NAMESPACE)/nginx-ingress-lb - --enable-metrics=false - --v=1
步骤三:配置Nginx Ingress ConfigMap
使用
kubectl edit cm -n kube-system nginx-configuration
更新ConfigMap,可参考以下代码示例:apiVersion: v1 kind: ConfigMap metadata: name: nginx-configuration namespace: kube-system data: allow-backend-server-header: "true" enable-underscores-in-headers: "true" generate-request-id: "true" ignore-invalid-headers: "true" log-format-upstream: $remote_addr - [$remote_addr] - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id $host [$proxy_alternative_upstream_name] max-worker-connections: "65536" proxy-body-size: 20m proxy-connect-timeout: "3" proxy-read-timeout: "5" proxy-send-timeout: "5" reuse-port: "true" server-tokens: "false" ssl-redirect: "false" upstream-keepalive-timeout: "900" worker-processes: "28" # 设置启动的Nginx进程数,请根据您的node节点规格进行实际调整,建议调整为cpu核数-2。 worker-cpu-affinity: auto upstream-keepalive-connections: "300" upstream-keepalive-requests: "1000" # 设置单个长连接最多可以发送多个。 keep-alive: "900" keep-alive-requests: "10000"
采用文件方式记录访问日志并对日志轮转。
默认的日志访问记录输出到/dev/stdout,在高并发场景下,会占用大量CPU,故采用文件方式记录访问日志并对日志设置轮转。
以SSH方式登录部署ingress-controller Pod的ECS节点上。具体操作,请参见通过密钥认证登录Linux实例。
在/etc/crontab文件结尾添加以下内容:
*/15 * * * * root /root/nginx-log-rotate.sh
说明此处以每隔15分钟对日志轮转一次为例,可根据实际需求进行调整。
在/root目录下添加文件nginx-log-rotate.sh。
Docker集群
#!/bin/bash # 最多保留日志文件个数,可根据需求进行调整。 keep_log_num=5 ingress_nginx_container_ids=$(docker ps | grep nginx-ingress-controller | grep -v pause | awk '{print $1}') if [[ -z "$ingress_nginx_container_ids" ]]; then echo "error: failed to get ingress nginx container ids" exit 1 fi # 随机睡眠5~10秒。 sleep $(( RANDOM % (10 - 5 + 1 ) + 5 )) for id in $ingress_nginx_container_ids; do docker exec $id bash -c "cd /var/log/nginx; if [[ \$(ls access.log-* | wc -l) -gt $keep_log_num ]]; then rm -f \$(ls -t access.log-* | tail -1); fi ; mv access.log access.log-\$(date +%F:%T) ; kill -USR1 \$(cat /tmp/nginx/nginx.pid)" done
containerd集群
#!/bin/bash # 最多保留日志文件个数,可根据需求进行调整。 keep_log_num=5 ingress_nginx_container_ids=$(crictl ps | grep nginx-ingress-controller | grep -v pause | awk '{print $1}') if [[ -z "$ingress_nginx_container_ids" ]]; then echo "error: failed to get ingress nginx container ids" exit 1 fi # 随机睡眠5~10秒。 sleep $(( RANDOM % (10 - 5 + 1 ) + 5 )) for id in $ingress_nginx_container_ids; do crictl exec $id bash -c "cd /var/log/nginx; if [[ \$(ls access.log-* | wc -l) -gt $keep_log_num ]]; then rm -f \$(ls -t access.log-* | tail -1); fi ; mv access.log access.log-\$(date +%F:%T) ; kill -USR1 \$(cat /tmp/nginx/nginx.pid)" done
执行以下命令,对nginx-log-rotate.sh文件添加可执行权限。
chmod 755 /root/nginx-log-rotate.sh