Day22 AWS Lambda / Lambda is your severless solution.

這段關係,都是 Lambda 在默默付出

  • 如果你沒有仔細看 Big Apple 大哥的指示 可能會錯過關於 images 的限制 d22-1
  • 這邊我們先默認大家都有正常的 .jpg, .png 只是大小不一定如要求是方正的,如果是從本機手動進行,每次都會花費蠢蠢的重複時間
  • 這時,我們就可以使用 Lambda 作為小幫手,讓他幫我們自動調整圖片大小,並且放到正確的位置

該怎麼做

  • 在 AWS lambda 選擇 Create function, 按照圖示進行,記得 Runtime 選擇 Provide your own bootstrap on Amazon Linux 2 (近期 AWS 會將較低版本的 Runtime 逐步淘汰,如 Golang 1.x…,所以要選用這個 Runtime) d22-2
  • 作者是 Big Apple 的擁護者,後面 build 的時候也會以 Mac 為考量,所以 Architectures 選擇 arm64
  • 後面的 role 可以繼續使用給予 github actions 的 IAM role ,因為同要都只需要對 S3 進行操作
  • 在這邊操作 Add trigger ,是指這個程式不需要被手動驅動,而是會被我們設定好的某個事件種類所觸發,這邊我們選擇 S3,如圖,並把 Prefix 限定在 images/,這樣就不會把其他上傳的檔案也觸發到(也可以限定在其他你想要的位置) d22-3
  • 在 Configuration/ General configuration/ Timeout 設定為 1 分鐘,避免 Lambda 事情還沒做完就被強制關閉 d22-4
  • 假設各位都是 Gopher, 可以使用我醜醜的 code 作為 lambda
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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 出來
1
 GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o bootstrap -tags lambda.norpc main.go
  • 再使用如下指令,把 lambda zip 起來
1
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 才知道目前住宿的青旅前身是個監獄,也參觀了古老的橋下穴居與墓園探險,很值得參加~ d22-5 d22-6
comments powered by Disqus
Yodering
Built with Hugo
Theme Stack designed by Jimmy