You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 01:17:07