Pod 被 Pod Security Admission 拒绝
症状
创建实例后,StatefulSet 出现,但未创建任何 Pod。StatefulSet 报告创建 Pod 失败,并显示 Pod Security Admission 违规,指出 restricted 配置文件。事件中的典型措辞如下:
create Pod chi-<instance>-<cluster>-0-0-0 in StatefulSet chi-<instance>-<cluster>-0-0 failed error:
pods "chi-<instance>-<cluster>-0-0-0" is forbidden: violates PodSecurity "restricted:latest"
实例自身的状态可能不会显示错误,因为 operator 提交的对象已被接受;被拒绝的是 Pod。
通过检查命名空间标签来重现此情况:
kubectl get ns <namespace> -o jsonpath='{.metadata.labels}'
pod-security.kubernetes.io/enforce: restricted 标签会触发此问题。
原因
设置 logVolumeClaimTemplate 会改变 Pod 的结构:operator 会附加一个名为 clickhouse-log 的第二个容器,以便读取日志卷而不干扰服务器。它生成的容器只会在其安全上下文中设置用户 ID。它不会设置 allowPrivilegeEscalation: false、删除 capabilities 或设置 seccomp 配置文件,而 restricted 配置文件要求具备所有这些设置。
Pod 中的其他容器即使完全符合要求,Pod 仍会被拒绝,因为准入检查会评估整个 Pod。
修复
在 Pod 模板中自行声明日志容器,并为其设置完整的安全上下文。当已存在一个名称完全匹配的容器时,operator 会复用你声明的容器,而不是生成一个新容器——只有在你未设置镜像,或将其设置为 default 时,operator 才会填充镜像。
apiVersion: clickhouse.altinity.com/v1
kind: ClickHouseInstallation
metadata:
name: e1-logs
spec:
defaults:
templates:
dataVolumeClaimTemplate: data-volume
logVolumeClaimTemplate: log-volume
podTemplate: ch-pod
configuration:
clusters:
- name: main
layout:
shardsCount: 1
replicasCount: 1
templates:
podTemplates:
- name: ch-pod
spec:
securityContext:
runAsUser: 101
runAsGroup: 101
fsGroup: 101
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: clickhouse
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
- name: clickhouse-log
securityContext:
runAsUser: 65534
runAsNonRoot: true
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
volumeClaimTemplates:
- name: data-volume
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
- name: log-volume
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
名称必须严格为 clickhouse-log。使用其他名称会同时保留你的 sidecar 和 operator 生成的容器,因此拒绝仍会发生。
替代方案:不持久化日志
如果不需要将日志保存到卷中,请移除 logVolumeClaimTemplate。没有该设置时,operator 不会添加日志容器,而是将一个 emptyDir 挂载到日志目录。这样,在 Pod 的生命周期内仍可读取日志,但 Pod 被替换时日志会丢失。
验证
kubectl -n <namespace> get pods -l clickhouse.altinity.com/chi=<instance>
kubectl -n <namespace> get pod <pod> \
-o jsonpath='{range .spec.containers[*]}{.name}{"\t"}{.securityContext}{"\n"}{end}'
两个容器 clickhouse 和 clickhouse-log 均具有完整的安全上下文。
ClickHouse 是 ClickHouse, Inc. 的注册商标。https://clickhouse.com
Alauda 是独立供应商。本产品与 ClickHouse, Inc. 不存在关联,也未获得其认可或赞助。所有商标均为其各自所有者的财产,此处仅用于标识目的。