研究這個部分起因是因為公司某些功能服務是使用AWS Serverless來處理計算,故而外訂立了三個月學習NodeJS的計畫,並開始試著實作Serverless服務,Jest測試還沒研究到,下次再補充說明。
這次練習主題是,使用AWS Serverless並搭配NodeJS程式語言,實作撈取匯率API,並設定排程定期撈取匯率後更新到S3上或是Google Sheet,搭配ChatGPT快速實作,這邊提供一個免費的匯率API叫全球即時匯率API,還有提供Python 跟 PHP範例Code。
相關NodeJS的筆記文章可以參考 NodeJS 初學(一) 這系列文章
這邊使用的是Serverless這個框架服務,幫助我們透過CLI處理部署跟測試,而如果安裝遇到一些問題,可以選擇強制安裝
npm install -g serverless
npm install -g serverless --force
安裝完畢後可以使用下列指令查看版本
serverless --version
執行下列指令創建一個serverless project,接著會有一個提示窗選擇哪種服務,第一次使用可以選擇AWS NodeJS - Starter,而其他選擇會根據你選擇的服務拉取適合你的Template模板。
//Create a new serverless project
serverless
接著下一步會詢問你project命名,可以Enter使用預設命名,或是額外建立一個新的名字。
這邊使用預設命名,接著會開始下載屬於的模板,這時候會問你註冊或是登入,這邊指的是Serverless提供的Dashboard,能夠幫助你觀察你的Serverless服務,而這邊我沒有使用。
接著會詢問你是否要部署這個Serverless,選擇NO,當你寫YES,他就會直接部署上去了。
選擇NO之後可以看到他已經幫我們創建完成,你可以在所在資料夾底下看到這個檔案
接著進到專案裡面,可以看到預設創建的檔案
這邊可以看到Serverless cli 幫我們創建了index.js檔案,這個是lambda執行邏輯的地方
對照serverless.yaml
檔,可以看到function1
這個名字,這是到時候本地測試時,對應的function名字,而執行這個function時,會去觸發function1:handler
底下的index.handler
,而這個index.handler
,就是index.js檔案下個handler
這邊將function1的名字改一下方便到時候本地測試時不會錯亂XDDD...,
接著你可以使用Cli指令進行本地測試
sls invoke local -f getRateApi
或者增加傳入參數
sls invoke local --function getRateApi --data {"a": "test"}
// --function 可以簡化成 -f
sls invoke local -f getRateApi --data '{"a": "我是測試參數"}'
確認都能正常執行之後開始撰寫NodeJS的邏輯,這邊NodeJS我也是還在學習階段,這次練習主要是搞懂Serverless運作觀念跟NodeJS。
首先要先創建一個package.json
,因為習慣使用 yarn 這邊直接用yarn 創建,加上-y
表示跳過那些問答,直接創建,接著你的文檔會多一個package.json
。
npm init -y
yarn init -y
接著安裝axios,主要是基於Promise的HTTP客户端,方便我們處理HTTP請求,可以參考這個包,GITHUB。
//安裝axois套件
yarn add axios
首先先建立一個負責處理google sheet 的Class,這邊看到要使用googleapis這個套件,故我們先安裝在引入。
yarn add googleapis
創建一個命名為GoogleSheetsHandler
的Class
,檔案路徑跟名稱命名為./service/google.js
幫我們把對google sheet
的操作抽出,利用Chatgpt協助生成程式碼,constrictor
傳入我們Google Sheet的credentials.json
檔及SpreadsheetId
,而申請googole服務可以參考這篇實作 Laravel 串接Google Sheet API,接著把這個Class export。
編寫index.js
主要邏輯,這邊有在額外使用moment
處理時間格式,可做可不做,只是想記錄他每天有沒有正常執行而已,引入 Class 命名為GoogleSheetsHandler
,使用axois
取得匯率api,接著做塞入資料的取得,接著就是針對取得的資料寫入google sheet 跟取得google sheet最後一行的處理,而這邊寫入是如果最後一行沒資料會從第二行開始A2~D2
寫入,主要是因為我的Google Sheet
有設置標題。
yarn add moment
註:spreadsheetId
統一使用process.env
的方式額外放在.env
環境變數檔,方便統一管理,而取得process.env
環境設定資料,得先修正serverless.yml
設定,才能在process.env
包含這個資料,一開始你可以先試著console.log(process.env)
印出裡面包含的檔案內容,會發現無SPREADSHEET_ID
這個值。
接著設定serverless.yml
,增加useDotenv: true
,這代表在serverless會自動將命名為.env環境變數自動加載,接著設定region
,避免到時候被部署到其他地區,接著我設定了events增加schedule來產生一個cron排程,時間是每天的8點跑這個function,這裡啟動時間會根據region
時區,應該是Tokyo,台灣和日本的時差為+1小時。 當台灣早上9點,日本是10點。
而這邊的profile是設定你的AWS Credentials
的,可以參考這裡的指令,而default
是我自己設定的profile name,你可以使用aws configure list
查看。
serverless config credentials --provider provider --key key --secret secret
大致上這些就差不多完成了,接著我們跑一次本地測試sls invoke local -f getRateApi,
可以看到數據成功寫入 Google Sheets的console.log
接著查看Google Sheet,也有正常寫入
確定都沒有問題之後我們就要開始執行第一次部署,而第一次部署時會創建一個.serverless
的資料夾,之後部署完畢後,則可以針對單一function來部署
// 第一次部署
sls deplo
// 單一 function 部署
sls deploy function -f getRateApi
部署時如果沒有配置好 AWS Credentials 則可能會出現錯誤訊息,像我就是忘記設定好,因為IAM要包含以下列出的權限,最簡單的方式在IAM設定時,Permissions policies增加AWSLambda_FullAccess權限,就會至少包含以下這些。
lambda:CreateFunction:允許建立 Lambda 函數。
lambda:UpdateFunctionCode:允許更新 Lambda 函數的程式碼。
lambda:UpdateFunctionConfiguration:允許更新 Lambda 函數的設定。
lambda:InvokeFunction:允許呼叫 Lambda 函數。
lambda:ListFunctions:允許列出 Lambda 函數。
部署完畢後可以看到Lambda的服務新增了一個function。
接著我們點擊進去,可以看到產生了一個lamba的服務跟一個EventBridge
而對Configuration
點擊到Trigger
可以看到設定資料,DailyRateUpdate
是我在serverless.yaml
檔設定的命名名稱,點擊進去可以看到設定好的時間內容
點擊DailyRateUpdate
進入,可以看到每日執行時間。
而在部署時會在這些檔案資料會被打包放到S3裡面
修改一下排程時間試著對單一function重新部署,接著我只改了serverless.yaml檔的排程時間,發現一切都沒有變化,故單一function部署應該是只針對index.js
檔案部分
最後使用 sls deploy
部署才有重新修改排程時間
以上就是一個創建Serverless with NodeJS
的練習,但實務上的設定可能又更複雜了些,例如使用SQS服務,創建Queue,然後在 trigger lambda function,這還沒研究到,可能要等下回合研究SQS服務的運作,才能在融會貫通,而我的之前的文章:
python 爬蟲玉山匯率並部署到aws lambda,這個教學主要是配合docker ECR的方式操作lambda,這個有一個問題就是ECR很容易超流量收費,後來就被我關掉了XDDD