Skip to content

EN_Linux_Kernel

somaz edited this page Jul 13, 2026 · 3 revisions

Linux Kernel Management & Parameter Tuning (Q7-Q8)

Q8: Linux Kernel Parameter Tuning

Question: Explain the kernel parameters (sysctl) commonly used in Linux, and present the key settings for network performance optimization and improved system stability.

Answer:

1. sysctl Basic Usage

# Check all kernel parameters
sysctl -a

# Check a specific parameter
sysctl net.ipv4.ip_forward
sysctl vm.swappiness

# Change a parameter (temporary)
sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -w vm.swappiness=10

# Change a parameter (permanent)
sudo vi /etc/sysctl.conf
sudo sysctl -p  # apply

2. Network Performance Optimization

# /etc/sysctl.conf or /etc/sysctl.d/99-network.conf

# ===== TCP/IP stack optimization =====

# net.core.rmem_max: maximum size of the TCP receive buffer
# - Default: 212992 (about 208KB)
# - Recommended: 134217728 (128MB) - 10Gbps high-speed network environment
# - Description: maximum size of the kernel buffer that stores packets received from the network card
# - Effect: improved throughput for large file transfers and streaming services
# - Caution: possibility of OOM under low memory, must consider system RAM
net.core.rmem_max = 134217728

# net.core.wmem_max: maximum size of the TCP send buffer
# - Default: 212992 (about 208KB)
# - Recommended: 134217728 (128MB)
# - Description: temporarily stores data sent by the application before transmitting it to the network card
# - Effect: improved send performance in high-bandwidth environments
# - Use cases: CDN servers, video streaming, large file servers
net.core.wmem_max = 134217728

# net.core.rmem_default / wmem_default: default buffer size when a socket is created
# - Description: used when the application does not explicitly specify a buffer size
# - Recommended: 16MB (suitable for typical web traffic)
net.core.rmem_default = 16777216
net.core.wmem_default = 16777216

# net.ipv4.tcp_rmem / tcp_wmem: per-socket TCP buffer auto-tuning (min, default, max)
# - Format: min default max
# - tcp_rmem = 4096 87380 134217728
#   * 4096 (4KB): minimum buffer - guaranteed even under low memory
#   * 87380 (85KB): default buffer - used for typical connections
#   * 134217728 (128MB): maximum buffer - auto-expands on high-speed networks
# - Description: the kernel dynamically adjusts buffer size according to network conditions
# - Effect: Bandwidth-Delay Product (BDP) optimization
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728

# ===== Connection queue management =====

# net.core.somaxconn: maximum value for the backlog parameter of the listen() system call
# - Default: 128 (very small!)
# - Recommended: 65535 (high-load web servers)
# - Description: size of the queue of fully connected (ESTABLISHED) sockets waiting before accept()
# - Problem: a small value causes "connection refused" errors
# - Effect: prevents connection loss even during traffic spikes
# - Example: works together with Nginx's listen 80 backlog=65535;
net.core.somaxconn = 65535

# net.core.netdev_max_backlog: size of the network device input queue
# - Default: 1000
# - Recommended: 100000 (10Gbps environment)
# - Description: queue where packets forwarded from the NIC to the kernel wait before being processed
# - Problem: a small value causes packet drops (RX dropped increases in ifconfig)
# - Check: netstat -s | grep "dropped"
# - Use cases: DDoS defense, high PPS (Packets Per Second) environments
net.core.netdev_max_backlog = 100000

# net.ipv4.tcp_max_syn_backlog: size of the SYN_RECV state socket queue
# - Default: 128-1024 (varies by distribution)
# - Recommended: 8192
# - Description: queue of half-open sockets that received a SYN but not yet an ACK
# - Problem: a small value is vulnerable to SYN Flood attacks
# - Effect: handles a large number of concurrent connection requests (traffic surge right after a web server boots)
# - Security: use together with tcp_syncookies
net.ipv4.tcp_max_syn_backlog = 8192

# ===== TIME_WAIT socket optimization =====

# net.ipv4.tcp_tw_reuse: reuse TIME_WAIT sockets for new connections
# - Default: 0 (disabled)
# - Recommended: 1 (enable on the client side)
# - Description: immediately reuse TIME_WAIT sockets for outbound connections to external servers
# - Fixes: prevents "Cannot assign requested address" errors
# - Scenario: API Gateway or Reverse Proxy sending many requests to backend servers
# - Caution: no effect on the server side (inbound); may cause problems in NAT environments
# - Check: ss -tan | grep TIME_WAIT | wc -l
net.ipv4.tcp_tw_reuse = 1

# net.ipv4.tcp_fin_timeout: how long to hold the FIN-WAIT-2 state
# - Default: 60 seconds
# - Recommended: 30 seconds
# - Description: the time to wait in the FIN-WAIT-2 state when closing a TCP connection
# - Effect: quickly reclaims resources from abnormally terminated connections
# - Caution: if too short (e.g., 5 seconds), slow-client problems may occur
net.ipv4.tcp_fin_timeout = 30

# ===== TCP Keepalive settings =====

# net.ipv4.tcp_keepalive_time: time before sending a keepalive probe on an idle connection
# - Default: 7200 seconds (2 hours)
# - Recommended: 600 seconds (10 minutes)
# - Description: the time before checking whether the connection is alive after the last data transmission
# - Effect: early detection of zombie connections
# - Use cases: load balancers, database connection pools, keeping SSH sessions alive
net.ipv4.tcp_keepalive_time = 600

# net.ipv4.tcp_keepalive_intvl: retransmission interval for keepalive probes
# - Default: 75 seconds
# - Recommended: 30 seconds
# - Description: the interval at which the next probe is sent when there is no response
net.ipv4.tcp_keepalive_intvl = 30

# net.ipv4.tcp_keepalive_probes: maximum number of keepalive probe retries
# - Default: 9 times
# - Recommended: 3 times
# - Description: number of attempts before dropping the connection when there is no response
# - Calculation: total wait time = keepalive_time + (keepalive_intvl * keepalive_probes)
#        = 600 + (30 * 3) = the connection is closed after 690 seconds (about 11.5 minutes)
net.ipv4.tcp_keepalive_probes = 3

# ===== TCP Fast Open (TFO) =====

# net.ipv4.tcp_fastopen: TCP 3-way handshake optimization
# - Default: 0 (disabled)
# - Recommended: 3 (enable both client and server)
# - Meaning of the value:
#   * 1: enable client only (when connecting to external servers)
#   * 2: enable server only (accepting incoming connections)
#   * 3: client + server (bitwise OR: 1 | 2 = 3)
# - Principle: include data in the SYN packet -> save 1 RTT (Round Trip Time)
# - Effect: reduced connection latency (noticeable improvement in environments with many HTTP requests)
# - Requirement: both client and server must support it (kernel 3.7+)
# - Security: SYN Flood defense via the TFO Cookie
net.ipv4.tcp_fastopen = 3

# ===== IP forwarding =====

# net.ipv4.ip_forward: enable IPv4 packet forwarding
# - Default: 0 (disabled)
# - Recommended: 1 (routers, NAT, Kubernetes nodes)
# - Description: allows packets to be forwarded to other networks
# - Required scenarios:
#   * Kubernetes worker nodes (Pod-to-Pod communication)
#   * Docker bridge networks
#   * VPN gateways
#   * NAT routers
# - Check: cat /proc/sys/net/ipv4/ip_forward
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1

# ===== Local port range =====

# net.ipv4.ip_local_port_range: range of ephemeral ports used for outbound connections
# - Default: 32768 60999 (about 28,000 ports)
# - Recommended: 10000 65535 (about 55,000 ports)
# - Description: source ports automatically assigned when a client connects to an external server
# - Problem: a narrow range causes "Cannot assign requested address" errors
# - Scenario: Reverse Proxy or API Gateway making many connections to backends
# - Calculation: concurrent connections = (port range) / (TIME_WAIT time / connection duration)
# - Example: 1000 requests per second, TIME_WAIT 30 seconds -> at least 30,000 ports needed
# - Check: ss -tan | awk '{print $4}' | grep -oP ':\d+$' | sort | uniq -c
net.ipv4.ip_local_port_range = 10000 65535

3. Security-Related Settings

# ===== SYN Flood attack defense =====

# net.ipv4.tcp_syncookies: enable the SYN Cookie mechanism
# - Default: 1 (enabled by default on most distributions)
# - Recommended: 1 (mandatory)
# - Principle:
#   1. Normal: client SYN -> server SYN-ACK (stored in queue) -> client ACK
#   2. Attack: thousands of SYNs -> queue full -> normal connections refused
#   3. SYN Cookie: encode connection info into the SYN-ACK sequence number -> no queue needed
# - Effect: connections can still be accepted even when tcp_max_syn_backlog is exceeded
# - Downside: some TCP options (Window Scaling, etc.) may be lost
# - Check: netstat -s | grep "SYNs to LISTEN sockets dropped"
net.ipv4.tcp_syncookies = 1

# net.ipv4.tcp_max_syn_backlog: backup queue for SYN Flood defense
# - Use together with tcp_syncookies to strengthen attack defense
net.ipv4.tcp_max_syn_backlog = 8192

# ===== ICMP Redirect attack prevention =====

# net.ipv4.conf.*.accept_redirects: whether to accept ICMP Redirect messages
# - Default: 1 (accept)
# - Recommended: 0 (reject)
# - Attack scenario:
#   1. The attacker sends a forged ICMP Redirect message
#   2. The victim's routing table is altered
#   3. Traffic passes through the attacker -> MitM (Man-in-the-Middle) attack
# - Example: trick the victim into changing the gateway with a "there is a better route" message
# - Mandatory application: production servers, routers
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

# ===== Source Routing attack prevention =====

# net.ipv4.conf.*.accept_source_route: whether to accept Source Routing packets
# - Default: 0 (disabled on most distributions)
# - Recommended: 0 (reject)
# - Attack principle:
#   * Source Routing: the sender specifies the packet's route (normally decided by routers)
#   * an attacker specifies an arbitrary route -> firewall bypass, spoofing
# - Effect: blocks IP spoofing attacks
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# ===== ICMP Echo (Ping) response =====

# net.ipv4.icmp_echo_ignore_all: ignore Ping requests
# - Default: 0 (responds)
# - Recommended: 0 (general servers), 1 (high-security servers)
# - Advantage: evades network scans (Nmap, etc.)
# - Disadvantage: network debugging is harder (traceroute, ping unavailable)
# - Recommendation: it is better to control ICMP at the firewall
net.ipv4.icmp_echo_ignore_all = 0

# net.ipv4.icmp_echo_ignore_broadcasts: ignore broadcast Pings
# - Default: 1 (ignore)
# - Recommended: 1 (mandatory)
# - Attack: Smurf Attack (DDoS amplification via broadcast Ping)
net.ipv4.icmp_echo_ignore_broadcasts = 1

# ===== IP spoofing prevention (Reverse Path Filtering) =====

# net.ipv4.conf.*.rp_filter: reverse path filtering
# - Default: 0 (disabled) or 1
# - Recommended: 1 (Strict Mode)
# - Meaning of the value:
#   * 0: disabled (dangerous!)
#   * 1: Strict Mode - verify the reply packet would also go out through the interface it came in on
#   * 2: Loose Mode - only verify that the reply route exists in the routing table
# - Principle: verify against the routing table whether the packet's source IP is forged
# - Example:
#   * receive a packet on eth0 from 10.0.0.5
#   * check the routing table: is the route to 10.0.0.5 via eth0?
#   * if not -> judged as a spoofed packet and dropped
# - Effect: blocks source-IP forgery in DDoS attacks
# - Caution: use 2 (Loose Mode) in asymmetric routing environments
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# ===== Security logging =====

# net.ipv4.conf.*.log_martians: log abnormal packets
# - Default: 0 (no logging)
# - Recommended: 1 (log)
# - Martian Packets:
#   * reserved IP addresses (0.0.0.0, 127.0.0.0/8, 224.0.0.0/4)
#   * broadcast addresses
#   * multicast addresses
#   * invalid source IPs
# - Log location: /var/log/kern.log or dmesg
# - Example: "martian source 192.168.1.1 from 10.0.0.5"
# - Purpose: network attack detection, configuration error debugging
# - Caution: heavy logging increases disk I/O
net.ipv4.conf.all.log_martians = 1

# ===== SYN/ACK retransmission =====

# net.ipv4.tcp_synack_retries: number of SYN-ACK retransmissions
# - Default: 5 times (about 180 seconds of waiting)
# - Recommended: 2 times (about 7 seconds of waiting)
# - Description: number of SYN-ACK retransmissions when the client does not send an ACK
# - Effect: quickly reclaims resources during a SYN Flood attack
# - Retransmission intervals: 1s, 2s, 4s, 8s, 16s (exponential backoff)
net.ipv4.tcp_synack_retries = 2

# net.ipv4.tcp_syn_retries: number of SYN retransmissions (client side)
# - Default: 6 times (about 127 seconds)
# - Recommended: 3 times (about 7 seconds)
# - Description: number of SYN packet retransmissions when connecting to an external server
net.ipv4.tcp_syn_retries = 3

4. Memory Management

# ===== Swappiness =====

# vm.swappiness: aggressiveness of Swap usage (0-100)
# - Default: 60
# - Recommended:
#   * 0: minimize Swap (database servers, Redis, Elasticsearch)
#   * 10: performance-focused (web servers, application servers)
#   * 60: default (desktops, general servers)
#   * 100: aggressive Swap (low-memory environments)
# - Principle:
#   * higher value -> the kernel more aggressively moves memory to Swap
#   * lower value -> use RAM as much as possible, Swap is a last resort
# - Effect:
#   * 0: increased chance of the OOM Killer triggering but best performance
#   * 10: balance of performance and stability (recommended for production)
#   * 60: possible performance degradation from increased disk I/O
# - Check:
#   * cat /proc/sys/vm/swappiness
#   * free -h (check Swap usage)
#   * vmstat 1 (monitor Swap In/Out via the si/so columns)
# - Caution:
#   * setting it to 0 does not completely disable Swap
#   * fully disable with swapoff -a (recommended for Kubernetes)
vm.swappiness = 10

# ===== Dirty Page management =====

# vm.dirty_ratio: dirty page ratio threshold relative to total memory (%)
# - Default: 20 (20%)
# - Recommended: 15
# - Description:
#   * Dirty Page: page cache that has been modified but not yet written to disk
#   * when the threshold is reached -> processes block and are forced to start writing to disk
# - Problem: if too large (e.g., 40%) -> disk is written all at once -> system response lag
# - Example: 32GB RAM, dirty_ratio=15 -> forced write when 4.8GB of dirty pages accumulate
# - Effect: balance of write performance and system responsiveness
# - Check:
#   * cat /proc/meminfo | grep Dirty
#   * watch -n 1 'cat /proc/meminfo | grep -E "Dirty|Writeback"'
vm.dirty_ratio = 15

# vm.dirty_background_ratio: ratio at which background writing starts (%)
# - Default: 10 (10%)
# - Recommended: 5
# - Description:
#   * when this value is reached -> the pdflush/flush kernel threads start writing to disk in the background
#   * processes are not blocked (they keep running)
# - Principle:
#   1. dirty pages reach 5% -> background writing starts (smoothly)
#   2. dirty pages reach 15% -> forced writing (processes block)
# - Effect: spreads disk I/O out ahead of time to prevent response lag
vm.dirty_background_ratio = 5

# vm.dirty_expire_centisecs: dirty page expiration time (centiseconds, 1/100 second)
# - Default: 3000 (30 seconds)
# - Recommended: 3000
# - Description: dirty pages older than this time are written to disk with priority
# - Effect: prevents data loss (at most 30 seconds of data lost on power failure)
# - Scenario: file write -> power failure within 30 seconds -> data loss
vm.dirty_expire_centisecs = 3000

# vm.dirty_writeback_centisecs: pdflush thread execution interval (centiseconds)
# - Default: 500 (5 seconds)
# - Recommended: 500
# - Description: the cycle at which the pdflush kernel thread wakes up to check for dirty pages
# - Effect: controls the frequency of disk writes
# - Caution: setting the value to 0 disables background writing (dangerous!)
vm.dirty_writeback_centisecs = 500

# ===== OOM (Out Of Memory) Killer =====

# vm.overcommit_memory: memory overcommit policy
# - Default: 0 (heuristic)
# - Meaning of the value:
#   * 0: heuristic - the kernel evaluates and judges each request (default)
#   * 1: always allow - allows allocation beyond physical memory (dangerous!)
#   * 2: strict limit - allows only up to Swap + RAM * overcommit_ratio
# - Description:
#   * a process requests memory via malloc() -> physical memory is not allocated until actual use
#   * overcommit: total allocation requested > actual physical memory
# - Scenario:
#   * Mode 0: general servers (balanced)
#   * Mode 1: scientific computing (allocates a lot of memory but uses little)
#   * Mode 2: databases (predictable memory usage)
# - Check: cat /proc/meminfo | grep Committed
vm.overcommit_memory = 0

# vm.overcommit_ratio: allowed ratio when overcommit_memory=2 (%)
# - Default: 50 (50%)
# - Description: max allocation = Swap + (RAM * overcommit_ratio / 100)
# - Example: 32GB RAM, 8GB Swap, ratio=50 -> max 24GB (8 + 32*0.5)
vm.overcommit_ratio = 50

# vm.panic_on_oom: whether to kernel panic when OOM occurs
# - Default: 0 (run the OOM Killer)
# - Recommended: 0 (general servers), 1 (cluster nodes)
# - Description:
#   * 0: the OOM Killer terminates a process that uses a lot of memory
#   * 1: immediate kernel panic -> system reboot
# - Use cases:
#   * 0: single server (kill just one process and keep the system up)
#   * 1: HA cluster (restart the whole node to fail over)
vm.panic_on_oom = 0

# vm.oom_kill_allocating_task: terminate the process requesting memory when OOM occurs
# - Default: 0 (terminate the largest process)
# - Description:
#   * 0: terminate the process with the highest OOM Score
#   * 1: immediately terminate the process that requested memory
vm.oom_kill_allocating_task = 0

# ===== Huge Pages (large-memory applications) =====

# vm.nr_hugepages: number of Huge Pages
# - Default: 0 (disabled)
# - Recommended: calculation needed (application memory / 2MB)
# - Description:
#   * regular page: 4KB
#   * Huge Page: 2MB (x86_64)
#   * reduces TLB (Translation Lookaside Buffer) misses -> improved performance
# - Calculation:
#   * Oracle DB needs 10GB SGA -> 10240 MB / 2 MB = 5120 Huge Pages
# - Check:
#   * cat /proc/meminfo | grep -i huge
#   * hugeadm --pool-list
# - Use cases:
#   * Oracle Database (SGA)
#   * PostgreSQL (shared_buffers)
#   * Redis (large instances)
#   * SAP HANA
# - Caution:
#   * pre-allocated at system boot (cannot be swapped)
#   * setting too many starves regular applications of memory
vm.nr_hugepages = 0

# vm.hugetlb_shm_group: GID of the group allowed to use Huge Pages
# - Description: only users in this group can use Huge Pages
# - Example: oracle group GID=1001
vm.hugetlb_shm_group = 0

# ===== Transparent Huge Pages (THP) =====

# Note: THP is configured under /sys/kernel/mm/transparent_hugepage/, not via sysctl
# - Check: cat /sys/kernel/mm/transparent_hugepage/enabled
# - Disable (recommended for Redis, MongoDB, Oracle):
#   echo never > /sys/kernel/mm/transparent_hugepage/enabled
#   echo never > /sys/kernel/mm/transparent_hugepage/defrag
# - Reason: THP can cause latency due to dynamic allocation

5. File System and Kernel Limits

# File descriptor limits
fs.file-max = 2097152                       # system-wide maximum FDs
fs.nr_open = 1048576                        # maximum FDs per process

# inotify limits (file watching)
fs.inotify.max_user_watches = 524288        # maximum watches per user
fs.inotify.max_user_instances = 512         # number of instances

# AIO (asynchronous I/O)
fs.aio-max-nr = 1048576

# Kernel message buffer
kernel.printk = 4 4 1 7                     # console log level

# Core dump settings
kernel.core_uses_pid = 1                    # include PID in core dumps
kernel.core_pattern = /var/crash/core.%e.%p.%h.%t

6. Kubernetes/Docker Environment Optimization

# ===== Bridge network settings (mandatory!) =====

# net.bridge.bridge-nf-call-iptables: process bridge traffic through iptables
# - Default: 0 (disabled) or 1
# - Recommended: 1 (mandatory for Kubernetes)
# - Description:
#   * whether iptables rules are applied when Pod-to-Pod communication packets pass through the Linux bridge
#   * Kubernetes Service (kube-proxy) implements load balancing with iptables
# - Problem: Service Discovery does not work when disabled
# - Required scenarios:
#   * all Kubernetes nodes (master + worker)
#   * Docker Swarm
#   * Calico, Flannel, Weave network plugins
# - Check:
#   * lsmod | grep br_netfilter (check module is loaded)
#   * modprobe br_netfilter (load the module)
# - Caution: the br_netfilter kernel module must be loaded first
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1

# ===== IP forwarding (mandatory!) =====

# net.ipv4.ip_forward: routing of Pod-to-Pod packets
# - Mandatory in Kubernetes (Pod-to-Pod, Pod-to-Service communication)
# - Check: sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

# ===== Conntrack (connection tracking) table =====

# net.netfilter.nf_conntrack_max: maximum number of entries in the Conntrack table
# - Default: 65536 (too small!)
# - Recommended: 1048576 (1 million, large clusters)
# - Description:
#   * Conntrack: iptables tracks connections for its stateful firewall
#   * an entry is created for each TCP/UDP connection (5-tuple: src IP, src port, dst IP, dst port, protocol)
# - Kubernetes scenario:
#   * 100 Pods x 10 Services x 100 connections = 100,000+ entries
#   * even more entries when using NodePort, LoadBalancer
# - Problem: exceeding it causes "nf_conntrack: table full, dropping packet" errors
# - Check:
#   * cat /proc/sys/net/netfilter/nf_conntrack_count (current usage)
#   * cat /proc/sys/net/netfilter/nf_conntrack_max (maximum)
#   * conntrack -L | wc -l (actual number of connections)
# - Log: dmesg | grep conntrack
# - Calculation: roughly 25,000 entries possible per 1GB of memory
net.netfilter.nf_conntrack_max = 1048576
net.nf_conntrack_max = 1048576

# net.netfilter.nf_conntrack_tcp_timeout_established: TCP connection timeout
# - Default: 432000 (5 days!)
# - Recommended: 86400 (1 day) or 3600 (1 hour)
# - Description: how long an ESTABLISHED TCP connection is kept in the Conntrack table
# - Effect: quickly removes old connections to free up table space
# - Caution: if too short (e.g., 300 seconds), long-lived connections get dropped
net.netfilter.nf_conntrack_tcp_timeout_established = 86400

# net.netfilter.nf_conntrack_tcp_timeout_time_wait: TIME_WAIT timeout
# - Default: 120 seconds
# - Recommended: 30 seconds
# - Description: how long a TIME_WAIT connection is kept in Conntrack
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30

# ===== ARP (Address Resolution Protocol) table =====

# net.ipv4.neigh.default.gc_thresh1: ARP table soft minimum
# - Default: 128 (too small!)
# - Recommended: 8192
# - Description: garbage collection is not run below this value
# - Problem: a small value causes "Neighbour table overflow" errors
# - Kubernetes: an IP address per Pod -> ARP entries surge
net.ipv4.neigh.default.gc_thresh1 = 8192

# net.ipv4.neigh.default.gc_thresh2: ARP garbage collection start
# - Default: 512
# - Recommended: 32768
# - Description: garbage collection starts when this value is exceeded (removes old entries)
net.ipv4.neigh.default.gc_thresh2 = 32768

# net.ipv4.neigh.default.gc_thresh3: ARP table hard maximum
# - Default: 1024
# - Recommended: 65536
# - Description: can never be exceeded; new entries are rejected once exceeded
# - Check:
#   * ip -s neigh show (check the ARP table)
#   * arp -an | wc -l (number of entries)
net.ipv4.neigh.default.gc_thresh3 = 65536

# ===== File descriptors =====

# fs.file-max: system-wide maximum file descriptors
# - Default: hundreds of thousands (varies by system)
# - Recommended: 2097152 (2 million)
# - Kubernetes: each Pod uses many FDs (sockets, files)
# - Check:
#   * cat /proc/sys/fs/file-nr (in use / available / maximum)
#   * lsof | wc -l (number of open files)
fs.file-max = 2097152

# fs.inotify.max_user_watches: number of files inotify watches
# - Default: 8192 (very small!)
# - Recommended: 524288
# - Description: detects file changes (kubectl logs -f, ConfigMap auto-reload)
# - Problem: exceeding it causes "too many open files" or "no space left on device" (even though disk is plentiful)
# - Use cases:
#   * kubectl logs -f (real-time logs)
#   * Prometheus file watching
#   * IDEs (VS Code, IntelliJ)
# - Check:
#   * cat /proc/sys/fs/inotify/max_user_watches
#   * find /proc/*/fd -lname anon_inode:inotify | wc -l (in use)
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 512

# ===== Disabling Swap (recommended for Kubernetes) =====

# vm.swappiness: 0 is recommended in Kubernetes
# - Description:
#   * Kubernetes needs to accurately track memory resource limits
#   * memory usage becomes unpredictable when Swap is used -> Pod Eviction malfunctions
# - Official recommendation: completely disable Swap (swapoff -a)
# - Alternative: vm.swappiness=0 (some Swap may still be used depending on the kernel)
vm.swappiness = 0

# ===== PID limit =====

# kernel.pid_max: maximum process ID for the system
# - Default: 32768
# - Recommended: 4194304 (large clusters)
# - Kubernetes: many Pods + Containers -> many processes
# - Check: cat /proc/sys/kernel/pid_max
kernel.pid_max = 4194304

# ===== Network performance =====

# net.core.somaxconn: throughput for Ingress Controllers and Services
# - Kubernetes Ingress (Nginx, Traefik) needs a high backlog
net.core.somaxconn = 65535

# net.ipv4.tcp_max_syn_backlog: NodePort, LoadBalancer traffic
net.ipv4.tcp_max_syn_backlog = 8192

# ===== Security (optional) =====

# net.ipv4.conf.all.rp_filter: may cause problems with Calico, Flannel
# - Loose Mode (2) recommended (allows asymmetric routing)
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2

Kubernetes node application example:

# /etc/sysctl.d/99-kubernetes.conf
# Bridge network (mandatory)
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1

# IP forwarding (mandatory)
net.ipv4.ip_forward = 1

# Conntrack (large clusters)
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 86400

# ARP table
net.ipv4.neigh.default.gc_thresh1 = 8192
net.ipv4.neigh.default.gc_thresh2 = 32768
net.ipv4.neigh.default.gc_thresh3 = 65536

# File system
fs.file-max = 2097152
fs.inotify.max_user_watches = 524288

# Memory
vm.swappiness = 0
vm.overcommit_memory = 1

# Process
kernel.pid_max = 4194304

# Network
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 8192

# Apply
sudo modprobe br_netfilter
sudo sysctl --system

Verification script:

#!/bin/bash
echo "=== Kubernetes kernel parameter check ==="

echo "1. Bridge settings:"
sysctl net.bridge.bridge-nf-call-iptables
sysctl net.bridge.bridge-nf-call-ip6tables

echo "2. IP forwarding:"
sysctl net.ipv4.ip_forward

echo "3. Conntrack:"
echo "  current: $(cat /proc/sys/net/netfilter/nf_conntrack_count)"
echo "  maximum: $(cat /proc/sys/net/netfilter/nf_conntrack_max)"

echo "4. ARP table:"
echo "  entries: $(ip neigh show | wc -l)"
sysctl net.ipv4.neigh.default.gc_thresh3

echo "5. File descriptors:"
cat /proc/sys/fs/file-nr
sysctl fs.inotify.max_user_watches

echo "6. Swap:"
sysctl vm.swappiness
free -h | grep Swap

7. Practical Application Examples

High-performance web server (Nginx/Apache):

# /etc/sysctl.d/99-web-server.conf
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 100000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 10000 65535
vm.swappiness = 10
fs.file-max = 2097152

# Apply
sudo sysctl -p /etc/sysctl.d/99-web-server.conf

Database server (MySQL/PostgreSQL):

# /etc/sysctl.d/99-database.conf
vm.swappiness = 1                           # minimize Swap
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
kernel.shmmax = 68719476736                 # maximum shared memory (64GB)
kernel.shmall = 4294967296
fs.file-max = 2097152

# Huge Pages (e.g., 10GB)
vm.nr_hugepages = 5120

Kubernetes worker node:

# /etc/sysctl.d/99-kubernetes.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
net.netfilter.nf_conntrack_max = 1048576
vm.swappiness = 0
fs.inotify.max_user_watches = 524288
fs.file-max = 2097152

8. Checking and Verifying Kernel Parameters

# Check current settings
sysctl -a | grep tcp_rmem
sysctl net.ipv4.tcp_tw_reuse

# Verify applied settings
cat /proc/sys/net/ipv4/tcp_tw_reuse
cat /proc/sys/vm/swappiness

# Verify automatic application at boot
sudo sysctl --system

# Configuration file locations
/etc/sysctl.conf                # traditional location
/etc/sysctl.d/*.conf            # applied with priority (recommended)
/run/sysctl.d/*.conf            # runtime settings
/usr/lib/sysctl.d/*.conf        # system defaults

9. Quick Reference Table of Key Parameters

Parameter Default Recommended Purpose
vm.swappiness 60 10 Web/DB servers
net.core.somaxconn 128 65535 High-performance web servers
net.ipv4.tcp_tw_reuse 0 1 TIME_WAIT reuse
fs.file-max hundreds of thousands 2097152 File descriptors
net.ipv4.ip_forward 0 1 Routers/Kubernetes
net.netfilter.nf_conntrack_max 65536 1048576 Kubernetes
fs.inotify.max_user_watches 8192 524288 IDEs/build tools

Cautions:

  • Always back up before making changes
  • Test before applying in production environments
  • Verify the settings persist across system reboots (/etc/sysctl.conf or /etc/sysctl.d/)

References

References

Clone this wiki locally