背景
某个运行了两年多的 OpenShift 应用一直非常稳定。
某次由于 Node OOM,Pod 被驱逐并重新调度到其他节点。原本以为只是一次普通的重启,结果 Pod 无法启动,日志中出现大量文件和目录权限错误。
由于应用镜像、PVC 和 OpenShift 版本均未发生变化,因此问题一开始比较难定位。
故障现象
应用启动时出现类似错误:
1 | Permission denied |
查看 Pod 信息发现:
老 Pod:
1 | openshift.io/scc: anyuid |
新创建的 Pod:
1 | openshift.io/scc: restricted-v2 |
问题开始有了方向。
OpenShift SCC 机制
OpenShift 中的 SCC(Security Context Constraints)决定了 Pod 运行时的安全策略。
常见的 SCC 包括:
1 | restricted-v2 |
很多人会认为:
1 | openshift.io/scc: anyuid |
是 Deployment 或 StatefulSet 的固定配置。
实际上并不是。
SCC 是在 Pod 创建时动态选择的:
1 | ServiceAccount |
因此:
1 | 删除 Pod |
新 Pod 完全有可能获得与旧 Pod 不同的 SCC。
关键发现
检查一个两年前创建且从未重启过的 Pod:
1 | serviceAccountName: default |
说明系统安装时:
1 | default ServiceAccount |
否则 Pod 不可能获得 AnyUID SCC。
进一步验证:
1 | oc auth can-i use scc/anyuid \ |
结果:
1 | no |
说明当前的 default ServiceAccount 已经失去了使用 AnyUID 的权限。
Root Cause
系统安装时:
1 | default ServiceAccount |
因此创建出来的 Pod 使用:
1 | openshift.io/scc: anyuid |
后来某个时间点:
1 | SCC 或 RBAC 配置发生变化 |
导致:
1 | default ServiceAccount |
但是由于旧 Pod 一直没有重建,所以问题始终没有暴露。
直到:
1 | Node OOM |
OpenShift 重新选择 SCC。
由于 AnyUID 已不可用:
1 | restricted-v2 |
成为新的 SCC。
为什么 Restricted-v2 会导致启动失败
Restricted-v2 要求容器使用随机非 Root UID。
例如:
1 | uid=1000700000 |
而很多历史镜像中的目录权限是按照固定 UID 或 Root 用户设计的。
例如:
1 | /opt/app |
当随机 UID 无法访问这些目录时:
1 | Permission denied |
应用启动失败。
解决方案
方案一:调整 SecurityContext
例如:
1 | securityContext: |
或者根据应用实际情况调整:
1 | securityContext: |
使应用兼容 Restricted-v2。
这是推荐方案。
方案二:恢复 AnyUID 权限
执行:
1 | oc adm policy add-scc-to-user anyuid \ |
验证:
1 | oc auth can-i use scc/anyuid \ |
返回:
1 | yes |
之后重新创建 Pod,即可重新获得 AnyUID SCC。
排查过程中学到的经验
1. 长时间运行的 Pod 会隐藏问题
一个运行了几年都没有重建过的 Pod,并不能证明当前配置仍然正确。
很多问题只有在:
- Pod 重建
- 节点迁移
- 集群升级
时才会暴露出来。
2. SCC 是动态计算的
不要认为:
1 | openshift.io/scc: anyuid |
会永久存在。
每次创建 Pod 时都会重新计算。
3. 尽量不要依赖 Default ServiceAccount
推荐为应用创建专用 ServiceAccount:
1 | serviceAccountName: my-app-sa |
避免未来权限调整影响整个 Namespace。
4. 优先兼容 Restricted-v2
从 OpenShift 安全模型的发展趋势来看:
1 | restricted-v2 |
已经成为默认推荐方案。
新开发的应用应尽量避免依赖:
1 | anyuid |
等高权限 SCC。
总结
这次问题表面上看是文件权限异常:
1 | Permission denied |
实际上根因是:
1 | 历史 Pod 使用 AnyUID |
对于长期运行的 OpenShift 集群,定期检查 SCC、ServiceAccount 和 SecurityContext 配置,是避免此类问题的有效手段。