在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