Эффективное использование Composer и Docker для PHP-проектов

Раздел: DevOps -> Управление зависимостями

Управление зависимостями PHP с Composer в Docker

Организация работы Composer внутри контейнеров Docker требует выбора подхода, который балансирует между производительностью сборки, размером образа и удобством разработки. Рассмотрим несколько вариантов, от самого эффективного для продакшена до гибких решений для локальной разработки.

Как обеспечить минимальный размер продакшен-образа и быструю сборку с Composer?

Наиболее эффективный метод - использование multi-stage сборки. На первом этапе (builder) устанавливаются все зависимости Composer, на втором - копируется только папка vendor в финальный образ. Это исключает наличие инструментов сборки (PHP, Composer) в конечном контейнере.

# Dockerfile
FROM php:8.2-cli AS builder
WORKDIR /app
RUN apt-get update && apt-get install -y unzip git \
    && docker-php-ext-install pdo_mysql
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY composer.json composer.lock ./
RUN composer install --no-dev --prefer-dist --no-scripts --no-progress --optimize-autoloader

FROM php:8.2-fpm-alpine
WORKDIR /app
COPY --from=builder /app/vendor ./vendor
COPY . .
RUN docker-php-ext-install pdo_mysql
USER www-data
CMD ["php-fpm"]

Docker php composer (composer в docker php)

Пояснение шагов:

  • На этапе builder используется образ php:8.2-cli с необходимыми расширениями.
  • Composer добавляется из официального образа composer:latest - это избавляет от ручной установки.
  • Копируются только composer.json и composer.lock, что позволяет использовать кэш Docker для зависимостей при неизменности файлов.
  • composer install выполняется с флагами --no-dev (без dev-зависимостей), --prefer-dist (скачивание архивов), --optimize-autoloader (улучшение автозагрузки).
  • Финальный образ на базе Alpine - лёгкий и безопасный.

Типичная ошибка: при запуске контейнера возникает ошибка прав доступа к файлам внутри vendor (например, при записи логов).

Решение: в финальном образе установить пользователя www-data и скопировать файлы с соответствующими правами. Иногда требуется скопировать vendor с сохранением владельца или выполнить chown в entrypoint.

Как быстро настроить образ для разработки с Composer внутри?

Если требуется часто выполнять composer update или устанавливать пакеты в процессе разработки, удобно установить Composer непосредственно в рабочий образ. Это увеличивает размер образа, но упрощает работу.

FROM php:8.2-fpm
RUN apt-get update && apt-get install -y unzip git \
    && docker-php-ext-install pdo_mysql \
    && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
    && composer --version
WORKDIR /app
COPY . .
RUN composer install --no-interaction

Autoload php composer (автозагрузка классов с помощью composer в php)

Проблема: каждый раз при изменении исходного кода или composer.json происходит повторная установка всех зависимостей (если не используется кэширование слоёв).

Распространённая ошибка: отсутствие расширения zip или git приводит к сбою установки Composer.

Решение: явно устанавливать unzip и git перед запуском инсталлятора.

Как использовать официальный образ Composer, не устанавливая его в приложение?

Можно запустить контейнер composer/composer с монтированием проекта и выполнять команды внутри него. Это удобно для одноразовых действий, не требующих постоянного присутствия Composer.

docker run --rm -v $(pwd):/app -w /app composer/composer install --no-dev

Php composer package (управление пакетами composer в php)

Образ содержит только Composer и PHP, поэтому команда выполняется изолированно. Проблема: отсутствие расширений PHP, требуемых проектом, может вызвать ошибки при выполнении скриптов (например, composer scripts).

Ошибка: "The requested PHP extension ext-pdo_mysql * is missing in your system."

Решение: использовать собственный образ на основе composer/composer с доустановкой необходимых расширений через docker-php-ext-install. Либо передавать флаг --ignore-platform-reqs (но это рискованно на проде).

Как организовать управление зависимостями с помощью Docker Compose?

Docker Compose позволяет выделить сервис composer, который будет выполняться при старте проекта или по требованию.

# docker-compose.yml
version: '3'
services:
  app:
    image: php:8.2-fpm-alpine
    volumes:
      - .:/app
    working_dir: /app
  composer:
    image: composer:latest
    volumes:
      - .:/app
    working_dir: /app
    command: install --no-dev

Composer php 8.1 (установка composer для php 8.1)

Запуск: docker-compose run composer update. Это позволяет не менять Dockerfile и использовать один и тот же образ Composer для разных проектов.

Проблема: при использовании volumes на Windows возможны проблемы с правами доступа (файлы создаются от root).

Решение: задать переменную окружения COMPOSER_HOME и смонтировать папку для кэша, либо использовать файл .env с настройками пользователя.

Как выполнять команды Composer без изменения Dockerfile, используя volume?

Можно смонтировать локальную директорию проекта в контейнер с установленным Composer (например, на основе образа php:8.2-cli с Composer) и выполнить команду.

docker run --rm -v /path/to/project:/app -w /app php:8.2-cli bash -c "
  curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer &&
  composer install"

Этот метод подходит для CI/CD или разовых операций, но неудобен для регулярного использования из-за повторной установки Composer каждый раз.

Ошибка: при монтировании проекта права на vendor могут не совпадать с пользователем внутри контейнера.

Решение: использовать флаг --user (например, --user $(id -u):$(id -g)) или выполнять chown после установки.

Выбор подхода зависит от целей: для продакшена предпочтителен multi-stage, для разработки - установка Composer в образ или использование Docker Compose, для разовых задач - официальный контейнер Composer.

- Vendor php (директория vendor в php (composer))
- Composer php (composer менеджер зависимостей php)
- удалить php (удаление php)

Расширенные примеры использования Composer в Docker

Multi-stage с кэшированием Composer через BuildKit

Использование BuildKit позволяет кэшировать установленные пакеты Composer между сборками, даже если изменился код приложения, но не файл composer.lock. Для этого нужно передать флаг --mount=type=cache.

Пример
# syntax=docker/dockerfile:experimental
FROM php:8.2-cli AS builder
WORKDIR /app
RUN apt-get update && apt-get install -y unzip git \
    && docker-php-ext-install pdo_mysql
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY composer.json composer.lock ./
RUN --mount=type=cache,target=/root/.composer/cache \
    composer install --no-dev --prefer-dist --no-scripts --optimize-autoloader

FROM php:8.2-fpm-alpine
WORKDIR /app
COPY --from=builder /app/vendor ./vendor
COPY . .
CMD ["php-fpm"]
Результат: при повторной сборке без изменений composer.lock кэш не будет перезагружен, что сокращает время сборки на 50-80%.

Авторизация для частных репозиториев через auth.json

Для доступа к приватным пакетам (например, на Satis или Private Packagist) необходимо передать аутентификационные данные. Лучший способ - создать файл auth.json в корне проекта и скопировать его в builder.

Пример
# auth.json (не добавлять в git, использовать секреты CI)
{
    "http-basic": {
        "repo.example.com": {
            "username": "token",
            "password": "abc123"
        }
    }
}

# Dockerfile
COPY auth.json /app/auth.json
RUN composer install --no-dev
Результат: Composer использует учётные данные для доступа к защищённым репозиториям, не раскрывая их в образе (если удалить auth.json после установки).

Важно: на продакшене удалять auth.json из финального образа, чтобы не хранить пароли.

Оптимизация автозагрузчика и использование Horde/Parallel

Для ускорения установки зависимостей можно включить параллельную загрузку пакетов. В Composer 2 это уже включено, но в Docker можно дополнительно кэшировать пакеты.

Пример
# composer.json (пример дополнительных настроек)
{
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true
    }
}

# Команда установки с кэшированием через volume
RUN --mount=type=cache,target=/root/.composer/cache \
    composer install --no-dev --no-interaction --no-progress --optimize-autoloader --apcu-autoloader
Результат: автозагрузчик кэшируется в APCu (если расширение установлено), что повышает производительность приложения.

Интеграция с GitLab CI: параллельные сборки с Composer

В CI/CD удобно использовать слой кэширования Docker и отдельный этап для Composer. Пример .gitlab-ci.yml с кэшированием vendor.

Пример
stages:
  - build
  - test

variables:
  DOCKER_DRIVER: overlay2
  CACHE_FALLBACK_KEY: master

build:
  stage: build
  image: docker:20
  services:
    - docker:dind
  script:
    - docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - vendor/
    policy: pull-push

test:
  stage: test
  image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  script:
    - vendor/bin/phpunit
Результат: кэш папки vendor сохраняется между сборками, что ускоряет pipeline.

Передача SSH-ключей для доступа к Git-репозиториям

Если зависимости хранятся в приватных Git-репозиториях, можно монтировать SSH-агент или ключи во время сборки.

Пример
# Dockerfile (строится с использованием docker build --ssh)
# syntax=docker/dockerfile:1
FROM php:8.2-cli AS builder
RUN apt-get update && apt-get install -y git openssh-client
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
COPY composer.* ./
RUN --mount=type=ssh \
    composer install --no-dev --prefer-dist
Выполнение сборки: DOCKER_BUILDKIT=1 docker build --ssh default . Ключи не остаются в образе.

Установка Composer в Alpine образ с минимальным набором расширений

Для ультралегких образов (например, php:8.2-cli-alpine) нужно самостоятельно устанавливать Composer, так как официальный образ Composer может быть несовместим с отсутствующими библиотеками.

Пример
FROM php:8.2-cli-alpine
RUN apk add --no-cache git unzip openssh \
    && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
    && composer --version
WORKDIR /app
COPY . .
RUN composer install
Результат: образ размером около 150 МБ (без Alpine ещё меньше).

Эти примеры охватывают большинство сценариев использования Composer в Docker: от базового до продвинутого с кэшированием и безопасностью.

Composer в Docker PHP - comments

En
Docker php composer (php)