はじめに
- 毎月のAWSの課金情報をちゃんと把握したい
- いちいちAWSにログインして確認したしたくない
- そろそろLambda使ってみたい
- 自分が把握するものをSlackに集約している
こんな理由から、やってみようと考えた。
Slack
まずは課金情報を受け取るChannelを作成する。
名前や目的は後で修正できるけれど、ちゃんと決めておくことをオススメします。
続いて、Webhook URLの取得。
https://slack.com/services/new/incoming-webhook から取得できる。
通知を受け取るチャンネル(さっき作ったやつ)を指定する。
Webhook URLが出来上がるので、忘れずにコピーしておく。
ローカル(Mac)
いきなり壁にぶつかる
Terminalで以下コマンドを叩いてlambda-uploaderをインストール。
・・・とはうまくいかなかった。
$ pip install lambda-uploader
なんでだろ?と考えた結果、以下のメッセージが出ているからでは?と考えた。
You are using pip version 10.0.1, however version 18.0 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
よしわかった、アップグレードしてやろうじゃないか。
$ pip install --upgrade pip
途中でエラー発生。
Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/Library/Python/2.7/site-packages/pip-10.0.1-py2.7.egg/EGG-INFO/PKG-INFO'
Consider using the `--user` option or check the permissions.
仕方ない、やり直し。
$ pip install --upgrade pip --user
Successfullyは出ているけれど、ちゃんとできているか不安。
ここでPythonのバージョンを確かめてみようと思った。
$ python --version
Python 2.7.10
Python 3.5.0とか入れてなかったっけ?何インストールできるんだっけと思って、pyenvを実行。
$ pyenv install --list
-bash: pyenv: command not found
pyenvが使えない・・・仕方がないので、gitから持ってくることにする。
$ git clone git://github.com/yyuu/pyenv.git ~/.pyenv
$
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
ちょっと前のコマンドを実行。
$ pyenv install --list
インストールできるバージョンのリストが表示されたので、その中から3.5.0をインストールすることに。
$ pyenv install 3.5.0
インストールがエラーなくうまくいったので、2.7.10から3.5.0にバージョンを変えてみる。
$ pyenv global 3.5.0
$ python --version
Python 2.7.10
あれ?
Pythonはどこを見ている?
$ which python
/Users/xxxxxx/.pyenv/shims/python
色々調べて、以下の通り~/.bash_profileに追記をすることに。
$ export PATH="'$HOME/.pyenv/shims:$PATH"
$ source ~/.bash_profile
さて、これでどうだ。
$ python --version
Python 3.5.0
あぁ、ようやくうまくいった。
各種インストール
lambda-uploaderをインストール。
$ pip install lambda-uploader
OK、次にaws cliをインストール。
$ pip install awscli
続いてaws configureで設定をするのだが、Access KeyとSecret Access Keyが必要になる。
作成していない場合は、セキュリティ認証情報のページから作成する。
$ aws configure
AWS Access Key ID [None]: *****************
AWS Secret Access Key [None]: *****************
Default region name [None]: ap-northeast-1
Default output format [None]: text
東京リージョンを指定する場合は、ap-northeast-1
を指定するようだ。
AWS
CloudWatch
AWSの管理コンソール、請求ダッシュボード->設定に移動して、請求アラートを受け取る にチェックが付いていることを確認する。
付いていない場合はチェックを入れておく。
Lambda関数を作成
コードをlambda-uploader
でデプロイするためには、あらかじめ空の関数を用意する必要があるらしい。
Lambdaで 一から作成 を選択。
名前とロール名はわかりやすいものを指定、ランタイムは Python3.6 にした。
ロールは テンプレートから新しいロールを作成 を選択し、ポリシーテンプレートは 基本的な Lambda@Edge のアクセス権限 (CloudFront トリガーの場合) を選択。
これで大丈夫なはず。多分・・・。
関数の作成 ボタンを押して、空の関数の作成は完了。
IAMロール
Lambda関数を作成した時に、IAMロールを作成した。(テンプレートから新しいロールを作成を選んだから)
そのIAMロールにCloudWatchReadOnlyAccess
ポリシーをアタッチする。
コスト情報をLambdaから読みだすのに必要とのこと。
アタッチ後に、ロールARNをコピーしておく。
コード(ローカル)
ローカルでコードを編集する。
個人的に好きなATOMを利用して編集する。
ディレクトリとファイルは以下のようにする。
lambda_function.py
#!/usr/bin/env python
# encoding: utf-8
import json
import datetime
import requests
import boto3
import os
import logging
# Logger の設定
logger = logging.getLogger()
logger.setLevel(logging.INFO)
# Slack の設定
SLACK_POST_URL = os.environ['slackPostURL']
SLACK_CHANNEL = os.environ['slackChannel']
# CloudWatch
# region_nameはus-east-1にしておくこと
response = boto3.client('cloudwatch', region_name='us-east-1')
# ValueはUSDじゃないとダメ
get_metric_statistics = response.get_metric_statistics(
Namespace='AWS/Billing',
MetricName='EstimatedCharges',
Dimensions=[
{
'Name': 'Currency',
'Value': 'USD'
}
],
StartTime=datetime.datetime.today() - datetime.timedelta(days=1),
EndTime=datetime.datetime.today(),
Period=86400,
Statistics=['Maximum'])
cost = get_metric_statistics['Datapoints'][0]['Maximum']
date = get_metric_statistics['Datapoints'][0]['Timestamp'].strftime('%Y年%m月%d日')
def build_message(cost):
text = "%sまでのAWSの課金額は、$%sです。" % (date, cost)
color = "#ffffff" # black
atachements = {"text":text,"color":color}
return atachements
def lambda_handler(event, context):
content = build_message(cost)
# Slack に POST する内容を設定
slack_message = {
'channel': SLACK_CHANNEL,
"attachments": [content],
}
# Slack に POST
try:
req = requests.post(SLACK_POST_URL, data=json.dumps(slack_message))
logger.info("Message posted to %s", slack_message['channel'])
except requests.exceptions.RequestException as e:
logger.error("Request failed: %s", e)
lambda.json
- name: Lambda関数の名前を入れる
- description: Lambda関数の説明を入れる
- region: リージョンを入れる、東京ならこのまま。
- handler: ハンドラーの名前を入れる
- role: IAMロールのARNを入れる
- slackPostURL: SlackのWebhookURLを入れる
- slackChannel: Slackで投稿するチャネルを入れる ex.#aws
{
"name": "Lambda関数の名前",
"description": "Lambda関数の説明",
"region": "ap-northeast-1",
"handler": "lambda_function.lambda_handler",
"role": "IAMロールのARN",
"timeout": 300,
"memory": 128,
"variables":
{
"slackPostURL":"Slack WebhookのURL",
"slackChannel":"Slackの投稿チャネル"
}
}
requirements.txt
requests
デプロイする
デプロイするときは、上記ファイルを置いたディレクトリに移動してから行うこと。
$ lambda-uploader
λ Building Package
λ Uploading Package
λ Fin
AWS-CloudWatch
CloudWatchのイベントを作成する。
CloudWatchに移動して、イベント->ルールの作成 を選択する。
「スケジュール」にチェックを入れる。
「Cron式」に値を入れる。Cron式の書き方は参考にリンクを付けた。
ターゲットは「Lambda関数」で、機能で作成した関数を選択する。
結果
綺麗にうまくいった!と言いたいところだが、実際はうまく飛んでこなくて試行錯誤。
その結果が、上のコードです。
lambda_function.py
の region_name
と Dimensionsの Value
かな、引っ掛かったのは。
それ以外はうまくいった。
参考
- LambdaでAWSの料金を毎日Slackに通知する(Python3)
- pyenv, python3, lambda-uploader で AWS Lambda にアップロードする。
- pyenvを使って、pythonバージョンの変更
- pyenvのインストール、使い方、pythonのバージョン切り替えできない時の対処法
- pythonのバージョンが切り替わらない
- AWS CLI のインストールと設定(AWS公式)
- AWS Command Line Interface のインストール(AWS公式)
- AWS CLIのインストールから初期設定メモ
- ルールのスケジュール式(AWS公式)
修正
- AWS-CloudWatchの画像リンクが切れていたので、新しいものに差し替え(2020/11/7)