Задача этого материала — максимально предметно показать, как подготовить образ Docker с PHP Composer. Также мы будем делать multi-stage-билды. Конфигурации могут быть разными, поэтому посмотрим на общую концепцию и несколько примеров, а для закрепления создадим на практике приложение на Laravel, работающее в трех служебных контейнерах. Это практический how-to — здесь минимум теории, но максимум пошаговых инструкций, поэтому открываем свои системные терминалы и погнали следом за мной.
Содержание:
1. Что такое PHP Composer
2. Установка Composer
3. Docker multi-stage билд
4. Репозитории в composer.json
5. Composer user
6. Пример проекта на Laravel
Заключение
Composer — инструмент для установки библиотек при разработке проектов на PHP. Его аналоги в других языках — npm для Node.js, pip для Python и другие. Все они используются для того, чтобы разворачивать проекты вместе с зависимостями.
Необходимые для установки зависимости и их версии указываются в специальном файле. В случае с Composer это composer.json.
Чтобы установить Composer на Linux, запустите терминал и выполните команду:
curl -s https://getcomposer.org/installer | php
Затем проверьте тип файла:
file composer.phar
Убедитесь, что Composer работает:
php composer.phar
В выводе отобразится версия, а также рекомендации по использованию и справка.
Перенесите Composer в /usr/local/bin:
sudo mv composer.phar /usr/local/bin/composer sudo chmod +x /usr/local/bin/composer
Теперь создайте тестовый проект и переключитесь в папку с ним:
mkdir ~/Scripts/PHP/ComposerTest cd ~/Scripts/PHP/ComposerTest/
Можно начинать добавление зависимостей. Допустим, в этом проекте используется микрофреймворк Slim. Чтобы разворачивать его, нужно добавить зависимость в composer.json:
{
"require": {
"slim/slim": "2.*"
}
}
Запустите установку Composer:
composer install
Проверьте каталог vendor. Это дефолтная директория для Composer:
tree vendor/
Output:
vendor/
├── autoload.php
├── composer
│ ├── autoload_classmap.php
│ ├── autoload_namespaces.php
│ ├── autoload_psr4.php
│ ├── autoload_real.php
│ ├── autoload_static.php
│ ├── ClassLoader.php
│ ├── installed.json
│ └── LICENSE
└── slim
└── slim
├── composer.json
├── CONTRIBUTING.md
├── index.php
├── LICENSE
├── phpunit.xml.dist
├── README.markdown
├── Slim
│ ├── Environment.php
│ ├── Exception
...
Внутри — Composer и микрофреймворк Slim, который вы указали в списке зависимостей проекта.
Следующая задача — сборка Docker-образа, в котором будут PHP и Composer. Используйте для этого multi-stage builds, которые появились в Dicker 17.05. Подробнее о них вы можете узнать из документации.
Схема развертывания будет такой:
phar-файл.Внутри Dockerfile должно быть так:
FROM composer:latest AS composer FROM php:7.2.3 COPY --from=composer /usr/bin/composer /usr/bin/composer RUN composer --version && php --v
В первой строке вы задаете имя, на которое затем ссылаетесь в третьей строке при копировании.
Соберите образ:
docker build -t php-composer:1.0 .
Чтобы убедиться, что все работает, проверьте версию:
docker run -ti php-composer:1.0 --version
В качестве практики установите библиотеку, используя собранный образ. Для примера возьмем geoip2.
Обновите файл composer.json. Добавьте в него ссылку на репозиторий, из которого можно скачать библиотеку geoip2.
{
"require": {
"geoip2/geoip2": "~2.0"
},
"repositories": [{
"type": "vcs",
"url": "git@github.com:antimattr/GoogleBundle.git"}
]
}
Затем обновите Dockerfile. Добавьте в него Workdir и укажите каталог, в котором Composer найдет файл composer.json:
FROM composer:latest AS composer FROM php:7.2.3 COPY --from=composer /usr/bin/composer /usr/bin/composer WORKDIR /app
Соберите вторую версию образа:
docker build -t php-composer:2.0 .
Проверьте версию Composer, чтобы убедиться, что сборка прошла успешно:
docker run -ti --volume $(pwd)/:/app php-composer:2.0 composer --version
Удалите файл composer.lock, который остался от установки фреймворка Slim:
rm composer.lock
Запустите контейнер, передав команду composer install:
docker run -ti --volume $(pwd)/:/app php-composer:2.0 composer install
Сборка должна быть успешной за исключением того, что нет Git. Просто скопировать исполняемый файл гита нельзя из-за зависимостей библиотек. Нужно добавить его в установку.
Снова обновите Dockerfile:
FROM composer:latest AS composer FROM php:7.2.3 COPY --from=composer /usr/bin/composer /usr/bin/composer RUN apt update && apt install -y git WORKDIR /app
Соберите третью версию образа:
docker build -t php-composer:3.0 .
Запустите composer install:
docker run -ti --volume $(pwd)/:/app php-composer:3.0 composer install
Теперь ошибок быть не должно.
Осталось решить проблему с пользователем. Vendor и composer.lock создаются от root. Если не указано другое, то в самом контейнере используется тоже root. Это легко проверить:
FROM composer:latest AS composer FROM php:7.2.3 COPY --from=composer /usr/bin/composer /usr/bin/composer RUN apt update && apt install -y git RUN whoami WORKDIR /app
Соберите контейнер:
docker build -t php-composer:3.1 . Output: Step 5/6 : RUN whoami ---> Running in 8707eba18a3b root ... Successfully tagged php-composer:3.1
Если вы хотите, чтобы vendor оставался за тем пользователем, которого вы создали сами, то можно использовать два пути. Первый — с помощью инструкции USER добавить нужного пользователя во время сборки контейнера. Второй — запускать контейнер от пользователя, используя --user.
Обновите Docker-файл:
FROM composer:latest AS composer FROM php:7.2.3 COPY --from=composer /usr/bin/composer /usr/bin/composer RUN apt update && apt install -y git RUN adduser phpcomposeruser USER phpcomposeruser RUN whoami RUN id WORKDIR /app
Соберите новый контейнер:
docker build -t php-composer:3.2 .
Удалите каталог vendor и файл composer.lock:
sudo rm -rf vendor/ && sudo rm composer.lock
Соберите проект, используя версию 3.2:
docker run -ti --volume $(pwd)/:/app php-composer:3.2 composer install
Проверьте файлы:
ls -l Output: -rw-r--r-- 1 sample sample 142 Dec 13 15:21 composer.json -rw-r--r-- 1 sample sample 8286 Dec 13 15:21 composer.lock -rw-r--r-- 1 sample sample 222 Dec 13 15:18 Dockerfile drwxr-xr-x 6 sample sample 4096 Dec 13 15:21 vendor
Здесь может быть неверно определено имя пользователя. Если это так, вернитесь к логам сборки. Обратите внимание на Step 8/9. Там указан UID пользователя.
UID 1000 — это дефолтный пользователь на хосте. Тот пользователь, которого вы создали, будет иметь UID 1001. Его права на каталог vendor ограничены.
Второй способ — запускать контейнер от конкретного пользователя с помощью --user.
Уберите из Docker-файла USER. Верните первоначальный вид:
FROM composer:latest AS composer FROM php:7.2.3 COPY --from=composer /usr/bin/composer /usr/bin/composer RUN apt update && apt install -y git WORKDIR /app
Соберите версию 3.3:
docker build -t php-composer:3.3 .
Удалите каталог vendor и файл composer.lock:
sudo rm -rf vendor/ && sudo rm composer.lock
Соберите проект, добавив --user phpcomposeruser:
docker run --user phpcomposeruser -ti --volume $(pwd)/:/app php-composer:3.3 composer install
В терминале отобразится ошибка:
docker: Error response from daemon: linux spec user: unable to find user phpcomposeruser: no matching entries in passwd file.
Это связано с тем, что вы не создали пользователя с таким именем в образе php-composer:3.3. Чтобы устранить эту проблему, можно передать в контейнер UID и GID вместо имени пользователя.
Поменяйте владельца composer.json на phpcomposeruser:
sudo chown phpcomposeruser composer.json
Соберите проект:
docker run --user $(id -u phpcomposeruser):$(id -g phpcomposeruser) -ti --volume $(pwd)/:/app php-composer:3.3 composer install
Проверьте, что все работает:
ls -l total 24 -rw-r--r-- 1 phpcomposeruser sample 142 Dec 13 14:54 composer.json -rw-r--r-- 1 phpcomposeruser phpcomposeruser 8286 Dec 13 14:59 composer.lock -rw-r--r-- 1 sample sample 155 Dec 13 14:44 Dockerfile drwxr-xr-x 6 phpcomposeruser phpcomposeruser 4096 Dec 13 14:59 vendor
Готово, теперь образ собирается не от root, а от имени нового пользователя.
Для закрепления навыков создайте демонстрационное приложение на Laravel, которое будет работать в трех служебных контейнерах.
Пример Dockerfile такого проекта:
FROM php:7.4-fpm
# Arguments defined in docker-compose.yml
ARG user
ARG uid
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
chown -R $user:$user /home/$user
# Set working directory
WORKDIR /var/www
USER $user
Структура простая:
php:7.4-fpm.Последние два параметра гарантируют, что вы будете подключаться как обычный пользователь и находиться в правильной директории.
Создайте папку для хранения конфигурационных файлов nginx:
mkdir -p docker-compose/nginx
Создайте файл конфигурации nginx docker-compose/nginx/travellist.conf.
Пример его содержимого:
server {
listen 80;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/public;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
}
Файл указывает nginx на необходимость слушать порт 80 и использовать index.php в качестве страницы по умолчанию.
Чтобы настроить БД, откройте для общего доступа дамп. Он будет импортирован при инициализации контейнера.
Создайте новую папку:
mkdir docker-compose/mysql
Создайте и откройте файл docker-compose/mysql/init_db.sql, вставьте в него следующий код:
DROP TABLE IF EXISTS `cities`;
CREATE TABLE `cities` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`visited` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `cities` (name, visited) VALUES ('Kyiv',1),('Moscow',1),('Minsk',1),('Riga',0),('Helsinki',0),('London',0),('Paris',1),('Oslo',1),('Cancun',0),('Beijing',0);
Используйте Docker Compose, чтобы создать мультиконтейнерную среду. В ней службы могут использовать общие сети и тома хранения данных.
Для настройки мультиконтейнерной среды нужно создать docker-compose.yml. Так выглядит готовый файл для нашего проекта:
version: "3.7"
services:
app:
build:
args:
user: sample
uid: 1000
context: ./
dockerfile: Dockerfile
image: travel
container_name: travel-app
restart: unless-stopped
working_dir: /var/www/
volumes:
- ./:/var/www
networks:
- travel
db:
image: mysql:5.7
container_name: travel-db
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_USER: ${DB_USERNAME}
SERVICE_TAGS: dev
SERVICE_NAME: mysql
volumes:
- ./docker-compose/mysql:/docker-entrypoint-initdb.d
networks:
- travel
nginx:
image: nginx:alpine
container_name: travel-nginx
restart: unless-stopped
ports:
- 8000:80
volumes:
- ./:/var/www
- ./docker-compose/nginx:/etc/nginx/conf.d/
networks:
- travel
networks:
travel:
driver: bridge
Это лишь пример того, что должно быть внутри. В файле определены три службы: app, db и nginx. Служба app будет строить образ на базе созданного ранее Dockerfile. Контейнер запустит сервер php-fpm для синтаксической проверки кода. Результаты вернутся в службу nginx. Она работает в отдельном контейнере. Служба mysql определяет контейнер с запущенным сервером MySQL. Все службы соединены в сеть.
Соберите образ app:
docker-compose build app
Запустите среду в автономном режиме:
docker-compose up -d
Установите зависимости приложения:
docker-compose exec app composer install
Сгенерируйте уникальный ключ приложения с помощью artisan. Он нужен для шифрования пользовательских сеансов и других критичных данных.
docker-compose exec app php artisan key:generate
Откройте браузер и перейдите на ваш сервер или локальный хост с портом 8000:
http://server_domain_or_IP:8000
Убедитесь, что приложение работает.
Если вы хотите поставить среду Docker Compose на паузу, выполните команду:
docker-compose pause
Состояние всех служб сохранится. Чтобы запустить Compose заново, выполните:
docker-compose unpause
Чтобы закрыть Compose, удалить все контейнеры, сети и тома, выполните:
docker-compose down
Все команды Compose можно посмотреть в документации.
Мы рассмотрели лишь общие настройки, которые помогают сделать Composer Install внутри Docker-контейнера. В зависимости от особенностей проекта конфигурация меняется.
Чтобы практиковаться с созданием приложения было проще, посмотрите это дополняющее текст видео:
На фоне роста спроса на ликвидность в бычьем рынке 2025 года, криптозаймы снова выходят на…
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…