Как в Dockerfile сменить пользователя для выполнения команд внутри контейнера?

«Как в Dockerfile сменить пользователя для выполнения команд внутри контейнера?» — вопрос из категории Docker, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, для этого используется инструкция USER. Это критически важная практика безопасности, чтобы контейнер не работал от имени root по умолчанию.

Базовый пример:

FROM alpine:latest

# 1. Создаем непривилегированного пользователя и группу
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# 2. Копируем файлы приложения от имени root (у root есть права на запись)
COPY --chown=appuser:appgroup ./app /home/appuser/app
WORKDIR /home/appuser/app

# 3. Меняем пользователя на непривилегированного
USER appuser

# 4. Все последующие инструкции (RUN, CMD, ENTRYPOINT) будут выполняться от имени appuser
CMD ["python", "app.py"]

Ключевые моменты и лучшие практики:

  1. Порядок инструкций: Инструкции, требующие прав на запись (например, COPY, RUN для установки пакетов), должны выполняться до USER. После USER контейнер переходит в непривилегированный режим.
  2. Указание UID/GID: Для лучшей совместимости и контроля прав в Kubernetes лучше явно указывать числовые UID/GID. Это гарантирует, что пользователь будет одинаковым, даже если его имени нет в /etc/passwd внутри контейнера.
    RUN addgroup -g 1001 appgroup && adduser -u 1001 -G appgroup -S appuser
    USER 1001:1001
  3. Работа с volumes: Если смонтированный volume (том) создан от имени root на хосте, непривилегированный пользователь внутри контейнера не сможет в него писать. Решаю это либо правильной настройкой прав на хосте, либо использованием docker run --user для переопределения пользователя при запуске, либо инициализацией прав в entrypoint-скрипте.
  4. Проверка: После сборки образа можно проверить, от какого пользователя запускается процесс по умолчанию:
    docker run --rm my-image id  # Выведет uid=1001(appuser) gid=1001(appgroup)

Исключения: Некоторые официальные образы (например, nginx) уже содержат непривилегированного пользователя (например, nginx). В таких случаях можно просто указать USER nginx без предварительного создания.