AWS Study Note

Deploy Serverless Laravel by Bref

在宣布要推出 Laravel 6 的同時,也公開了 Vapor 這個可以讓 Laravel 也變身為 Serverless 的平台,但如果不想用這個平台,我們能自己輕鬆愜意地做到嗎?來試試 Bref 吧~

Azole (小賴)

--

Update at 2020/11/27: Bref 1.0 釋出後,有些做法不太一樣了,可以參考這一篇「用 Bref 1.0 讓 Laravel 8 serverless 起來」,這篇記錄了怎麼用 Bref 1.0 把 Laravel 8 專案部署至 AWS Lambda,並且可以存取 Amazon ElastiCache Redis。

前幾天 pahud 大分享了一篇文章 https://mnapoli.fr/serverless-case-study-externals/,是關於把一個原本是 LAMP 的網站移轉到 AWS Lambda 上,而且成本非常低廉的 show case,看了一下,發現他們是用 Bref 這個工具做到的,好奇之下,決定用我自己最常用的 Laravel 來試試看。

(毫無意義地放上這張圖,純粹只是要做文章封面)…

本文的範圍也僅侷限於怎麼運用 Bref 把 Laravel 傳到 AWS Lambda,再利用 API Gateway 來作為介面的作法,所有的資料都來自於 Bref 的官網。這次就先不深入探討,目標是成功地把 Laravel 專案放上去,其他部分留給下篇文,之後研究的更深入一點後,再分享研究的成果。如果可以,還想要用 AWS CDK 來試試看呢!

ps. Vapor 底層也是用 AWS Lambda 喔~

Bref

Bref 官網開宗明義就寫了它立志幫大家很輕鬆愜意地把 PHP 部署到 AWS Lambda 上去。

Bref provides the tools and documentation to easily deploy and run serverless PHP applications.

有在用 AWS Lambda 的都知道,AWS Lambda 並不支援 PHP,雖然說提供了 custom runtime,可以自己包 Runtime 上去,但還是覺得有點麻煩。又雖然說是可以包在 layer 裡,就不用每次都包,但,好吧,就是不夠輕鬆愜意。(到底是有多想要輕鬆愜意!)

有興趣研究自己包 Runtime 的,請看這篇:AWS Lambda Custom Runtime for PHP: A Practical Example

Bref 本身是一個 Composer package,在我們的 PHP 專案中,只需要用 composer require 就能裝起來,然後它就能幫我們把 PHP 專案部署到 AWS 上,作為一個 AWS Lambda 來運作。

聽起來是不是很簡單?但人生總不是這樣的,首先,你必須要先準備好一個 AWS 帳號!(好啦,這一點都不困難…)

Bref 雖然本身安裝很簡單,但它需要一點環境的支持。它背後其實是依靠 serverless 這個工具,所以你必須要有 nodejs 跟 npm 的環境,不過還好,在這個 Javascript 征服宇宙的年代,相信大家的電腦裡都已經有 nodejs 跟 npm 了,所以這應該不是問題,對你來說是問題的話,請自行 google。

除了依賴於 serverless 外,它需要的 PHP 版本是 7.2+,我沒有想到這個對我來說是個問題,公司專案目前的環境是 PHP 7.1,不過還好(again),在這個容器盛行的年代,需要 PHP 7.2+ 是吧,那就 docker pull 一下吧,如果覺得 pull 下來後,要自己安裝 composer 等工具很麻煩,我也準備好了一個簡單的 Dockerfile,希望可以幫助大家儘快可以開始試用 Bref。當然,如果你原本的環境就已經是 PHP 7.2+,那很恭喜你。

看來人生的兩大難題(誤)都已經解決了,現在就來開始試用一下吧。

以下會假設你已經有 PHP 7.2+, composer 及 serverless 了,還沒有的話看結尾,有提供一個 github,裡面會提供一些相關的安裝指令。

建立 Laravel 專案

composer create-project laravel/laravel laravel58-bref --prefer-dist

安裝 Bref

composer require bref/bref

這邊要注意,如果你的環境不是 PHP 7.2+,例如是 PHP 7.1,那將會裝到舊版的 Bref,然後如過按照目前 Bref 官網上的 serverless.yml 來部署,就會失敗…

調整 Laravel 專案

這邊是參考 Bref 官網調整的,也可以自行參考官網: https://bref.sh/docs/frameworks/laravel.html

  • 編輯 bootstrap/app.php
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
// 加上這句
$app->useStoragePath($_ENV['APP_STORAGE'] ?? $app->storagePath());

必須要加上這句的原因是因為,在 Lambda 環境下,除了 /tmp 外,其他的檔案系統都是唯讀的,所以我們自己來改寫一下,把 storage path 改到 /tmp 下。(之後會用環境變數來設定)

  • 編輯 .env
VIEW_COMPILED_PATH=/tmp/storage/framework/views  # We cannot store sessions to disk: if you don't need sessions (e.g. API) then use `array`, else store sessions in database or cookies SESSION_DRIVER=array  # Logging to stderr allows the logs to end up in Cloudwatch LOG_CHANNEL=stderr

VIEW_COMPILED_PATH 也是設定到 /tmp 上去,理由同上。

SESSION_DRIVER 這個就先暫時改成 array 吧,正式網站應該都會用 redis 或 DB 來儲存的。

LOG_CHANNEL 則是設定到 stderr,這樣 Lambda 會幫你轉到 CloudWatch 上去。

  • 編輯 app/Providers/AppServiceProvider.php
// Make sure the directory for compiled views exist
if (! is_dir(config('view.compiled'))) {
mkdir(config('view.compiled'), 0755, true);
}

這步沒什麼,建立一下檔案夾而已。

部署

準備 Severless.yml,這是 serverless 需要用的檔案:

service: hello-laravel-brefprovider:
name: aws
region: us-west-2
runtime: provided
environment:
# Laravel environment variables
APP_STORAGE: '/tmp'
plugins:
- ./vendor/bref/bref
functions:
website:
handler: public/index.php
timeout: 30 # in seconds (API Gateway has a timeout of 30 seconds)
layers:
- ${bref:layer.php-73-fpm}
events:
- http: 'ANY /'
- http: 'ANY /{proxy+}'
artisan:
handler: artisan
timeout: 120 # in seconds
layers:
- ${bref:layer.php-73} # PHP
- ${bref:layer.console} # The "console" layer

service: 服務名稱,之後在 AWS 上建立的服務,也都會以這個名字當作 prefix,請大家自己取好。

region: 要使用的 AWS region,這邊請找一個自己愛用的,之後要觀察 Bref 跟 Serverless 時請記得切換到這個區域去看。

其他的都可以不用改。

然後我們就可以部署了,就只要這樣就可以開始部署了,有沒有覺得很害怕…

serverless deploy

然後你就會看到畫面一直跑,一直跑,然後就完成了,是不是很簡單,簡單到我懷疑人生…

ps. 要刪除的話就執行這個指令:

serverless remove

觀察一下

在 deploy 的時候可以觀察一下過程,其實他就是在建立一個 CloudFormation 的 Stack,登入到 AWS Console 去,也的確會看到一個 Stack 被建立出來,這邊可以看看這個 Stack 建立出了哪些資源出來。

在切去 AWS API Gateway,也會看到有一個 API Gateway 被建立,去 stage 裡找到網址,點開它,將將將將~

(完全無法證明什麼、更沒意義的一張圖)

再回到 AWS Console 點開 S3,會發現被建立了一個 Bucket,進去看看,裡面有一個 CloudFormation Template 以及一個 zip 檔,可以下載下來研究研究,這是下次要分享的部分,包括其他被建立出來的資源,所以暫且不表。

不想用 Serverless 怎麼辦…

由於我個人沒有很愛用 serverless,所以,我自己就做了一個實驗,我去它建立出來的 CloudFormation Template 找到他用的 AWS Lambda Layer,然後自己把另外一個有裝 Bref 的 Laravel 專案打包上傳到 Lambda 上去,再手動設定引用了有 Bref Runtime 的 Layer,再手動去設定 API Gateway,一樣也能 work 喔,所以我在想,可以改用 CDK 來改寫看看,不需要依賴 Serverless,決定下次來試試看,或是有試出的朋友,也可以分享一下。

  • 如果你還不知道什麼是 CDK,快來看看這篇文章: AWS CDK 初探
  • Bref

結論

這次只部署了一個空的 Laravel 專案,我想大家一定跟我一樣好奇,那如果要執行 Queue Job 或是其他 Laravel 的功能呢?也能一樣這麼簡單嗎?而 Bref 背後是怎麼運作的呢?還有剛剛說的,如果不想用 serverless 呢?為了部署到 Lambda 去做了一些調整,結果本地不能跑了,這???

這些題目提供給大家當做研究、寫作的題材,有研究出來,記得一起分享到這裡來 XD

最後提供一個 github,裡頭是一個空的 Laravel 專案,但該做的調整、該有的 serverless.yml 都有了,如果沒有環境的話,也提供了一個 Dockerfile 讓你可以用 docker container 來建環境,有什麼問題的話再回饋給我,感謝大家。

https://github.com/azole/laravel58-bref

參考資料

--

--

Azole (小賴)

As a passionate software engineer and dedicated technical instructor, I have a particular fondness for container technologies and AWS.