Докеризация приложения Laravel 11

Источник: «Dockerize a Laravel 11 app»
Докеризация Laravel приложения не так проста, как кажется, поэтому сегодня рассмотрим процесс создания Docker-образа для приложения Laravel 11. Для этого настроим полное окружение с помощью Docker Compose, чтобы приложение Laravel было готово к развёртыванию в любой среде.

Создание необходимых конфигурационных файлов

Для начала создадим в проекте следующие файлы:

Эти файлы содержат необходимую конфигурацию для создания образа Docker и управления контейнерами.

Создание Dockerfile

Dockerfile определяет среду разработки для приложения Laravel. В данном случае разделим её на два этапа: один — для создания приложения, другой — для его запуска в продакшен (не обязательно), как показано ниже:

# deploy/Dockerfile

# Этап 1: этап сборки
FROM php:8.3-fpm-alpine as build

# Установка системных зависимостей и php расширений
RUN apk add --no-cache \
zip \
libzip-dev \
freetype \
libjpeg-turbo \
libpng \
freetype-dev \
libjpeg-turbo-dev \
libpng-dev \
nodejs \
npm \
&& docker-php-ext-configure zip \
&& docker-php-ext-install zip pdo pdo_mysql \
&& docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-enable gd


# Установка composer
COPY --from=composer:2.7.6 /usr/bin/composer /usr/bin/composer

WORKDIR /var/www/html

# Копирование необходимых файлов и изменение разрешений
COPY . .
RUN chown -R www-data:www-data /var/www/html \
&& chmod -R 775 /var/www/html/storage \
&& chmod -R 775 /var/www/html/bootstrap/cache


# установка php и node.js зависимостей
RUN composer install --no-dev --prefer-dist \
&& npm install \
&& npm run build


RUN chown -R www-data:www-data /var/www/html/vendor \
&& chmod -R 775 /var/www/html/vendor


# Этап 2: этап продакшена
FROM php:8.3-fpm-alpine

# Установка nginx
RUN apk add --no-cache \
zip \
libzip-dev \
freetype \
libjpeg-turbo \
libpng \
freetype-dev \
libjpeg-turbo-dev \
libpng-dev \
oniguruma-dev \
gettext-dev \
freetype-dev \
nginx \
&& docker-php-ext-configure zip \
&& docker-php-ext-install zip pdo pdo_mysql \
&& docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ \
&& docker-php-ext-install -j$(nproc) gd \
&& docker-php-ext-enable gd \
&& docker-php-ext-install bcmath \
&& docker-php-ext-enable bcmath \
&& docker-php-ext-install exif \
&& docker-php-ext-enable exif \
&& docker-php-ext-install gettext \
&& docker-php-ext-enable gettext \
&& docker-php-ext-install opcache \
&& docker-php-ext-enable opcache \
&& rm -rf /var/cache/apk/*


# Копирование файлов с этапа сборки
COPY --from=build /var/www/html /var/www/html
COPY ./deploy/nginx.conf /etc/nginx/http.d/default.conf
COPY ./deploy/php.ini "$PHP_INI_DIR/conf.d/app.ini"

WORKDIR /var/www/html

# Добавление всех папок, в которых хранятся файлы, требующие постоянного хранения, если необходимо. В противном случае удалите эту строку.
VOLUME ["/var/www/html/storage/app"]

CMD ["sh", "-c", "nginx && php-fpm"]

Создание файл docker-compose.yml

Этот файл определяет сервисы, необходимые для запуска Laravel-приложения в Docker. В приведённом ниже файле docker-compose.yml определяется сервис для приложения Laravel, а также сервис для базы данных MySQL.

# deploy/docker-compose.yml

version: '3.8'

services:
laravel:
restart: unless-stopped
container_name: laravelapp
build:
context: ../
dockerfile: ./deploy/Dockerfile
# При необходимости выделите столько томов, сколько нужно.
volumes:
- ../storage/app:/var/www/html/storage/app
environment:
APP_NAME: ${APP_NAME}
APP_ENV: ${APP_ENV}
APP_DEBUG: ${APP_DEBUG}
APP_KEY: ${APP_KEY}
APP_VERSION: ${APP_VERSION}
APP_URL: ${APP_URL}
DB_CONNECTION: mysql
DB_HOST: database
DB_PORT: 3306
DB_DATABASE: ${DB_DATABASE}
DB_USERNAME: ${DB_USERNAME}
DB_PASSWORD: ${DB_PASSWORD}
MAIL_MAILER: ${MAIL_MAILER}
MAIL_HOST: ${MAIL_HOST}
MAIL_PORT: ${MAIL_PORT}
MAIL_USERNAME: ${MAIL_USERNAME}
MAIL_PASSWORD: ${MAIL_PASSWORD}
MAIL_ENCRYPTION: ${MAIL_ENCRYPTION}
MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS}
MAIL_FROM_NAME: ${MAIL_FROM_NAME}
ports:
- "8080:80"
networks:
- n-laravel
depends_on:
- database

database:
restart: unless-stopped
image: mariadb:lts-jammy
volumes:
- v-database:/var/lib/mysql
environment:
MARIADB_DATABASE: ${DB_DATABASE}
MARIADB_USER: ${DB_USERNAME}
MARIADB_PASSWORD: ${DB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
networks:
- n-laravel

volumes:
v-database:


networks:
n-laravel:
driver: bridge

В конфигурации тома (volumes) можно добавить или удалить нужные тома. В данном случае добавляется только том для папки storage/app, поскольку предполагается, что это единственная папка, нуждающаяся в постоянном хранении. Также, если он не нужен, его можно удалить.

Аналогично, не обязательно использовать каталог в качестве тома; можно без проблем использовать том Docker.

Конфигурирование сервера Nginx

Далее настроим файл nginx.conf для обслуживания Laravel-приложения. Этот файл определяет конфигурацию сервера Nginx и то, как обрабатывать запросы к приложению.

# deploy/nginx.conf

server {
listen 80 default_server;
listen [::]:80 default_server;

root /var/www/html/public;
client_max_body_size 10M;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";

index index.php;

charset utf-8;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location = /favicon.ico {
access_log off; log_not_found off;
}
location = /robots.txt {
access_log off; log_not_found off;
}

error_page 404 /index.php;

location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}

Конфигурирование PHP

Если необходимо настроить PHP, это можно сделать через файл php.ini. Как показано в следующем примере, где максимальный размер загружаемого файла установлен в 10 МБ.

# deploy/php.ini
upload_max_filesize = 10M

Создание файла .dockerignore

В этом файле указывается, какие файлы или каталоги должны игнорироваться Docker при сборке образа. Например, не следует копировать каталог vendor для совместимости, времени и т. д.

# .dockerignore
/deploy/docker-compose.yml
/deploy/Dockerfile
/.phpunit.cache
/node_modules
/public/build
/public/hot
/public/storage
/public/bucket
/storage/*.key
/vendor
.env
.env.example
.env.backup
.env.production
.phpunit.result.cache
Homestead.json
Homestead.yaml
auth.json
npm-debug.log
yarn-error.log
/.fleet
/.idea
/.vscode
.git

Конфигурация переменных среды

По умолчанию при создании проекта Laravel создаётся файл .env с необходимыми переменными среды для разработки.

Но если вдруг файл .env отсутствует, необходимо создать его в корне проекта и определить необходимые переменные среды для приложения. Вот ссылка, на пример, как должен выглядеть .env-файл: https://github.com/laravel/laravel/blob/11.x/.env.example

Из всего этого набора настроек важно отредактировать параметры базы данных. Которые по умолчанию до редактирования выглядят следующим образом:

DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=

Необходимо изменить их на:

DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=admin
DB_PASSWORD=admin
DB_ROOT_PASSWORD=root

В данном случае игнорируются следующие параметры: DB_CONNECTION, DB_HOST и DB_PORT. Причина в том, что эти параметры уже определены в файле docker-compose.yml.

Кроме того, добавляем: DB_ROOT_PASSWORD, необходимый для корректной сборки образа MySQL, так как он требует пароль пользователя root.

Создание Docker-образа

Когда всё настроено, пришло время собрать Docker-образ. Для этого воспользуемся следующими командами:

Сборка и установка контейнеров

docker compose -f deploy/docker-compose.yml --env-file ./.env up --build

Запуск миграций Laravel

docker exec -t laravelapp php artisan migrate

Запуск Laravel seeder-ов

На этом шаге не достаточно только выполнить команду, если используется библиотека fakerphp/faker, необходимо изменить файл composer.json, переместив библиотеку из списка зависимостей разработки в список зависимостей продакшена.

Это происходит потому, что при создании образа указано не устанавливать зависимости разработки, и поэтому при запуске команды будет выдана ошибка о невозможности найти библиотеку.

Пример, как должен выглядеть composer.json:

До:

{
"require": {
...
},
"require-dev": {
"fakerphp/faker": "^1.23"
}
}

После:

{
"require": {
...
"fakerphp/faker": "^1.23"
},
"require-dev": {
...
}
}

А теперь можно выполнить команду:

docker exec -t laravelapp php artisan db:seed

Настройка томов

Как вы знаете, в Dockerfile мы определяем том для папки storage/app приложения. Аналогично, в файле docker-compose.yml том настраивается как каталог для постоянного хранения файлов.

Однако можно столкнуться с проблемой, когда при записи в этот каталог будет возникать ошибка прав доступа.

Это происходит потому, что Nginx не имеет достаточных прав на запись в каталог. Моим решением этой проблемы стало выполнение следующей команды для изменения и добавления этих разрешений:

# Первое: изменение группы (nginx)
sudo chown -R :81 storage/app
# Второе: изменение разрешений
sudo chmod -R 775 storage/app

Доступ к приложению

После того как образ создан и контейнеры подняты с помощью команды docker compose, можно проверить работоспособность приложения в браузере.

Убедитесь, что обращаетесь к URL http://localhost:8080, и если всё в порядке, увидите главную страницу приложения Laravel.

Заключение

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

Стоит отметить, что необходимо тщательно проверить, не нужно ли добавить дополнительные зависимости в Dockerfile, а также изменить другие параметры, которые могут потребоваться для работы приложения: Nginx, php.ini и даже версию используемого PHP, возможно, придётся изменить.

Дополнительные материалы

Предыдущая Статья

Что делает aria-hidden=true с интерактивными элементами на самом деле

Следующая Статья

WeakMap — скрытое сокровище в PHP