Блог Amazon Web Services

Представляем новый бессерверный LAMP-стек, часть 4: создаём бессерверное приложение на Laravel

Зарегистрируйтесь, чтобы получать приглашения на мероприятия AWS на русском языке.

Оригинал статьи: ссылка (Benjamin Smith, Senior Developer Advocate)

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

Это четвёртая статья в серии о бессерверном LAMP-стеке. В предыдущих статьях мы рассмотрели следующие темы:

Laravel – это фреймворк с открытым исходным кодом для веб-приложений на языке PHP. С помощью фреймворков разработчики могут работать более эффективно благодаря использованию стандартных компонентов и модулей. Долгосрочная поддержка становится проще вследствие внедрения единых стандартов разработки. Однако, даже использование фреймворков не избавляет от проблем с масштабированием традиционного LAMP-стека. Развёртывание фреймворка с использованием бессерверного подхода может помочь с их решением.

Есть несколько подходов, упрощающих установку Laravel-приложений на бессерверную инфраструктуру. Решение, которое мы покажем в этой статье, использует шаблон AWS Serverless Application Model (AWS SAM). С помощью него вы можете развернуть всё приложение в одной Lambda-функции. Эта функция будет использовать среду выполнения Bref FPM для запуска PHP. Шаблон AWS SAM развёртывает инфраструктуру, описанную в статье «Представляем новый бессерверный LAMP-стек, часть 3: Заменяем веб-сервер»:

Бессерверный LAMP-стек

Бессерверный LAMP-стек

Установка Laravel и Bref с помощью AWS SAM

Composer – это инструмент для управления зависимостями в приложениях на PHP. Он позволяет описывать зависимости и управлять библиотеками, которые используются в вашем проекте, такими как Laravel и Bref.

Установите Laravel и Bref с помощью AWS SAM, используя следующие шаги:

  1. Скачайте установочный файл Laravel, используя Composer:
    composer global require Laravel/installer
  2. Установите Laravel:
    composer create-project --prefer-dist laravel/laravel blog
  3. В проекте Laravel установите Bref, используя Composer:
    composer require bref/laravel-bridge
  4. Создайте клон шаблона AWS SAM в корневой директории вашего приложения:
    git clone https://github.com/aws-samples/php-examples-for-aws-lambda/
  5. Перейдите в директорию 0.4-Building-A-Serverless-Laravel-App-With-AWS-SAM:
    cd 0.4-Building-A-Serverless-Laravel-App-With-AWS-SAM
  6. Установите приложение с помощью управляемого развёртывания AWS SAM CLI:
    sam deploy -g

После того, как AWS SAM установит приложение, он вернёт доменное имя раздачи (distribution) Amazon CloudFront. Оно будет использоваться в качестве точки входа в бессерверное Laravel-приложение.

Доменное имя раздачи CloudFront, созданной в шаблоне AWS SAM

Доменное имя раздачи CloudFront, созданной в шаблоне AWS SAM

Настройка Laravel в Lambda

Для запуска Laravel внутри функции Lambda нужно произвести несколько дополнительных настроек.

Хранение данных сессий

Хотя Lambda и предоставляет временную файловую систему на 512 МБ, она не предназначена для длительного хранения данных, так как отсутствует гарантия того, что для каждого вызова Lambda-функции будет использоваться одна и та же среда выполнения.

Поэтому, если вам необходимо хранить данные сессий Laravel, это нужно делать вне Lambda-функции. Есть несколько подходов для управления состоянием приложения в бессерверной инфраструктуре. Данные сессии рекомендуется хранить либо в базе данных, либо в cookies в браузере.

Поменяйте файл .env Laravel и установите параметр session_driver в значение cookie.

SESSION_DRIVER=cookie

Логи

В качестве интерфейса для записи логов сразу в несколько мест назначения Laravel использует библиотеку PHP под названием Monolog. Настроить эти места можно с помощью log channels (каналов логов). Каждый канал задаётся в файле /config/logging.php в виде ассоциативного массива.

Так как файловая система Lambda может быть разной при разных вызовах функции, логи приложения необходимо сохранять во внешнее централизованной хранилище, такое как Amazon CloudWatch Logs. Все ошибки, предупреждения и уведомления, выдаваемые PHP, должны отправляться в CloudWatch Logs. Благодаря этому будет упрощён процесс просмотра, поиска, фильтрации и архивации логов для последующего анализа. Чтобы настроить такую отправку, добавьте следующую строку в файл .env:

LOG_CHANNEL=stderr

Эта настройка указывает на использование канала stderr для записи всех логов приложения. Из него они будут автоматически отправляться в CloudWatch Logs. Данный канал задаётся в файле /config/logging.php:

'stderr' => 
    [ 
    'driver' => 'monolog', 
    'handler' => StreamHandler::class, 
    'formatter' => env('LOG_STDERR_FORMATTER'), 
    'with' => [ 
        'stream' => 'php://stderr', 
    ], 
],
Логи в консоли CloudWatch Logs для одного вызова Lambda

Логи в консоли CloudWatch Logs для одного вызова Lambda

Скомпилированные шаблоны (compiled views)

Шаблоны содержат HTML-код, что позволяет разделить логику приложения и логику представления. По умолчанию, шаблоны компилируются по требованию в директории storage самого приложения.

Так как у Lambda нет прав за запись в указанную директорию, Laravel должен быть настроен так, чтобы шаблоны записывались в директорию /tmp. Это временная файловая система, на которой хранятся данные, необходимые только для выполнения одного HTTP-запроса.

В файле .env добавьте следующую строку, чтобы настроить Laravel на использование новой директории для скомпилированных шаблонов:

VIEW_COMPILED_PATH=/tmp/storage/framework/views

Laravel использует сервис-провайдеров (service providers) для регистрации компонентов вашего приложения. В файле AppServiceProvider.php настраивается центральное местоположение для передачи данных между шаблонами. Добавьте следующий исходный код в файл Providers/AppServiceProvider.php:

public function boot() { 
    // Make sure the directory for compiled views exist 
    if (! is_dir(config('view.compiled'))) { 
        mkdir(config('view.compiled'), 0755, true); 
    } 
}

С помощью него вы можете убедиться, что директория для шаблонов автоматически создаётся, по необходимости, при каждом вызове Lambda-функции.

Абстракция файловой системы с помощью Amazon S3

Laravel использует пакет Flysystem для абстракции файловой системы. Так как директория /tmp в Lambda является временной, файловая система должна находиться вне функции. Вы можете использовать драйвер файловой системы Amazon S3 путём добавления следующей строки в файл .env:

FILESYSTEM_DRIVER=s3

В шаблоне AWS SAM создаётся бакет S3 для хранения необходимых объектов:

Storage:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: php-example-laravel-FileSystemBucket

Название бакета передаётся в Lambda-функцию в виде переменной окружения:

    Environment:
      Variables:
        AWS_BUCKET: !Ref Storage

С помощью следующей политики IAM Lambda-функция получает доступ на чтение и запись в указанный бакет S3:

Policies:
        - S3FullAccessPolicy:
            BucketName: !Ref Storage

Настроить файловую систему нужно в файле config/filesystems.php. Именно там вы задаёте «диск» S3, используя переменную окружения, описанную в шаблоне AWS SAM.

's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'token' => env('AWS_SESSION_TOKEN'),
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
            'endpoint' => env('AWS_ENDPOINT'),
        ],

Информацию об аккаунте AWS и ARN бакета можно получить из переменных среды Lambda, в которой запущен PHP, с помощью функции env() в Laravel.

Публичные статические файлы

Laravel использует драйвер публичного диска для хранения файлов, которые должны быть доступны всем пользователям, например, изображений и файлов CSS. По умолчанию он хранит файлы в директории storage/app/public/, но мы, вместо этого, будем хранить файлы в S3. Для этого поменяйте файл config/filesystems.php следующим образом:

+ 'public' => env('FILESYSTEM_DRIVER_PUBLIC', 'public_local'),
    
    'disks' => [

        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],

- 'public => [
+ 'public_local' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
        ],

        's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'token' => env('AWS_SESSION_TOKEN'),
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
            'endpoint' => env('AWS_ENDPOINT'),
        ],

+ 's3_public' => [ + 'driver' => 's3', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'token' => env('AWS_SESSION_TOKEN'), + 'region' => env('AWS_DEFAULT_REGION'), + 'bucket' => env('AWS_PUBLIC_BUCKET'), + 'url' => env('AWS_URL'), + ],

    ],

Это добавляет диск с названием s3_public, который использует драйвер S3. Для настройки названия бакета функция env() в Laravel получает значение переменной окружения AWS_PUBLIC_BUCKET, которое было передано в Lambda-функцию.

Добавьте следующую строку в файл .env, чтобы использовать S3 для публичного диска:

FILESYSTEM_DRIVER_PUBLIC=s3

Ссылки на статические файлы в шаблонах

Вспомогательная функция asset() в Laravel генерирует URL для файла, используя текущий протокол запроса (HTTP или HTTPS):

$url = asset('img/photo.jpg');

Эти файлы должны храниться в S3 и предоставляться через глобальный CDN Amazon CloudFront. Настройте URL-хост в переменной ASSET_URL в файле .env:

ASSET_URL=https://{YourCloudFrontDomain}.cloudfront.net

Это поможет приложению корректно ссылаться на файлы в S3 через домен CloudFront. Вспомогательная функция asset() в Laravel используется в шаблонах следующим образом:

<img src="{{ asset('assets/icons.png') }}">
Бессерверное приложение Laravel в Lambda

Бессерверное приложение Laravel в Lambda

Другие способы развёртывания бессерверных приложений Laravel

  1. В Bref, среде запуска PHP с открытым исходным кодом, недавно был интегрирован новый pull request для автоматической конфигурации Laravel в Lambda. Кроме того, он предоставляет возможность интеграции Amazon SQS с системой Laravel Queues Jobs.
  2. Laravel Vapor– это платформа для бессерверного развёртывания Laravel. Она представляет собой платный сервис, который команда Laravel создала в облаке AWS.

Заключение

В этой статье мы показали, как развернуть бессерверное приложение на PHP, использующее Laravel, с помощью AWS SAM. Мы рассмотрели шаги, необходимые для настройки хранения сессий и централизованных логов, а также внешней файловой системы и хранения статических файлов на S3.

Теперь команды, использующие PHP в своих приложениях, могут сосредоточиться на создании исходного кода без необходимости внесения изменений в процесс разработки.

Исходный код из этой статьи и соответствующие инструкции вы можете найти в репозитории GitHub.