22
Lambda でででで log-driven ササササササ 2016 で 6 で 11 で ででで

Jawsug福岡 201606 up

Embed Size (px)

Citation preview

Page 1: Jawsug福岡 201606 up

Lambda で始める log-drivenサービス構築

2016 年 6 月 11 日木村健一郎

Page 2: Jawsug福岡 201606 up

名前:木村健一郎所属:株式会社コム・アンド・コムお仕事:技術に関することはなんでも好きな言語: perl好きな DB : PostgreSQL

Page 3: Jawsug福岡 201606 up

今日のお題:  Lambda で log-driven なサービスを作る

Page 4: Jawsug福岡 201606 up

Log-driven ?

•私が思いついた言葉なのでググらないように• Log-driven development なんてこと言ってる人はい

るみたいですが、読んでません•リクエストに対して直接アクションするのではなく、出力されたログに基づいてアクションするアーキテクチャ• ログは取らないわけないよね?ならそれを中心に

してしまいましょう• ログをリクエストバッファに使うイメージといえ

ばいいんでしょうか・・・どういう需要があるの?

Page 5: Jawsug福岡 201606 up

ところで

みなさん、前回の森田さんの発表 ( 月額 10 円から作るServerLess Website) 、憶えてますか?

Page 6: Jawsug福岡 201606 up

超ざっくり言うと、

・ S3 に static HTML と js 置いて、お問い合わせの入力を受ける・入力は js から S3 に保存される・保存されたら Lambda が拾ってアクションする

( )※ もっと沢山の素晴らしいアイデアが含まれてるので、是非発表資料をご覧になってください

Page 7: Jawsug福岡 201606 up

私:「 js 動かない ガラケーはどうしましょ?」森田さん:「あきらめましょう」 ( 要約 )

・・・・ (´ ・ ω ・ `)

Page 8: Jawsug福岡 201606 up

何かやりようがあるのでは?

寝ないで3日考えた ( 嘘 )

入力を全部 GET で渡してログを解析すればいいんじゃね?

Page 9: Jawsug福岡 201606 up

想定動作

•名前とメールアドレス、問い合わせ内容を受け付ける•入力したら完了ページを出す•入力された内容を Slack で通知する• アクションは何でもいいんですが、前回のコード

を使い回してるので slack へ飛ばしてます•ガラケーでも w3m でも lynx でも動くこと

Page 10: Jawsug福岡 201606 up

構成 ( レガシー )

インターネットhttp アクセス

S3Fluentd でログを S3 に保存

GET /result.php?body=hogehogehoge

Slack に通知

入力を受け付け、 Slack に流す WEB アプリ

Page 11: Jawsug福岡 201606 up

今回の構成

インターネットhttp アクセス

S3ログを S3 に保存

イベント通知

ログ読み込み

GET /result.html?body=hogehogehoge

Slack に通知

Page 12: Jawsug福岡 201606 up

S3 の設定 (1)S3 で static HTML サーバを作ります。 HTML は以下のような感じで。

<HTML><head><meta http-equiv="content-type" content="text/html;charset=shift_jis"></head><body>お問い合わせはこちらからどうぞ。 <BR><FORM action="result.html" method="GET">メールアドレス :<INPUT type="text" name="from"><BR>お名前 :<INPUT type="text" name="lname"><BR>本文 :<BR><TEXTAREA name="body" rows="10" cols="40"></TEXTAREA><BR><INPUT type="submit" value=" 送信 "></FORM></BODY></HTML>

<HTML><head><meta http-equiv="content-type" content="text/html;charset=shift_jis"></head><body>お問い合わせありがとうございました。 <BR>追って担当より御連絡申し上げます。 <BR></BODY></HTML>

input.html result.html

Page 13: Jawsug福岡 201606 up

S3 の設定 (2)ログ用のバケットを作成して、ログを設定します。

Page 14: Jawsug福岡 201606 up

Lambda Function を書きます。ログのパースに apachelog モジュールを、そこからクエリーパラメータをパースするのに urlparseを使います。まずは s3 からオブジェクト読み込んで、ログ解析用のフォーマットを設定。

Lambda ファンクション

# coding: utf-8import boto3import jsonimport sysimport ConfigParserimport urlparseimport apachelogimport slackwebimport re

def lambda_handler(event, context): record = event["Records"][0] bucket_region = record["awsRegion"] bucket_name = record["s3"]["bucket"]["name"] log_object_key = record["s3"]["object"]["key"] s3 = boto3.client('s3', region_name=bucket_region) logobj = s3.get_object(Bucket = bucket_name, Key = log_object_key) try: log = logobj["Body"].read().decode('utf-8'); except: log = '' fname = 'result.html' format = r'%{id} %{backetname} %t %h %x %{uid} %{action} %f \"%r\" %>S %{z} %{a} %{b} %{c} %{d} \"%{Referer}i\" \"%{User-Agent}i\" %y' al = apachelog.parser(format)

Page 15: Jawsug福岡 201606 up

S3 オブジェクトから 1 行ずつ取り出して、対象の WEB アクセスであれば解析して Slack に飛ばします。

Lambda の設定(2)

for line in log.split('\n'): try: ldata = al.parse(line) if ldata['%{action}'] == 'WEBSITE.GET.OBJECT' and ldata['%f'] == fname: url = re.sub('^GET \/(.*) HTTP\/1..$',r"\1",ldata['%r'],re.U) o = urlparse.parse_qs(urlparse.urlparse(url).query) from = o['from'][0].decode('shift_jis') lname = o['lname'][0].decode('shift_jis') body = o['body'][0].decode('shift_jis') inifile = ConfigParser.SafeConfigParser() inifile.read("./config.ini") attachments = [] attachment = { "fallback": u"From:%s\n%s" % (lname,body), "pretext": u"From:%s\nSub:%s" % (lname,from), "color": "#aaaaaa", "text": body } attachments.append(attachment) slack = slackweb.Slack(url=inifile.get('slack', 'hook_url')) slack.notify(attachments=attachments, channel=inifile.get('slack', 'channel'), username=inifile.get('slack', 'username'), icon_emoji=inifile.get('slack', 'icon_emoji'))

Page 16: Jawsug福岡 201606 up

try のキャッチと関数からの return 。

Lambda の設定( 3 )

except: print(line) return "CONTINUE"

Page 17: Jawsug福岡 201606 up

制限はあります

• s3 へのログの書き込みがリアルタイムでない• 大体 30 分~ 1 時間かかる• バッチ処理で十分な案件には使える

• URL の長さの上限がある• IE は 2MB ?ガラケーはもっと小さいはず

• URL でダダ漏れなので、機密情報は入れないように

Page 18: Jawsug福岡 201606 up

使い道はありそう

• ちょっとしたデータを受け付ける CGI のためだけに EC2を動かさないでいい• 無記名アンケートなんかはいいかも?

• 「完了ページに入力内容を出したい」なんてことは出来ない• その程度なら SSI でいけるから EC2 で WEB サーバ作る

にしても超軽量で OK

Page 19: Jawsug福岡 201606 up

注意とお詫び

このコードだと日本語がどうしても通りませんでした・・

• ローカルでは動くので、 urlparse のバージョンの問題? (´ ・ ω ・ `)• たぶん UTF8 なら動くけど、それじゃガラケーが動かないし・・• Python3 なら parse_qs に encoding ってパラメータがあるんですけどね。• Java で書いたらもっと楽な気がした

Page 20: Jawsug福岡 201606 up

応用

これで終わったらさみしいので、応用を考えてみた。

• ログを S3 に書けばいいんだから、 fluentd と組み合わせる• swatch の代わりに lambda を使う• アクセスログに基づいて WAF や VPC の ACL に設定を突っ込む

• Apache の mod_dosdetector みたいなこととか

Page 21: Jawsug福岡 201606 up

感想

• やっぱり Lambda 超便利 (^o^)• 頑張ればガラケー向けの問い合わせページもサーバレス

で作れます! (`・ ω ・ ´)• 「バッチのための EC2 を Lambda 置き換える」と同じ発

想で色々応用できそう• ログをトリガーに lambda( じゃなくてもいいけど ) で色々

やることを「 log-driven サービスアーキテクチャ」と名前つけたらかっこよくない?

Page 22: Jawsug福岡 201606 up