AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub

sysctl —— 内核运行时参数

一句话定义

sysctl 读写 Linux 内核运行时参数(暴露在 /proc/sys/ 下的几千个调节器)。K8s 装机必调几个网络 / 内存参数 —— 不调装不上、调错性能差。

典型场景

  • Day0 装 K8s 前:sysctl --system 让 net.bridge.bridge-nf-call-iptables = 1 等生效
  • 排查"conntrack 表满":sysctl net.netfilter.nf_conntrack_max
  • 高并发 K8s 节点调优:fd 上限 / TCP 参数
  • 容器节点:vm.max_map_count(Elasticsearch / 大内存应用)

三种用法

# 1. 读
sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 1

# 2. 改(临时,重启失效)
sysctl -w net.ipv4.ip_forward=1

# 3. 改(持久,写配置文件)
echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-k8s.conf
sysctl --system                              # 重新加载所有 sysctl.d 配置

参数名 = /proc/sys/ 路径

sysctl net.ipv4.ip_forward
# 等价于
cat /proc/sys/net/ipv4/ip_forward

参数名里 . 和 /proc/sys/ 里的 / 一对一映射。所以:

sysctl 名对应文件
net.ipv4.ip_forward/proc/sys/net/ipv4/ip_forward
vm.swappiness/proc/sys/vm/swappiness
kernel.pid_max/proc/sys/kernel/pid_max
net.bridge.bridge-nf-call-iptables/proc/sys/net/bridge/bridge-nf-call-iptables

可以直接读写 proc 文件,等价:

sysctl -w vm.swappiness=10
# 等于
echo 10 > /proc/sys/vm/swappiness

但 sysctl 命令更标准、可重复用。


看 / 搜参数

sysctl -a                                    # 列所有参数(几千个)
sysctl -a | grep ip_forward                  # 搜
sysctl -a | grep -i "conntrack"
sysctl -n vm.swappiness                      # 只输出值(脚本用)

配置文件:/etc/sysctl.d/*.conf + /etc/sysctl.conf

历史上 /etc/sysctl.conf 是主文件。现代做法:

  • /etc/sysctl.conf —— 老地方,仍然有效
  • /etc/sysctl.d/*.conf —— 推荐:按主题分文件
  • /usr/lib/sysctl.d/*.conf —— 包管理器装的(不要手改)
  • /run/sysctl.d/*.conf —— 运行时

加载顺序:按文件名字母序合并、后面的覆盖前面。所以习惯写 99-myname.conf 让自己的设置在最后。

重新加载

sysctl --system                              # 重读所有 sysctl.d/ 和 sysctl.conf
sysctl -p                                    # 只读 /etc/sysctl.conf
sysctl -p /etc/sysctl.d/99-k8s.conf          # 读单文件

改完一定 sysctl --system,否则不生效。


K8s 必调参数(装机第一步)

K8s 不调这几个根本装不上:

cat > /etc/sysctl.d/99-k8s.conf <<'EOF'
# 容器网络转发(kube-proxy 必需)
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1

# 主机作 router(pod 间通信跨节点)
net.ipv4.ip_forward                 = 1
net.ipv6.conf.all.forwarding        = 1

# 文件描述符
fs.inotify.max_user_instances       = 8192
fs.inotify.max_user_watches         = 524288

# 路由相关(CNI 用)
net.ipv4.conf.all.rp_filter         = 0    # 关 reverse-path filter(CNI 转发需要)
net.ipv4.conf.default.rp_filter     = 0
EOF

# 加载 bridge 模块(不然 net.bridge.* 设置不上)
modprobe br_netfilter
echo 'br_netfilter' > /etc/modules-load.d/k8s.conf

# 应用
sysctl --system

验证

sysctl net.bridge.bridge-nf-call-iptables    # 必须 = 1
sysctl net.ipv4.ip_forward                    # 必须 = 1

大集群 / 高并发节点加这些

cat >> /etc/sysctl.d/99-k8s.conf <<'EOF'
# conntrack 表大小(大流量 K8s 节点要调高)
net.netfilter.nf_conntrack_max      = 1048576

# TIME_WAIT 复用
net.ipv4.tcp_tw_reuse                = 1

# 端口范围(容器多端口 NAT)
net.ipv4.ip_local_port_range         = 32768 65535

# 最大文件句柄
fs.file-max                           = 2097152

# 最大进程 / PID
kernel.pid_max                        = 4194304

# 内存
vm.max_map_count                      = 262144   # Elasticsearch / JVM 大堆需要
vm.swappiness                         = 0        # K8s 节点禁 swap、设 0 兜底

# 防 oom 内核 panic
vm.panic_on_oom                       = 0
kernel.panic                           = 10
kernel.panic_on_oops                  = 1
EOF

几个最常调的参数

vm.swappiness

sysctl vm.swappiness
# vm.swappiness = 60                          ← 默认 60,太爱 swap

K8s 节点应该禁 swap(kubeadm 强制),但万一启用、降到 1 或 0:

sysctl -w vm.swappiness=1

vm.max_map_count

进程能 mmap 的最大块数。默认 65530。Elasticsearch / 大堆 JVM 需要更高:

sysctl -w vm.max_map_count=262144

ES 启动报 max virtual memory areas vm.max_map_count [65530] is too low 就是这个。

fs.inotify.max_user_watches

inotify 监视的最大文件数。K8s ConfigMap / Secret 自动重载用 inotify。VS Code 也用。默认低(8192),节点上几千个 pod 远不够:

sysctl -w fs.inotify.max_user_watches=524288
sysctl -w fs.inotify.max_user_instances=8192

net.netfilter.nf_conntrack_max

netfilter 连接跟踪表大小。kube-proxy iptables 模式靠这个。

sysctl net.netfilter.nf_conntrack_max
# 65536

# 看当前用量
sysctl net.netfilter.nf_conntrack_count
# 看比例
echo "scale=2; $(sysctl -n net.netfilter.nf_conntrack_count) / $(sysctl -n net.netfilter.nf_conntrack_max) * 100" | bc
# 60.25%

到 80% 就该调高:

sysctl -w net.netfilter.nf_conntrack_max=1048576

不调的话 dmesg 会出现:

nf_conntrack: table full, dropping packet

net.ipv4.tcp_*

sysctl -w net.ipv4.tcp_tw_reuse=1                       # TIME_WAIT 复用
sysctl -w net.ipv4.tcp_fin_timeout=30                   # FIN 超时
sysctl -w net.ipv4.tcp_keepalive_time=600               # keepalive 间隔
sysctl -w net.ipv4.ip_local_port_range="32768 65535"    # 临时端口范围

调这些的前提:你知道当前默认值有问题(通过 ss / dmesg 看到瓶颈),不要盲调。

kernel.pid_max

最大 PID。容器多了之后默认 32768 不够:

sysctl kernel.pid_max
# 4194304    ← 现代内核默认就大

老内核可能要调。


sysctl --system 输出长这样

$ sysctl --system
* Applying /usr/lib/sysctl.d/10-console-messages.conf ...
* Applying /usr/lib/sysctl.d/50-default.conf ...
* Applying /etc/sysctl.d/99-k8s.conf ...
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
...
* Applying /etc/sysctl.conf ...

每行 * Applying 是个文件,下面是该文件应用的参数。

报错:

sysctl: cannot stat /proc/sys/net/bridge/bridge-nf-call-iptables: No such file or directory

说明 br_netfilter 模块没装。先 modprobe(见 modprobe.md)。


看哪些参数不是默认值

sysctl -a 2>/dev/null > /tmp/current.sysctl
# 然后对比 /usr/lib/sysctl.d/*.conf

或者更精确:

sysctl --pattern "ipv4" | head
sysctl --pattern "tcp"

--pattern 是 regex 过滤。


namespace 化的 sysctl(容器 K8s 视角)

某些 sysctl 是 per-network-namespace——容器里改不影响节点。例如:

  • net.core.somaxconn
  • net.ipv4.tcp_* (部分)
  • net.ipv4.ip_local_port_range

K8s pod 允许通过 securityContext.sysctls 配某些 "safe" sysctl:

spec:
  securityContext:
    sysctls:
    - name: net.core.somaxconn
      value: "1024"

"unsafe" sysctls 需要 kubelet 启动时 --allowed-unsafe-sysctls=... 显式放行。


常见踩坑

坑 1:sysctl -w 改了,重启就没

sysctl -w vm.swappiness=10
reboot
sysctl vm.swappiness
# 60                                          ← 又回默认

-w 只在内存里。要持久写 /etc/sysctl.d/:

echo 'vm.swappiness = 10' > /etc/sysctl.d/99-tune.conf
sysctl --system

坑 2:参数名打错

sysctl -w net.ipv4.ip_forwarding=1
# sysctl: cannot stat /proc/sys/net/ipv4/ip_forwarding: No such file or directory

正确:ip_forward(无 ing)。sysctl -a | grep forward 找正确名字。

坑 3:bridge sysctl 在 br_netfilter 没装时报错

sysctl -w net.bridge.bridge-nf-call-iptables=1
# sysctl: cannot stat /proc/sys/net/bridge/...

必须先 modprobe br_netfilter。配合 /etc/modules-load.d/k8s.conf 开机自动加载。

坑 4:sysctl.conf 写错语法

net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
net.ipv4.ip_forward =1

三种都接受(等号两边空格可有可无)。但值不能多空格:

net.ipv4.ip_forward = 1 2     ← 报错

坑 5:同名参数被多个文件覆盖

/usr/lib/sysctl.d/50-default.conf:  vm.swappiness = 60
/etc/sysctl.d/99-k8s.conf:           vm.swappiness = 1

99-k8s.conf 排序更靠后、生效。自己的设置永远用 99- 前缀。

坑 6:容器里改 sysctl 不影响节点

kubectl exec my-pod -- sysctl -w net.ipv4.tcp_tw_reuse=1
# 看着改了,节点上没变

network namespace 隔离了一部分 sysctl。要节点级改 → 节点上改。 要 pod 级改 → securityContext.sysctls。

坑 7:reboot 之后 net.bridge.* 没生效

reboot
sysctl net.bridge.bridge-nf-call-iptables
# sysctl: cannot stat ...

br_netfilter 没在开机时加载。写 /etc/modules-load.d/k8s.conf:

echo 'br_netfilter' > /etc/modules-load.d/k8s.conf
echo 'overlay' >> /etc/modules-load.d/k8s.conf       # containerd overlay 需要

sysctl.d/99-k8s.conf 必须在 module 之后才能生效,但开机时 systemd 处理顺序保证了这点。

坑 8:调了 net.netfilter.nf_conntrack_max 但内存吃光

sysctl -w net.netfilter.nf_conntrack_max=10000000     # 太大了

每个 conntrack entry 占约 300 字节。1M = 300 MB;10M = 3 GB。根据可用内存合理调:

# 推荐 4G 内存以上节点
net.netfilter.nf_conntrack_max = 1048576              # 1M = 300 MB

坑 9:rp_filter 改错让 K8s pod 不通

net.ipv4.conf.all.rp_filter = 1                       ← 默认严格 RP filter

Pod 跨节点 traffic 经过 SNAT 后回包路径可能"不对称",RP filter 把它当伪造包丢。K8s 节点必须设 0:

net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0

不然偶发性 pod 间通信失败、超难排查。


实战:Day0 标准 sysctl 配置

ssh root@$ip 'bash -s' <<'EOF'
# 1. 内核模块
cat > /etc/modules-load.d/k8s.conf <<'MOD'
br_netfilter
overlay
MOD
modprobe br_netfilter
modprobe overlay

# 2. sysctl
cat > /etc/sysctl.d/99-k8s.conf <<'SYSCTL'
# 必需
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                  = 1
net.ipv6.conf.all.forwarding         = 1
net.ipv4.conf.all.rp_filter          = 0
net.ipv4.conf.default.rp_filter      = 0

# inotify(K8s ConfigMap / Secret 监视)
fs.inotify.max_user_instances        = 8192
fs.inotify.max_user_watches          = 524288

# 内存
vm.swappiness                         = 0
vm.max_map_count                      = 262144
vm.panic_on_oom                       = 0

# 网络高并发
net.netfilter.nf_conntrack_max       = 1048576
net.ipv4.ip_local_port_range          = 32768 65535
net.ipv4.tcp_tw_reuse                  = 1
SYSCTL

# 3. 应用
sysctl --system

# 4. 验证关键项
sysctl net.bridge.bridge-nf-call-iptables
sysctl net.ipv4.ip_forward
EOF

关联命令

  • modprobe —— 内核模块;某些 sysctl 依赖模块
  • systemctl —— systemd-sysctl.service 在开机时跑 sysctl --system
  • dmesg —— sysctl 不调时报错(conntrack 满等)在 dmesg
  • /proc/sys/ —— sysctl 的本质就是读写 proc
  • iptables —— net.netfilter.* 配合 conntrack
在 GitHub 上编辑此页