Переделываем Laravel Sail для productionВ прошлом году я активно начал изучать фреймворк Laravel. Использование началось с Laravel Sail и это оказалось действительно удобно для быстрого старта. По мере углубления оказалось что Sail не годиться для production, но не хочется терять столь удобный инструмент, поэтому попытаемся привести его к нужному виду.
В документации Laravel есть инструкция по настройке окружения Laravel + Docker через пакет Sail. Это окружение в Docker действительно настраивается легко и просто.
Упрощенно Laravel Sail - это bash скрипт, предоставляющий удобный интерфейс для взаимодействия с приложениями в
Dockerконтейнерах.
Конечно есть кодовая база на php, которая встраивается в приложение, генерация docker-compose.yml файла, и возможность без знаний Docker сконфигурировать среду разработки. Однако, большая часть использований для меня свелась к bash скрипту, потому что просто управлять приложениями в контейнерах (в рамках работы с фреймворком).
Рассмотрим некоторые детали.
Чтобы поднять новый проект нужно (example-app заменить на название будущего проекта):
$ curl -s https://laravel.build/example-app | bash
В книге "UNIX И LINUX РУКОВОДСТВО СИСТЕМНОГО АДМИНИСТРАТОРА" пишут:
Направление результатов работы команды
curlв оболочку в среде системных администраторов рассматривается как типичный промах новичков, поэтому, если вы это сделаете, никому об этом не говорите. Исправить ситуацию легко: просто сохраните сценарий во временном файле, а затем запустите сценарий на отдельном этапе после успешного завершения загрузки.
А чтобы установить Sail в существующий проект, например в склонированный репозиторий с Laravel, то нужно:
$ docker compose run --rm \
    -u "$(id -u):$(id -g)" \
    laravelsail/php82-composer:latest \
    composer install --ignore-platform-reqs
Теперь добавим алиас sail в ~/.bashrc чтобы не писать длинный путь ./vendor/bin/sail каждый раз:
alias sail='[ -f sail ] && sh sail || sh vendor/bin/sail'
А теперь можно использовать магию Sail, вот некоторые примеры (остальное в документации):
Docker$ sail up
artisan, composer:$ sail composer require 
php$ sail php script.php
Именно эта магия оказалась повседневной при разработке приложений на Laravel.
После инициализации приложения через Sail у нас в корне появляется docker-compose.yml, при помощи которого поднимается инфраструктура нашего приложения в docker. На ранних этапах прототипирования все устраивало, но когда речь зашла о переезде на сервер, встала необходимость думать о production окружении.
Мой прототип реализовывал web API, а также нужна отдача статики. И первая проблема это CORS.
Мне привычно использовать Nginx, тем более что проблемы с CORS решаются просто:
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' '*' always;
add_header 'Access-Control-Allow-Headers' '*' always;
if ($request_method = 'OPTIONS') {
    return 204;
}
Вторая проблема была в производительности, точнее в привычном для меня production понимании организации инфраструктуры с заделом на будущее.
Если еще раз посмотреть в docker-compose.yml, который был создан после инициализации приложения, то можно увидеть что внутри единственного контейнера функционирует веб-сервер для разработки при помощи php artisan, который реализован на PHP.
Нам же для production нужен php-fpm, а значит контейнер с php придется менять, но здесь есть несколько нюансов:
php должен быть пользователь sail, потому что так устроен bash скрипт sail, можно поискать exec -u sail, более того процессы fpm должны запускаться от этого пользователя, иначе будут странные проблемыsail должны быть права на эти файлыВ этом репозитории я решил вышеперечисленные проблемы удобным для меня способом:
php теперь поддерживает PHP-FPM. В соответствии с Sail внутри есть пользователь sail и от него запускаются fpm процессы. Для конфигурации этого пользователя нужно в файле .env задать в WWW_UID и WWW_GID (если они отличаются от дефолтных 1000:1000), чтобы не было конфликтов прав между хостовым обычным юзером и юзером sail внутри контейнера.CORS и поддерживает отдачу статики.Обязательно нужно создать
.envи задать нужные параметры, чтобы окружение вело себя предсказуемо.
Для инициализации нового приложения нужно следовать документации Sail, а затем можно взять конфигурацию из репозитория. Либо можно заморочиться с инициализацией нового проекта на новом окружении из репозитория примерно так:
# поднимаем инфраструктуру
$ docker compose up -d
# создаем проект
$ docker compose exec -u "$(id -u):$(id -g)" php composer create-project laravel/laravel example-app
# перемещаем содержимое директории example-app в корень
$ docker compose exec -u "$(id -u):$(id -g)" php mv ./example-app/* .
# все что не переместилось из директории example-app перемещаем в корень руками, совмещая файлы
Для инициализации существующего приложения с окружением как в репозитории достаточно:
$ docker compose run --rm -u "$(id -u):$(id -g)" php composer install
Дальнейшее конфигурирование зависит от условий эксплуатации и личных предпочтений, поэтому детальной проработки конфигов не проводилось, в основном используется дефолт.