LoginSignup
35
26

More than 3 years have passed since last update.

GoとLambdaでAWS使用料金を毎日LINE通知させる

Last updated at Posted at 2020-01-11

AWSの使用料金こわい

おっしゃ AWSのコンソールいじるで〜 :nerd:
お、そういや〜AWS今いくらかかっとんねんやろ :nerd:
マイ請求ダッシュボード ポチ〜っと :nerd:
awsbilling.png

んん!?? :innocent::innocent::innocent:


ECSを放置して$100超えの請求がきたり、
キルしたはずのRDSインスタンスが知らぬ間に復活していて地味に$40くらい請求がきたり、
この通過儀礼をいい加減なんとかしようと簡単な料金通知システムを作りました。 :nerd:

やったこと

Go言語でLINE notifyの通知APIをキックする関数を実装して
AWS Lambdaにデプロイ:nerd:Cronで定期実行して、毎日AWSの使用料金を自分へLINEしてくれる簡単なシステムを作りました。

実装の準備

LINE notifyからTokenを発行する

LINE notifyにアクセスします。
line_notify_header.png

ログインするアカウントはもちろん通知がきてほしい自分のLINEアカウントです。
アプリ側からメールアドレス・パスワードを設定して、PCからログインします。そしてマイページへ移動:nerd:
スクリーンショット 2020-01-11 0.23.20.png
PCからのアクセスならばこのようなコンポーネントが現れトークンを受け取ることができます。

serverless framework

AWS Lambdaをちゃちゃっと実装したいのでもちろんserverless frameworkを使います!
Go用の雛形をさくっとコマンドで準備:nerd:

$ sls create -u https://github.com/serverless/serverless-golang/ -p goserverless

serverless.yamlは最低限、以下のような記述にあれば動かせます。
cronは日本時間の朝8時に通知がくるように設定してあります。
IAMはCloudWatchReacOnlyAccessのものをまるっと貼り付けてます。

serverless.yaml

service: goserverless

provider:
  name: aws
  runtime: go1.x
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - 'autoscaling:Describe*'
        - 'cloudwatch:Describe*'
        - 'cloudwatch:Get*'
        - 'cloudwatch:List*'
        - 'logs:Get*'
        - 'logs:List*'
        - 'logs:Describe*'
        - 'logs:TestMetricFilter'
        - 'logs:FilterLogEvents'
        - 'sns:Get*'
        - 'sns:List*'
      Resource:
        - '*'

package:
 exclude:
   - ./**
 include:
   - ./bin/**

functions:
  billing_notify:
    handler: bin/main
    events:
      - schedule: cron(0 23 * * ? *)
    environment:
      LINEpostURL: https://notify-api.line.me/api/notify
      LINEnotyfyToken: <Token>

実装

Go言語を使用します。pythonでは割と実装例があるようですが、Goでの実装は私の観測範囲では見当たらなかったのでレシピを載せておきます。:nerd:

Go言語で CloudWatchから料金情報を取得する処理

CloudWatchの料金情報は以下のように構造体を埋めると取得することができます。料金情報のため、リージョンは us-east-1 です。

main.go
func Handler() (Response, error) {
    svc := cloudwatch.New(session.New(), &aws.Config{Region: aws.String("us-east-1")})

    params := &cloudwatch.GetMetricStatisticsInput{
        Dimensions: []*cloudwatch.Dimension{
            {
                Name:  aws.String("Currency"),
                Value: aws.String("USD"),
            },
        },
        StartTime:  aws.Time(time.Now().Add(time.Hour * -24)),
        EndTime:    aws.Time(time.Now()),
        Period:     aws.Int64(86400),
        Namespace:  aws.String("AWS/Billing"),
        MetricName: aws.String("EstimatedCharges"),
        Statistics: []*string{
            aws.String(cloudwatch.StatisticMaximum),
        },
    }
    resp, err := svc.GetMetricStatistics(params)
    if err != nil {
        fmt.Println(err)
    }

    // ...省略

}

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

Go言語で LINE notify API にPOST

LINE Notify API Documentによれば以下のようなリクエストヘッダーが必要です。
リクエストパラメータに自分のLINEに通知したい内容を載せます。messageは必須で、ほかにもイメージをPOSTして通知として飛ばせます:nerd:

main.go

func Handler() (Response, error) {

    // ...省略

    val := url.Values{}
    val.Add("message", param)
    request, err := http.NewRequest("POST", os.Getenv("LINEpostURL"), strings.NewReader(val.Encode()))
    if err != nil {
        fmt.Println(err)
    }
    request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    request.Header.Add("Authorization", "Bearer "+os.Getenv("LINEnotyfyToken"))
    lineResp, err := http.DefaultClient.Do(request)
    if err != nil {
        fmt.Println(err)
    }

    return Response{
        Message: fmt.Sprintf("%v", lineResp),
    }, nil
}

無事に毎日AWS使用料金を把握できた

ほんま焦るで〜 :nerd:
もうこれで見落としで使用料金えらいことならんやろ〜:nerd:

従量課金のAWSサービスを試す前には使用料金を通知する仕組みを是非つくっておくことが大事ですよね。お財布を守るためにも...。

35
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
26