You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在k3s中以非root用户app挂载Kubernetes卷部署Django项目的问题

在k3s中以非root用户app挂载Kubernetes卷部署Django项目的问题

看起来你已经把Django镜像的非root用户配置做得有模有样了!不过在k3s里部署的时候,最容易踩坑的就是卷挂载后的权限问题——毕竟Kubernetes默认创建的卷目录权限都是root:root,你的app用户根本没权限读写,轻则静态文件加载失败,重则连媒体文件上传都搞不定。我来给你一步步梳理解决思路,都是实战里踩过坑的经验:

先把你没写完的Dockerfile补全(确保镜像本身没问题)

咱先把你中断的Dockerfile补成生产环境可用的版本,重点加上完整的依赖安装、代码复制和启动配置:

###########
# BUILDER #
###########

# pull official base image
FROM python:3.11-slim AS builder

# set work directory
WORKDIR /usr/src/app

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# install python dependencies
COPY ./requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt


#########
# FINAL #
#########

# pull official base image
FROM python:3.11-slim

# create directory for the app user
RUN mkdir -p /home/app

# create the app user
RUN addgroup --system app && adduser --system --group app

# create the appropriate directories
ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir $APP_HOME
RUN mkdir $APP_HOME/static
RUN mkdir $APP_HOME/media  # 要是你的Django用到媒体文件上传,一定要加这个
WORKDIR $APP_HOME

# install dependencies
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /usr/src/app/requirements.txt .
RUN pip install --upgrade pip
RUN pip install --no-cache-dir /wheels/*

# copy project files
COPY . $APP_HOME

# change to the app user
USER app

# 启动命令(根据你的Django部署方式调整,这里用gunicorn示例)
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "config.wsgi:application"]

核心问题解决:卷挂载的权限处理

当你在k3s里用PersistentVolumeClaim(PVC)挂载到/home/app/web/static或者/home/app/web/media时,默认PVC的目录权限是root:root,app用户碰都碰不了。给你两个靠谱的解决办法:

方法1:在Dockerfile里提前锁死目录权限

在创建完静态/媒体目录后,直接把目录的所属用户改成app,这样即使卷挂载覆盖了目录,至少基础权限是对的:

RUN mkdir $APP_HOME/static
RUN mkdir $APP_HOME/media
RUN chown -R app:app $APP_HOME/static $APP_HOME/media  # 新增这行,把权限给app用户

不过这个方法有个小缺点:如果你的PVC是从外部存储挂载的(比如NFS),那外部存储的权限还是会覆盖这个设置,所以更适合用emptyDir或者本地存储的场景。

方法2:在Kubernetes Deployment里用securityContext兜底(生产环境首推)

在Deployment的Pod模板里加上securityContext,指定运行用户为app的UID,同时设置fsGroup——这个参数会让K8s自动调整挂载卷的目录权限,让app用户能正常读写,简直是救星:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: django-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: django
  template:
    metadata:
      labels:
        app: django
    spec:
      # 重点是这里的securityContext配置
      securityContext:
        runAsUser: 1000  # 这里要填app用户的UID,你可以用`docker run --rm 你的镜像名 id -u app`查询
        runAsGroup: 1000  # 对应app用户组的GID,同样用上面的命令查询
        fsGroup: 1000  # 自动把挂载卷的组权限改成app用户组,解决读写问题
      containers:
      - name: django
        image: 你的Django镜像名:标签
        ports:
        - containerPort: 8000
        volumeMounts:
        - name: static-volume
          mountPath: /home/app/web/static
        - name: media-volume
          mountPath: /home/app/web/media
      volumes:
      - name: static-volume
        persistentVolumeClaim:
          claimName: django-static-pvc  # 提前创建好的PVC
      - name: media-volume
        persistentVolumeClaim:
          claimName: django-media-pvc  # 提前创建好的PVC

这个方法不管你用什么存储类(k3s默认的local-path-provisioner也没问题),都能自动修正权限,稳得一批。

k3s特有的小细节要注意

  • k3s默认用local-path-provisioner提供PVC,创建的目录在节点的/var/lib/rancher/k3s/storage下,权限是root,但上面的fsGroup设置会自动把这个权限修正,不用手动改节点上的目录。
  • 要是你需要把静态文件收集到挂载的卷里,生产环境建议在构建镜像时就做好collectstatic,或者用单独的K8s Job来执行这个操作;要是图省事,也可以在启动命令里加一步:
command: ["/bin/sh", "-c"]
args: ["python manage.py collectstatic --noinput && gunicorn --bind 0.0.0.0:8000 config.wsgi:application"]

不过要确保app用户有权限写入static目录哦。

踩坑排查小技巧

  • 要是启动后Django报“Permission denied”,先进Pod查目录权限:kubectl exec -it <你的Pod名> -- ls -l /home/app/web/static,看看是不是app用户有读写权限。
  • 要是镜像允许的话,你可以切换到root用户查详情:kubectl exec -it <你的Pod名> -- su - root,然后用ls -ld /home/app/web/static看权限。
  • 一定要确认app用户的UID/GID和Deployment里的securityContext设置一致:kubectl exec -it <你的Pod名> -- id app

备注:内容来源于stack exchange,提问作者Viktor

火山引擎 最新活动