iT邦幫忙

2023 iThome 鐵人賽

DAY 3
1

設定Lambda+API Gateway

接著就是要來設定AWS Lambda+API Gateway了~

1.複製以下測試用的code,部屬一個簡單的LINEBOT

以下程式碼之後正式開發會不太一樣,所以先不詳細解釋,這邊就簡單開一個main.go複製貼上去做測試就好,目標是確認昨天的存在SSM的key們能被正常讀取,同時部署一個Gin框架做的簡易Linebot上去,確認AWS到Line這段是沒問題的~


package main

import (
	"context"
	"fmt"
	"log"
	"net/http"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ssm"
	"github.com/aws/aws-sdk-go/service/ssm/ssmiface"
	ginadapter "github.com/awslabs/aws-lambda-go-api-proxy/gin"
	"github.com/gin-gonic/gin"
	"github.com/line/line-bot-sdk-go/v7/linebot"
)

var (
	ginLambda *ginadapter.GinLambda
	ssmsvc    *SSM
)

func init() {
	ssmsvc = NewSSMClient()
	lineSecret, err := ssmsvc.Param("CHANNEL_SECRET", true).GetValue()
	if err != nil {
		log.Println(err)
	}
	lineAccessToken, err := ssmsvc.Param("CHANNEL_ACCESS_TOKEN", true).GetValue()
	if err != nil {
		log.Println(err)
	}
	bot, err := linebot.New(
		lineSecret,
		lineAccessToken,
	)
	if err != nil {
		log.Fatal(err)
	}
	// stdout and stderr are sent to AWS CloudWatch Logs
	log.Printf("Gin cold start")
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})

	r.POST("/callback", func(c *gin.Context) {
		// ctx := c.Request.Context()
		events, err := bot.ParseRequest(c.Request)
		if err != nil {
			if err == linebot.ErrInvalidSignature {
				log.Println(err)
				c.JSON(http.StatusBadRequest, err)
			} else {
				log.Println(err)
				c.JSON(http.StatusInternalServerError, err)
			}
			return
		}
		for _, event := range events {
			if event.Type == linebot.EventTypeMessage {
				switch message := event.Message.(type) {
				case *linebot.TextMessage:
					if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.Text)).Do(); err != nil {
						log.Print(err)
					}
				case *linebot.StickerMessage:
					replyMessage := fmt.Sprintf(
						"sticker id is %s, stickerResourceType is %s", message.StickerID, message.StickerResourceType)
					if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(replyMessage)).Do(); err != nil {
						log.Print(err)
					}
				}
			}
		}
	})

	ginLambda = ginadapter.New(r)
}

func Handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
	// If no name is provided in the HTTP request body, throw an error
	return ginLambda.ProxyWithContext(ctx, req)
}

func main() {
	lambda.Start(Handler)
}

type SSM struct {
	client ssmiface.SSMAPI
}

func Sessions() (*session.Session, error) {
	sess, err := session.NewSession()
	svc := session.Must(sess, err)
	return svc, err
}

func NewSSMClient() *SSM {
	// Create AWS Session
	sess, err := Sessions()
	if err != nil {
		log.Println(err)
		return nil
	}
	ssmsvc := &SSM{ssm.New(sess)}
	// Return SSM client
	return ssmsvc
}

type Param struct {
	Name           string
	WithDecryption bool
	ssmsvc         *SSM
}

func (s *SSM) Param(name string, decryption bool) *Param {
	return &Param{
		Name:           name,
		WithDecryption: decryption,
		ssmsvc:         s,
	}
}

func (p *Param) GetValue() (string, error) {
	ssmsvc := p.ssmsvc.client
	parameter, err := ssmsvc.GetParameter(&ssm.GetParameterInput{
		Name:           &p.Name,
		WithDecryption: &p.WithDecryption,
	})
	if err != nil {
		return "", err
	}
	value := *parameter.Parameter.Value
	return value, nil
}

記得把"CHANNEL_SECRET","CHANNEL_ACCESS_TOKEN",換成你的SSM紀錄的KEY名稱

2.打包檔案成zip檔

LINUX 比較簡單如下:
arm64:

GOOS=linux GOARCH=arm64 go build -tags lambda.norpc -o bootstrap main.go

x86_64:

GOOS=linux GOARCH=amd64 go build -tags lambda.norpc -o bootstrap main.go

然後把編譯後的二進制檔壓縮成zip

zip myFunction.zip bootstrap

而window比較麻煩,要先裝

go install github.com/aws/aws-lambda-go/cmd/build-lambda-zip@latest

x86_64: (記得CMD要開powershell)

$env:GOOS = "linux"
$env:GOARCH = "amd64"
$env:CGO_ENABLED = "0"
go build -tags lambda.norpc -o bootstrap main.go
build-lambda-zip -o myFunction.zip bootstrap

arm64:

$env:GOOS = "linux"
$env:GOARCH = "arm64"
$env:CGO_ENABLED = "0"
go build -tags lambda.norpc -o bootstrap main.go
build-lambda-zip -o myFunction.zip bootstrap

詳細可以參考下面網址
Deploy Go Lambda functions with .zip file archives - AWS Lambda

3.Lambda的設定

  1. 按到Lambda建立一個新的layer,上傳剛剛弄好的zip檔
    Runtime選provided.al2(Amazon Linux 2),不要選Go 1.X (2023/12/31就不能用了)
    https://ithelp.ithome.com.tw/upload/images/20230918/20115990c2wNadT4er.png

  2. 然後去建立函式,一樣的設定

    https://ithelp.ithome.com.tw/upload/images/20230918/20115990EEVPrtdu2L.png

  3. 到裡面按新增層,選擇剛剛的layer

    https://ithelp.ithome.com.tw/upload/images/20230918/20115990hu9LiPzTUr.png

    https://ithelp.ithome.com.tw/upload/images/20230918/20115990iNAdtww0LR.png

  4. 給角色增加SSM的許可
    點進組態-許可,點進他幫我們創好的角色名稱
    https://ithelp.ithome.com.tw/upload/images/20230918/20115990gqAlE2txJe.png

  5. 連接政策

    https://ithelp.ithome.com.tw/upload/images/20230918/20115990vVVWqJmbSb.png

  6. 搜尋SSM,打勾FullAccess,往下滑 ⇒新增許可
    https://ithelp.ithome.com.tw/upload/images/20230918/20115990uiCsALiX78.png

  7. 測試一下,選個APIGATEWAY的範本

    https://ithelp.ithome.com.tw/upload/images/20230918/20115990ZOIaCdptFl.png

有打到就可以來去設定API Gateway了~

4.API Gateway的設定

到API GateWay的頁面,先建立一個REST API

https://ithelp.ithome.com.tw/upload/images/20230918/20115990cJBiC3I1Nt.png

然後,創建一個資源,設定代理資源,CORS打勾

https://ithelp.ithome.com.tw/upload/images/20230918/201159901loomuBdfl.png

然後綁定自己的Lambda函數

https://ithelp.ithome.com.tw/upload/images/20230918/201159909A1F0PdPyg.png

記得最後部屬API,階段名稱可以是production

https://ithelp.ithome.com.tw/upload/images/20230918/20115990XV6NmdHvbs.png

回到Lambda就能成功看到綁定好了

https://ithelp.ithome.com.tw/upload/images/20230918/20115990wiVYfL6TWf.png

5.回到Line Developer測試

如果上面都設定好,可以在上一步最後找到API Gateway的API endpoint。
接著用拿到的API endpoint來更新Line的webhook
因為我們寫的gin後端用來處理line的路由是/callback,所以我們把url最後面換掉~
像下面這樣:

https://ithelp.ithome.com.tw/upload/images/20230918/20115990VfByHp3K3W.png

如果更新成功,顯示success,就代表沒問題拉~ 那我們明天見:)


上一篇
Day02 前置準備-01(Line Developer + AWS SSM)
下一篇
Day04 加上Github Action
系列文
Golang LineBot X GoogleDrive:LINE有各種限制!? 那就丟上Drive吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言