用CloudWatch定時產生Event丟檔案到S3


1. 建立S3 Bucket

建立後記得改後面的程式碼的var bucketName變數的值。

2. IAM新增Role 

先在IAM新增一個role,連接AWSLambdaExecute政策,這個政策會包含可以在S3放檔案的權限。

3. 新增Lambda函數

選擇"從頭開始撰寫"
  • 函數名稱,看你喜歡,我是設"myLambda"
  • 執行時間,使用"Node.js 12.x"
  • 選擇或建立執行角色,使用已存在角色,選擇步驟1所建立的Role。

放置Lambda程式碼

var AWS = require('aws-sdk');

var bucketName = '{your-bucket-name}';

function putFileToS3(key, body, callback) {
    var s3 = new AWS.S3();
    s3.putObject({Bucket: bucketName, Body: body, Key: key}, callback);
}

exports.handler = (event, context, callback) => {
    console.log('my lambda');
    console.log('Received event:', JSON.stringify(event, null, 2));
    putFileToS3(event.id, JSON.stringify(event, null, 2),
        (err, response) => {
            if (err) {
                console.error(err);
                callback(err);
            } else {
                console.log('put to s3 succeed, obj:' + event.id);
                callback(null, 'put is succeed!');
            }
        }
    );
};

4. 測試Lambda函數

在Lambda函數右上角可以選擇測試用的資料,我們選擇CloudWatchEvent(如圖),按下"測試"系統就會自動產生一組Event,稍等一下就會在Lambda頁面最上方顯示測試結果。

測試時有時候會發生timeout的狀況,可以在下方的"基本設定"改timeout時間,正常執行上面的程式碼應該不會超過3秒。我是設為10秒。

5. 建立CloudWatch事件

在CloudWatch中的事件中建立新的規則(rule),選擇排程5分鐘產生一個事件,然後目標選擇Lambda函數。如下圖所示。
如果你找不到剛建立的Lambda函數,就是Lambda建立的AWS區域和CloudWatch的AWS區域不一樣所導致,請分別進入控制面板後看右上角的區域是否相同,以我的設定來說是"東京"。

CloudWatch設置完後會直接開始一個事件,你可以在日誌部分看到執行結果的log。(如下圖)

6. Lambda中使用其他node.js套件

假設上面的程式我改node-uuid套件動態產生新的檔案名稱,會發生Cannot find module 'node-uuid'的執行錯誤
...
    var uuid = require('node-uuid');
    var keyName = 'lambda_put_' + uuid.v4()
    putFileToS3(keyName, JSON.stringify(event, null, 2),
...

經由AWS官方文件描述打包其他node.js套件進行下面的修改。

1. 將本機程式碼目錄下整個打包成zip,含node_modules,如果壓縮後的檔案比較大>10MB,AWS建議是放到S3再使用。

2. 在Lambda頁面選擇將打包檔案上傳,記得按右上角"儲存"


3. 確定Lambda要執行的js檔案,以我的來說,從原本線上編輯器用的index.handler要改成我的js名稱getEventStoreItV2.handler即可。

7. 如果是跨帳號的存取

如果是帳號A的Lambda要放到個帳號B的S3,可以參考官方文件設置。

概略來說:
1. 在帳號A的lambda函數的role內attach自訂的policy可以putObject到另一個s3的ARN中。
2. 在帳號B的S3的bucket中加入自訂的Principal的權限,指定可讓帳號A的特定role可以putObject。

留言