2020年3月振り返り

今月も振り返ります。

仕事

プロジェクトでやったこと

  • 要件定義
  • 仕様書作成
  • アーキテクチャ図作成
  • etc...

今月は設計・ドキュメント作成が仕事の大半を占める。

仕様書、設計書等のドキュメントを書く力が足りなさすぎることを実感しました。

以下、ドキュメントを書く際に意識する(自分に対して)

  • ドキュメントの目的はなにか
  • どのような読者を想定しているか
  • このシステムの特徴はなにか
  • どういったことを仕様として書くのか
  • そのワーディングの定義は?
    • ないなら定義する
    • ブレたワーディングを使わない
    • 他のシステムとの連携があるなら、共通のワードを使うなど
  • 自分がそのドキュメントで伝えたい思いはなにか
  • 思いを論理的に書く
  • etc...

プライベート

読書

  • ズボラPDCA
    • うーんって感じ
  • 理科系の作文技術
    • 学生のときに読んだのを思い出して、読み返してみた
    • ドキュメント書く上で学ぶことが多い
    • これは何度も読み直す必要あり
  • まんがでわかる 理科系の作文技術
    • サクッと読める
  • 1%の努力
    • めちゃ良かった
    • The Third Doorを読み直したくなった
  • 世界で一番やさしい 会議の教科書
    • 会議仕切るのを参考にするために読んだ
    • 良い!
  • マイクロサービスパターン(読み終わってない)
    • まだ読み始めたばかりだけど、面白い!
  • Design It!
    • 良い!
    • これも噛めば噛むほど味が出るやつ
  • 実践 AWS CDK
    • 良い
    • VPCを使ったAWSサービスの使用例をほしかった
  • ブルーピリオド
    • 久しぶりに当たり!
  • 筋トレが最強のソリューションである
    • 筋トレします

開発

  • https://100list.app のAndroid版を開発中
  • Android難しいが、もっといろんなアプリのコード読んで学びたい

筋トレ

  • コロナでジムに行くのを躊躇うので、家でダンベル持ち上げるぐらい
  • ちゃんと運動したい

2020年2月振り返り

はい、今月も振り返ります。

といっても、あんまり記憶ないです。 ちゃんと記録しとかないとどんどん忘れますね...

仕事

  • 2月は1月に落ち着いたプロジェクトの仕様変更依頼などに対応
  • バグ修正
  • 2月から新しいプロジェクトが立ち上がったので、それのアーキテクチャ設計と調査
    • 大規模のプッシュ配信システムのアーキテクチャ考えるの楽しい
    • 仕様書やDesign It!っていう本で書かれているASRを考える・書くことは大切ですね(大変だけど)
    • データモデリング
    • ワーディング大切。曖昧に言葉を使って仕様書書くとブレる。

プライベート

  • https://100list.appのAndroid版をとにかく開発
    • iOSはすでにリリースされてるので焦ってる
    • 引き続きがんばります
  • 仕事終わったらとりあえずスタバに行って22時ぐらいまで開発してた(おそらく3月もそうなる)
  • ジムは2月は13回行った
  • ランニング5km走れるようになった
  • ドメイン駆動設計入門を読んだ
  • AOJのC++でプログラミング入門を始めた

2020年1月振り返り

今年から1ヶ月ごとの振り返りを書いていく。

理由は、毎年毎年年末になると何してたのか思い出せず自分の棚卸しさえできてないけど、毎月書けば振り返りもしやすそうだから。

とりあえず、お試しで毎月書くようにするよ!

仕事

  • 今関わっているチームの小さいプロジェクトが一段落しそうってことで、去年よりも時間的に余裕のある仕事ができている
  • 本番運用時にエラーや障害の検知、運用時に毎回検知しておきたいログ等をメール、Slack、Push通知で知らせるように、AWS CDKでCloudWatch Alarm, Cloud Watch Logsのフィルターを作成
  • CloudWatch Alarmのアクションで実行されるAWS Lambdaをserverless frameworkで実装(Rust)
  • バグ修正
  • Cコンパイラの実装は関数宣言まで(https://www.sigbus.info/compilerbook)

プライベート

  • https://100list.app のLP修正
  • Androidアプリの実装(急ぎます)
  • Pythonでスクレイピングのためのコード書いた
    • 期日のほんとギリギリでデータ取れたので良かった
  • 1/11(土)にジムに契約して、1/13日(日)からジム行き始めた
    • 週3でジムに通って1時間ほど鍛えるのが目標だけど、週5ぐらいで行ってるし継続できてる
    • チェストプレス、ショルダープレス、アブドミナル、ラットプルダウンあたりのマシンで70kgを軽々できるようになるのが直近の目標
      • どのマシンもまだ50kg台程度しか重量上げられてない。。。
    • ランニングは20kmぐらい走れるようになりたい
      • ジム行き始めは10分もきつかったけど、今は9km/h で25分ぐらい走れるようになったよ(体調次第のところもある)
    • 体重はまだ全然減らないんだけど?
    • プロテインとかサプリメントも飲みだしたよ
  • 30日プランクチャレンジも始めた
    • この記事書いてる日で9日目  * 今の自己ベストは105秒
  • 1/25に梅田のb-monsterに初めて行った
    • 朝7時から自分の限界まで追い込むので最高
    • まだ入会してないけど、あれだけ追い込めるなら価値あるから悩んでる
    • 朝から活動するの良いですね(いつも起きるの遅いから改善必須)
  • ブログは技術ネタのみで今年50記事書くのが目標で、今月4記事
  • AtCoderの練習問題を解き始めた
    • コンテストはまだ参加してない

最後に

やりたいことを管理して日頃から見返すとやる気出るからLISTっていうアプリはおすすめです!

https://100list.app

Amazon Linux2にPython3をインストールする

Pythonは書いたことなかったんですがスクレイピングするためにサクッと書いて、それをローカルではなくEC2上で動かす必要性が出てきました。

利用しようとしたAmazon Linux2にプリインストールされているのはPythonの2系なのですが、ローカルで書いたスクリプトはPython3系で書いたため、EC2上にPython3をインストールする必要がありました。

そのときに実行した手順を備忘録として書いておきます。

前提

  • Amazon Linux 2 AMI(ami-011facbea5ec0363b)でEC2を起動

手順

Python3をインストール

sudo amazon-linux-extras install python3 -y

pip3をアップデート

sudo pip3 install --upgrade pip

Python3のバージョンを確認

python3 --version

Python 3.6.2(現時点だと3.8.1が最新なので、ちょっと古いね...)

必要なパッケージをインストールする

pip3 install boto3
pip3 install requests
pip3 install beautifulsoup4

おまけ

端末から抜けたりしても、スクリプトは実行し続けてほしい場合は、nohup使うと良いよ

nohup python3 main.py > ~/output.log &

プロセス確認する場合

ps aux | grep main.py

Serverless FrameworkとGoでAWS利用費を毎朝Slackに通知する

f:id:ryskit:20200119180331p:plain

以前、「AWS LambdaでAWS利用費を毎朝Slackに通知する」というタイトルで記事を書きました。 この中では、Serverless Frameworkを使わず、Goで書いたコードをビルドしてZip化、AWSリソースは手作業で作成、デプロイももちろん手作業でZipをアップロードしていました。

blog.ryskit.com

ただ正直、AWSリソースを手で作成するの面倒だし、修正してコマンド一発でデプロイしたいところです。

で、今回それを解決するためにServerless Frameworkを導入し、手作業ではなくターミナルからコマンドでデプロイできるようにします。

それでは、いってみましょう!

前提

AWS LambdaでAWS利用費を毎朝Slackに通知する - そうきたか で作成したコードを利用します。

ソースコードはこちらからダウンロードできます。

github.com

Serverless Frameworkをインストールする

すでに僕の環境にはNodeが入っていたので、npmでインストールしました。

npm install -g serverless

以下のリンク先にインストール方法は書いてあるので、参考にしてみてください!

serverless.com

Serverless Frameworkの設定ファイルを作る

以下のようなコマンドを実行すれば、ServerlessFrameworkの雛形を作成できますが今回は使いません。

serverless create -u https://github.com/serverless/serverless-golang/ -p hello-go-lambda

今回はすでに作成した環境があるので、そこにserverless.yml という名前のファイルを作成します。

service: aws-billing-notification

provider:
  name: aws
  runtime: go1.x
  stage: prd
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: Allow
      Action:
        - "logs:CreateLogGroup"
        - "logs:CreateLogStream"
        - "logs:PutLogEvents"
        - "ce:GetCostAndUsage"
      Resource:
        - "*"

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

functions:
  billing-notification:
    handler: bin/main
    events:
      - schedule: cron(0 22 * * ? *)

あと、もう一つ作業があります。ファイルをリネームします。

以前、billing-notification.goという名前でファイルを作成していたのですが、main.go という名前にリネームしておいてください。

リネームできたら以下のコマンドでビルドします。

GOOS=linux go build -o bin/main

これで準備は完了です。

デプロイ

serverless frameworkのCLIコマンドでデプロイします。

以下のように実行してみてください。

sls deploy

これでしばらく待って、AWS Lambda, IAMロール, CloudwatchEvent等が作成されていればOKです!

試してみよう

以下のコマンドを実行して、請求金額がSlackに通知できれば完璧です!!

sls invoke -f billing-notification

最後に

いかがでしたでしょうか?

手作業で作成してデプロイするよりも遥かに簡単になりました!

以下に対応したコードをあげているので、参考にして試してみてください!

github.com

AWS CDKで作成したリソースのARN文字列を取得して加工する方法

f:id:ryskit:20200109205701p:plain

AWS-CDKではいくつかのコンストラクトでAWSリソースを作成することが可能です。

今回は低レベルのコンストラクトを利用したAWSリソースのArnを取得して、その文字列を加工してCWAlarmのDimensionのvalueに渡そうとしたときに詰まった部分を書いていきます。

前提

  • AWS-CDKはTypeScriptで記述している
  • Application LoadBalancerはCfnLoadBalanerを使ってリソースを作成している

実現したいこと

Application LoadBalancer(ALB)のTargetResponseTime(リクエストがロードバランサーから送信され、ターゲットからの応答を受信するまでの経過時間 (秒))をメトリクスとしてCloudWatchAlarmを作成したい。

Application LoadBalancerメトリクスの説明

ALBのTargetResponseTimeをメトリクスとする場合、リソースを作成するときにディメンションに以下のどれかを指定する必要がある。

  • LoadBalancer
  • AvailabilityZone、LoadBalancer
  • TargetGroup、LoadBalancer
  • TargetGroup、AvailabilityZone、LoadBalancer

参考: Application Load Balancer の CloudWatch メトリクス

今回は、LoadBalancerのみを指定するが、 以下の説明に記載されているように指定する必要があります。

ディメンション 説明
LoadBalancer ロードバランサーでメトリクスデータをフィルタリングします。ロードバランサーを次のように指定します。app/ロードバランサー名/1234567890123456 (ロードバランサー ARN の最後の部分)。

ALBのARNの例: arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/example-alb/abcdefg123456789

ディメンションには上記のARNのloadbalancer/以降の文字列をValueとして渡してあげれば問題ない。

問題点

例えば、以下のようなALBのリソースを記述したコードがあります。

const alb = new elb.CfnLoadBalancer(this, 'example', {
   ....
});

alb.ref のように書くとARNを取得できるので、以下のようにリソースを作成するコードを書いてみたけど、 作成されたCW AlarmのLoadBalancerのディメンションには、そのままのARN arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/example-alb/a123bcd456e7f8g9 が指定されており、TargetResponseTimeを取得できない状態でした。

※ alb.refの返り値は文字列です

const albDimentionValue = alb.ref.replace(/.+loadbalancer\/(.+)/, '$1');
const albTargetResponseTimeAlarm = new cw.CfnAlarm(this, 'targetResponseTimeAlarm', {
      actionsEnabled: true,
      alarmName: 'TargetResponseTimeAlarm',
      alarmActions: [scalingPolicy.ref],
      comparisonOperator: "GreaterThanOrEqualToThreshold",
      threshold: 3,
      evaluationPeriods: 3,
      namespace: "AWS/ApplicationELB",
      metricName: "TargetResponseTime",
      statistic: "Average",
      dimensions: [
        {
          name: "LoadBalancer",
          value: albDimentionValue
        }
      ],
      period: cdk.Duration.minutes(1).toSeconds(),
    });
    albTargetResponseTimeAlarm.addDependsOn(scalingPolicy);

解決策

どうやって解決したかというと、CloudFormationにもある組み込み関数を使えば、ARNの文字列を加工することができました。 CDKにもCloudFormationと同じ組み込み関数がcoreに定義されているのでそれを利用しました。

const splitAlbArn = cdk.Fn.split('/', alb.ref);
const albDimensionValue = `${cdk.Fn.select(1, splitAlbArn)}/${cdk.Fn.select(2, splitAlbArn)}/${cdk.Fn.select(3, splitAlbArn)}`;
const albTargetResponseTimeAlarm = new cw.CfnAlarm(this, 'targetResponseTimeAlarm', {
      actionsEnabled: true,
      alarmName: 'TargetResponseTimeAlarm',
      alarmActions: [scalingPolicy.ref],
      comparisonOperator: "GreaterThanOrEqualToThreshold",
      threshold: 3,
      evaluationPeriods: 3,
      namespace: "AWS/ApplicationELB",
      metricName: "TargetResponseTime",
      statistic: "Average",
      dimensions: [
        {
          name: "LoadBalancer",
          value: albDimensionValue
        }
      ],
      period: cdk.Duration.minutes(1).toSeconds(),
    });
    albTargetResponseTimeAlarm.addDependsOn(scalingPolicy);

最後に

AWS-CDKに関する記事はまだまだ少ないので、参考になれば幸いです。

AppThemeでNoActionBarを指定して、ToolbarにOptionMenuを表示したい

f:id:ryskit:20200108210016p:plain

まだまだAndroid開発のことがわからない、ryskitです。

ActionBarにオプションメニューを表示するには、 onCreateOptionsMenu() をActivityに書いてあげれば表示できると理解していたので書いてみたけど、表示されない。

なんでかなと思ってサクッと調べたことを書きます。

前提

  • styleで Theme.AppCompat.Light.NoActionBar がparentのAppThemeを使用
  • onCreateOptionsMenu() はoverrideしてちゃんと表示できるようにしていた
  • ToolBarをlayout側で定義している

結論

さっそく結論から言うと、styleで Theme.AppCompat.Light.NoActionBar がparentのAppThemeを使っているから、Activity側でToolbarのオブジェクトを setSupportActionBar() にToolbarを渡してあげると表示できた!

ちゃんとGoogleもドキュメント書いてくれてたよ!

developer.android.com

デフォルトのActionBarとToolbarどっち使えば良い?

GoogleさんはデフォルトのテーマのActionBarには機能がドンドン追加されてて、デバイスによって挙動が変わってくると言ってるみたい。

Toolbar のサポート ライブラリのバージョンには最新の機能が追加されており、サポート ライブラリを使用できるすべてのデバイスでこれらの機能を使用できます。 サポートライブラリのツールバーを使用すると、さまざまなデバイスでアプリが一貫して動作するようになります。

あと、上記のようなことも言ってるので、基本的にNoActionBar指定して、Toolbarを使うほうが良さそう。

最後に

Android開発は難しく感じるけど、新しいことをやるのはやはり楽しい! モバイル開発になれてない人は一緒に頑張りましょう!

AWS LambdaでAWS利用費を毎朝Slackに通知する

f:id:ryskit:20200102190802p:plain

明けましておめでとうございます! 今年もよろしくお願いします!

今年は、「個人ブログで技術ネタ50記事書く」という目標も立てたので早速1本目を書きます!

今回作りたいのはAWS Lambdaを使ってAWS利用費を毎朝通知する仕組みです。

イメージとしては、今日が2019年12月25日なら、2019年12月1日から2019年12月24日までのAWS利用費を朝7:00にSlackに通知するというものです。

では、さっそくいってみましょう!

Slack Appを作る

まず、AWS利用費を通知するためにSlack Appを作成して通知先のエンドポイントを発行する必要があります。

以下のURLにアクセスします。

https://api.slack.com/apps

アクセスしたら、 Create New App をクリックします。

f:id:ryskit:20200102172328p:plain

クリックするとモーダルが表示されるので、名前Workspace を指定します。

Workspace は自身のものや会社のSlackのWordspaceを指定すれば良いと思います。

f:id:ryskit:20200102172701p:plain

Create App をしたら以下のように Basic Informationのページに遷移するので、 そこで表示されている、Incoming Webhook をクリックします。

f:id:ryskit:20200102173102p:plain

Incoming Webhook をクリックしたら、以下のページに遷移します。

Activate Incoming webhookをon にしてあげます。

f:id:ryskit:20200102174011p:plain

すると、以下のように表示内容が変わります。

まだ、WorkspaceにWebhookを追加してない状態なので、Add New Webhook to Workspace をクリックします。

f:id:ryskit:20200102174209p:plain

クリックしたら、以下のようにアクセス権限を与えて良いか確認されます。 どのチャンネルにAWS利用費を通知するか決めたら、そのチャンネルを選択して、許可 をクリックします。

f:id:ryskit:20200102173417p:plain

許可したら、Webhookが追加されます。

ここで発行されたWebhook URLが必要になってくるので、コピーしておくなどしておいてください。

f:id:ryskit:20200102174734p:plain

ひとまず、Slack Appの準備は完了です。

AWS Lambdaのコードを書く

次はSlackへ通知するための、AWS Lambdaを作っていきます。 サクッとやってしまいたいのでFramework等は使わず、GoでLambdaを書いてみたかったので言語はGoを使います。

コードはこんな感じ。

package main

import (
    "bytes"
    "context"
    "encoding/json"
    "fmt"
    "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/costexplorer"
    "net/http"
    "time"
)

const (
    SlackApi   string = "ここにSlack Appで発行したWebhook URLをコピペする"
    DateLayout string = "2006-01-02"
)

func NewCostExplorerClient() *costexplorer.CostExplorer {
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        Config: aws.Config{
            Region: aws.String("ap-northeast-1"),
        },
        SharedConfigState: session.SharedConfigEnable,
    }))
    return costexplorer.New(sess, aws.NewConfig().WithRegion("ap-northeast-1"))
}

type CostInfo struct {
    Start  string `json:"start"`
    End    string `json:"end"`
    Amount string `json:"amount"`
}

type SlackMessage struct {
    Text string `json:"text"`
    Mrkdwn bool `json:"mrkdwn"`
}

type TimeStringHelper struct {
    Location *time.Location
    Now time.Time
}

func NewTimeStringHelper(locationName string) *TimeStringHelper {
    location, _ := time.LoadLocation(locationName)
    return &TimeStringHelper{
        Location: location,
        Now: time.Now().In(location),
    }
}

func (helper TimeStringHelper) GetBeginningOfLastMonth() string {
    return time.Date(helper.Now.Year(), helper.Now.Month() -1, 1, 0, 0, 0, 0, helper.Location).Format(DateLayout)
}

func (helper TimeStringHelper) GetBeginningOfMonth() string {
    return time.Date(helper.Now.Year(), helper.Now.Month(), 1, 0, 0, 0, 0, helper.Location).Format(DateLayout)
}

func (helper TimeStringHelper) GetYesterday() string {
    return time.Date(helper.Now.Year(), helper.Now.Month(), helper.Now.Day() -1, 0, 0, 0, 0, helper.Location).Format(DateLayout)
}

func (helper TimeStringHelper) GetToday() string {
    return time.Date(helper.Now.Year(), helper.Now.Month(), helper.Now.Day(), 0, 0, 0, 0, helper.Location).Format(DateLayout)
}

func (helper TimeStringHelper) IsTodayFirst() bool {
    return helper.Now.Day() == 1
}

func (helper TimeStringHelper) GetStartTimePeriod() string {
    if helper.IsTodayFirst() {
        return helper.GetBeginningOfLastMonth()
    } else {
        return helper.GetBeginningOfMonth()
    }
}


func GetCostInfo(helper *TimeStringHelper) *CostInfo {
    start := helper.GetStartTimePeriod()
    end := helper.GetToday()
    costExplorer := NewCostExplorerClient()
    output, err := costExplorer.GetCostAndUsage(&costexplorer.GetCostAndUsageInput{
        Granularity: aws.String("MONTHLY"),
        Metrics: []*string{
            aws.String("AmortizedCost"),
        },
        TimePeriod: &costexplorer.DateInterval{
            Start: aws.String(start),
            End:   aws.String(end),
        },
    })
    if err != nil {
        panic(err)
    }
    total := output.ResultsByTime[0].Total["AmortizedCost"]
    amount := aws.StringValue(total.Amount)

    return &CostInfo{
        Start:  start,
        End:    end,
        Amount: amount,
    }
}

func makeSlackMessage(costInfo *CostInfo, helper *TimeStringHelper) SlackMessage {
    return SlackMessage{
        Text: fmt.Sprintf("*期間*: `%s ~ %s`\n*料金*: `$%s`",
            costInfo.Start,
            helper.GetYesterday(),
            costInfo.Amount),
        Mrkdwn: true}
}

func PostToSlack(message SlackMessage) {
    input, _ := json.Marshal(message)
    fmt.Println(string(input))
    http.Post(SlackApi, "application/json", bytes.NewBuffer(input))
}

type Response struct {
    Message []byte `json:"message"`
}

func BillingNotification(ctx context.Context) (Response, error) {
    helper := NewTimeStringHelper("Asia/Tokyo")
    fmt.Println(helper.Now.Format("2006/01/02 15:04:05"))
    costInfo := GetCostInfo(helper)
    message := makeSlackMessage(costInfo, helper)
    PostToSlack(message)
    json, _ := json.Marshal(message)
    return Response{Message: json}, nil
}

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

Githubにもアップしてるので、試してみたい方はぜひ使ってみてください。

github.com

コードに関して全ては説明しないですが、ピックアップして説明します。

AWS利用費の取得には、Cost Explorer を使います。 以下の部分ですね。

GranularityにはMONTHLY を指定します。 TimePeriodは、利用料の取得期間です。 たとえば、Startに 2019-12-01 、 Endに 2019-12-31を指定すると、 2019-12-01 から 2019-12-30までのAWS利用料を取得できます。 ここが間違えやすところかもしれません。

参考: https://docs.aws.amazon.com/aws-cost-management/latest/APIReference/API_GetCostAndUsage.html#awscostmanagement-GetCostAndUsage-request-TimePeriod

output, err := costExplorer.GetCostAndUsage(&costexplorer.GetCostAndUsageInput{
    Granularity: aws.String("MONTHLY"),
    Metrics: []*string{
        aws.String("AmortizedCost"),
    },
    TimePeriod: &costexplorer.DateInterval{
        Start: aws.String(start),
        End:   aws.String(end),
    },
})

Slackへ通知する際のmessageのpayloadも決まっているので、 それに合わせてメッセージをPostする必要があります。

func makeSlackMessage(costInfo *CostInfo, helper *TimeStringHelper) SlackMessage {
    return SlackMessage{
        Text: fmt.Sprintf("*期間*: `%s ~ %s`\n*料金*: `$%s`",
            costInfo.Start,
            helper.GetYesterday(),
            costInfo.Amount),
        Mrkdwn: true}
}

参照: api.slack.com

定数のSlackApi にはSlack Appで発行したWebhookのURLを貼り付けておいてください。

これができたら、ビルドしてzip化します。

ビルドは以下のコマンドで実行してください。

オプションをつけ忘れるとLambdaが実行できないので気をつけましょう!

GOARCH=amd64 GOOS=linux go build

ビルドしたら実行ファイルが生成されるので、以下のコマンドでzip化します。

zip billing-notification.zip ./billing-notification

そうすると、billing-notification.zip というzipファイルが生成されます。 これはあとでAWSコンソールでLambda関数を作るときに使います。

AWSコンソールからLambda実行用IAMサービスロールを作成する

IAMサービスロールにアタッチするポリシーのJSONは以下のように書きます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "ce:GetCostAndUsage"
            ],
            "Resource": "*"
        }
    ]
}

IAMサービスロールはLambdaを選択してください。

f:id:ryskit:20200102181522p:plain

あとはよしなにIAMサービスロールを作成します。

AWSコンソールからLambdaの関数を作成する

AWSコンソールからLambdaを開いて作成してきます。

関数名: billing-notification ランタイム: Go 1.x 実行ロール: 先程作成したサービスロールを指定するので、既存のロールを使用する を選択し、セレクトボックスから作成したロールを探して選択します。

f:id:ryskit:20200102182049p:plain

関数を作成できたら、LambdaのトリガーにCloudWatch Events を指定しておいてください。

そして、zip化したLambdaのコードをアップロードします。

ハンドラ名は billing-notification と入力し、保存します。

f:id:ryskit:20200102182941p:plain

もうこれでSlackに通知することができます!

試しにテストしてみましょう。

テストイベントの設定をします。 作成したことがあれば以下のように表示されますし、してなければ テストイベントの設定 と表示されているはず?なので、 テスト をクリックします。

f:id:ryskit:20200102183614p:plain

もし新規で作る場合は以下のようにモーダルが表示されるので、適当な名前をつけて保存してください。

f:id:ryskit:20200102183805p:plain

そして、もう一度テストをクリックすると、Slackに利用料が通知されるはず!!

f:id:ryskit:20200102183930p:plain

ほぼできた🎉🎉🎉

作業もあと少しです!

AWSコンソールからCloudWatch Eventsの設定

Slackに通知する仕組みは作れました。

あとは、毎朝7時にAWS Lambdaを実行するようにしておきたいですよね?

そのためにCloucWatch Eventsを利用します。

Lambdaを作成したときにトリガーにCloudWatch Eventsを指定したのはそのためです。

それでは、AWSコンソールからCloudWatchを開きます。

開いたら以下のように、ルールと書かれた箇所をクリックします。

f:id:ryskit:20200102184644p:plain

クリックしたら以下のようにルールの作成をクリックします。

f:id:ryskit:20200102184907p:plain

そうしたら、以下のように設定してみてください。

Cron式0 22 * * ? * と指定していますが、UTC表記なのでこのままで問題ありません。

設定できたら 設定の詳細 をクリックします。

f:id:ryskit:20200102184801p:plain

ステップ 2: ルールの詳細を設定する 画面では、状態を有効化してルールを作成してください。

これで、毎朝7時にLambdaが実行されてSlackに通知が来るはずです🎉🎉🎉

f:id:ryskit:20200102185242p:plain

最後に

いかがでしたでしょうか?

Lambdaを使えばサクッとAWS利用費を通知できるので、今どれぐらい使っていて請求が来るのか把握しやすくなりました!

もしこの記事が良ければ、Twitterなどでシェアしてくださいね!

読んでくださってありがとうございました!

※ アイキャッチには@tentenのGopher by tenntenn CC BY 3.0を利用させていただいています。

Gitのあるコミット間で変更されたファイルを一覧で取得したい

git diffコマンドのオプションである --name-only をつけてあげると変更ファイルの一覧を取得できます。

git diff --name-only [コミットID] [コミットID]

以下のように出力されるので、これを加工する場合はパイプでつないでいけば良いですね。

wp-includes/js/dist/list-reusable-blocks.min.js
wp-includes/js/dist/media-utils.js
wp-includes/js/dist/media-utils.min.js
wp-includes/js/dist/notices.js
wp-includes/js/dist/notices.min.js
wp-includes/js/dist/nux.js
wp-includes/js/dist/nux.min.js
wp-includes/js/dist/plugins.js
wp-includes/js/dist/plugins.min.js
wp-includes/js/dist/priority-queue.js
wp-includes/js/dist/priority-queue.min.js
wp-includes/js/dist/redux-routine.js
wp-includes/js/dist/redux-routine.min.js
wp-includes/js/dist/rich-text.js
wp-includes/js/dist/rich-text.min.js
wp-includes/js/dist/server-side-render.js
wp-includes/js/dist/server-side-render.min.js
wp-includes/js/dist/shortcode.js
wp-includes/js/dist/shortcode.min.js
wp-includes/js/dist/token-list.js
wp-includes/js/dist/token-list.min.js
wp-includes/js/dist/url.js
wp-includes/js/dist/url.min.js
wp-includes/js/dist/vendor/lodash.js
wp-includes/js/dist/vendor/lodash.min.js
wp-includes/js/dist/vendor/react-dom.js
wp-includes/js/dist/vendor/react-dom.min.js
wp-includes/js/dist/vendor/react.js
wp-includes/js/dist/vendor/react.min.js
wp-includes/js/dist/vendor/wp-polyfill-fetch.min.js
wp-includes/js/dist/vendor/wp-polyfill.js
wp-includes/js/dist/vendor/wp-polyfill.min.js

おまけ

xargsの -I オプションを使うことで、標準入力で受け取った値をxargsに渡した引数のコマンドの任意の位置に展開することが可能です。 なので、git diff --name-onlyとxargs -Iを組み合わせることで、以下のようなことができます。

git diff --name-only c62ce56 52f858f | xargs -IIN scp IN aws-dev:/home/ec2-user

これはgit diffであるコミット間で変更されたファイルの一覧を標準出力してパイプでxargsに渡しています。 そして、パイプで受け取った標準入力は、xargsの-I オプションで任意の位置に展開してscpコマンドを実行してサーバーにファイルをコピーしています。 IN は自分で決めた値で、ここはXXXやYYYでも問題ありません。