Задача этого материала — максимально предметно показать, как подготовить образ 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-контейнера. В зависимости от особенностей проекта конфигурация меняется.
Чтобы практиковаться с созданием приложения было проще, посмотрите это дополняющее текст видео:
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…