Главная >> Инструкции >> Ошибка Permission Denied в Docker

Ошибка Permission Denied в Docker

Ошибка Permission Denied в Docker Compose может возникнуть по нескольким причинам. Прежде всего и проще всего, у вашего пользователя может не быть прав для взаимодействия с сервисом Docker. Кроме того, поскольку в контейнере находится отдельная файловая система со своими правами и пользователями, если процесс в контейнере пытается получить доступ к файлам в хост-системе, вы тоже получите такую ошибку.

В этой небольшой статье мы рассмотрим, почему может возникнуть ошибка Permission Denied в Docker, а также как её исправить.


Содержание статьи

Как исправить ошибку Permission Denied в Docker

1. Когда нет прав доступа к сервису Docker

Тут все очень просто. Поскольку сервис Docker запущен от имени суперпользователя, с ним могут взаимодействовать только суперпользователь или пользователи, которые находятся в группе docker. Например, вы можете получить ошибку, когда выполняете такую команду:

docker compose up

Во-первых, её можно выполнить с правами суперпользователя:

sudo docker compose up

Или же, вы можете добавить своего пользователя в группу docker:

sudo usermod -aG docker $USER

После этого нужно перелогиниться в системе или в терминале, и всё заработает.

Вы можете проверить, в какие группы добавлен пользователь, с помощью такой команды:

id

2. Доступ к папкам, смонтированным в контейнер из хост-системы

Иногда необходимо иметь доступ к файлам, смонтированным в контейнер из хост-системы. Независимо от того, запущен контейнер от суперпользователя или нет, если пользователь, которому принадлежат файлы в контейнере, и в хост-системе не совпадает, то вы при попытке открыть файл из хост-системы без прав root получите permission denied.

Связи между именами пользователей в контейнере и в хост-системе нет. Но есть связь между их идентификаторами. Например, в хост-системе есть пользователь serhii с идентификатором 1000. В контейнере есть пользователь mysql, который тоже имеет идентификатор 1000. Тогда ядро Linux будет считать, что это один и тот же пользователь, и разрешит serhii из хост-системы доступ к файлам, которые в контейнере принадлежат пользователю mysql.

Итак, для того чтобы все заработало, нужно, чтобы ID пользователя в системе и в Docker контейнере совпадал. Для этого многие контейнеры позволяют задать ID пользователя и его группу с помощью переменных UID и GID или PUID и PGID. Для того чтобы узнать точно, какие переменные использовать, нужно смотреть документацию контейнера, который вам нужно запустить. Например, для lscr.io/linuxserver/mariadb это будет выглядеть так:

services: mariadb: image: "lscr.io/linuxserver/mariadb:latest" restart: "always" volumes: - "./data:/config" environment: PUID: 1000 PGID: 1000 MYSQL_ROOT_PASSWORD: "password" MYSQL_DATABASE: "test_db" MYSQL_USER: "test_user" MYSQL_PASSWORD: "password"

Но это не единственный способ. Большинство официальных контейнеров такого не поддерживают. Поэтому можно изменить пользователя и группу, от имени которой запускается контейнер, на другую с помощью директивы user. Здесь можно указать либо имя пользователя и группы, либо ID. Например:

services: mariadb: user: "1000:1000" image: "mariadb:latest" restart: "always" volumes: - "./data/db:/var/lib/mysql" environment: MYSQL_ROOT_PASSWORD: "password" MYSQL_DATABASE: "test_db" MYSQL_USER: "test_user" MYSQL_PASSWORD: "password"

Аналогично можно изменить пользователя с помощью директивы USER в Dockerfile. Это будет работать так же. Но в обоих случаях папку, которую вы монтируете, нужно создать заранее, потому что если папка не существует, её создаст демон Docker, а он запущен от root. Следовательно, папка будет тоже принадлежать root, и тогда сервис не сможет ничего записать:

mkdir -p data/db docker compose up ls -l data

Но если проблема уже случилась и вы не хотите удалять файлы, в следующем разделе рассмотрим, как исправить.

3. Нет прав на запись в смонтированную папку

Если вы столкнулись с ошибкой permission denied внутри контейнера и вы монтировали в этот контейнер папки из файловой системы, и пользователь, от имени которого выполняется программа в контейнере, не root, то проблема, скорее всего, в этом. Если папка в хост-системе, которую вы хотите смонтировать в контейнер, не существовала до запуска проекта, то Docker её создаст. Но поскольку Docker запущен от root, то папка будет принадлежать root. Если процесс, который выполняется в контейнере, выполняется не от имени root, то доступа к этой папке он иметь не будет.

Давайте рассмотрим это на примере контейнера mariadb. Вот конфигурация, которая запускает сервис в контейнере от имени пользователя mysql и монтирует в него локальную папку data для сохранения файлов базы данных:

vi docker-compose.yaml

services: mariadb: user: "mysql" image: "mariadb:latest" restart: "always" volumes: - "./data/db:/var/lib/mysql" environment: MYSQL_ROOT_PASSWORD: "password" MYSQL_DATABASE: "test_db" MYSQL_USER: "test_user" MYSQL_PASSWORD: "password"

Если мы запустим контейнер в таком виде, но не создадим папок, то возникнет вот такая ошибка:

И вот почему: процесс mysql принадлежит пользователю mysql, но смонтированная папка доступна для записи только root:

ls -l ./

Для того чтобы исправить проблему, нужно либо поменять права на папку, либо использовать root внутри контейнера, как было по умолчанию, убрав директиву user. Для того чтобы проверить ID пользователя в контейнере, можно запустить контейнер с помощью команды run:

docker compose run --rm mariadb bash id

Тут видим, что контейнер выполняется от имени пользователя mysql, и этот пользователь имеет ID 999. Поэтому мы можем выполнить такую команду, чтобы исправить права на папку:

sudo chown -R 999:999 ./data

И после этого можно запускать MySQL в контейнере не от root, и всё будет работать. Я специально в этом примере выбрал пользователя mysql, который есть в контейнере, чтобы статья была проще для восприятия. Если бы мы настроили пользователя с ID 1000:1000, всё тоже работало бы аналогично. Но поскольку такого пользователя в контейнере нет, то команда id и другие показывали бы много ошибок. Если вам нужно, чтобы ID пользователя в системе и в контейнере совпадал и нужно работать в терминале контейнера, то лучше контейнер перепаковать и заменить ID пользователя mysql в Dockerfile на нужный:

vi mariadb/Dockerfile

FROM mariadb:latest ARG USER_ID=1000 ARG GROUP_ID=1000 RUN usermod -u ${USER_ID} mysql RUN groupmod -g ${GROUP_ID} mysql USER mysql

Теперь используем новый образ в docker-compose:

vi docker-compose.yaml

services: mariadb: build: context: "./mariadb" restart: "always" volumes: - "./data/db:/var/lib/mysql" environment: MYSQL_ROOT_PASSWORD: "password" MYSQL_DATABASE: "test_db" MYSQL_USER: "test_user" MYSQL_PASSWORD: "password"

Тогда каталог с базой данных тоже будет выглядеть вот так:

Выводы

В этой статье мы рассмотрели, почему может возникнуть ошибка Permission Denied в Docker при использовании Docker Compose, а также как её исправить. В целом это типичная проблема Docker, вызванная тем, что демон Docker и контейнеры запускаются от root. Предполагается, что и процессы в контейнерах должны запускаться от root. А когда вы начинаете пытаться запускать их от имени обычного пользователя, начинаются проблемы с правами.

Оставьте свой Email для того чтобы получать анонсы новых статей и полезную информацию о Linux по электронной почте
Поделиться

Оставьте комментарий