Монтирование тома Kubernetes от имени непривилегированного пользователя

Вопрос или проблема

Я пытаюсь развернуть проект 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 для изменения прав доступа является самым надежным способом решения вашей проблемы. Это гарантирует, что перед запуском вашего основного приложения все необходимые права уже установлены, и вы избежите ошибок с правами доступа на этапе выполнения.

Убедитесь также, что вы тестируете эти изменения в тестовой среде перед развертыванием в продакшн.

Оцените материал
Добавить комментарий

Капча загружается...