這段關係,都是 Lambda 在默默付出
- 如果你沒有仔細看 Big Apple 大哥的指示 可能會錯過關於 images 的限制
- 這邊我們先默認大家都有正常的
.jpg
, .png
只是大小不一定如要求是方正的,如果是從本機手動進行,每次都會花費蠢蠢的重複時間
- 這時,我們就可以使用 Lambda 作為小幫手,讓他幫我們自動調整圖片大小,並且放到正確的位置
該怎麼做
- 在 AWS lambda 選擇 Create function, 按照圖示進行,記得 Runtime 選擇
Provide your own bootstrap on Amazon Linux 2
(近期 AWS 會將較低版本的 Runtime 逐步淘汰,如 Golang 1.x...,所以要選用這個 Runtime)
- 作者是 Big Apple 的擁護者,後面 build 的時候也會以 Mac 為考量,所以 Architectures 選擇
arm64
- 後面的 role 可以繼續使用給予 github actions 的 IAM role ,因為同要都只需要對 S3 進行操作
- 在這邊操作 Add trigger ,是指這個程式不需要被手動驅動,而是會被我們設定好的某個事件種類所觸發,這邊我們選擇 S3,如圖,並把 Prefix 限定在 images/,這樣就不會把其他上傳的檔案也觸發到(也可以限定在其他你想要的位置)
- 在 Configuration/ General configuration/ Timeout 設定為 1 分鐘,避免 Lambda 事情還沒做完就被強制關閉
- 假設各位都是 Gopher, 可以使用我醜醜的 code 作為 lambda
package main
import (
"bytes"
"context"
"fmt"
"image"
"image/jpeg"
"io"
"strings"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/disintegration/imaging"
)
func main() {
lambda.Start(handler)
}
func handler(ctx context.Context, s3Event events.S3Event) error {
sess, err := session.NewSession(&aws.Config{
// Tokyo region is ap-northeast-1
Region: aws.String("ap-northeast-1")},
)
if err != nil {
// check error, lambda logs also show up in cloudwatch
fmt.Println("message: error = ", err.Error())
return err
}
svc := s3.New(sess)
fmt.Println("message: get session")
// only deal with one file at a time
object := s3Event.Records[0].S3.Object
// key is the file name with all prefix
key := object.Key
// bucket is the bucket name
bucket := "{Your Bucket Name}"
// check the file key
fmt.Println("message: key = ", key)
resp, err := svc.GetObject(&s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(key),
})
if err != nil {
fmt.Println("message: error = ", err.Error())
return err
}
defer resp.Body.Close()
content, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("message: error = ", err.Error())
return err
}
img, _, err := image.Decode(bytes.NewReader(content))
if err != nil {
fmt.Println("message: error = ", err.Error())
return err
}
resized := imaging.Resize(img, 3000, 3000, imaging.Lanczos)
buf := new(bytes.Buffer)
err = jpeg.Encode(buf, resized, nil)
if err != nil {
fmt.Println("message: error = ", err.Error())
return err
}
// get the file name with prefix
keyPath := strings.Split(key, "/")
imageName := keyPath[len(keyPath)-1]
// put the new resized image to the another folder, avoid infinite loop
newKey := "/podcast/images/" + imageName
_, err = svc.PutObject(&s3.PutObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(newKey),
ContentType: aws.String("image/jpeg"),
Body: bytes.NewReader(buf.Bytes()),
})
if err != nil {
fmt.Println("message: error = ", err.Error())
return err
}
fmt.Println("message: success")
return nil
}
- 並使用如下指定,把 lambda build 出來
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o bootstrap -tags lambda.norpc main.go
zip myFunction.zip bootstrap
- 在 Lambda Code/ Code source 選擇 Upload from/ .zip file,並且上傳剛剛的 myFunction.zip 檔案
- 這樣每當有圖片上傳到 images/ 以下的位置,就會觸發 lambda,並且把圖片 resize 到 3000x3000 的大小,並且放到 podcast/images/ 以下的位置,這邊的大小就是 Apple 老大哥所要求的了
- 答拉~
其他延伸
- 編寫 Lambda 時,可以注意有各種觸發的 Event 可以選擇,你也可以自訂自己的 struct,只要是你預期的觸發方式就好,不一定都需要從 aws-lambda-go/events package 中選擇
- 在 build, zip 的時候,注意各種設定與環境,如果 Lambda 不如預期,也可以從 Monitor/ Logs 中去看看發生了什麼事,所以建議 Lambda 中可以多一些 message 幫助 debug
- lambda 便宜所以可以多玩玩,但因為上傳的是已經 build 好的 binary,所以最好也把原始碼放在 github 上,這樣可以方便管理與維護
- 這支 Lambda 只負責把圖片壓成 3000x3000,不負責 crop 或修圖喔
外出取材
- 愛丁堡是個小小的城市,可以參加各種有趣的 Tour,會有不同的體驗與了解,參加 Tour 才知道目前住宿的青旅前身是個監獄,也參觀了古老的橋下穴居與墓園探險,很值得參加~