初めてAWSのLambdaを触ってみた

この記事は、最終目的に向けて複数回にわたってtryする話

最終目的

  • AWSの利用料金を毎朝Slacknに通知して請求額が跳ね上がるのを防ぎたい

なぜそんなことするのか?

  • Terraformの学習をしてた際に、applyした後にdestroyし忘れて個人としては痛い額の請求がきたからです。
    • 個人的観測範囲だと個人でのプロダクト持ってない人では、上位に食い込んでいるのでは?

今回やること

  • 今更だがLambdaに入門してSlackに通知を送ってみること

次回以降に行うこと

  • その日までの利用料金を取得しSlackに通知する
  • deploy方法
    • GithubActions or serverless
    • どちらかを使用して行えるといいなと思っています

参照

qiita.com

前提

  • AWSのアカウントを作成している人
  • Goが動く環境

実装

aws

  • アカウント作成
  • IAMロールの作成

  • aws

    • IAMでユーザーを作成している前提で話を進めます。

      コードを lambda-uploader でデプロイするためには、あらかじめ空の関数を用意する必要があります。

    • と書いてあるので予めにlambdaにて空の関数を作成します
      f:id:hironekosun:20200909160349p:plain
      create_lambda_function
      • 右上に存在している関数の作成を押下、「一から作成」を行います
      • 以下の画像のように入力し、関数の作成を押下します
        f:id:hironekosun:20200909160433p:plain
        create_lambda_function_2

        関数定義の際にポリシーテンプレートから自動作成された IAM ロールに CloudWatchReadOnlyAccess ポリシーをアタッチします。コスト情報を Lambda から読み込むのに必要です。 ロール ARN はあとで必要になるのでメモしておきます。

    • と記載があるのでこちらも対応しましょう
      • IAM > ロールで先ほど作成したロールを選択します。
      • 選択したら以下の画像のように表示されますので
        f:id:hironekosun:20200909160545p:plain
        iam_user_create
      • ポリシーをアタッチしますボタンを押下しましょう
      • 遷移後に検索窓にCloudWatchReadOnlyAccessと入れてチェックを入れて ポリシーのアタッチを行ってください。アタッチが完了したら以下の画像のようになっているはずです。
        f:id:hironekosun:20200909160608p:plain
        policy_attach
  • aws側の作業は一旦ここで終わりです。

Goで作る

package main

import (
    "encoding/json"
    "net/http"
    "net/url"

    "github.com/aws/aws-lambda-go/lambda"
    "github.com/pkg/errors"
)

type Slack struct {
    Blocks []Block `json:"blocks"`
}

type Block struct {
    Type string `json:"type"`
    Text Text `json:"text"`
}

type Text struct {
    Type string `json:"type"`
    Text string `json:"text"`
}

func run() error {
    incomingUrl := "slackのincoming hook URL"

    // slackの指定するjson形式じゃないとエラーになる
    slackMap := Slack{
        Blocks: []Block{
            Block{
                Type: "section",
                Text: Text{
                    Type: "mrkdwn",
                    Text: "検証",
                },
            },
        },
    }

    p, _ := json.Marshal(slackMap)

    resp, err := http.PostForm(
        incomingUrl,
        url.Values{"payload": {string(p)}},
    )

    if err != nil {
        return errors.WithStack(err)
    }

    defer resp.Body.Close()

    return nil

}

func main() {
    lambda.Start(run)
}
  • Goのfileをzipに固める
GOOS=linux GOARCH=amd64 go build -o main
zip handler.zip ./main
  • Go error: \$ GOPATH / go.mod exists but should not
    • このエラーが出たら自分は以下のコマンドで回避しました
export GOPATH=
  • 作成したものをawsのlambdaにアップロードしテストを実行すればslackに通知がきているかと思います

  • 今回は、ここまでとします。