Вопрос или проблема
Я пытаюсь развернуть проект Django на k3s. Я собираю свой образ для запуска от имени пользователя app
:
###########
# СТРРОИТЕЛЬ #
###########
# загружаем официальный базовый образ
FROM python:3.11-slim AS builder
# устанавливаем рабочую директорию
WORKDIR /usr/src/app
# устанавливаем переменные окружения
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# устанавливаем зависимости Python
COPY ./requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt
#########
# ФИНАЛ #
#########
# загружаем официальный базовый образ
FROM python:3.11-slim
# создаем директорию для пользователя приложения
RUN mkdir -p /home/app
# создаем пользователя приложения
RUN addgroup --system app && adduser --system --group app
# создаем соответствующие директории
ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir $APP_HOME
RUN mkdir $APP_HOME/static
WORKDIR $APP_HOME
# устанавливаем зависимости
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 /wheels/*
# копируем проект
COPY . $APP_HOME
# изменяем владельца всех файлов на пользователя приложения
RUN chown -R app:app $APP_HOME
# переключаемся на пользователя приложения
USER app
EXPOSE 8000
CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "myapp.wsgi"]
Я хочу примонтировать папку со статическими файлами к постоянному тому. Но когда я запускаю развертывание, папка /home/app/web/static
принадлежит root:root
. Что я делаю не так?
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-deploy
namespace: myapp
labels:
app: myapp
spec:
replicas: 2
template:
metadata:
labels:
app: myapp
type: backend
spec:
securityContext:
runAsUser: 100
runAsGroup: 101
fsGroup: 2000
volumes:
- name: staticfiles
persistentVolumeClaim:
claimName: static-pvc
containers:
- name: backend-pod
image: myapp-backend-arm64:1.0
imagePullPolicy: Always
envFrom:
- secretRef:
name: backend-secret
- configMapRef:
name: backend-cm
ports:
- containerPort: 8000
volumeMounts:
- mountPath: "/home/app/web/static"
name: staticfiles
selector:
matchLabels:
app: myapp
type: backend
app@backend-deploy-7595c5d447-z9ztz:~/web$ id
uid=100(app) gid=101(app) groups=101(app),2000
app@backend-deploy-7595c5d447-z9ztz:~/web$ ls -la
total 48
drwxr-xr-x 1 app app 4096 Sep 26 16:04 .
drwxr-xr-x 1 root root 4096 Sep 25 20:00 ..
-rw-r--r-- 1 app app 1375 Sep 26 15:54 Dockerfile
-rwxr-xr-x 1 app app 662 Sep 25 19:07 manage.py
-rw-r--r-- 1 app app 58 Sep 25 19:07 requirements.txt
drwxr-xr-x 1 app app 4096 Sep 26 17:06 myapp
drwxr-xr-x 2 root root 0 Sep 26 14:11 static
Ответ или решение
Ваша проблема заключается в том, что при монтировании постоянного тома Kubernetes (Persistent Volume) для статических файлов, этот том создается с правами доступа по умолчанию, которые, скорее всего, устанавливаются на пользователя root. Это приводит к тому, что когда пользователь app
(UID 100) пытается получить доступ к директории /home/app/web/static
, он видит, что ее владелец — root, и таким образом не имеет прав для записи в эту директорию.
Чтобы решить эту проблему, необходимо установить правильные права доступа к вашей директории static
на момент создания или монтирования Persistent Volume. Вы можете использовать несколько подходов для этого:
Решение 1: Использование Init Containers
Вы можете использовать Init Container для настройки прав доступа к директории перед запуском основного контейнера. Пример использования Init Container:
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-deploy
namespace: myapp
spec:
replicas: 2
template:
metadata:
labels:
app: myapp
type: backend
spec:
securityContext:
runAsUser: 100
runAsGroup: 101
fsGroup: 2000
volumes:
- name: staticfiles
persistentVolumeClaim:
claimName: static-pvc
initContainers:
- name: init-static-permissions
image: busybox
command: ['sh', '-c', 'chown -R 100:101 /mnt/static']
volumeMounts:
- name: staticfiles
mountPath: /mnt/static
containers:
- name: backend-pod
image: myapp-backend-arm64:1.0
imagePullPolicy: Always
envFrom:
- secretRef:
name: backend-secret
- configMapRef:
name: backend-cm
ports:
- containerPort: 8000
volumeMounts:
- mountPath: "/home/app/web/static"
name: staticfiles
selector:
matchLabels:
app: myapp
type: backend
Этот Init Container выполнит команду chown
, чтобы изменить владельца и группу директории на app:app
до того, как основной контейнер будет запущен.
Решение 2: Настройка прав на уровне Persistent Volume
Если вы используете файлы на диске, возможно, вам нужно будет изменить набор прав на доступ к этому Persistent Volume на момент его создания. Если вы управляете Persistent Volume (PV) и Persistent Volume Claim (PVC) вручную, попробуйте изменить спецификацию, чтобы явно установить нужные права доступа к каталогам.
Решение 3: Использование fsGroup
в securityContext
Вы уже указываете fsGroup: 2000
в вашем конфигурационном файле. Убедитесь, что UID и GID соответствуют пользователю app
(проверить соответственно в контейнере). fsGroup
устанавливает группу, к которой будет принадлежать все файлы при монтировании, но это не всегда работает с некоторыми типами хранилищ (например, NFS или другим внешним хранилищем). Убедитесь сами, что ваша установка поддерживает это.
Итог
Использование Init Container для изменения прав доступа является самым надежным способом решения вашей проблемы. Это гарантирует, что перед запуском вашего основного приложения все необходимые права уже установлены, и вы избежите ошибок с правами доступа на этапе выполнения.
Убедитесь также, что вы тестируете эти изменения в тестовой среде перед развертыванием в продакшн.