StatefulSet独立目录权限问题:非root用户无写入权限
我要创建一个包含3个副本的Headless Service和StatefulSet,运行简易计算器Web应用。应用的Docker镜像通过以下配置创建了非root用户appuser(UID=10001):
ARG UID=10001 RUN adduser \ --disabled-password \ --gecos "" \ --home "/data" \ --shell "/sbin/nologin" \ --no-create-home \ --uid "${UID}" \ appuser USER appuser
我需要让每个Pod拥有专属独立目录且具备读写权限,编写了如下YAML配置文件:
apiVersion: v1 kind: Namespace metadata: name: myns --- apiVersion: v1 kind: Service metadata: namespace: myns name: calc-headless spec: clusterIP: None # headless ports: - port: 3000 selector: app: calc --- apiVersion: apps/v1 kind: StatefulSet metadata: namespace: myns labels: app: calc name: calc spec: serviceName: calc-headless replicas: 3 minReadySeconds: 5 selector: matchLabels: app: calc template: metadata: labels: app: calc spec: terminationGracePeriodSeconds: 3 securityContext: runAsUser: 10001 runAsGroup: 10001 fsGroup: 10001 fsGroupChangePolicy: "Always" containers: - image: path/to/my/image name: calc ports: - containerPort: 3000 volumeMounts: - name: node-data mountPath: /my-data securityContext: runAsUser: 10001 runAsGroup: 10001 volumeClaimTemplates: - metadata: name: node-data spec: accessModes: [ "ReadWriteOncePod" ] resources: requests: storage: 1Gi
执行kubectl apply -f headless.yml后,K8s成功创建Service和Pod,但通过kubectl exec -it calc-0 -- /bin/sh查看发现,/my-data目录属于root:root,导致Pod无写入权限。请问遗漏了什么配置?
更新信息
使用Minikube环境,kubectl get storageclasses输出如下:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE standard (default) k8s.io/minikube-hostpath Delete Immediate false 45d
kubectl get pv输出如下:
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE pvc-170ff701-8b9e-4df1-b88f-78f4758a19f4 1Gi RWOP Delete Bound ckad/node-data-calc-0 standard <unset> 6m22s pvc-21d2bca0-be99-4765-8ad1-7c8b28583d8b 1Gi RWOP Delete Bound ckad/node-data-calc-1 standard <unset> 6m12s pvc-a85807e8-8f48-474e-9ca6-eaf91a8f70a4 1Gi RWOP Delete Bound ckad/node-data-calc-2 standard <unset> 6m2s
问题出在Minikube默认的hostpath存储类上,它创建的PV目录权限默认是root:root,而Kubernetes的fsGroup机制在这类本地存储驱动下,不会自动递归调整已有目录的权限,尤其是PV首次挂载时。
以下是几种可行的解决方法:
方法1:添加初始化容器调整权限
在StatefulSet的Pod模板中加入一个以root身份运行的初始化容器,提前修改挂载目录的权限:
spec: template: spec: initContainers: - name: fix-permissions image: busybox:latest command: ["chown", "-R", "10001:10001", "/my-data"] volumeMounts: - name: node-data mountPath: /my-data securityContext: runAsUser: 0 # 以root身份运行 # 原有容器配置...
这个容器会在主容器启动前,将/my-data目录的所有者改为appuser的UID/GID,确保主容器拥有读写权限。
方法2:自定义存储类指定权限
Minikube的hostpath存储类支持通过参数设置目录的所有者和组,创建一个自定义存储类:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: hostpath-custom provisioner: k8s.io/minikube-hostpath reclaimPolicy: Delete volumeBindingMode: Immediate allowVolumeExpansion: false parameters: owner: "10001" group: "10001"
然后在StatefulSet的volumeClaimTemplates中指定使用这个存储类:
volumeClaimTemplates: - metadata: name: node-data spec: storageClassName: hostpath-custom accessModes: [ "ReadWriteOncePod" ] resources: requests: storage: 1Gi
注意:需要先删除已有的PVC和PV,再重新创建StatefulSet,才能让新的PV使用自定义存储类的权限配置。
方法3:在Docker镜像中预配置目录权限
在Dockerfile中提前创建/my-data目录并设置权限:
ARG UID=10001 RUN adduser \ --disabled-password \ --gecos "" \ --home "/data" \ --shell "/sbin/nologin" \ --no-create-home \ --uid "${UID}" \ appuser # 创建挂载目录并设置归属 RUN mkdir -p /my-data && chown -R appuser:appuser /my-data USER appuser
这种方式从镜像层面提前做好权限配置,避免容器启动时的权限冲突问题。
补充说明
你配置的fsGroupChangePolicy: "Always"虽然生效,但对于hostpath这类本地存储,Kubernetes不会自动递归修改已有root权限目录的归属,因此初始化容器是最直接的临时解决手段。
内容的提问来源于stack exchange,提问作者fade2black

