Provision dedicated nodes, configure autoscaling, and tune NGINX parameters to sustain peak traffic.
-
Because the open-source Ingress NGINX project will no longer be maintained after March 2026, Container Service for Kubernetes will discontinue maintenance for the NGINX Ingress controller component. Be aware of the associated risks. See Product announcement: Discontinuation of maintenance for the NGINX Ingress controller component.
-
The following configurations are for reference only. Choose parameters and specifications based on your actual NGINX Ingress controller load.
Ensure sufficient component resources
Deploy on a dedicated node pool
A dedicated node pool isolates the NGINX Ingress controller from other workloads, preventing resource contention.
Setting resources.limits for NGINX Ingress controller pods may trigger OOM errors from memory restrictions or cause service interruptions and jitter from CPU throttling. Do not configure resource limits. If you must, set CPU to at least 1 core and memory to at least 2 GiB.
Create a dedicated node pool
Create a dedicated node pool for the NGINX Ingress controller pods. Note the following:
-
Select an instance type: Pod network performance is limited by the host node's instance type. For example, if a node's PPS is 300,000, the maximum PPS per pod is also 300,000. Choose a network-optimized instance with 32+ CPU cores.
-
Number of nodes: The NGINX Ingress controller deploys two pods with anti-affinity by default, so the node pool requires at least two nodes.
-
Configure taints and labels: Add taints and labels to prevent other pods from being scheduled to these nodes. For example, add
system-addon: nginx-ingressas both a taint and label, with Effect set toNoSchedule. -
Select a pod size: Due to NGINX base overhead, one high-spec pod (for example, 32 cores) outperforms multiple low-spec pods (for example, two 16-core pods) with the same total resources. Prefer fewer high-spec pods while maintaining high availability.
Configure the component
Log on to the ACK console. On the Add-ons page, find the NGINX Ingress controller card and click Configuration.
-
In NodeSelector, add the label of the dedicated node pool.
Do not delete the existing NodeSelector labels.
-
In Tolerations, add the taint of the dedicated node pool and set Effect to NoSchedule.
-
Click Confirm, then verify that pods are scheduled to the dedicated node pool.
Adjust the CLB instance specification
The CLB instance specification determines the maximum connections and QPS for the NGINX Ingress controller. Use a high-specification instance.
Edit the Service to specify the CLB instance specification with the service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec annotation:
kubectl edit service -n kube-system nginx-ingress-lb
apiVersion: v1
kind: Service
metadata:
annotations:
...
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-spec: "slb.s3.large" # Specify the CLB instance specification
name: nginx-ingress-lb
namespace: kube-system
...
spec:
...
Only pay-by-specification CLB instances created before June 2025 support this operation. See Performance specifications.
Use HPA for autoscaling
If dedicated node pool pods cannot absorb traffic bursts, configure HPA to autoscale the NGINX Ingress controller.
Scaling in pods may disrupt some active connections. Configure your scale-in policy with caution.
Save the following as nginx-hpa.yaml and apply with kubectl apply -f nginx-hpa.yaml:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-ingress-controller-hpa
namespace: kube-system
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-ingress-controller
minReplicas: 2
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
Ensure graceful shutdown for backend workloads
During rolling updates, the NGINX Ingress controller maintains in-flight connections to terminating pods. If a pod exits immediately, these requests fail.
A preStop hook keeps the pod running after SIGTERM, allowing in-flight requests to complete:
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
lifecycle:
# Configure a preStop hook to wait for 30 seconds before exiting.
# The sleep command must exist in the container.
preStop:
exec:
command:
- sleep
- 30
...
Set thepreStopwait time to 1.5–2× your maximum response time. Ensuresleepis available in the container image.
Monitor component status with metrics and logs
SLS logs
-
In the ACK console, go to the NGINX Ingress Overview tab on the page. Here, you can view the log dashboard to check client access data. You can also go to and select nginx-ingress to view specific log entries.
-
If the log dashboard shows null data points, or the nginx-ingress logs in Logstore are empty, logging was not enabled during cluster creation. See Collect and analyze NGINX Ingress access logs.
Prometheus monitoring
Log on to the ACK console, and navigate to to view the monitoring dashboard.
-
If a component is not installed, follow the prompts to install it and check the dashboard.
-
Select the Ingresses tab. In the Controller Class dropdown, select k8s.io/ingress-nginx to view NGINX Ingress metrics. If k8s.io/ingress-nginx is not listed, the NGINX Ingress controller is not installed.
Add ahostfield to your Ingress resources. Resources withouthostare not scraped for metrics by default. To skip per-host monitoring, add--metrics-per-host=falseto thecontrollerargs in the NGINX Ingress Deployment.
Optimize NGINX configuration
Configure automatic log rotation
NGINX Ingress controller pods log to both /dev/stdout and /var/log/nginx/. As log files grow, writing new entries consumes more resources. Automatic rotation mitigates this by periodically archiving and clearing logs.
-
Log on to the node running the NGINX Ingress controller pod.
-
Create
nginx-log-rotate.shin/root.Containerd node
#!/bin/bash # The maximum number of log files to keep. Adjust as needed. keep_log_num=5 # Get the IDs of all running ingress-nginx containers. 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 # Sleep for a random interval between 5 and 10 seconds. 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)" doneDocker node
#!/bin/bash # The maximum number of log files to keep. Adjust as needed. keep_log_num=5 # Get the IDs of all running ingress-nginx containers. 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 # Sleep for a random interval between 5 and 10 seconds. 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 -
Make
nginx-log-rotate.shexecutable.chmod 755 /root/nginx-log-rotate.sh -
Add the following to
/etc/crontab:This rotates logs every 15 minutes. Adjust the schedule as needed.
*/15 * * * * root /root/nginx-log-rotate.sh
Disable metrics collection
Metrics collection is enabled by default and consumes CPU. Disable it if you do not need metrics.
Edit the controller Deployment (kubectl edit deploy nginx-ingress-controller -n kube-system). Add --enable-metrics=false to the container args to disable metrics.
v1.9.3 or earlier
spec:
containers:
- args:
- ...
- --enable-metrics=false
Versions later than v1.9.3
NGINX Ingress controller versions later than v1.9.3 allow disabling specific metrics. For example, add --exclude-socket-metrics to stop collecting socket-related metrics. See cli-arguments.
spec:
containers:
- args:
- ...
- --enable-metrics=true
- --exclude-socket-metrics # Effective only when --enable-metrics=true
Enable Brotli compression
The Brotli algorithm typically achieves 15%–30% better compression than gzip for text-based web resources.
Actual improvement depends on your scenario.
Edit the NGINX Ingress ConfigMap (kubectl edit cm -n kube-system nginx-configuration) to enable Brotli compression.
data:
enable-brotli: "true"
brotli-level: "6"
brotli-types: "text/xml image/svg+xml application/x-font-ttf image/vnd.microsoft.icon application/x-font-opentype application/json font/eot application/vnd.ms-fontobject application/javascript font/otf application/xml application/xhtml+xml text/javascript application/x-javascript text/plain application/x-font-truetype application/xml+rss image/x-icon font/opentype text/css image/x-win-bitmap"
-
enable-brotli: Specifies whether to enable Brotli. Valid values:true,false. -
brotli-level: Compression level. Valid values: 1–11. Default: 4. Higher values consume more CPU. -
brotli-types: MIME types to compress with Brotli.
Adjust the timeout policy
Reducing FIN_WAIT2 and TIME_WAIT timeouts allows the NGINX Ingress controller to recycle finished connections faster, freeing resources.
FIN_WAIT2 and TIME_WAIT parameters directly affect NGINX Ingress controller connection recycling. Improper settings can cause connection pool exhaustion, port depletion, or congestion under high concurrency. Ensure you understand TCP connection principles before adjusting. After modification, continuously monitor connection status and resource usage.
Edit the NGINX Ingress controller Deployment (kubectl edit deploy nginx-ingress-controller -n kube-system).
Add the following to initContainers:
-
net.ipv4.tcp_fin_timeout: FIN_WAIT2 timeout. Default: 60 seconds. -
net.netfilter.nf_conntrack_tcp_timeout_time_wait: TIME_WAIT timeout. Default: 60 seconds.
dnsPolicy: ...
initContainers:
- command:
- /bin/sh
- -c
- |
if [ "$POD_IP" != "$HOST_IP" ]; then
mount -o remount rw /proc/sys
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
sysctl -w kernel.core_uses_pid=0
sysctl -w net.ipv4.tcp_fin_timeout=15 # Set the timeout for the FIN_WAIT2 state to 15 seconds
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30 # Set the timeout for the TIME_WAIT state to 30 seconds
fi
env:
...
image: ...
imagePullPolicy: IfNotPresent
name: init-sysctl
Optimize HTTPS performance
Adjust the following parameters in the nginx-configuration ConfigMap.
kubectl edit cm -n kube-system nginx-configuration
-
SSL session cache and timeout
Setting the SSL session cache size and timeout reduces handshake overhead.
data: ssl-session-cache-size: "10m" ssl-session-timeout: "10m" -
Enable OCSP stapling to reduce certificate verification time.
data: enable-ocsp: "true" -
Enable TLS 1.3 0-RTT to let clients send data before the handshake completes, reducing connection setup latency.
data: ssl-early-data: "true" ssl-protocols: "TLSv1.3" -
Adjust cipher priority (no manual tuning required)
Cipher suite priority affects latency. The NGINX Ingress controller default is already optimized.
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers on; # Prioritize the server's cipher configuration.
Configure other performance-related options
The following nginx-configuration ConfigMap options also affect performance. Run kubectl edit cm -n kube-system nginx-configuration to edit.
|
Category |
Parameter |
Description |
|
downstream |
|
The maximum time a downstream |
|
|
The maximum number of downstream |
|
|
upstream |
|
The maximum number of upstream |
|
|
The maximum upstream |
|
|
|
The maximum time an upstream |
|
|
|
The idle timeout for upstream |
|
|
Maximum connections per worker |
|
The maximum connections a single worker can handle. |
|
Timeout settings Adjust based on your use case. |
|
The timeout for establishing a TCP connection. |
|
|
The timeout for reading data. |
|
|
|
The timeout for sending data. |
|
|
Retry mechanism Excessive retries can increase backend load and cause cascading failures when services are unstable. See the Ingress-nginx official documentation. |
|
Retries after failure. Default: 3 (one initial attempt + two retries). |
|
|
Retry conditions. Set to |
|
|
|
Timeout for request retries. Adjust based on your scenario. |
References
The CNI plugin affects cluster network performance, which impacts the NGINX Ingress controller. We recommend using the Terway network plugin.