kubelet 会拉起 /etc/kubernetes/manifests 下的所有 Pod 吗?
结论
不会。 kubelet 只处理 .yaml、.yml、.json 三种扩展名的文件,其他文件(.txt、.md、.bak、二进制文件、无扩展名文件等)会被直接忽略,不记录错误,也不会创建 Pod。子目录不会递归扫描。即使是 yaml 文件,内容解析失败或校验不通过也不会拉起 Pod。
分析版本
- 软件:Kubernetes kubelet
- 版本:v1.29(源码逻辑自 v1.6 引入后长期稳定,v1.20+ 无变化)
- 源码路径:
pkg/kubelet/config/file.go - 核心函数:
extractFromPath()、isPodManifestFile()
详细分析
1. 静态 Pod 目录监控机制
kubelet 通过启动参数 --pod-manifest-path 指定静态 Pod 清单目录,默认值为 /etc/kubernetes/manifests。
kubelet 启动时会创建一个文件源(sourceFile),定期扫描该目录,并通过 fsnotify 监听文件变化。当目录中有文件新增、修改或删除时,kubelet 会触发重新扫描。
2. 文件过滤逻辑(核心)
扫描目录时,extractFromPath() 函数对每个文件依次做以下判断:
2.1 跳过子目录
if file.IsDir() {
continue // 子目录直接跳过,不递归扫描
}
manifests 目录下的子目录不会被递归处理,子目录里的 yaml 文件也不会被读取。
2.2 只识别三种扩展名
func isPodManifestFile(filename string) bool {
ext := filepath.Ext(filename)
return ext == ".yaml" || ext == ".yml" || ext == ".json"
}
只有扩展名是 .yaml、.yml、.json 的文件才会进入下一步解析。其他文件直接跳过,不记录任何日志。
这意味着:
test.txt→ 忽略README.md→ 忽略pod.yaml.bak→ 忽略(扩展名是.bak)pod(无扩展名)→ 忽略pod.yaml→ 处理pod.yml→ 处理pod.json→ 处理
2.3 读取并解析文件内容
通过扩展名过滤后,kubelet 读取文件内容,尝试解析为 Pod 对象:
pod, err := kubetypes.DecodePod(data)
if err != nil {
klog.ErrorS(err, "Failed to decode pod manifest file", "path", path)
continue
}
- 解析失败 → 记录错误日志(
Failed to decode pod manifest file),不创建 Pod - 解析成功 → 进入字段校验
2.4 字段校验
解析成功后,kubelet 还会对 Pod 字段做基本校验:
metadata.name必填spec不能为空- 容器列表不能为空
- 等等
校验不通过的 Pod 同样会被拒绝,不会创建。
3. 完整处理流程
扫描 /etc/kubernetes/manifests 目录
│
▼
是子目录吗? ──是──→ 跳过
│否
▼
扩展名是 .yaml/.yml/.json 吗? ──否──→ 直接跳过(无日志)
│是
▼
读取文件内容
│
▼
解析为 Pod 对象 ──失败──→ 记录错误日志,跳过
│成功
▼
字段校验 ──不通过──→ 记录错误,跳过
│通过
▼
创建/更新静态 Pod ✅
4. 验证方法
4.1 放入非 yaml 文件测试
# 放一个 txt 文件
echo "test content" > /etc/kubernetes/manifests/test.txt
# 查看 kubelet 日志,不会有任何关于 test.txt 的记录
journalctl -u kubelet -f --since "1 min ago" | grep -i "test.txt"
# 无输出 → 说明被直接忽略
# 查看 pod,不会有 test 相关的 pod
kubectl get pods -A | grep test
4.2 放入无效 yaml 文件测试
# 放一个格式错误的 yaml
cat > /etc/kubernetes/manifests/bad.yaml <<EOF
apiVersion: v1
kind: Pod
metadata
name: bad-pod
EOF
# 注意:上面 metadata 后面少了冒号,yaml 语法错误
# 查看 kubelet 日志,会有解析错误
journalctl -u kubelet -f --since "1 min ago" | grep -i "bad.yaml"
# 输出类似:Failed to decode pod manifest file ... bad.yaml
4.3 查看当前静态 Pod
# 静态 Pod 的命名格式是 <pod-name>-<node-name>
kubectl get pods -A | grep -E "etcd|kube-apiserver|kube-controller|kube-scheduler"
# 这些控制平面组件通常都是以静态 Pod 方式运行的
5. 注意事项
-
文件扩展名严格匹配:
pod.yaml.bak的扩展名是.bak,不会被处理。如果想临时禁用某个静态 Pod,把文件重命名为pod.yaml.disabled即可。 -
大小写敏感:Linux 上
pod.YAML不会被识别(扩展名是大写的.YAML),必须是小写。 -
符号链接:kubelet 会跟随符号链接,如果 manifests 目录下有指向外部 yaml 文件的软链接,也会被处理。
-
文件权限:kubelet 需要有读取文件的权限,通常以 root 运行所以没问题,但如果以非 root 用户运行需要注意权限。
-
删除文件即删除 Pod:从 manifests 目录删除 yaml 文件,kubelet 检测到后会自动删除对应的静态 Pod。
6. 源码位置参考
kubernetes/
└── pkg/
└── kubelet/
└── config/
├── file.go # sourceFile 实现,extractFromPath、isPodManifestFile
├── file_linux.go # Linux 平台特定的文件监听
└── types.go # Pod 配置类型定义
核心函数 isPodManifestFile 在 pkg/kubelet/config/file.go 中,自 Kubernetes v1.6 引入静态 Pod 目录扫描机制以来,该过滤逻辑一直保持稳定,截至 v1.29 无变化。
浙公网安备 33010602011771号