AWS Lambda提供serverless的運算服務,serverless意思是開發者不需要管server的任何資源,也就是說你不需要創建一個EC2 instance,然後還要煩惱auto scaling, HA等設定,AWS Lambda替開發者解決這些問題,它會自動scale。
開發者只需要專心在code就好,你的code會透過Event
來驅動,
這個Event
可以來自於AWS上的服務,例如S3, API Gateway等服務,舉例來說你可以設定,當上傳檔案至S3時,S3會發送一個Event
給你的code來回應這個Event
。這篇文章就會以AWS上建立縮圖的example來說明。
而AWS Lambda的費用是取決於你的code執行時間,也就是說當沒有任何Event去trigger你的code時,是不需要收費的,在某些應用情況來說,是比EC2來得優惠。但AWS Lambda還是有它的缺點,因為你不需要也無法管server的任何設定/資源,在某些應用情況來說,替開發者帶來了些限制,所以當想要更有彈性,或者喜歡hands-on架構的開發者,或許就可以考慮EC2。
1. Prerequisite
開始之前,請先去下載並且安裝AWS CLI,安裝及設置文件可以參考這篇文章。
2. 創建2個Bueckts,並且上傳一個測試檔案
首先先在S3上創建2個buckets,2個的名稱請自己取,但記得第2個名稱結尾一定要是resized,這篇的example分別為
- kenyang-image
- kenyang-imageresized
創建完成以後,在kenyang-image
裡上傳一張圖片。
3. 創建Deployment Package
在這一步驟要創建一個Deployment package
,它是一個zip檔案,而這zip檔案裡面包含了Lambda code + dependencies。
首先先安裝2個packages:
- aysnc: Async utility module
- gm: GraphicsMagick用來轉圖
$ cd test-lambda-s3
$ npm install async gm
安裝完以後,創建一個CreateThumbnail.js
,並把下面的code貼入。這份code是利用async去依序完成三個工作:
- 從S3下載檔案至buffer
- 轉檔案
- 上傳檔案至S3
// dependencies
var async = require('async');
var AWS = require('aws-sdk');
var gm = require('gm')
.subClass({ imageMagick: true }); // Enable ImageMagick integration.
var util = require('util');
// constants
var MAX_WIDTH = 100;
var MAX_HEIGHT = 100;
// get reference to S3 client
var s3 = new AWS.S3();
exports.handler = function(event, context, callback) {
// Read options from the event.
console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
var srcBucket = event.Records[0].s3.bucket.name;
// Object key may have spaces or unicode non-ASCII characters.
var srcKey =
decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
var dstBucket = srcBucket + "resized";
var dstKey = "resized-" + srcKey;
// Sanity check: validate that source and destination are different buckets.
if (srcBucket == dstBucket) {
callback("Source and destination buckets are the same.");
return;
}
// Infer the image type.
var typeMatch = srcKey.match(/\.([^.]*)$/);
if (!typeMatch) {
callback("Could not determine the image type.");
return;
}
var imageType = typeMatch[1];
if (imageType != "jpg" && imageType != "png") {
callback('Unsupported image type: ${imageType}');
return;
}
// Download the image from S3, transform, and upload to a different S3 bucket.
async.waterfall([
function download(next) {
// Download the image from S3 into a buffer.
s3.getObject({
Bucket: srcBucket,
Key: srcKey
},
next);
},
function transform(response, next) {
gm(response.Body).size(function(err, size) {
// Infer the scaling factor to avoid stretching the image unnaturally.
var scalingFactor = Math.min(
MAX_WIDTH / size.width,
MAX_HEIGHT / size.height
);
var width = scalingFactor * size.width;
var height = scalingFactor * size.height;
// Transform the image buffer in memory.
this.resize(width, height)
.toBuffer(imageType, function(err, buffer) {
if (err) {
next(err);
} else {
next(null, response.ContentType, buffer);
}
});
});
},
function upload(contentType, data, next) {
// Stream the transformed image to a different S3 bucket.
s3.putObject({
Bucket: dstBucket,
Key: dstKey,
Body: data,
ContentType: contentType
},
next);
}
], function (err) {
if (err) {
console.error(
'Unable to resize ' + srcBucket + '/' + srcKey +
' and upload to ' + dstBucket + '/' + dstKey +
' due to an error: ' + err
);
} else {
console.log(
'Successfully resized ' + srcBucket + '/' + srcKey +
' and uploaded to ' + dstBucket + '/' + dstKey
);
}
callback(null, "message");
}
);
};
接著就把所有檔案zip起來,
$ zip -r9 ~/create-thumbnail.zip *
4. 替Lambda Function建立一個IAM Role
在這一步驟要創建一個IAM Role專門去執行我們的lambda function,
[1] 打開IAM console https://console.aws.amazon.com/iam/.
[2] 選擇【Create role】
[3] 在【Select type of trusted entity】中,請選擇AWS service, 然後選Lambda,並點擊【Next Permissions】。(如下圖)
[4] 在【Filter: 】中輸入【AWSLambdaExecute】,並點擊【Next: Review】(如下圖)
[5] 在【Role name】中輸入想要的角色名稱,並且點擊【Create role】
[6] 接著點擊打開剛剛創建的角色
[7] 點擊右下角的【Add inline policy】
[8] 在Service,點擊【Choose a service】,並且選擇【S3】
[9] 在Actions,點擊【Select actions】,接著把【Write】展開,找到【PutObject】並且打勾
[10] 在Resources,把右下角的【Any】checkbox勾起來
[11] 點擊【Choose Review policy】,接著輸入Name,並且點擊【Create policy】
[12] 在Summary的頁面中,記下Role ARN,待會我們會用到(如下圖)
5. 上傳Deployment Package
執行下面的指令把剛剛的Deployment package上傳上去,請修改幾個參數:
- region: 這篇使用ap-northeast-1
- role-arn:上面第三步驟所創建的role arn
- runtime: 這篇使用nodejs6.10
- zip-file: 你的zip檔案路徑
$ aws lambda create-function \
--region ap-northeast-1 \
--function-name CreateThumbnail \
--zip-file fileb://file-path/CreateThumbnail.zip \
--role role-arn \
--handler CreateThumbnail.handler \
--runtime nodejs6.10 \
--timeout 30 \
--memory-size 1024
成功的話會回傳一串JSON回來,請把FunctionArn記下來,待會會用到
6. 手動調用Lambda Function
上傳上去以後,就可以來進行手動
測試,先創建一個input.txt
,並把下面的內容貼進去,需修改
- awsRegion: 這篇使用ap-northeast-1
- name: 改成上面我們創建的bucket名稱,這篇是kenyang-image
- arn: 把後面的kenyang-image改成你的bucket名稱,這篇是kenyang-image
- key: 上傳上去的測試檔名
{
"Records":[
{
"eventVersion":"2.0",
"eventSource":"aws:s3",
"awsRegion":"ap-northeast-1",
"eventTime":"1970-01-01T00:00:00.000Z",
"eventName":"ObjectCreated:Put",
"userIdentity":{
"principalId":"AIDAJDPLRKLG7UEXAMPLE"
},
"requestParameters":{
"sourceIPAddress":"127.0.0.1"
},
"responseElements":{
"x-amz-request-id":"C3D13FE58DE4C810",
"x-amz-id-2":"FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD"
},
"s3":{
"s3SchemaVersion":"1.0",
"configurationId":"testConfigRule",
"bucket":{
"name":"kenyang-image",
"ownerIdentity":{
"principalId":"A3NL1KOZZKExample"
},
"arn":"arn:aws:s3:::kenyang-image"
},
"object":{
"key":"test.jpg",
"size":1024,
"eTag":"d41d8cd98f00b204e9800998ecf8427e",
"versionId":"096fKKXTRTtl3on89fVO.nfljtsv6qko"
}
}
}
]
}
接著就可以執行下面的指令進行測試,一樣要修改
- region: 這篇是使用ap-northeast-1
- payload: input.txt路徑
$ aws lambda invoke \
--invocation-type Event \
--function-name CreateThumbnail \
--region ap-northeast-1 \
--payload file:///file-path/input.txt \
outputfile.txt
然後就可以去bucket kenyang-imageresized
看看有沒有產生縮圖。
7. 設定Amazon S3 發送Events給Lambda
7-1. 替S3設定InvokeFunction的權限
這步驟是給予S3去調用Function的權限,且只有在下列個二個條件下才會去調用function:
- 檔案被創建在你指定的bucket下
- 且這bucket是由該lambda account所創建的,話句話說,如果把此bucket刪除,接著別的帳號用戶去創建相同名稱的bucket,並且上傳檔案,此時並不會去調用function.
執行下方的指令即可給予S3此權限,請替換下列參數:
- region: 這篇是使用ap-northeast-1
- staement-id: unique的ID即可
- source-arn: 把kenyang-image改為你的bucket名稱
$ aws lambda add-permission \
--function-name CreateThumbnail \
--region ap-northeast-1 \
--statement-id 1234 \
--action "lambda:InvokeFunction" \
--principal s3.amazonaws.com \
--source-arn arn:aws:s3:::kenyang-image
7-2. 設置S3 notification
在這步驟要設定當上傳檔案至此bucket時,要發送notification,以及收到notification時,要去調用上面創建的AWS Lambda Function。
[1] 點擊該Bucket
[2] 點擊【Properties】
[3] 找到【Advanced settings】
[4] 點擊【Events】
[5] 點擊【Add notification】
[6] 勾選【ObjectCreate (All)】
[7] 在【Send to】中選擇【Lambda Function】
[8] 在【Lambda】中找到創建的function【CreateThumbnail】
[9] 點擊【Save】
7-3. 測試
完成上述步驟以後,此時就可以進行測試,上傳檔案至指定的bucket裡面,然後去另外一個對應的bucket中看看thumbnail是否有被創建。