使用Role Binding时查找ServiceAccount报错问题排查
我创建了一个包含Post-Install Hook Job模板、自定义资源及ConfigMap的Helm Chart,Job代码如下:
apiVersion: batch/v1 kind: Job metadata: name: postinstall-hook annotations: "helm.sh/hook": "post-install" "helm.sh/hook-delete-policy": hook-succeeded # 不加这个注解Hook不会自动删除 spec: serviceAccountName: {{ .Values.serviceAccount }} automountServiceAccountToken: true template: spec: containers: - name: kubectl image: bitnami/kubectl imagePullPolicy: Always command: ["/bin/bash", "-c", "while true; do running_jobs=$(kubectl get jobs -n {{ .Release.Namespace }} -o jsonpath='{.items[?(@.status.active==1)].metadata.name}'); if [ -z \"$running_jobs\" ]; then echo \"All jobs have completed\"; break; else echo \"Waiting for the following jobs to complete: $running_jobs\"; sleep 30; fi; done"] restartPolicy: Never terminationGracePeriodSeconds: 10
我使用devops命名空间下的devops-deploy ServiceAccount进行Helm部署,原本该账号仅拥有devops命名空间权限,现在需要在k6命名空间部署,因此已为其配置了k6命名空间的Role和RoleBinding。但部署时Job执行失败,报错如下:
Error creating: pods "postinstall-hook-" is forbidden: error looking up service account ns2/serviceaccountname: serviceaccount "serviceaccount" not found
该ServiceAccount确实不存在于k6命名空间,但我希望直接使用devops命名空间中已存在的ServiceAccount,并已配置了相关RBAC规则,完整的ServiceAccount及RBAC清单如下:
apiVersion: v1 kind: ServiceAccount metadata: name: devops-deploy namespace: devops automountServiceAccountToken: false --- apiVersion: v1 kind: Secret metadata: name: devops-deploy-secret namespace: devops annotations: kubernetes.io/service-account.name: devops-deploy type: kubernetes.io/service-account-token --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: devops-deploy-role namespace: devops rules: - apiGroups: ["apps"] resources: ["deployments","replicasets"] verbs: ["*"] - apiGroups: [""] resources: ["pods"] verbs: ["*"] - apiGroups: [""] resources: ["secrets"] verbs: ["*"] - apiGroups: [""] resources: ["configmaps"] verbs: ["create","get","watch","list","update","patch","delete"] - apiGroups: [""] resources: ["services"] verbs: ["*"] - apiGroups: [""] resources: ["serviceaccounts"] verbs: ["*"] - apiGroups: ["extensions"] resources: ["ingresses"] verbs: ["*"] - apiGroups: ["autoscaling"] resources: ["horizontalpodautoscalers"] verbs: ["*"] - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["*"] - apiGroups: ["k6.io"] resources: ["k6s"] verbs: ["create","delete","get","list","patch","update","watch"] - apiGroups: ["batch", "extensions"] resources: ["jobs"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: devops-deploy-rb namespace: devops subjects: - kind: ServiceAccount name: devops-deploy roleRef: kind: Role name: devops-deploy-role apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: job-exec-from-ns1 namespace: k6 roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: devops-deploy-role subjects: - kind: ServiceAccount name: devops-deploy namespace: devops --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: kube-describe-cr rules: - apiGroups: [""] resources: ["services"] verbs: ["get","create","delete","update","list","watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: kube-describe-crb subjects: - kind: ServiceAccount name: devops-deploy namespace: devops roleRef: kind: ClusterRole name: kube-describe-cr apiGroup: rbac.authorization.k8s.io
问题根源
Kubernetes中,Pod的serviceAccountName字段默认会在当前Pod所在命名空间查找对应的ServiceAccount。你的Hook Job部署在k6命名空间,所以Kubernetes会尝试在k6下找指定的ServiceAccount,而非devops命名空间的,这就是报错的核心原因。
解决步骤
修改Job模板,指定ServiceAccount的命名空间
Kubernetes 1.24及以上版本支持通过嵌套的serviceAccount字段指定ServiceAccount的命名空间,替代原有的serviceAccountName。修改后的Job模板如下:apiVersion: batch/v1 kind: Job metadata: name: postinstall-hook annotations: "helm.sh/hook": "post-install" "helm.sh/hook-delete-policy": hook-succeeded spec: template: spec: serviceAccount: name: {{ .Values.serviceAccount }} namespace: devops # 明确指定ServiceAccount所在的命名空间 automountServiceAccountToken: true containers: - name: kubectl image: bitnami/kubectl imagePullPolicy: Always command: ["/bin/bash", "-c", "while true; do running_jobs=$(kubectl get jobs -n {{ .Release.Namespace }} -o jsonpath='{.items[?(@.status.active==1)].metadata.name}'); if [ -z \"$running_jobs\" ]; then echo \"所有Job已完成\"; break; else echo \"等待以下Job完成: $running_jobs\"; sleep 30; fi; done"] restartPolicy: Never terminationGracePeriodSeconds: 10若你的Kubernetes版本低于1.24,不支持上述嵌套字段,需手动挂载ServiceAccount Token:
- 从
devops命名空间获取devops-deploy-secret的内容 - 在Job的Pod模板中,将该Secret挂载到
/var/run/secrets/kubernetes.io/serviceaccount路径
- 从
验证RBAC权限有效性
执行以下命令,确认devops-deploy账号拥有k6命名空间下Job相关的权限:kubectl auth can-i list jobs -n k6 --as=system:serviceaccount:devops:devops-deploy返回
yes则权限配置正确。确认Token自动挂载配置
你的devops-deployServiceAccount设置了automountServiceAccountToken: false,但Job模板中开启了automountServiceAccountToken: true,该配置会覆盖ServiceAccount的默认设置,确保Pod能正确挂载Token,无需修改。
内容的提问来源于stack exchange,提问作者Ido Segal

