НейроАгент

Разрешение проблем доступа к файлам между Docker-контейнерами

Решение проблемы доступа к файлам между Docker-контейнерами с разными UID/GID. Настройка прав доступа для корректного обмена файлами в Laravel-приложениях.

Почему один 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

Когда два 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 и вашей основной группы на хост-системе:

bash
id -u  # Показывает ваш текущий UID
id -g  # Показывает GID вашей основной группы

Шаг 2: Настройка контейнеров с одинаковыми UID/GID

Модифицируйте ваши Dockerfile для обоих контейнеров (horizon и php-fpm), чтобы они использовали одинаковые UID/GID:

dockerfile
# В 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, файлы, созданные в одном контейнере, будут доступны в другом:

bash
# Проверка прав доступа в контейнере
ls -la /path/to/shared/files

Настройка Dockerfile для общего пользователя

Для Laravel-приложений с php-fpm и horizon рекомендуется создать общего пользователя в Dockerfile.

Пример Dockerfile для php-fpm:

dockerfile
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:

dockerfile
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 можно указать пользователя для каждого сервиса:

yaml
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 контейнеров, можно использовать скрипты для исправления прав доступа.

Скрипт для исправления прав:

bash
#!/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:

yaml
services:
  php-fpm:
    # ... другие настройки
    volumes:
      - ./:/var/www
    # Запуск скрипта исправления прав при старте
    entrypoint: ["./fix-permissions.sh"]
    command: ["php-fpm"]

Практические примеры для Laravel

Пример конфигурации для Laravel с php-fpm:

yaml
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:

yaml
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:

yaml
services:
  php-fpm:
    user: "${UID}:${GID}"
    environment:
      - UID=${UID}
      - GID=${GID}

Лучшие практики

1. Используйте одинаковые UID/GID для всех контейнеров

Это самый надежный способ избежать проблем с правами доступа:

dockerfile
# В обоих 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:

yaml
services:
  php-fpm:
    user: "${UID}:${GID}"

3. Настройте правильные права для Laravel

Убедитесь, что директории storage и bootstrap/cache имеют правильные права:

bash
chmod -R 775 storage
chmod -R 775 bootstrap/cache

4. Используйте volume с правильными опциями

В docker-compose.yml можно указать режим доступа для volume:

yaml
volumes:
  - ./:/var/www:rw,cached

5. Регулярно проверяйте права доступа

Добавьте в ваш процесс разработки проверку прав:

bash
# Скрипт проверки
find . -type f -not -user ${UID} -exec echo "Файл {} имеет неправильного владельца" \;
find . -type d -not -group ${GID} -exec echo "Директория {} имеет неправильную группу" \;

Заключение

Проблема совместного доступа к файлам между Docker-контейнерами решается несколькими способами:

  1. Основное решение - сопоставление UID/GID между контейнерами и хост-системой
  2. Настройка Dockerfile - создание общего пользователя для обоих контейнеров
  3. Конфигурация docker-compose.yml - указание одинаковых пользователей для сервисов
  4. Автоматизация исправления прав - использование скриптов для установки правильных прав доступа

Для вашей конкретной ситуации с контейнерами horizon и php-fpm в Laravel-приложении рекомендуется:

  • Создать в обоих Dockerfile пользователя с одинаковым UID/GID (например, 1000:1000)
  • Указать этого пользователя в docker-compose.yml для обоих сервисов
  • Убедиться, что директории storage и bootstrap/cache имеют права 775
  • Использовать переменные окружения для управления UID/GID в разных средах

Эти меры обеспечат корректный обмен файлами между контейнерами и предотвратят ошибки “Permission denied”.

Источники

  1. Avoiding Permission Issues With Docker-Created Files
  2. Permission denied on accessing host directory in Docker - Stack Overflow
  3. What is the (best) way to manage permissions for Docker shared volumes? - Stack Overflow
  4. Fixing permissions issues with Docker Compose and PHP
  5. Understanding file permissions - Docker PHP - Server Side Up
  6. Solve Permission Denied error while using a dockerized PHP environment
  7. File permissions when developing with Docker - Nicholas Tsim