AWS DevDay Tokyo 2018 Software Design/Serverless & Mobile トラック+α まとめ

(2018/11/12 更新) Amazon Web Services ブログで資料が公開されましたので、末尾にリンクを追記しました。

AWS DevDay Tokyo 2018 が10/29-11/2 の5日間に渡って行われました。 私は10/31(水)のみ現地で参加し、11/1(木),2(金) はライブストリーミングでちょこちょこ参加しました。 aws.amazon.com

非常に内容が濃く、素晴らしいイベントでしたので、10/31(水)のSoftware DesignトラックとServerless & Mobile トラックについて自分の聴講メモと公開された資料をまとめて残したいと思います。

10/31(水) Software Design トラック

セキュア開発プロセスアジャイル開発に適用するには

講師: 徳丸 浩 さん(EGセキュアソリューションズ株式会社代表、独立行政法人情報処理推進機構IPA)非常勤研究員)

アジャイルのような段階的に機能を作り込んだり追加していったりするプロセスにおいて、セキュリティ施策をどう組み込んでいくか現実的な落とし所を考えるセッションでした。

聴講メモ

  • アジャイル開発とセキュアプログラミングは相性が悪い?
  • セキュリティ施策を分類する
    • セキュリティ方針決定系や教育系、予算確保は1回のみ
    • それ以外は繰り返す → 自動化したい
  • セキュリティ施策の優先度
    • エアバッグのない自動車は販売できる(法令上は)が、ブレーキのない自動車は販売できない
    • ログイン機能のないWebサイトはリリースできないが、二要素認証がないWebサイトはリリースできる
  • アジャイル型開発での脆弱性対処
  • 脆弱性診断をインクリメンタルに実施する
    • アジャイル開発の場合は新規にコミットしたソースコードが対象になる
    • リリースごとにサイト全体の診断をするのは現実的ではない
    • が、リグレッションの可能性もある
    • → 汎用の脆弱性診断ツールを用いる(OWASP ZAPのAPIを活用)
    • 汎用のテストツールで脆弱性診断できないか?
    • 継続的テストに特化したツール・サービスを用いる
    • ソースコード診断ツールを用いる
      • 高価
      • 誤検知が多い
  • プラットフォームのセキュリティ
    • OpenVASやNessusで自動化
  • デモ: OWASP ZAP で脆弱性診断したときのURLをPHPUnitで叩いて単体テスト脆弱性診断を組み込む
  • が、ツールによる診断では十分とは言えない

ドメインモデリングの始め方

講師: 加藤 潤一 さん(ChatWork株式会社) speakerdeck.com

あなたの推しテクをもっと伝えるプレゼンテーション術

講師: 長沢 智治 さん(エバンジェリズム研究所 代表) speakerdeck.com

The Twelve-Factor App で考える AWS のサービス開発

講師: 千葉 悠貴 さん、畑 史彦 さん(アマゾン ウェブ サービス ジャパン株式会社 ソリューションアーキテクト)

外部に依存したコードもテストで駆動する

講師: 和田 卓人 さん(タワーズ・クエスト株式会社 取締役社長、プログラマテスト駆動開発者)

Alexa Skillのコードを元にTDDでコードを改善していくセッションでした。

speakerdeck.com

聴講メモ

  • Alexa Skillのフレームワークに依存している
  • 網羅性はいらない。脳天気な正常系(Happy Path)でいいので動くテストがほしい
    • alexa-skill-test-framework
      • 高機能かつ抽象化されており、かゆいところに手が届きにくい
      • Easy指向
    • aws-lambda-mock-context
      • 機能が少なく、レイヤが薄い
      • Simple指向
    • 今回はaws-lambda-mock-contextを採用
  • ランダムな応答を返すもののテストはどうやるか?
    • レガシーコードのジレンマ
    • 接合部(Seam)を作る
    • 固定値を外からねじ込めるように書き換える
  • テストで品質は良くならない
    • テストは品質がよくなるためのきっかけ
  • モデルを分離する
    • Lambdaレベルのテストをグリーンに保ちながら、ロジックをモデルクラスに引き剥がしていく
    • モデルクラスはテスト駆動開発で新規開発する
  • 環境依存を減らす
  • アーキテクチャを定める
    • 安定依存の原則 … 変化しやすいものに依存しない
    • 情報 を扱うレイヤと 事実 を扱うレイヤを分ける

日経電子版におけるPWA活用事例

講師:安田 竜 さん (株式会社日本経済新聞社

実践!リーンなプロダクト開発 ~リーンでアジャイルなUI/UXデザイン検証~

講師: 奥原 拓也 さん (dely 株式会社) speakerdeck.com

10/31(水) Serverless & Mobile トラック

浸透するサーバーレス、実例に見るユースケースと実装パターン

講師: 杉 達也 さん (アマゾン ウェブ サービス ジャパン株式会社 事業開発マネージャ (サーバーレス担当))

Serverless Application Security on AWS

講師: 桐山 隼人 さん(アマゾン ウェブ サービス ジャパン株式会社 技術統括本部 ソリューションアーキテクト)

AWS Well-Architected Framework の Serverless Applications Lens を読み解くセッションでした。

聴講メモ

  • セキュリティの柱
  • IDとアクセス管理
    • APIアクセスの認証認可をどのようにしていますか
      • Cognito User Pools Authorizer
      • AWS IAM Authorization
      • Lambda Authorizers
    • LambdaファンクションがアクセスできるAWSサービスをどのように保護していますか
  • 発見適当性の考慮事項
    • サーバーレスアプリケーションのログをどのように分析していますか
      • アプリケーションログはCloudWatch Logsをつかう、とか
      • AWSサービスAPI呼び出しは CloudTrailをつかう、とか
      • ログに機微情報が含まれる可能性、とか
    • アプリケーションの依存関係や脆弱性をどのように監視していますか
  • インフラストラクチャー保護の考慮事項
    • LambdaファンクションがアクセスできるVPC内のAWSリソースに関して、どのようにネットワーク境界を保護していますか
      • ネットワークACLやセキュリティグループによるネットワーク境界保護
  • データ保護
    • サーバーレスアプリケーション内の機微な情報をどのように保護していますか
    • どのように入力値チェックをしますか
      • 通信データの暗号化
      • クライアントサイド暗号化
      • 保護すべきデータの外部化
        • AWS SystemManager Parameter Store
        • AWS Secrets Manager
        • Secrets Manager を使える場合はSecrets Managerを使うのがオススメ
  • インシデントレスポンスの考慮事項

開発者におくるサーバーレスモニタリング

講師: 小梁川 貴史 さん(アマゾン ウェブ サービス ジャパン株式会社 技術統括本部 ソリューションアーキテクト)

AWS Lambdaを中心にmetricsの意味や監視ポイントを解説するセッションでした。

聴講メモ

  • 自分が作ったものがどう使われているのか・動いているのかを把握できることが重要
  • AWS Lambdaの起動パターン
    • イベントベース
      • API Gateway
      • S3
      • など
      • イベント数:Lambda = n:n
    • ストリームベース
      • Kinesis Streams
      • DynamoDB Streams
      • ストリームのシャード数:Lambda = 1:1 -シャードの追加に自動追従 SQSベース
      • SQS
      • log polling型、Queueの数に応じてLambda起動数がAutoScaling
  • duration の意味
    • ENIの作成~ランタイム起動・初期化 までの時間はdurationに含まれない
  • SQS起動における注意
    • メッセージ数 > 処理量 の傾向が続いて処理が追いつかない状況になるとコンカレンシーリミットまでスケールする
    • コンカレンシーリミットを設定していないと、アカウントの上限までスケールして他のLambdaに影響を与えてしまう
  • AWS X-Ray
  • CloudWatch Logs filter pattern
    • 大文字・小文字は区別される
    • 正規表現は利用できない
    • 簡単なパターンマッチのみ利用可能
    • 検索しやすいログ設定を!
    • Amazon Elasticsearchに投げたりLambda経由でS3に投げて解析したりとか

ZOZOTOWN の膨大な画像ファイルを移行したときの過程の話(オンプレミスからクラウドへ)

講師: 柴田 翔 さん(株式会社ZOZOテクノロジーズ《旧:株式会社スタートトゥデイテクノロジーズ》ZOZOバックエンド部ネットワークブロック)

数億点の画像ファイルをS3に移行した事例についてのセッションでした。

聴講メモ

  • 移行背景
    • 容量不足
      • ZOZOUSED(中古=同じ商品が無い)のサービスが好調
      • 画像数億点 約60TB (オリジナル画像+リサイズ画像)
    • 監視したくない
      • 逼迫の恐怖
      • 画像アップロードの量が多い
        • オンプレミス画像サーバが耐えられない
      • オンプレミスの保守
      • 夜間アラート
        • 夜間アラートの60%が画像サーバ関連
    • スケーラビリティが必要
      • サービス拡大による画像アップロード数の増加
  • なぜS3なのか
    • 高い耐久性、容量制限がない
    • 公開ナレッジが多い
    • AWS SAの手厚い技術的サポート
  • 移行する上で重要視したポイント
    • 運用コスト削減のため、なるべくマネージド
    • 画像データの容量を気にしなくていい
    • 短期間での移行のため、開発対象を少なくし、テスト工数も削減したい
  • 画像移行パターン
    • パターン1:Snowballでの移行 → ボツ
      • 転送速度の計算
        • 約60TB
        • 平均オブジェクトサイズ 128KB
        • 転送速度 10MB/s
        • → 72日
      • 暗号化に時間がかかる
      • 出す・入れる で2倍
      • 移行用クライアントが必要
      • オフライン同期のため、差分同期が面倒
    • パターン2:S3に直接PUT → ボツ
      • 転送速度を計算
        • 転送速度 42MB/s(バッチ3並列の実測値)
        • → 17.3日
      • 転送速度4倍
      • Snowballの手配が不要に
    • パターン3:オリジン画像のみS3直接PUT、リサイズはLambda → 採用
      • 転送速度を計算
        • 約30TB(オリジナル画像のみ)
        • 転送速度 42MB/s(バッチ3並列の実測値)
        • → 8.6日
      • Snowballの8倍、全画像PUTの2倍 リサイズ用オンプレサーバ不要に
  • 移行後の構成
    • 1次受けバケット → Lambda → オリジナル画像、リサイズ画像バケット
    • オリジナル画像のコピーとリサイズ処理が終わったら1次受けバケットから画像を消す
    • 破損した画像ファイルや何らかの事情でLambdaが起動しなかった画像ファイルが1次受けバケットに残る
  • ポイント
    • Lambdaの修正の楽さ
      • 属人化が排除できた
    • 公開ナレッジの多さ
    • 画像変換用サーバが不要に
  • 移行過程で発生した問題
    • S3バケットの制限
      • S3 GET制限とPrefix
        • 800GET/sec
      • 現サーバへのリクエスト数(オリジナル画像+リサイズ画像)
        • 795GET/sec
      • バケットを分けてGET数を分散
      • S3 GET/PUTのパフォーマンス向上 のリリース
        • → クリア

クックパッドの動画事業での AppSync 活用事例 - Firebaseからの移行 -

講師: 渡辺 慎也 さん (メディアプロダクト開発部部長 CookpadTV株式会社取締役 CTO)

AppSyncをMicrservicesの一部として組み込んで使う事例のセッションでした。 speakerdeck.com

聴講メモ

  • コメントやハートの実装
    • Firebase Realtime Databaseを使っていた
    • 当時はまだAppSyncが東京リージョンに来ていなかった
  • 移行のモチベーション
    • データをAWSとFirebaseに分散させたくなかった
    • AppSyncはDynamoDBやLambdaなどコントローラブルな点が多い
  • WRITEはサーバー経由、READは直接
    • コメントはNGワードのフィルタリングなどをかけたいので
    • スタンプはポイントが必要なのでチェックが要る
  • AppSyncのボトルネック
    • Cognitoの制限
      • Cognitoの GetCredentialsForIdentityの同時実行数
      • API Keyを利用すれば回避できる
    • Mutation per second制限
    • アプリへのファンアウト数
      • 細かいメッセージをたくさん飛ばすより、ある程度バッファリングした方が良い
  • Service Mesh
    • SDK実装ではなくSidecar Proxy(Envoy)経由で通信する
  • cookpadTV message and MBR
    • メッセージ送信サービスはGoで実装
    • MBW ... Message Buffer Writerの略
      • AppSyncへの mutations per seconds を軽減させるため
      • 47分の放送時間中にハートが150万回送信された
        • 単純計算すると平均 532rps
      • 設計方針
        • コメントの反映は送らせない
        • 順序保証は行わない
        • 最悪データのロストを許容
          • 永続化は別で行っている
          • リアルタイ性がないコメントはあまり意味がない
          • ストレージ不要でオンメモリ処理が可能
        • Subscribeで流れてくるメッセージは番組毎
  • AppSync Shcema
    • 複数 Subscriptions
      • コメント、ハート、スタンプ、ユーザ数 はそれぞれ別 Subscription
    • 受信データは配列
      • サーバ側でバッファリングできるように
  • AppSync Resolver
    • 当初DynamoDB Data sourceを使っていたがwriteがボトルネック
    • 結局 Data source type None にした
  • サーバサイドからAppSyncに書き込むことが想定されてないのでSDKなどがなく、自前で書いた(Go)

Serverlessを極めるためにDynamoDBデータモデリングを極めよう

講師: 照井 将士 さん (株式会社サーバーワークス Solution Specialist)

AWS上のServerlessアプリケーションのデータストア層として採用されることが多いDynamoDBにおけるモデル設計についてのセッションでした。 speakerdeck.com

  • DynamoDB Best Practicesを読もう
  • Partition Keyのハッシュでパーティションが分散される
    • なので、Partition Keyに連番を振ってもあまり意味がない
    • 論理的に一意であればOK
  • DynamoDB内のデータは Partition Keyで分散した中で Sort Keyで整列 しているというイメージを持つ
  • 結果整合性 って大丈夫なの?
    • RDBでもリードレプリカから読み込む場合は結果整合性なので、変わらない
  • DynamoDBの設計アプローチとRDBの設計アプローチ
    • RDB
    • DynamoDB
      • スキーマレス
      • 非正規化
      • まずアクセス(使われ方)を考えて、それに合わせたデータを作る
      • アプリケーションとデータモデルは同時に設計する
  • ACIDトランザクションが無い問題
    • ACIDとは 原子性・一貫性・独立性・永続性
    • DynamoDBの場合、非正規化して1つの実体について1つのアイテムに収める
    • 1アイテムの更新はアトミックであり原子性は保たれる
  • 非正規化してあるので読み込みツラい問題
    • CQRS (Command Query Responsibility Segregation)
    • 書き込むデータと読み込むデータは同じである必要は無い
      • 結果整合性を受け入れて非同期で読み込みデータを作る
    • Command の完了をもってQuery用のデータを作る
      • マテビュー的な
    • とはいえ、複数の実体にまたがるトランザクションはできない

その他

ライブストリーミングで以下のセッションを聴講しました。
どれも素晴らしかったですが、DynamDB 関連のセッションが特に最高でした。

Amazon DynamoDB Advanced Design Pattern

講師: 江川 大地 さん(アマゾン ウェブ サービス ジャパン株式会社 技術統括本部 ソリューションアーキテクト)

DynamoDBの設計についてのセッションでした。

www.slideshare.net

おそらく昨年の re:Inventの以下↓ のセッションが基になっているのだと思うのですが、元のセッションも素晴らしかったですし、説明の順序が改善されて日本語になった本セッションは今まで聞いたDynamoDBの説明の中で一番わかりやすいと感じました。

www.youtube.com

DynamoDB Backed なテレコムコアシステムを構築・運用してる話

講師: 安川 健太 さん(株式会社ソラコム CTO)

あのSORACOMのバックエンドでDynamoDBをどのように使っているかのセッションでした。
複数の値を一度に更新したい場合の対処法 で紹介されていた方法は初見で、直接情報をアイテムに残すことが難しければデータ(事実)を記録してあとで必要な情報が生成できるようにすればよい、と理解しました。

www.slideshare.net

マイクロサービス時代の認証と認可

講師: 都元 ダイスケ さん(クラスメソッド株式会社 事業開発部 シニアシステムアーキテクト

認証と認可とは何か、から始まってよくあるWebシステムで必要とされる認証・認可について考えるセッションでした。
後半Twitchの中継が止まってしまって聞けなかったのが残念でした…

www.slideshare.net

さいごに

時間がかぶった関係で観られなかったセッションも多かったので、動画の公開が楽しみです!

Amazon Web Services ブログで公開された資料

aws.amazon.com

aws.amazon.com

Mackerel の1分粒度メトリックデータをCSVでバックアップする

私が現在運用しているシステムではシステム・サービス監視やキャパシティ管理のツールとして Mackerel https://mackerel.io/ というSaaS型のサービスを使っています。 各サーバのCPU利用率やメモリ利用率といったホストメトリック情報はもちろん、特定のサーバには紐付かない情報、例えばサービス利用ユーザ数やお問い合わせの件数といった値もサービスメトリックとしてMackerelに投稿し、Mackerel上でグラフ化したりしきい値を設定してアラートを上げたりできるので便利です。

サーバについてはパブリッククラウド上でインスタンスがぽこぽこ入れ替わるので、ホストメトリックを永続的に保管したい要求はあまりないのですが、ユーザ数の推移といったサービス運営状況に関わるデータは Mackerelのデータ保持期間( 2018年10月13日現在では460日間) を超えた長期間分のデータを確認したい場合があるため、常にMackerelと自分たちで管理できる他のDBの両方にデータを登録し続けるか、データを登録するのはMackerelのみにして定期的にMackerelからデータをバックアップするか、といった対処が必要になります。

今回は後者の、Mackerelから定期的にメトリックデータをバックアップする方法について調べてみました。 といっても、サービスメトリックもホストメトリックもデータを取得するためのAPIが公開されていますので、それをいかに効率よく叩くかだけを考えればOKです。

mackerel.io mackerel.io

APIドキュメントを参考にパラメータを変えながらAPIを叩いていると、from と to で指定するデータ取得対象期間の長さによって取得できるメトリックデータの粒度が変わることを発見しました。

例えば from = 1538319600 (epoch秒。日本時間で2018/10/01 00:00:00) 、to = 1538362800 (日本時間で2018/10/01 12:00:00) として12時間分のデータを取得した場合は60秒間隔のメトリック値が返ってきますが、from = 1538319600 (日本時間で2018/10/01 00:00:00) 、to = 1538406000 (日本時間で2018/10/02 00:00:00) として24時間分のデータを取得した場合は300秒間隔のメトリック値(おそらく60秒間隔のメトリック値5個分の平均値) が返ってきていました。1年前から今日までの1年間分データを取得した場合は86,400秒間隔、つまり1日間隔のメトリック値が返ってきました。

そこでもう少しいろいろ試して調べてみたところ、どうもサービスメトリック、ホストメトリック共に、以下のような仕様になっているようでした。

取得できるメトリックデータの粒度(秒) 最大データ取得期間(秒) 備考
60 72,239 1,204分(≒20時間強)未満までは1分粒度のデータを返す。
300 599,999 1,204分以上 10,000分(≒7日間弱)未満では5分平均のデータを返す。
600 866,999 10,000分以上 14,450分(≒10日間強)未満では10分平均のデータを返す。
3,600 7,199,999 14,450分以上 120,000分(≒2,000時間≒12週間弱)未満では1時間平均のデータを返す。
7,200 14,399,999 120,000分以上 240,000分(≒4,000時間≒約5.5ヶ月間)未満では2時間平均のデータを返す。
14,400 20,807,999 240,000分以上 346,800分(=5,780時間≒約8ヶ月間)未満では4時間平均のデータを返す。
86,400 20,808,000~ 346,800分以上の期間のデータを要求すると1日平均のデータを返す。

サービスメトリックで記録するようなデータのうち、ユーザ数の推移などは長期期間で眺める場合は1日間隔のデータで全く問題ないのですが、もし仮に最も細かい粒度である1分間隔のメトリックデータを長期期間分保存しておかなければならなくなった場合はどうやるのが良いか、を考えてみました。
上の表で見てわかるとおり、fromからtoまでの間隔が 72,239秒以内であればAPIは1分間隔のメトリック値を返してくれるので、このfrom とto を72,239秒づつずらしながらAPIを叩くようなバッチを作れば良さそうです。
また、APIのレスポンスはJSON形式なのでそのまま非エンジニアである企画・営業系のメンバーに共有しても集計やグラフ化などを行うにあたって扱いにくいため、CSV形式で保存できるようにします。

というわけで書いてみたスクリプトがこちら。curl コマンドと jq コマンドがインストールされている必要があります。

gist.github.com

いたってシンプルに、curlAPIを叩いてそのレスポンスをjqでCSVに変換する という処理をwhile文で繰り返しているだけです。 ここではMackerel のAPI Keyや各種パラメータをコード内にべた書きにしていますが、実際は環境変数コマンドライン引数として渡せるようにしてcronで定期実行させるのが楽かと思います。

あとは注意点として、2017年12月1日以前のデータについては1分粒度のメトリックデータは取得できないようです。

mackerel.io

Ubuntu14.04にCloudMapperをインストール

同僚が社内チャットで教えてくれたCloudMapperが面白そうだったのでインストールして試してみました。

www.publickey1.jp

インストールするまで微妙にハマったのでメモを残します。

CloudMapper を動かすまで

$ sudo apt-get install autoconf automake libtool python-dev jq python-pip
  • AWS CLI のインストール
$ sudo pip install awscli
$ aws configure  
AWS Access Key ID [None]: (各自の環境に応じて)  
AWS Secret Access Key [None]: (各自の環境に応じて)   
Default region name [None]: (各自の環境に応じて)  
Default output format [None]: (各自の環境に応じて)  
  • CloudMapperのインストール
$ git clone https://github.com/duo-labs/cloudmapper.git
$ cd cloudmapper/
$ pip install -r requirements.txt
  • 後々必要になるpipモジュールのインストール
    • この後の手順でいろんなPythonスクリプトを実行するが、pipライブラリが足りなければその都度エラーで怒られるのでインストールしていく
    • 自分の環境の場合、以下の3つを入れたら最後まで進めました
$ sudo pip install boto3 pyjq netaddr
  • AWSのアカウント情報をCloudMapperの設定ファイルに書く
    • config.json.demo を config.json にコピーして自分のAWSのアカウントIDに書き変える
    • name は自由につけてOK。例えば dev とします
    • ciders のところはよくわからず。変更しなくても動作はしてるっぽい?
$ cat config.json
{  "accounts":
    [
        {"id": "xxxxxxxxxxxx", "name": "dev", "default": true}
    ],
    "cidrs":
    {
        "1.1.1.1/32": {"name": "SF Office"},
        "2.2.2.2/28": {"name": "NY Office"}
    }
}
  • AWSアカウント内の構成情報を集める
$ python cloudmapper.py gather --account-name dev
  • CloudMapper表示用にデータを整形する
$ python cloudmapper.py prepare --account dev
  • Web サーバを立ち上げて公開する
$ python cloudmapper.py serve
  • これだとローカルホストから http://127.0.0.1:8000 でならアクセスできるものの、リモートからアクセスできない。 リモートからアクセスする場合は --public オプションをつける。
$ python cloudmapper.py serve --public

結果

f:id:kmiya_bbm:20180223171914p:plain

ちゃんと情報取れてそう! 吐き出された図はそのままでは見にくいところもあるので、手でグリグリ修正するほうが良さそうです。

Amazon Cognito の SDK for JavaScript と CLI と API と、それらに対応するIAMポリシーを整理する

Cognito まわりのSDKCLIは、AWSのサービスの中でもなんだかすごくややこしい気がする。
公式ドキュメントを読み込んだところ、まとめるとたぶん下の表みたいになるはずなんだけれど、合っているか非常に自信がない。

SDK for JavaScript CLI API IAM
User Pool AWS.CognitoIdentityServiceProvider aws cognito-idp Amazon Cognito User Pools API cognito-idp:**
Federated Identities AWS.CognitoIdentity aws cognito-identity Amazon Cognito Federated Identities API cognito-identity:**
Sync AWS.CognitoSync aws cognito-sync Amazon Cognito Sync API cognito-sync:**

さらに Higher-Level Client SDKs としてAmazon Cognito SDK for JavaScript amazon-cognito-identity-js というSDKがあり、SDKs for Amazon Cognito User Pool App Integration and Federation ?として Amazon Cognito Auth SDK for JavaScript amazon-cognito-auth-js というのがある模様。

docs.aws.amazon.com

きびしい・・・。

AWS re:Invent2017 の会場でソリューションアーキテクト - アソシエイト を受験して合格した

年末年始のバタバタにかまけてすっかりブログを書く機を逸してしまいましたが、昨年、念願だったAWS re:Invent に初めて参加しました。 イベント自体からも他の参加者からもいろんな刺激を受けまくって、とても充実した一週間でした。

あまりにも刺激を受けすぎて、当初全く受験する予定のなかったAWS認定試験を、その場の勢いでre:Invent最終日に滑り込みで受験したのでその顛末を記そうと思います。
なお、試験対策的な情報は一切ありません。実際受験する流れはどんな感じなのかについての単なる自分用の記録ですが、もしもAWS認定試験に興味がある方のお役に立つことがあれば望外の喜びです。

受験のきっかけ

re:Invent最終日の前日(11/30)、前々から興味はあったAWSの認定試験を受けてみようと急に決めました。そう思い立った要因はいくつかあったのですが、AWS re:Inventの会期中ずっとAWSの情報漬けになっていたので、それらのアウトプットとして何か形に残したくなったのと、道中で知り合って滞在中ずっと仲良く付き合ってくれた日本からの参加者の方の一人がソリューションアーキテクト のプロフェッショナルを持ってらしたのに刺激を受けたのが大きいです。ラスベガスとre:Inventの空気感で受験費用がなんか安いと錯覚できたのもあったかもしれません。いや、確実にありました。勢いは大事だなと思います。

受験までの流れ

で、いきなり Mirage の試験会場に行って「今から試験受けられる?」と聞いてみましたが、事前に登録が必要なことがわかりました。そのへんは通常の認定試験のフローと何ら変わらないようです。

webからAWS認定アカウントの作成と試験予約を行うことができます。 AWS認定アカウントのマイページにある「新しい試験の予約」というボタンから試験の会場と日程を決める画面に遷移します。 普通なら、ここで自宅から近い会場を選択すれば良いわけですが、今回はre:Inventの会場で受験するため The Mirageを探す必要があります。

The Mirageの住所は以下の通り。

3400 S Las Vegas Blvd
Las Vegas, NV 89109

個人的には試験そのものよりもこの事前登録のほうが難しかったと感じました。

当日のうちに受験したかったのですが、あいにくその日の日程は埋まっていたため翌日12/1の午前中の日程に申し込みました。

受験当日

試験開始時間の30分前には受付に来るよう言われていたのですが、到着するとすでに受付には結構な行列ができていて、なるほど30分の余裕は必要かなと思いました。受付では写真付きの身分証明書を2つ提示すること求められますが、re:Inventの会場では re:Inventの参加証 + パスポート でOKでした。無事に受付が済むと、番号が書かれた紙のカードを貰えます。これが試験会場で着席する席の番号となっています。 会場が乾燥しているからか、受付では自由にもらえるトローチが用意されていました。

f:id:kmiya_bbm:20180112125817j:plain 受け付け・待合場所の様子

時間になると待合室に試験監督の方が来て受験者に注意事項をアナウンスします。それが終わると、別室の試験会場に移動します。自分が受験した回の受験者は30人ほどはいたでしょうか。結構な人数がいた気がします。

スマホなどは電源を切らなければいけないので写真は撮ってないのですが、試験会場はかなり広い部屋にデスクトップPCが置かれた長机が何列かズラーっと並んでおり、自分の番号の席を自分で探します。隣の席との間につい立て等はなく、本当に長机にPCが並べて置いてあるだけ、という感じでした。

リュックなどの大きな荷物は壁際の棚に、ウェストポーチのような小さな荷物は自席の椅子の下におきます。バッグを持っていない場合は、受付で透明なビニール袋がもらえるのでそこにスマホや財布を入れて自席の椅子の下に置きます。

最初、自席のPCで、試験を受けるためにAWS認定アカウントにログインして間違いがないか確認するよう指示が出るのですが、その後は試験開始の合図等はなく、各々試験を始めていました。これには最初ちょっと戸惑ったのですが、試験時間が異なるアソシエイトレベルとプロフェッショナルレベルの受験者が同じ試験会場にいたっぽいことと、試験を開始したところからPCの画面上に残りの試験時間が表示される形式になっていたことから、各々勝手に試験を始めてよかったのだろうと安心しました。

試験の内容については公式の情報や参考書、いろんな方のブログに載っているので割愛しますが、自分の場合はEBSについての知識があやふやで勉強し直す必要を感じました。

全ての問題の回答と確認が終わったら、PC上で終了ボタンを押して合否の結果を確認します。そして挙手して試験監督さんに退出する旨を申告します。 合否はすぐに表示されるのですが、合格していても試験会場なので声に出して大喜びすることが出来ず、試験会場を退出するまでひとりニヤニヤしていました。 試験会場を退出したら、受付に戻って合格した旨を伝えます。受付の人たちがハイテンションで祝福してくれたのでとても嬉しかったです。その場でTシャツがもらえるので、サイズを申告して受け取ります。

f:id:kmiya_bbm:20180112131537j:plain
かわいいドット絵が描かれたTシャツ。やったー

合格すると

Tシャツやステッカーなどの記念品がもらえるほか、会場内に設置されている認定者ラウンジに入ることができるようになります。 認定者ラウンジはAWS Summit Tokyoなどでも設置されていますが、どの種類・レベルでもいいので1つでもAWS認定を持っていれば入ることができます。 中では電源や軽食、ドリンクなどが用意されている他、認定者同士で交流しやすくするためか休憩スペースやゲームなども設置されています。
f:id:kmiya_bbm:20180112221004j:plain f:id:kmiya_bbm:20180112221048j:plain

随感

AWS re:InventというAWSの各種イベントの中でも最も熱量が高いであろう空気感に当てられて受験しましたが、無事に合格できてよかったです。

IT系の資格というのはなかなかとらえ方が難しく、資格を持っていれば実力があるというわけでもないですし、実力はめちゃくちゃあっても資格の類を一切取ってない人もいます。自分が勤めている会社は製造業で、IT企業や、ましてSIerの会社ではないので、IT系の資格は受験料も自腹ですし、合格しても一時金や昇給などの実利はありません。
それでも自分はIT系の資格試験に挑戦すること、合格することには一定の意義があると思っています。

  • 業務 +αの勉強をする習慣をつけることができる
  • 業務では触れない分野の知識も試験のために勉強することがあり、見識が広がる
  • 合格すると、一定の知識量や実力を必要とする資格に合格できる程度の「学習力があること」を対外的にも自分自身にも示せる

つまり、継続して学ぶ習慣をつけるきっかけとして資格試験というのはいいモチベーションになるのではないかと考えています。

今回、AWSの認定試験を受験すること自体は突発的に決めたことでしたが、AWSなどのクラウドサービスについて調べたり学んだりすることはずっと続けていた(AWSは東京リージョンができる前から追っていた)ことであり、アソシエイトレベルではありますが今回ソリューションアーキテクトの認定に合格できたのは継続的な学習の成果だと思っているのでとても嬉しかったです。

まとめ

AWS re:Invent2017の会場でAWS認定試験を受験したときの流れをまとめました。
AWSの認定資格は初級レベルでもなんでも1つ持っていれば認定者ラウンジに入ることができたり記念品がもらえたりするので、普段AWSを利用している方は認定試験を受けてみるのもよいのではないでしょうか。

AWS Lambdaを1分間隔より短い間隔で定期実行させる

やりたいこと

タイトルの通りです。

AWS LambdaのトリガとしてCloudWatch Events Schedule を指定することで、Lambdaを定期実行することができます。

docs.aws.amazon.com

しかし、Unix系OSのCronと同様、1分間隔より短い間隔を指定することはできません。

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

現状 CloudWatch Events Schedule によって1分間隔で起動させているLambdaを、10秒間隔、15秒間隔など秒単位で定期実行したい要件があり、実装方法を検討したのでその結果を残します。

Lambdaを定期的に起動するLambdaを導入してみた

1分毎に起動して、指定したLambdaを指定した間隔で起動し、1分後に終了するLambdaを作れば良いのでは、という案を思いつきました。 10秒間隔で Lambda を定期実行させる Lambda をNode.js v6.10 で素朴に作ってみました。

gist.github.com

funcName に1分間隔より短い間隔で定期実行させたいLambdaの名前を指定します。 このLambda を CloudWatch Events Schedule で1分間隔で定期実行させることで、このソースコードの例では10秒間隔で指定したLambdaを定期実行することができます。

注意点

  • funcName に指定した Lambda (10秒間隔で実行したいLambda)のトリガとしてCloudWatch Events Scheduleの定期実行設定が残っていると多重起動してしまうので、そちらのトリガは削除しておかないといけません
  • この「10秒間隔で Lambda を定期実行させる Lambda」に割り当てるIAMロールへは、InvokeするLambda(10秒間隔で実行したいLambda)に対して lambda:InvokeFunction Actionを実行できる権限を付与しておく必要があります
  • この「10秒間隔で Lambda を定期実行させる Lambda」のタイムアウト値は 60秒以上を設定する必要があります

...あれ?

できたはできたけど...

注意点の最後に挙げた項目が Lambda の、というかイベント駆動で動くFaaSの旨味を思いっきり消してしまっている気がします。 要するにこの「10秒間隔で Lambda を定期実行させる Lambda」は1分間起動し続けていなければならず、それもうEC2でも良くね?という気持ちが芽生えてきます。

実際にLambdaとEC2でそれぞれ1日中稼働させた場合のコストを比較すると、

Lambdaで運用

  • メモリ割当 128MB、1回あたりの課金時間を 61,000ms(61秒)とする
    • 実際には60,600ms くらいで終わることも多いのですが、ここでは多めに見積もります
  • 1日の実行回数は 1440回
    • 60(min) × 24(h)
    • 毎月最初の 1,000,000 回は無料、かつ、それ以上実行しても $0.0000002 /回 という安価さなので計算から除外する

料金 - AWS Lambda(サーバーレスでコードを実行)|AWS

$0.000000208(/100 ミリ秒) × 610(100ミリ秒/回) × 1440(回) =$0.1827072

EC2で運用

  • オンデマンド料金で算出する
  • インスタンスタイプは一番小さい t2.nano、台数は1台とする

オンデマンドインスタンスの料金 - Amazon EC2 (仮想サーバー) | AWS

  • 東京リージョンの場合

$0.0076(/1h) × 24(h) = $0.1824

$ 0.0058(/1h) × 24(h) = $0.1392

結論

費用面だけ見ると、EC2(t2.nano)を常時起動していても対して変わらない、むしろ安い場合もある。という結果になりました。 しかし、EC2上で秒単位で起動するworkerを動かす場合と比較して、Lambdaで実行するのには以下のメリットがありそうです。

  • 実装が簡単
  • コケても次回(1分後)の実行に影響が出ないので一度軌道に乗れば運用は楽
  • そもそもLambdaの実行のためにEC2を動かすのはなんかスッキリしない

逆に、何らかの用途ですでに常時起動しているEC2がいる場合はコストを考えて秒単位で起動するworkerを相乗りするのも手ですね。

・・・ひどく当たり前の結論になってしまいました。
秒単位でLambdaを定期実行したいときって、どうするのがスマートなのでしょうね??

Mackerelの公式プラグインをAWS Lambdaで実行してAmazon RDS for MySQL を監視する

Mackerelの公式プラグイン集や公式チェックプラグイン集は、各種ミドルウェアの詳細監視ができたり、AWS Integrationを使わなくてもRDSやELBなどのマネージドサービスのメトリック情報を取得することができたりと、大変便利なものです。

github.com

このプラグインAWSのEC2など mackerel-agentがインストールできる環境からは簡単に使うことができるのですが、例えばAWS上に Web-アプリケーション-DB の3層アーキテクチャを構成している場合に、EC2がAutoScaling対象のWebサーバやアプリケーションサーバしかないことがあり、DB(RDS)を監視するのにこのプラグインをどのEC2から使うか、少々悩ましいことがあります。

  • AutoScaling対象のEC2全てからプラグインを実行する場合
    • チェックプラグインの場合、RDSに異常が発生するとAutoScaling対象のEC2の台数分(重複して)アラートが上がってしまう
  • AutoScaling対象のEC2とは別に、RDS監視用のEC2を用意する場合
    • 監視用EC2に障害が発生するとRDSの監視が止まってしまうので、冗長構成にするなど監視用EC2の可用性を高める工夫をしなければならない
    • 監視用EC2自体の監視も必要になるため、Mackerel監視対象のホスト数が増えてしまう = コストが増えてしまう ことになる

そこで、この便利なプラグインAWS Lambdaから定期的に実行できれば、安く*1、アラートも重複せず、安定してRDSなどのマネージドサービスを監視できるのでは、と考えました。

この記事では、MySQLのメトリックを取得する mackerel-plugin-mysql を使ってAmazon RDS for MySQL を監視する例をまとめます。

事前準備

AWSやMackerelのアカウントは取得済みとします。
またAWS上にすでにシステムは稼働しており、監視対象の RDS for MySQLの構築やその他セキュリティグループ等の設定は済んでいるものとします。

公式プラグインのバイナリを用意する

AWS Lambdaで実行できる形式のバイナリファイルを作成するため、一時的にEC2を立ち上げます。
まずはAWS公式サイトの情報を元に、AWS Lambdaの実行基盤となっているAmazon LinuxのAMIイメージを探します。 2017/10/15 時点だと amzn-ami-hvm-2017.03.1.20170812-x86_64-gp2 です。

docs.aws.amazon.com

当該AMIを使ってEC2インスタンスを起動します。

  • インスタンスタイプは t2.micro で十分です
  • VPCやネットワーク、セキュリティグループについては、監視対象のRDSと通信できるようになっている必要があります

起動したEC2にSSHでログインし、mackerel-agent, 公式プラグイン集 mackerel-agent-plugins をインストールします。

$ curl -fsSL https://mackerel.io/file/script/amznlinux/setup-all-yum.sh | MACKEREL_APIKEY='<YOUR API KEY>' sh
$ sudo yum install mackerel-agent-plugins

Mackerelのプラグインが正しくインストールされたかを確認するため、手動でpluginのコマンドを実行してみます。
-host オプションで指定するRDSのエンドポイントはAWSマネジメントコンソールのRDSのメニューから確認してください。

$ mackerel-plugin-mysql -host=sample-db.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -username=<USER_NAME> -password=<PASSWORD>

以下のように、{metric name}\t{metric value}\t{epoch seconds} (\t はタブ文字) の形式でたくさんの情報が標準出力に表示されれば成功です。

mysql.innodb_buffer_pool.pool_size      38208.000000    1507986274
mysql.innodb_buffer_pool.database_pages 2717.000000     1507986274
mysql.innodb_buffer_pool.free_pages     35484.000000    1507986274
mysql.innodb_buffer_pool.modified_pages 0.000000        1507986274
mysql.innodb_row_lock_waits.Innodb_row_lock_waits       0.000000        1507986274
mysql.innodb_adaptive_hash_index.hash_index_cells_total 1238989.000000  1507986274
(中略)
mysql.innodb_semaphores.spin_waits      0.000000        1507986274
mysql.innodb_semaphores.spin_rounds     0.000000        1507986274
mysql.innodb_semaphores.os_waits        0.000000        1507986274

MackerelにRDS用のホストを登録し、メトリックを投稿する

先ほど立ち上げたAmazonLinuxのEC2に、Mackerel の CLIツールである mkr コマンドをインストールします。

$ sudo yum install mkr

Mackerelに監視対象のRDSをホストとして登録します。
以下の例ではホスト名をtest-RDS、Mackerel上のロール名を TEST:DB としてホストを作成しています。

$ mkr create test-RDS -R TEST:DB
   created SAMPLE12345

成功するとHostIDが表示されるので、これを控えておきます。 今回だと SAMPLE12345 です(実際には11文字のランダム文字列)。
Mackerelの画面でもホストとサービス・ロールが登録されていることが確認できます。

f:id:kmiya_bbm:20171014223900p:plain

続いて今登録したホストのカスタムメトリックとしてRDS上のMySQLのメトリック情報を投稿します。 先ほど動作確認に使ったコマンドの結果をパイプで mkr throw に渡してMackerelに投稿します。

$ mackerel-plugin-mysql -host=sample-db.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -username=<USER_NAME> -password=<PASSWORD> | mkr throw --host SAMPLE12345

以下のような結果が標準出力に表示されれば成功です。

thrown SAMPLE12345 'custom.mysql.join.Select_full_join      0.000000        1507987901'
thrown SAMPLE12345 'custom.mysql.join.Select_full_range_join        0.000000        1507987901                                           '
thrown SAMPLE12345 'custom.mysql.join.Select_range  0.000000        1507987901'
thrown SAMPLE12345 'custom.mysql.join.Select_range_check    0.000000        1507987901'
(中略)
thrown SAMPLE12345 'custom.mysql.innodb_buffer_pool_read.read_evicted       0.000000        15                                           07987901'
thrown SAMPLE12345 'custom.mysql.innodb_buffer_pool_read.read_random_ahead  0.000000        15                                          07987901'
thrown SAMPLE12345 'custom.mysql.innodb_checkpoint_age.uncheckpointed_bytes 0.000000        15                                          07987901'

Mackerel上で見てもメトリックが投稿されグラフが作成されていることがわかります。

f:id:kmiya_bbm:20171014223725p:plain

ここまでの手順で作成したプラグインや mkrコマンドのバイナリファイルを、普段お使いの開発マシンなどにコピーしておきます。
このAmazonLinux EC2についてはLambda上で実行できる形式のバイナリファイルを作成するのが目的だったので、もう停止・削除してしまって構いません。

AWS Lambdaから実行できるようにする

今までの手順で作成した (Lambdaの実行基盤であるAmazonLinux 上でインストールして生成された) mackerel-plugin-mysql と mkr のバイナリファイルをLambdaのコードと一緒に固めてアップロードし、ハンドラ関数の中でそのバイナリファイルを実行するようなLambdaファンクションを作ります。それをCloudWatch Eventsで定期スケジュール実行すればよいことになります。

今回はCloudWatch EventsやIAM Role等の周辺設定を自動で行うため Serverless Framework (v1.23.0)を使って Node.js 6.10 のLambdaファンクションを実装しました。 Serverless Framework のインストール手順やサービス作成手順等は公式サイトやネット上に情報がありますので割愛します。

(任意のディレクトリ)/
 ├ .gitignore
 ├ bin/
 │ ├ mackerel-plugin-mysql
 │ └ mkr
 ├ handler.js
 ├ package.json
 └ serverless.yml

  • serverless.yml
service: sls-postCustomMetricToMackerel # 任意のサービス名

provider:
  name: aws
  runtime: nodejs6.10
  region: ap-northeast-1 # 監視対象のRDSがあるリージョン

functions:
  mackerel:
    handler: handler.postCustomMetricToMackerel
    name: ${self:service}
    events:
      - schedule: rate(1 minute)  # CloudWatch Eventsで1分毎にスケジュール実行
    environment:
      DBHOST: sample-db.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com  # 監視対象のRDSのエンドポイント
      DBUSER: sampleuser  # 監視対象のRDSの接続ユーザ名
      DBPASS: S@mple      # 接続ユーザのパスワード
      MACKEREL_HOSTID: SAMPLE12345 # 監視対象のRDSのMackerel上のHostID
      MACKEREL_APIKEY: # MackerelのAPI KEY
    vpc:
      securityGroupIds:
        - sg-xxxxxxxx      # 監視対象のRDSにMySQL接続できるセキュリティグループを指定
      subnetIds:
        - subnet-yyyyyyyy  # 監視対象のRDSにMySQL接続できるサブネットを指定
        - subnet-zzzzzzzz  # 監視対象のRDSにMySQL接続できるサブネットを指定

簡単のため、DBの認証情報をそのまま環境変数に渡していますが、実運用上はKMSなどで暗号化して渡し、Lambdaの中で復号して使うのが良いでしょう。

  • handler.js
'use strict';

const exec = require('child_process').exec;

const dbhost = process.env.DBHOST;
const dbuser = process.env.DBUSER;
const dbpass = process.env.DBPASS;
const mackerelhostid = process.env.MACKEREL_HOSTID;
const mackerelApi = process.env.MACKEREL_APIKEY;
const basedir = process.env.LAMBDA_TASK_ROOT;

const cmd = `${basedir}/bin/mackerel-plugin-mysql -host=${dbhost}
               -username=${dbuser} -password=${dbpass}
             | MACKEREL_APIKEY=${mackerelApi}
               ${basedir}/bin/mkr throw --host ${mackerelhostid}`;

module.exports.postCustomMetricToMackerel = (event, context, callback) => {
  let child =  exec(cmd, function(err, stdout, stderr){
    if (!err) {
      console.log('standard out: ' + stdout);
      console.log('standard error: ' + stderr);
      callback(null, 'Success!');
    } else {
      console.log("error code: " + err.code + "err: " + err);
      callback(err);
    }
  });

};

sls deploy コマンドでデプロイすると、LambdaファンクションとそのトリガとなるCloudWatch Events、Lambdaファンクションに割り当てるIAM Roleが作成されます。 AWS Lambdaのコンソールからテスト実行して成功すれば、あとは放っておくだけで1分毎に RDS for MySQL のメトリック情報がMackerelに投稿されます。

f:id:kmiya_bbm:20171015213920p:plain

まとめ

Mackerelの公式プラグインAWS Lambdaで定期実行する仕組みを試作しました。これにより、監視専用のEC2インスタンスを立ち上げることなくRDSなどのマネージドサービスの監視を行うことができました。
ただし、実運用に投入する際はCloudWatch AlarmなどでこのLambdaファンクションが正常に実行されているかなどを監視する必要があります。

*1:AWS Integrationを使わないので、MackerelのFreeプランでも利用できます