Почему один Docker-контейнер не может получить доступ к файлу, созданному другим контейном, и как это исправить?
У меня есть два Docker-контейнера: horizon и php-fpm. Когда контейнер horizon создает лог-файл (например, laravel-2025-10-08.log) со своими правами доступа, контейнер php-fpm не может получить к нему доступ или записывать в него. Как настроить контейнеры для корректного обмена файлами?
Примеры прав доступа:
- Для файла laravel-2025-10-08-1.log (скопированного): -rw-r–r-- 1 root root 1637496 Oct 8 08:59
- Для файла laravel-2025-10-08.log: -rw-r–r-- 1 1000 1000 49113 Oct 8 08:59
Как обеспечить совместный доступ к файлам между контейнерами с разными пользователями?
Основная проблема совместного доступа к файлам между Docker-контейнерами возникает из-за разных идентификаторов пользователей и групп (UID/GID), под которыми работают контейнеры. Когда один контейнер создает файл со своими правами доступа, другой контейнер не может получить к нему доступ, так как его пользователь не имеет необходимых разрешений на чтение или запись.
Содержание
- Основная проблема прав доступа в Docker
- Решение через сопоставление UID/GID
- Настройка Dockerfile для общего пользователя
- Конфигурация docker-compose.yml
- Автоматизация исправления прав
- Практические примеры для Laravel
- Лучшие практики
Основная проблема прав доступа в Docker
Когда два Docker-контейнера обращаются к одной и той же общей папке (volume), они создают файлы под своими собственными пользователями. Это приводит к ситуации, где один контейнер может создать файл, а другой получает ошибку “Permission denied” при попытке доступа к нему.
Почему это происходит:
- Разные UID/GID: Каждый контейнер имеет своего пользователя по умолчанию с уникальным идентификатором пользователя (UID) и группы (GID)
- Различные права доступа: Файлы создаются с правами, соответствующими пользователю контейнера
- Несовместимость: Пользователь из одного контейнера не имеет прав на файлы, созданные пользователем из другого контейнера
Пример из вашего случая:
- Файл
laravel-2025-10-08-1.logсоздан пользователемroot(UID 0, GID 0)- Файл
laravel-2025-10-08.logсоздан пользователем с UID 1000, GID 1000- Контейнер php-fpm, работающий под другим пользователем, не может получить доступ к этим файлам
Решение через сопоставление UID/GID
Самый надежный способ решения проблемы — обеспечить, чтобы оба контейнера использовали одинаковые UID/GID для доступа к общим файлам.
Шаг 1: Определение UID/GID на хост-системе
Сначала определите UID и вашей основной группы на хост-системе:
id -u # Показывает ваш текущий UID
id -g # Показывает GID вашей основной группы
Шаг 2: Настройка контейнеров с одинаковыми UID/GID
Модифицируйте ваши Dockerfile для обоих контейнеров (horizon и php-fpm), чтобы они использовали одинаковые UID/GID:
# В Dockerfile для horizon
RUN groupadd -g 1000 laravel && \
useradd -u 1000 -g laravel -s /bin/sh -m laravel
USER laravel
# В Dockerfile для php-fpm
RUN groupadd -g 1000 laravel && \
useradd -u 1000 -g laravel -s /bin/sh -m laravel
USER laravel
Шаг 3: Проверка прав доступа
После настройки обоих контейнеров с одинаковыми UID/GID, файлы, созданные в одном контейнере, будут доступны в другом:
# Проверка прав доступа в контейнере
ls -la /path/to/shared/files
Настройка Dockerfile для общего пользователя
Для Laravel-приложений с php-fpm и horizon рекомендуется создать общего пользователя в Dockerfile.
Пример Dockerfile для php-fpm:
FROM php:8.2-fpm
# Установка зависимостей
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
# Установка PHP расширений
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath
# Создание пользователя с указанием UID/GID
RUN groupadd -g 1000 laravel && \
useradd -u 1000 -g laravel -s /bin/sh -m laravel
# Установка правильных прав для /var/www
RUN chown -R laravel:laravel /var/www && \
chmod -R 755 /var/www
USER laravel
WORKDIR /var/www
Пример Dockerfile для horizon:
FROM php:8.2-cli
# Установка зависимостей
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
# Установка PHP расширений
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath
# Создание того же пользователя
RUN groupadd -g 1000 laravel && \
useradd -u 1000 -g laravel -s /bin/sh -m laravel
# Установка правильных прав для /var/www
RUN chown -R laravel:laravel /var/www && \
chmod -R 755 /var/www
USER laravel
WORKDIR /var/www
Конфигурация docker-compose.yml
В файле docker-compose.yml можно указать пользователя для каждого сервиса:
version: '3.8'
services:
php-fpm:
build:
context: .
dockerfile: docker/php/Dockerfile
container_name: app-php
user: '1000:1000' # Указываем UID/GID
volumes:
- ./:/var/www
networks:
- app-network
horizon:
build:
context: .
dockerfile: docker/horizon/Dockerfile
container_name: app-horizon
user: '1000:1000' # Тот же UID/GID
volumes:
- ./:/var/www
depends_on:
- php-fpm
networks:
- app-network
networks:
app-network:
driver: bridge
Важно: Убедитесь, что UID/GID в docker-compose.yml соответствуют тем, что вы использовали в Dockerfile и на хост-системе.
Автоматизация исправления прав
Если вы не хотите изменять UID/GID контейнеров, можно использовать скрипты для исправления прав доступа.
Скрипт для исправления прав:
#!/bin/bash
# fix-permissions.sh
# Путь к общей директории
PROJECT_DIR="."
# UID и GID вашего пользователя на хосте
HOST_UID=$(id -u)
HOST_GID=$(id -g)
# Установка правильных прав
sudo chown -R ${HOST_UID}:${HOST_GID} ${PROJECT_DIR}
sudo find ${PROJECT_DIR} -type d -exec chmod 755 {} \;
sudo find ${PROJECT_DIR} -type f -exec chmod 644 {} \;
# Распространение прав на storage и bootstrap/cache
sudo chmod -R 775 ${PROJECT_DIR}/storage
sudo chmod -R 775 ${PROJECT_DIR}/bootstrap/cache
Использование в docker-compose.yml:
services:
php-fpm:
# ... другие настройки
volumes:
- ./:/var/www
# Запуск скрипта исправления прав при старте
entrypoint: ["./fix-permissions.sh"]
command: ["php-fpm"]
Практические примеры для Laravel
Пример конфигурации для Laravel с php-fpm:
services:
php-fpm:
image: php:8.2-fpm
container_name: app-php
user: 'www-data:www-data' # Стандартный пользователь php-fpm
volumes:
- ./:/var/www
working_dir: /var/www
environment:
- APP_ENV=local
entrypoint: ["/bin/sh", "-c", "chown -R www-data:www-data /var/www/storage && exec docker-php-entrypoint php-fpm"]
Пример конфигурации для Horizon:
services:
horizon:
build:
context: .
dockerfile: docker/horizon/Dockerfile
container_name: app-horizon
user: 'www-data:www-data' # Тот же пользователь
volumes:
- ./:/var/www
working_dir: /var/www
command: ["php", "artisan", "horizon"]
depends_on:
- php-fpm
Использование переменных для UID/GID:
services:
php-fpm:
user: "${UID}:${GID}"
environment:
- UID=${UID}
- GID=${GID}
Лучшие практики
1. Используйте одинаковые UID/GID для всех контейнеров
Это самый надежный способ избежать проблем с правами доступа:
# В обоих Dockerfile
RUN groupadd -g 1000 appuser && \
useradd -u 1000 -g appuser -s /bin/sh -m appuser
USER appuser
2. Используйте .env файл для управления UID/GID
Создайте .env файл в корне проекта:
UID=1000
GID=1000
И используйте его в docker-compose.yml:
services:
php-fpm:
user: "${UID}:${GID}"
3. Настройте правильные права для Laravel
Убедитесь, что директории storage и bootstrap/cache имеют правильные права:
chmod -R 775 storage
chmod -R 775 bootstrap/cache
4. Используйте volume с правильными опциями
В docker-compose.yml можно указать режим доступа для volume:
volumes:
- ./:/var/www:rw,cached
5. Регулярно проверяйте права доступа
Добавьте в ваш процесс разработки проверку прав:
# Скрипт проверки
find . -type f -not -user ${UID} -exec echo "Файл {} имеет неправильного владельца" \;
find . -type d -not -group ${GID} -exec echo "Директория {} имеет неправильную группу" \;
Заключение
Проблема совместного доступа к файлам между Docker-контейнерами решается несколькими способами:
- Основное решение - сопоставление UID/GID между контейнерами и хост-системой
- Настройка Dockerfile - создание общего пользователя для обоих контейнеров
- Конфигурация docker-compose.yml - указание одинаковых пользователей для сервисов
- Автоматизация исправления прав - использование скриптов для установки правильных прав доступа
Для вашей конкретной ситуации с контейнерами horizon и php-fpm в Laravel-приложении рекомендуется:
- Создать в обоих Dockerfile пользователя с одинаковым UID/GID (например, 1000:1000)
- Указать этого пользователя в docker-compose.yml для обоих сервисов
- Убедиться, что директории
storageиbootstrap/cacheимеют права 775 - Использовать переменные окружения для управления UID/GID в разных средах
Эти меры обеспечат корректный обмен файлами между контейнерами и предотвратят ошибки “Permission denied”.
Источники
- Avoiding Permission Issues With Docker-Created Files
- Permission denied on accessing host directory in Docker - Stack Overflow
- What is the (best) way to manage permissions for Docker shared volumes? - Stack Overflow
- Fixing permissions issues with Docker Compose and PHP
- Understanding file permissions - Docker PHP - Server Side Up
- Solve Permission Denied error while using a dockerized PHP environment
- File permissions when developing with Docker - Nicholas Tsim