Головна » Інструкції » Помилка 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 електронною поштою
Поширити

Залишити коментар