在 AWS Serverless 平台上部署 Laravel (laravel-mix) 应用程序

Posted

技术标签:

【中文标题】在 AWS Serverless 平台上部署 Laravel (laravel-mix) 应用程序【英文标题】:Deploying Laravel (laravel-mix) application on AWS Serverless platform 【发布时间】:2021-03-23 11:40:24 【问题描述】:

我正在尝试在 AWS 无服务器平台上部署我的 Laravel 应用程序,我在我的 laravel-mix 中使用动态导入和代码拆分来编译资产,执行此操作我按照bref package 文档中的步骤进行操作我按照指示安装了所需的库,我还将我的公共目录与我的 s3 存储桶同步

npm run prod
aws s3 sync public/ s3://<bucket-name>/ --delete --exclude index.php

并将我的.env 文件配置为:

MIX_ASSET_URL=https://<bucket-name>.s3.amazonaws.com
ASSET_URL=https://<bucket-name>.s3.amazonaws.com

接下来我将blade 文件配置为:

<script src=" asset('nits-assets/js/app.js') "></script>

我的webpack.mix.js 文件有:

const mix = require('laravel-mix')

const webpack = require('webpack');

const ASSET_URL = process.env.ASSET_URL + "/";

mix.js('resources/js/app.js', 'public/nits-assets/js')
    .postCss('resources/sass/app.css', 'public/nits-assets/css', [
        require("tailwindcss"),
    ])
    .webpackConfig(
        output: 
            chunkFilename: 'nits-assets/chunks/[name].[contenthash].js',
            publicPath: ASSET_URL
        ,
        resolve: 
            symlinks: false,
            alias: 
                NitsModels: path.resolve(__dirname, 'Models'),
            ,
        ,  
        plugins: [
            new webpack.DefinePlugin(
                "process.env.ASSET_PATH": JSON.stringify(ASSET_URL)
            )
        ],
    ).sourceMaps().version();

由于我将代码拆分为块,因此在获取块时遇到了麻烦,我最初的 app.js 文件从 s3 存储桶加载,但为了加载块,它尝试通过公共目录获取。

如何配置我的 laravel-mix 以从与我的公共目录同步的 s3 存储桶加载块?

编辑:

按照答案中的建议,我更改了 serverless.yml,它看起来像这样:

service: laravel

provider:
    name: aws
    # The AWS region in which to deploy (us-east-1 is the default)
    region: ap-south-1
    # The stage of the application, e.g. dev, production, staging… ('dev' is the default)
    stage: dev
    runtime: provided.al2
    environment:
      AWS_BUCKET: # environment variable for Laravel
        Ref: Storage
      iamRoleStatements:
        # Allow Lambda to read and write files in the S3 buckets
        - Effect: Allow
          Action:
            - s3:PutObject
            - s3:ListBucket
            - s3:GetObject
          Resource:
            - Fn::GetAtt: Storage.Arn # the storage bucket
            - Fn::Join: [ '', [ Fn::GetAtt: Storage.Arn, '/*' ] ] # everything in the storage bucket

resources:
  Resources:
    Storage:
      Type: AWS::S3::Bucket

package:
    # Directories to exclude from deployment
    exclude:
        - node_modules/**
        - public/storage
        - resources/assets/**
        - storage/**
        - tests/**

functions:
    # This function runs the Laravel website/API
    web:
        handler: public/index.php
        timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
        layers:
            - $bref:layer.php-74-fpm
        events:
            -   httpApi: '*'
    # This function lets us run artisan commands in Lambda
    artisan:
        handler: artisan
        timeout: 120 # in seconds
        layers:
            - $bref:layer.php-74 # PHP
            - $bref:layer.console # The "console" layer

plugins:
    # We need to include the Bref plugin
    - ./vendor/bref/bref

现在我得到了:

发生错误:ArtisanLambdaFunction - 属性变量的值必须是具有字符串(或简单类型)属性的对象。

编辑 2:

问题在于 serverless.yml 中的 indent(tab) 配置:

environment:
  AWS_BUCKET: # environment variable for Laravel
    Ref: Storage
iamRoleStatements:
  # Allow Lambda to read and write files in the S3 buckets
  - Effect: Allow
    Action: s3:*

但现在有一个单独的问题:

错误:CloudFormation 模板无效:模板错误:每个 Fn::GetAtt 对象都需要两个非空参数,资源名称和资源属性

【问题讨论】:

之前没用过这个,但是在解析配置的时候某个地​​方,它期望对象中的所有值必须是简单类型或字符串,它找到了另一个对象,数组或函数,不能应用于流程。 它可以在属性Resource: - Fn::GetAtt 上返回一个对象而不是简单类型的字符串吗? @KeitelDOG 我修复了前一个问题,但现在我遇到了Error: The CloudFormation template is invalid: Template error: every Fn::GetAtt object requires two non-empty parameters, the resource name and the resource attribute 问题你能帮我解决这个问题吗? Fn::GetAtt 需要 2 个参数。格式可以像Fn::GetAtt: [ logicalNameOfResource, attributeName ]。官方文档:docs.amazonaws.cn/en_us/AWSCloudFormation/latest/UserGuide/… 包含所需属性的资源的逻辑名称(也称为逻辑 ID)。您想要其值的资源特定属性的属性名称。有关该资源类型可用属性的详细信息,请参阅资源的参考页面。 检查模板结构。真的有resources.Resources吗?也许您只想指定 Resources.Storage [type: AWS::S3::Bucket , ...] 并在 Fn::GetAtt: [ "Storage", "BucketName" ] 或任何其他属性名称中指定 Bucket 的有效属性。 Fn::GetAtt 是一个函数,它在模板中获取资源的属性,以使它们可重用。因此,我认为它必须存在于您的模板中,隐含地来自 AWS 模板或您的语法。 S3 存储桶属性:docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/… 【参考方案1】:

403 错误表明您未经授权或存在某种权限错误。

基于此页面:

https://bref.sh/docs/frameworks/laravel.html

您能否确认您已为 lambda 设置适当的权限以从您使用的 s3 存储桶读取和写入?

...

provider:
    ...
    environment:
        AWS_BUCKET: # environment variable for Laravel
            Ref: Storage
    iamRoleStatements:
        # Allow Lambda to read and write files in the S3 buckets
        -   Effect: Allow
            Action: s3:*
            Resource:
                - Fn::GetAtt: Storage.Arn # the storage bucket
                - Fn::Join: ['', [Fn::GetAtt: Storage.Arn, '/*']] # everything in the storage bucket

resources:
    Resources:
        Storage:
            Type: AWS::S3::Bucket

文档继续说您必须在 config/filesystems.php 中添加来自以下 sn-p 的令牌行。你这样做了吗?

'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'),
        ],

我不使用 Laravel,所以上述建议只是基于查看您的错误并阅读文档。但如果你提供更多信息,我很乐意看看

【讨论】:

我已经添加了 serverless.yml 配置内容。现在我收到An error occurred: ArtisanLambdaFunction - Value of property Variables must be an object with String (or simple type) properties. @NitishKumar 错误解释了问题所在 - 检查您的属性变量。 这个错误是在我配置了我的serverless.yml 文件之后出现的。我是新手,不知道如何解决。在此错误之前,我遇到了An error occurred: WebLambdaFunction - Value of property Variables must be an object with String (or simple type) properties.,我点击了这个链接:forum.serverless.com/t/… 现在错误出现在ArtisanLambdaFunction 上找不到更好的解决方案。 @NitishKumar 该错误表明您的变量必须是对象或字符串。只需逐行浏览您的文件,检查每个条目的格式是否不正确。跨度> @NitishKumar 请参阅 GetAtt 的文档... 如果您使用的是完整形式,则语法为 Fn::GetAtt: [LogicalNameOfResource, attributeName] ... 如果您使用的是简短形式你应该使用 !GetAtt

以上是关于在 AWS Serverless 平台上部署 Laravel (laravel-mix) 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

手把手教你在Serverless平台上部署应用

AWS副总裁:谈容器和微服务及下一代Serverless

浅谈对Serverless的一点理解

真送礼物1 分钟 Serverless 极速部署盲盒平台,自己部署自己抽!

Serverless 在 Conda 虚拟环境中找不到我的 AWS 凭证是不是有原因?

Spring Boot Serverless 实战系列“部署篇” | Mall 应用