Node.js × AWS Lambda アプリケーション開発Tips

これは AWS Lambda Advent Calendar 2017 の12日目の記事です。

先日の 東京Node学園祭2017 にて Lambda についてライトニングトークしてきました。

スクリーンショット 2017-12-12 12.47.14.png
Node.js × AWS Lambda アプリケーション開発Tips (SlideShare)

興味がある方は上記のリンクから内容を見て頂ければ。

今回はスライド中で一番時間をかけて書いた下記の図について、手前味噌ですがなかなかよく書けたんじゃないかなと思うので、紹介させていただきます^^

スクリーンショット 2017-12-12 12.55.54.png

Lambda は図の左上のように AWS のイベント経由で起動する他に、左下のように HTTP 経由で起動することができます。Lambda は AWS 内の各種リソースにアクセスできるのはもちろんなのですが、Lambda からHTTPで外に出られるので、インターネット上の任意のサービスにアクセスできます。また HTTP 経由でなくても定期実行(CloudWatch イベント)ができるので、定期的に何かをする、といった用途にも使えます。

インフラにがっつり AWS を使ってなければ、Lambda は馴染みがないだろうと思われがち?なのですが、HTTP 経由で Lambda を利用して、必要あらばLambda から HTTP 経由で他のサービスを利用する、といったことは、がっつりAWSを利用するといった用途でなくてもサーバの管理が必要ないアプリケーションの実行環境として利用できるのかなと思います。スライドの中でも触れてるように、(Amazon Linux 上で動かせる)任意の実行ファイルも動かせます。

少しでも AWS Lambda に可能性を感じ、AWS Lambda を触ってみるキッカケになれば幸いです。それでは!

続きを読む

動画を探して自動ツイートしてくれるPython製botをAWSに載せてみた(後編)

TL;DR

  • YouTubeから動画を拾ってTweetするbotをPythonで開発し、AWS Lambdaに載せてみました
  • 全2記事です。後編のこちらでは、主にAWS Lambdaでのデプロイ・運用にフォーカスします
    • Pythonプログラムのパッケージングとアップロードに際しハマった知見を共有します
    • AWS CloudWatchと連携し、指定時間での自動ツイートを実現します
  • 前編はこちらです

AWS Lambda

AWS Lambdaとは

AWS Lambda はサーバーをプロビジョニングしたり管理しなくてもコードを実行できるコンピューティングサービスです。…コードが実行中でなければ料金はかかりません。

「一定の時刻に起動してツイート」さえしてくれればいいようなbotを動かすには、常時起動のサーバは必須ではありません。Lambdaのようなプラットフォームは今回のユースケースにうってつけと言えます。

関数をアップロードしておき、任意のイベントによって関数をトリガーするのがLambdaの基本的な使い方です。実際にやってみます。

ハマる、ハマる

が、実際には色々困りました…。順番に知見を共有します。

パッケージング

デプロイパッケージの作成 (Python)

Lambda 関数を作成するには、最初に Lambda 関数デプロイパッケージ (コードと依存関係で構成される .zip ファイル) を作成します。

ということで、プロジェクトのディレクトリに依存関係をインストールし、ZIP化する必要があります。pipのオプションでライブラリのインストール先は指定できるので、プロジェクトディレクトリに移動して…

$ pip3 install -r requirements.txt -t ./lib

ところが、エラーで失敗。

DistutilsOptionError: must supply either home or prefix/exec-prefix — not both

HomeBrewでPython導入しているとpip3 install -tが失敗する

らしいです。StackOverflowに同様の問題がありました。

ただ、回避の手段も回答されてます。ホームディレクトリに.pydistutils.cfgという名前のファイルを作って、以下の設定(というか、空のprefixを指定するハック)を書けば通るようになります。

pydistutils.cfg
[install]
prefix=

パッケージングの自動化について

pip installができるようになったのはいいとしても、増えた依存モジュールを再インストールして、もう一回.zipの中にモジュールを入れて…とか毎回手作業でやるのは辛いです。パッケージ管理ツールを導入して自動化できないかなあ、と調べたのですが色々動きが激しいようで。

ライブラリの配布について | Python Snippets

この辺りはベスプラを知りたいところではあります。追うのが大変そうだったのと、今回は大した規模でもないのでシェルスクリプトでなんとかすることにしました。

package_lambda.sh
#!/usr/bin/env bash

rm lambda.zip

cd src
pip3 install -r requirements.txt -t ./lib
zip ../lambda.zip *.py
cd lib
zip -r ../../lambda.zip *

src配下には自分で書いたPythonスクリプト群を配置しています。src/lib配下に依存モジュールをインストールし、それぞれ順番にZIPの直下に詰めてます。結論としてこれで大丈夫だったので先に進みます。

ハンドラ関数の定義

AWS Lambdaのコンソールに移ります。関数を作成、ランタイムには”Python3.6″を選びます。コードエントリで「.ZIPファイルをアップロード」を選び、作ったZipをアップしましょう。

スクリーンショット 2017-12-10 22.55.08.png

さて、次は画面右側の「ハンドラ」で処理の起点となる関数の名前を指定します。公式の説明では、

関数の filename.handler-method 値。たとえば、「main.handler」は、main.py で定義されたハンドラーメソッドを呼び出します。

すなわち[ファイル名].[関数名]とすれば良いので、前回作った感じだとmain.mainかなー、とか指定してテスト実行すると…

スクリーンショット 2017-12-10 23.08.36.png

落ちます。

ハンドラ関数の引数の数が間違っていると落ちる

"errorMessage": "main() takes 0 positional arguments but 2 were given"

Lambda 関数ハンドラー (Python)

まあドキュメントを読めという話でお恥ずかしいのですが、引数が合ってないわけですね。イベントハンドラであるところのLambda関数はeventとcontextを受けるのが基本ですから、その形に沿ったハンドラ定義が必要です。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from tube_crawler import TubeCrawler
from tweeter import Tweeter
import config

def main():
    t = TubeCrawler()
    movies = t.movies_from_query("Hybrid Rudiments")
    chosen = t.choose(movies)

    tw = Tweeter()
    tw.reply(config.REPLY_TO, chosen)
+   return chosen

+def lambda_handler(event, context):
+   result = main()
+   return { 'tweetedURL': result }

if __name__ == '__main__':
    main()

あとは、コンソールでmain.lambda_handlerをハンドラに指定すればOKです。せっかくなので実際にツイートされた動画のURLを呼び出し元に返す仕様にしてみました。

定期実行

デプロイはできたので、次は定時実行の仕組みを作ります。

スクリーンショット 2017-12-11 22.05.53.png

コンソール画面の「トリガーの追加」から「CloudWatch Events」を選びます。トリガーのルールにcron式を選べば、今回やりたいことは実現できますね。

Rate または Cron を使用したスケジュール式

  • 日または週日の値は疑問符である必要がある
  • UTCしか使用できない(ので、日本時間に合わせてずらす)

あたりが注意点でしょうか。今回は平日の定時につぶやいて欲しいので、こんな式にしてみます。

cron(15 10 ? * MON-FRI *)

運用してみて

運用して1週間ほど様子を見てみましたが、無料利用の範囲内でおおむね問題なく動いております。
今度はTedみたいな勉強系の動画やらブログ記事やら拾わせても面白いかもしれませんね。

よかったこと

一気通貫して人が使えるサービスの形まで持って行くと、否応無しに広く技術をさらうことになります。インフラよりに苦手意識があったので半ば無理やりにでも触るのはいい経験になりました。

反省

  • YouTubeAPIとか使えばもっと楽に実装できたんじゃないか疑惑
  • パッケージングとAWS周りでハマりすぎた。アップロードが絡むあたりからはTry&Errorより前にドキュメントを読もう

お読みいただきありがとうございました。

リンク

続きを読む

【AWS】S3の特定のディレクトリ配下の容量を確認する方法

バケットであれば、CloudWatchのメトリクスから確認できるのですが、
バケット内のディレクトリ単位(厳密にはディレクトリという概念ではない)ではCWでは見れません。
(自作すればCWからも見れるようになるだろうけど)

じゃあどうするかというとaws s3 コマンドにとあるオプションを追加することで取得できます。

aws s3 ls s3://バケット名/ディレクトリ名/ --summarize --recursive --human-readable

という形で確認できます。

これの注意点なのですが、lsコマンドをrecursiveで叩いたあとにその各オブジェクトの合計サイズをサマライズしてくれるというものなので、
lsの結果がずら~っとでてきます。

もし目に毒だと言う方は、

aws s3 ls s3://バケット名/ディレクトリ名/ --summarize --recursive --human-readable | tail

でお尻だけみるようにしましょう。(やらしいでぇ)

また、S3ではlistを取るだけでも確か課金がかかるため、オブジェクトの量によってはもしかしたら、
1円くらいかかってしまうかもしれません。

続きを読む

Beanstalk運用の日常風景

ハンズラボ Advent Calendar 2017 11日目の記事です。

Elastic Beanstalkの運用をそれなりに続けてきたので、溜め込んだTIPS+失敗事例を放出します。
プラットフォームはPHPです。

Daily Buildしましょう

「いやいやうちはデイリーどころか1日複数回buildしてdeployですよ」という方もいらっしゃるでしょうが、すべてのアプリケーションに対して毎日、というわけではないのでは?
「同じソースコードをeb deployして昨日は通ったのに今日は落ちる」ということがあります。
AWSは日夜プロダクトを改善していて、ユーザとして恩恵に預かっているわけですが、ときに牙をむくことがあります。
ということで、平日の出勤時間帯にdeployスクリプトをスケジュール実行しておいて、deploy成功していると安心して出勤できます。

  • 2016年9月、eb-activity.logにて、ascii以外の文字列が入っているエラーが出てdeploy失敗しました。
    (コメントに入ってもNG)
  • 本番以外の環境で、immutableかrolling with additional batchでのdeploy検証できていると、安心です。この二つはEC2を新規に起動するので、後述のpreinit hookのスクリプトから順に動くためです。
    • と言いつつ、.ebextensionsでシンボリックリンクを貼る、みたいなことをしているときに、already existsで落ちるケースも。本番deployして初めて失敗する、みたいなケースは辛い・・・。

ライブラリのバージョンを固定しましょう

常に最新版のライブラリを適用するのがセキュリティ的には望ましいですが、なかなかそうはいかないのが悩ましいところです。。。
検証環境では最新のライブラリ、本番環境は検証済みライブラリ、とかで分けて管理できればいいのですが・・・。なかなか腰が重いです。

  • とあるpeclライブラリをバージョン指定せずにpecl installしていたところ、最新版がPHP7のみのサポートになってdeployに失敗しました。。。
  • プラットフォームのバージョンは検証環境のみ「管理された更新」を適用しています。これも便利。動作に問題がなければ本番環境へ。

eb-activity.logを読みましょう

Beanstalkが管理しているEC2が起動するときや、Application Versionをdeployするときにeb-activity.logが更新されます。
実際に動いてるのは/opt/elasticbeanstalk/hooks配下のスクリプトです。ここに、.ebextensionsで書いた設定やらシェルスクリプトやらも入ってきます。

$ pwd
/opt/elasticbeanstalk/hooks
$ ls
appdeploy  configdeploy  postinit  preinit  restartappserver
  • deployがtimeoutする原因について調べていたところ、composer updateは–no-devがついて実行されていたのに、composer installはオプション無しで実行されていました。.ebextensionsで記述していないAWS製のdeployスクリプトの中で、EC2新規起動時はcomposer installを実行する作りになっていました。
  • 試行錯誤の結果、下記のようにcomposer_optionsで–no-dev指定することにしました。合わせて、hirakさんのprestissimoを使ってcomposer install/updateの並列実行を実現しています。
    • EC2の起動が遅い問題、C5/M5インスタンスが東京リージョンに来てパッと解決してほしい・・・。
composer.config
commands:
  01_update_composer:
    command: export COMPOSER_HOME=/root && /usr/bin/composer.phar self-update 1.5.2 && /usr/bin/composer.phar global require hirak/prestissimo

option_settings:
  - namespace: aws:elasticbeanstalk:application:environment
    option_name: COMPOSER_HOME
    value: /root
  - namespace: aws:elasticbeanstalk:container:php:phpini
    option_name: composer_options
    value: --no-dev

Time Based Scaling しましょう

Elastic BeanstalkはAuto Scalingもよしなにやってくれますが、スパイクアクセスには弱いです。
日常的にiOS/Androidアプリへモバイルプッシュなどを行っていると、プッシュのタイミングでスパイクアクセスが発生します。
プッシュを登録する担当者と相談して、プッシュ送信する時間帯を制限し、その時間帯はスケールアウトしておくことで対策しています。
BeanstalkだけでなくDynamoDBもTime Based Scalingに対応しましたね!(こちらはまだAWS CLIのみで設定可能・・・)

  • BeanstalkのメトリクスだけではELBへの負荷がわからない場合があります。その場合はELBのメトリクスを参照しましょう。AWS CLIでcloudwatchのメトリクスとるときも、NamespaceはELBのものを使います。
  • CPU負荷、デフォルトの平均じゃなくて最大でみたほうがいいことがあります。CPU使用率の平均40%だから平気平気、と思ってたらELBが503返してて、CPU使用率を最大で見たら90%超えててEC2が死んでた、とかあるので・・・。
  • サポートの方に「503頻発してELB足りないぽいから日常的にPreWarmingお願いします」と依頼したら、「SpillOverCount(過剰数)のカウントが上がっていますのでEC2増やしてください」と返答ありました。AWSサポートの皆様、スキル高くて頼りになります。
  • NLB化も検討したいところ。

まとめ

Elastic Beanstalk、AWSにおまかせできる部分が多くて楽ができますが、特有の癖みたいなものがあるので気をつけて使うと安全安心です。

ハンズラボ Advent Calendar 2017 明日12日目は@sr-mtmtです!

続きを読む

中途入社のAWSエンジニアが、稼働中サービスの運用状況をキャッチアップするために意識すること

Classiアドベントカレンダー11日目です。
今回は、AWSエンジニアが稼働中のAWSの管理アカウントを渡されて、ビクビクしながらキャッチアップを行っていったときのメモになります。

1.TL;DR

AWSアカウントのログイン前に準備できることもあるし、AWSアカウントにログインしてわかることもあるし、サーバーにログインしてわかることもある。それぞれのレイヤーでどういったことを確認するかを意識しながらキャッチアップを進めていきましょう。

2.AWSアカウントログイン前の事前準備

pre_aws.png

サービスが稼働しているのであれば、AWSアカウントにログインせずとも、たくさんの情報をキャッチアップすることができます。1日目から何らかの大きなアウトプットを出さないと解雇するような会社は、(おそらく)存在しない筈です。まずは落ち着きましょう^^;

2-1.ドキュメント読み込み

サービスのインフラにAWSが使われることが多くなったからといって、入社前に経験したAWS運用フローがそのまま活かせる訳ではありません。まずは、前任者や運用中のドキュメント管理ツールの中から、今までどのような運用を行っていたかを確認します。
ドキュメントを見たときに意識する観点としては、

  • フロー型:時間による鮮度の劣化があるドキュメント
  • ストック型:システム仕様など、メンテナンスが求められるドキュメント

どちらの情報であるかを意識して読むことが重要です。
フロー型の情報は、障害などで一時的な対応用にメモっていることもあり、運用の中で解決済みのことがあります。そのため、ストック型のドキュメントを中心に見ることが素早いキャッチアップになると思います。
とはいえ、ドキュメントの全てがメンテナンスされている会社というのは稀だと思いますので、各種ドキュメントを見ながら、仮説程度に自分なりのシステム構成図などを書いてみましょう。
要件定義書や各種構成図の変更履歴、課題管理表、リスクコントロール表といったドキュメント類があるのであれば、目を通しておきましょう。

2-2.運用フローを観察する

サービス側のドキュメントについては、まだ文書化されてることが多いですが、運用系ツールに関しては、ドキュメント化されていないことがあります。今の開発スタイルであれば、何らかのチャットツール(Slack,ChatWork,HipChat)上で、

  • デプロイ
  • 各種の通知
  • 運用Bot

の運用といったことが行われていると思います。また、チャットだけでなく、メールでの運用フローも存在しているかもしれません。
こうした運用系ツールの存在は、今後自分がリファクタするときに、「必須要件ではないが、重宝している」ということで、「リファクタ後にも、あの機能を実装して欲しい」といった声が社内から上がると思います。
そのため、このような運用フローがどこで実装されているかを見極めることが重要になってきます。

2-3.インフラ部分のコード読み

「俺はフルスタックエンジニアだ!」という強い意思がある方は、この時点で稼働中のアプリ側のコードまで読み込んでいただければよいですが、まずは入社前に期待されたであろう、インフラまわりのコード化部分を把握しておきましょう。どのみち、いずれはメンテナンスを任されたり、質問されることが増えてきますので、自分のメンテナンスする部分を優先的に確認しておきましょう。
実サーバーの運用はAWSに任せているので、ここで意識しておくことは、

  • Infrastructure Orchestration Tools:Terraform, CloudFormationなど
  • Server Configuration Tools:Chef,Ansible,Itamaeなど

あたりのコードがgithubなどに保存されているからといって、メンテナンスされていない可能性もあります。
コードの設計方針などを確認するのは当然必要なのですが、コードの変更履歴が年単位で放置されていないかどうかも見ておきましょう。特に、AWS関連のコードについては、担当する人がアプリ側よりも少ないので、構築当初のコードのままなのか、運用されているコードなのかはPRなどで確認しておいた方がよいです。

3.AWSのアカウント内を調査する

aws_kansatsu.png

実際にAWSアカウントにログインしたり、APIで各種設定を確認していきます。Web系サービスであれば、TCP/IPモデルやC/Sモデルを意識しながら、下層レイヤー回りから調査していき、ネットワークがどうせ設定されているかを確認していきます。
おそらく、ここで多くの疑問(場合によっては、絶望)が生まれる段階です。「あれ?ドキュメントにこう記述されているけど、設定上は違うような…」という沼にハマることがあるでしょう。負けないでください、一人で抱え込まずに闇を共有できる仲間を見つけましょう。

3-1.外部システム連携の確認

関連するAWSサービス

VPC関連のサービスを中心に、自AWSアカウント以外の連携がないかの確認を行います。

関連しやすいAWSサービス例)

  • DirectConnect
  • NAT Gateway
  • Peering Connection
  • Customer Gateways
  • Virtual Private Gateways
  • VPN Connections
  • NetWorkACL
  • SecurityGroup
  • EIP

などに、何らかのインスタンスが稼働していて、productionやhonbanなどの文言がついたものがあれば、それはドキュメント上には存在しないが、サービス上何らかの理由で稼働しているものである可能性があります。
自社のサービスがAWSアカウント内だけで完結しているのであればよいのですが、誤ってここのインスタンスなどを削除すると、場合によってはシステム復旧できないぐらいの痛手になるので、慎重に確認していきましょう。
特に、SecurityGroupは、最近でこそInboundルールにDescriptionをつけられるようになりましたが、数年運用されているシステムには、何で利用しているIPアドレスなのかがわからないことがあるので、設定確認中に不明なIPアドレスを見つけたら社内で有識者に聞いてみましょう。

3-2.システム導線の確認

関連するAWSサービス

インスタンス障害があるとユーザー影響がありそうな、システム導線を追っていきます。

関連しやすいAWSサービス例)

  • ELB(CLB,ALB,NLB)
  • CloudFront
  • EC2
  • ElasticCache(redis,memcached)
  • RDS(Aurora,MySQL,PostgreSQL,SQLServer)
  • ElasticSearch
  • DynamoDB
  • S3

各種のインスタンスサイズが適切かを確認するのはもちろんですが、DB関連についてはバックアップ関連の設定がちゃんと行われているかどうかも確認しておきましょう。バックアップウィンドウの世代数やメンテナンスウィンドウの時間が営業時間内になっているとかは、結構ありがちな設定漏れケースになります。パラメータストアの設定については、本番で稼働している設定が正義なので、設計と違う場合は、社内で経緯を追ってみましょう。

3-3.運用導線の確認

関連するAWSサービス

直接のユーザー影響はないものの、バッチ系およびログインやログ連携など、システム運用で必要な運用導線を追っていきます。

関連しやすいAWSサービス例)

  • EC2
  • Lambda
  • ElasticSearch(& kibana)
  • IAM
  • CloudTrail
  • AWS Config
  • CloudWatch Logs
  • S3
  • Glacier

24224というポート開放を見れば、そのシステムはfluentd関連のフローがあるのはほぼ確定なので、ログの発生から可視化ツールおよびバックアップのフローまで追っていきましょう。また、バッチ系のEC2に関しては、最近のAWSだと、FargateやECS、Lambdaなどで定期バッチを行うことも可能なので、単一障害点をなくすことができないか、今後の計画のために、バッチ系が整理されているドキュメントなどを探してみましょう。

4.サーバー内の設定を確認する

server_chosa.png

最近だと、Server Configuration Toolsが大分普及していたり、コンテナ系の運用が発達してきているので、このあたりのキャッチアップ期間が少なくなるのかなと思います。とはいえ、SSH接続を頻繁に行うサーバーや起動時間が長いサーバーだと、コードの設定と異なる部分が出てきていることがあるかもしれません。
OSの設定やミドルウェアのバージョンなど、SSH接続すると確認した方がよいところは多々ありますが、Server Configuration Toolsの設定と異なっていたり、運用中のアラート設定などで差異がでやすそうな部分を以下に記載します。

4-1.各種メトリクス確認

メモリやプロセスの状況は、通常CloudWatchだけではわからないので、MackerelやZABBIXなどの監視ツールエージェントを入れているのであれば、各サーバーのメトリクスを確認しておきましょう。

4-2.稼働プロセスの確認

pstreeなどで、稼働しているプロセスを確認します。SSH接続が禁止されているのであれば、AWSのSSMエージェントなりで確認できないかを検討してみましょう。設計上のソフトウェアスタックに存在しないプロセスが常駐している場合は、何のエージェントが動いているかを追っておきましょう。

4-3.不要なファイルが出力されていないかの確認

ログレベルがデバッグのままだったり、ログファイルのローテートがなされていない場合があり、アラートは上がっていないけど、サーバー内のリソースを侵食しているときがあります。また、生成されるログファイルが小さすぎると、ディスクに余裕がありそうに見えても、inodeが先に枯渇するときもあります。lsofdf -iなどを可視化するなどして、サーバー内のディスク状況を確認しておきましょう。

4-4.同期処理と非同期処理のプロセス確認

同期処理のプロセスは意識しやすいので、監視対象に入っている可能性が高いです。ただ、非同期系プロセス(Rubyだとsidekiq,Pythonだとcelery,PHPだとphp-resqueなど)が監視対象に入っていないこともあるので、どのサーバーで非同期処理が行われているかを把握しておきましょう。

5.まとめ

AWSや他のパブリッククラウドが全盛になった今でも、3層アーキテクチャのシステム構成やOSI7階層などのレイヤーを意識しながらキャッチアップを行うと、システムを俯瞰しながらキャッチアップを進めることができるのではないかなと思います。とはいえ、前任者がコード化しきれなかった部分もある筈なので、そこは社内で過去経緯を知っている人に笑顔で質問をしてみましょう。技術が発達しても、人に蓄積されるノウハウはまだまだ多いので…
AWSエンジニアが転職する際などのご参考になれば。

続きを読む

[AWS Cloud9]EC2自動停止を検知して別の処理を始める

はじめに

AWS Cloud9はIDEのブラウザを閉じたとき、自動でEC2インスタンスが停止する機能があります。
何分後に、自動停止するかは、設定から変更が可能です。
1.PNG

AWS Cloud9を1週間使うと、EC2インスタンスが自動停止するのが「便利 → 当たり前」という感覚になりました。そして、思いました。自動停止を検知してもっと楽できないかと。

やりたいこと

AWS Cloud9の機能で

  • 検知した情報をトリガーに別の処理を動作させてみる。
  • 今回は、サンプルに以下を動作確認
    • 自動停止のお知らせメール (実装したら、イチイチお知らせが来てウザくなった)
    • RDSの自動停止 (IDEとセットで使ってたので、止め忘れがなくなり非常に便利になった)

自動停止したことを検知

CloudWatchのルールを作成。

  • イベントパターンを選択
  • サービス名:EC2
  • イベントタイプ:EC2 Instance Status-change Notification
  • 特定の状態:インスタンスの停止を設定
  • Specific instance Id(s):AWS Cloud9のインスタンスIDを設定
    2.PNG
{
  "source": [
    "aws.ec2"
  ],
  "detail-type": [
    "EC2 Instance State-change Notification"
  ],
  "detail": {
    "state": [
      "running",
      "stopped"
    ],
    "instance-id": [
      "AWS Cloud9のインスタンスID"
    ]
  }
}

検知した情報をトリガーに別の処理を動作

ターゲットに今回は2つ(SNS(メール送信)とLambda(rds停止)を設定しました。)
SNSは使い道を思いつかなかったのでEメールを設定したのみ。jsonがそのままメールに飛んでくる。

3.PNG

LambdaはついでにIDE起動したときの動作も記述。

  • IDE起動→EC2開始→RDS開始
  • IDE終了→30分後EC2停止→RDS停止
IAMロール
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "rds:StartDBInstance",
                "rds:StopDBInstance"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}
lambda_function.py
import boto3

def lambda_handler(event, context):
    dbinstance = 'RDSインスタンス名'
    rds = boto3.client('rds')
    instanceState = event['detail']['state']
    if instanceState == 'stopped':
        result = rds.stop_db_instance(DBInstanceIdentifier = dbinstance)
    else:
        result = rds.start_db_instance(DBInstanceIdentifier = dbinstance)
    print(result)    
  • 開始状態のRDS

4.PNG

  • EC2が停止するイベントが発生

5.PNG

  • RDSが自動で停止
    6.PNG

まとめ

  • CloudWatchを使うことでIDEの終了後、EC2自動停止を検知できました。
  • 後続処理を自動化できることが分かったので、一日の作業終了をブラウザを閉じるだけに出来そうです。

関連

続きを読む

LambdaとCloudWatchでサーバレスなTwitterBot作ってみた

こんにちは。駆け出しインフラエンジニアの(@k4ri474)です。
この記事はVASILY Advent Calendar 2017 11日目の記事です。

Twitterでbotを作ろうと思った時、ざっくり二つ選択肢が頭に浮かびますよね?
巷に溢れているbot作成サービスに登録するか、
はたまた自作するか。

エンジニアの方は、とりあえずプログラミングしてみっか〜となることが多いような気がします。
Twitter APIに関してはもちろん公式ドキュメントがありますし、プログラムもググれば山ほど先人たちのものが見れるので、
なんちゃらキーやらなんちゃらトークンさえ取得できれば、肝心のツイートはチョチョイのジョイかと思います。

ただ、継続的に動かすbotとして考えるとベースのサーバはどうしても必要になるのでちと悩みますよね。
自分のサイトをホスティングしてメールサーバ動かしてついでにbotを回す、などといったような状況ならクラウドでサーバを立てとけばいいんですが、botだけでいい時には少々大げさです。

そこでAWS Lambda + Amazon CloudWatch Eventsを使ってサーバレスに、かつ継続的に実現します。

概要

1postするためのプログラムをpythonで書き、それをLambdaにセットします。
そしてLambdaをCloudWatch Eventsで定期的に発火させ、botの体をなすようにします。

実装(Lambda)

まず、こちらが普通のつぶやきプログラムです。

from requests_oauthlib import OAuth1Session

CK = 'CONSUMER_KEY'
CS = 'CONSUMER_SECRET'
AT = 'ACCESS_TOKEN'
AS = 'ACCESS_TOKEN_SECRET'

URL = 'https://api.twitter.com/1.1/statuses/update.json'

tweet = "Hello World"
session = OAuth1Session(CK, CS, AT, AS)

params = {"status": tweet }
session.post(URL, params = params)

Twitterに接続するにはOAuth認証が必要なのでrequests_oauthlib(https://github.com/requests/requests-oauthlib)
というPython用のOAuth認証ライブラリを利用しました。
Lambdaではライブラリとプログラムコードを一まとめにzip圧縮する必要があるので、プログラムと同じディレクトリにインストールしておきます。

% pip install requests requests_oauthlib -t ./

各種キーは苦労して取得したら、それらを各々セットしていただければあとはつぶやきをいじって実行するだけです。

さて、上のプログラムをLambda用に書き換えます。
Lambdaから関数を呼び出してもらうためには、ハンドラー関数を作成する必要があります。
パラメータとして eventcontext を取る関数で、Lambdaを呼び出したイベントデータやランタイム情報を内部で使えますが、今回はシンプルに使わない方向でいきます。

from requests_oauthlib import OAuth1Session

CK = 'CONSUMER_KEY'
CS = 'CONSUMER_SECRET'
AT = 'ACCESS_TOKEN'
AS = 'ACCESS_TOKEN_SECRET'

URL = 'https://api.twitter.com/1.1/statuses/update.json'

def my_handler(event, context):
    tweet = "Hello World"
    session = OAuth1Session(CK, CS, AT, AS)

    params = {"status": tweet }
    session.post(URL, params = params)

これで準備は完了です。
こちらのファイル群をzip化し、コマンドでアップロードしてみます。

% aws lambda create-function \
--region ap-northeast-1 \
--function-name "sample" \
--runtime "python3.6" \
--role "MY_ROLE" \
--handler "sample.my_handler" \
--zip-file "fileb://./sample.zip" \
--profile PROFILE

注意したいのはhandlerオプションです。構文は実行ファイル名.ハンドラー関数名ですので、作成したプログラム名とハンドラー関数名に合わせて適宜編集してください。

また、セットするroleにCloudWatchLogsの権限を与えておくと実行結果をログ出力できるようになるのでオススメです。
今回は定義済みのポリシー、arn:aws:iam::aws:policy/CloudWatchLogsFullAccessをアタッチしたロールを事前に作成していたので、そちらをセットしてみました。
ポリシーは以下の通りです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:*"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}

以上でLambdaへのアップロードは完了です。

実装(CloudWatch Events)

さて、あとはこのLambda関数を定期実行するだけです。
まずはCloudWatch Eventsをトリガーにセットします。

スクリーンショット 2017-12-10 23.09.08.png

Lambdaのダッシュボードから関数を選択し、設定画面でトリガーを設定します。上図のようにCloudWatch Eventsをトリガーにセットしたら、下にスクロールしてトリガーの詳細を設定します。

スクリーンショット 2017-12-10 23.09.56.png

例としてはこんな感じでしょうか。
ルールタイプをスケジュール式に選択すると、おなじみのcron記述で定期実行の間隔をコントロールできます。
僕は試しにもう一方のrate式を使ってみることにしました。

このような感じで設定して保存すると無事トリガーとして機能します。
お疲れ様です。

成果物

このままのプログラムでは全く同じ内容をつぶやくばかりで面白くないので、
プログラムをちょちょっといじってimgurから猫画像のリンクを拾ってきてpostする感じのbotを作ってみました。

https://twitter.com/k4ri474/status/937562270476812290

自分の猫postで心が洗われます。
皆さんもサーバレスTwitter botでぜひ遊んでみてくださいb

続きを読む

re:Invent 2017にみるAWSとクラウドの進化する方向性

11月27日から12月1日までの5日間にわたり、ラスベガスに4万3,000人の人を集めたAWSの年次イベント”re:Invent 2017”。AWS CEOのAndy JassyやAmazon CTOのWerner Vogelsなどのキーノートでは、今年もさまざまな真サービスが発表されました。仮想環境の管理を用意にするKubernetesをマネージド型で提供するサービスやサーバーレスのデータベースサービス、マシンラーニングのモデル構築から学習、デプロイ、API化まで一気通貫でサポートするサービスなどオンラインメディアからピックアツプして紹介します。

※下記サイトからの転載。ビッグデータ・AIなどに関するトピックを毎週取り上げています。
TechCrowd: https://www.techcrowd.jp/related/

クラウドは次のフェーズへ――、「AWS re:Invent 2017」でアンディ・ジャシーCEOが示した5年間の総決算

クラウドWatchのre:Invent 2017のレポート記事です。Andy Jassyのキーノートで発表された新サービスを紹介しながら、AWSが描こうとしているあらたなクラウドの世界を展望してくれています。

まずは、各種メディアでも今年のre:Invent 2017での新サービス発表の中でも一番にとりあげられている「Amazon Elastic Container Service for Kubernetes(Amazon EKS)」。Kubernetesのマネージドサービスであり、ユーザーのVPC内でコンテナが稼働するインスタンスを起動できるほか、CloudTrailやCloudWatch、ELB(Elastic Load Balancing)といったAWSのさまざまなサービスとKubernetesのスムーズな連携が可能です。

Andy Jassy CEOはキーノートの中で、「インスタンス」「コンテナ」「サーバーレス」の3つのアーキテクチャをAWSのコンピュートリソースとして位置づけ。クラウドの基盤を支えるアーキテクチャがインスタンスという仮想サーバだけだった時代からコンテナやサーバーレスまで含むものにはっきりと拡張してきていることを感じさせます。

次に、Andy Jassy CEOがとりあげたのはデータベース。プロプライエタリなRDBからの解放、データベースの自由を実現するものとして、AWSの各種データベース機能に関する新サービスを発表。その中でももっとも注目を集めたのはAurora Multi-Master。リード重視のAuroraがリード/ライトの両方でスケールできるようになるとのこと。現時点ではシングルリージョン/マルチマスターのみのプレビュー提供だが、Andy Jassy CEOは「2018年の早い段階でマルチリージョン/マルチマスタに対応する」とのべています。

データアナリティクスをより効率的にするものとして発表されたのが、「Amazon S3 Select」と「Amazon Glacer Select」。いずれも必要なオブジェクトデータのみを標準的なSQLを使ってフィルタリング(SELECT)する機能。オブジェクト全体にアクセスする必要がなくなるため、データアクセスのパフォーマンスが最大400%と劇的に向上するとのこと。S3やGlacerが単なるオブジェクトストレージからデータレイクへと進化しつつあることを示す機能追加です。

また、マシンラーニングをより身近な存在とする新サービスもいろいろ発表されています。もっとも注目されているのが”Amazon SageMaker”。マシンラーニングのモデル構築から学習、デプロイ、API化まで一気通貫でサポートするスケーラブルなマネージドサービス。(GA、バージニア/オレゴン/オハイオ/アイルランド)

モデル作成にはデータサイエンスで標準的に使われているJupyter Notebook環境をワンクリックで設定できるほか、トレーニングもデプロイもワンクリックで利用可能。まさにオールインワンのマシンラーニングサービスとのことです。

AWSのSageMakerを使えばふつうのデベロッパーが機械学習のモデルを作れる

TechCrunshのre:Invent 2017レポート記事で、特に機械学習のモデル制作プロセスを管理するためのフレームワークを提供し、そのプロセスに含まれる複雑面倒な部分を取り去る Amazon SageMakerに焦点をあてたものです。

この新しいツールには、三つの主要部分「Notebook」「Jobs」「Models」があるとのこと。Notebookはオープンソースの標準的なツールJupyter Notebooksを使って、モデルのベースとなるデータを概観し整理する。

re:Inventのステージで、Andy Jassy CEOはSageMakerの柔軟性を強調。すぐに簡単に使えるツールとして使ってもよいし、自分のフレームワークを持ち込んでもよい。どちらの場合でも、そしてソースが何であっても、サービスはもっともポピュラーなアルゴリズム向けに調整されているとのこと。

Amazon、re:inventカンファレンスでグラフDB、Neptune発表

TechCrunshのre:Invent 2017レポート記事で、特にAWSの新しいデータベース、Amazon Neptuneに焦点をあてたものです。Amazon Neptuneは、グラフ関係の処理を目的としたサービス。サービスにソーシャルネットワーク的要素を組み込もうとしているならこのデータベースは役に立つかもしれません。

伝統的なリレーショナルDBの問題点は、もともと複雑なソーシャルグラフを扱うようにデザインされていないこと。そのためRDBでは友達関係やフォロー関係のリストを扱うのが難しく、ソーシャルグラフから共通の友達を抽出しようとすると、そのたびにきわめて複雑なクエリーを発行する必要がありました。

Neptuneは数十億に上るソーシャル関係を処理するために最適化されており、複雑なソーシャルグラフも高速に処理し、一つのクエリーを処理するのに1000分の1秒単位の時間しかかからないとのこと。

AWS re:Invent 2017、データベースもサーバーレスの時代へ

週刊BCNのre:Invent 2017レポート記事。数多くの新サービスが発表されていくなかで、
最も盛り上がったのがデータベース関連の新サービスとのことで、「Amazon Aurora Serverless」などを紹介しています。

「Amazon Aurora Serverless」は、利用した分だけ課金されるサーバーレスのリレーショナルデータベース。インスタンスの管理が不要で、自動でスケール。サーバーレスサービスの「AWS Lambda」と同様、閾値などをトリガーにSQL文を実行するなど、まずはIoT分野での活用が想定されるとのこと。また、クラウドネイティブなシステムにおいても、サーバーレスの特徴を生かした活用方法に期待が高まるとのことです。

続きを読む

CodeBuildの実行結果をslackに通知する

はじめに

Globis Advent Calendar10日目は、弊社のエンジニアチームを支えるインフラ技術をお伝えいたします。
開発スピードをさらに促進するために、Blue Green Deployment, Infrastrucure as Code, ChatOps など新しい運用思想を積極的に取り入れて、手動でのオペレーションを極力なくしています。
今回は、弊社で実運用しているChatOpsの一例として、CodeBuildの実行結果をslackに通知する方法を、可能な範囲で具体的にお伝えいたします。

設定方法

AWS Lambdaの設定

コード

import os
import json
import urllib.request

URL = os.environ['WEBHOOK_URL']


def send_slack(obj):  ## slackに通知
    method = "POST"
    headers = {"Content-Type" : "application/json"}
    js = json.dumps(obj).encode("utf-8")
    request = urllib.request.Request(URL, data=js, method=method, headers=headers)
    with urllib.request.urlopen(request) as response:
        response_body = response.read().decode("utf-8")


def check_status(status):
    fail = False
    if status == 'IN_PROGRESS':
        color = '#008000'  ## green
    elif status == 'SUCCEEDED':
        color = '#00BFFF'  ## deepskyblue
    else:
        color = '#FF00FF'  ## magenta
        fail = True
    return color, fail


def parse_event(event):  ## cloudwatch event から渡された event(dict型)をパース、slackに渡すobjectを生成。
    detail = event['detail']
    status = detail['build-status']
    initiator = detail['additional-information']['initiator']
    log = detail.get('additional-information', {}).get('logs', {}).get('deep-link', 'Not Exist')
    color, fail = check_status(status)
    fields = [{'title': 'Initiator', 'value': initiator, 'short': False},
              {'title': 'Status', 'value': status, 'short': False},
              {'title': 'LogLink', 'value': log, 'short': False}]
    obj = {'attachments': [{'color': color, 'fields': fields}]}
#    if fail == True:  ## Fail時にチャンネルメンション飛ばしたい時はコメントを外す。
#        obj['attachments'][0]['text'] = '<!channel>'
    return obj


def lambda_handler(event, context):  ## lambdaから最初にcallされる関数。
    obj = parse_event(event)
    send_slack(obj)
    return

環境変数の設定

CloudWatch Event の設定

slackでの通知結果

  • ワンクリックでビルドログを眺めることができます。

運用事例のご紹介

  • AWS Athenaのテーブルにクエリを実行し、中間テーブルを生成するETL処理のバッチ
  • Ruby on Rails アプリケーションデプロイ時の db:migrate 処理
  • 最近はCodeBuildをVPC内で実行できるようになったので、利用できる幅が広がっています!

おわりに

いかがでしたでしょうか。python初心者(僕)でもChatOpsに貢献できます。
グロービスではSREエンジニアを募集しています!
インフラの運用担当だけど手作業を自動化したいと考えている方、開発者だけどインフラも含めてコードで管理したい方、一緒に理想のインフラを作ってみませんか?

続きを読む