SwaggerのAPI定義をRuby DSLで書いてAPI Gatewayにデプロイできる「rapis」というgemを作った
背景
API Gatewayはとにかく設定が面倒である。Serverlessの概念はシステムをシンプルに保てるとても素晴らしいものだが、それを実現するための設定が複雑になって、運用に支障が出たりするのは厳しい。*1
「柔軟なリソース定義を担保しようと思ったらまあ仕方ないよね」みたいな気持ちもあるが、やっぱり面倒なものは面倒だ。
便利だけど、1リソースでモックのレスポンス返すだけのAPI定義で50行超か・・・ / “AWS CloudFormation が Amazon API Gateway をサポートしたので使ってみた | Developers.IO” https://t.co/vgKAk7BVHY
— Masashi Terui (@marcy_terui) 2016年5月10日
Terraformですらこの記述量なのか。。。 / “TerraformでAPI Gatewway - @ijin” https://t.co/KPf9jV4wzl
— Masashi Terui (@marcy_terui) 2016年5月2日
Swaggerですら面倒くさい。1APIにつき3行くらいで記述したい。
— Masashi Terui (@marcy_terui) 2016年5月2日
俺達(俺)は書いたコードをサクッと上げてサクッとAPI公開したいだけなんだ!!1
書いたコードをサクッとLambdaで実行出来るようにするツールはすでにある。
問題はAPI Gatewayの方。現状でAPI定義をする上で一番マシだと思えるのがSwaggerのインポートによる方法だが、それでも、x-amazon-apigateway-integration
みたいなAPI Gatewayの独自要素*2に色々突っ込む必要があったりして、まだまだ十分とはいえないし、冗長な表現も多い。
先人の知恵を借りてみる
同じように、非常に生のJSONで扱うのがツラい某CloudFormation
というものがあるが、これをRuby DSL*3でかけるようにすることで劇的(当社比)に見通しが良くなり、冗長な表現を避けることができるようになるツールとして、kumogata
がある。ただ変換を行うだけではなく、実際にデプロイを行ったりするための運用に便利な機能も付いていて、最近もv2になってChange Sets(プレビュー的な機能)に対応したりプラグイン機構を導入したりして進化してる。本当にいつもお世話になってます。
じゃあ、Swagger定義も同じようにRuby DSL化すれば楽になるのでは?
というのが今回の趣旨。併せて、運用に便利なdiffを取る機能や定義のデプロイ等も含めてツール化してみた。
使い方
とりあえずインストールはgemなのでこれです。
gem install rapis
詳しくはREADMEを読んでいただければと思いますが、ざっくり主なコマンドの解説だけ。
API Gatewayの仕様上の注意事項としては、Swagger定義のインポートはAPIのベースとなる設定に対して行うが、実際にAPIとして公開されるステージにデプロイ(反映)する作業は別のステップとなっており、エクスポートについてはベースの定義を出力することはできず、デプロイ済みのステージから抜くことしかできないということ(デプロイはまあ良いとしても、大本の設定は抜けるようにしてほしい。。。)*4
- API作成
rapis create -n <API名>
- APIとそれらが持つステージを一覧表示
rapis list
- 既存API定義をエクスポート
rapis export -r <APIのID> -s <Stage名>
rapis diff -r <APIのID> -s <Stage名>
rapis apply -r <APIのID>
rapis deploy -r <APIのID> -s <Stage名>
記述について
今のところ、機械的にRuby DSLに置き換えるとシンタックスエラーになるような部分以外は特に特別な記述に置き換えるようなことはしていないが、これから使っていく中で汎用的に使えるような省略表現やメソッドなんかを入れていくことで、もっと楽にかけるようにしていきたい。目指せ1APIあたり3行!
ちなみ現状(2016-06-02)ではにこれが
{ "swagger": "2.0", "info": { "version": "2016-05-27T17:07:04Z", "title": "PetStore" }, "host": "p0dvujrb13.execute-api.ap-northeast-1.amazonaws.com", "basePath": "/test", "schemes": [ "https" ], "paths": { "/": { "get": { "consumes": [ "application/json" ], "produces": [ "text/html" ], "responses": { "200": { "description": "200 response", "headers": { "Content-Type": { "type": "string" } } } }, "x-amazon-apigateway-integration": { "responses": { "default": { "statusCode": "200", "responseParameters": { "method.response.header.Content-Type": "'text/html'" }, "responseTemplates": { "text/html": "<html></html>" } } }, "requestTemplates": { "application/json": "{\"statusCode\": 200}" }, "passthroughBehavior": "when_no_match", "type": "mock" } } } }, "definitions": { "Empty": { "type": "object" } } }
こんな感じになる
rest_api do swagger "2.0" info do version "2016-05-27T17:07:04Z" title "PetStore" end host "p0dvujrb13.execute-api.ap-northeast-1.amazonaws.com" basePath "/test" schemes ["https"] paths do path "/" do get do consumes ["application/json"] produces ["text/html"] responses do code 200 do description "200 response" headers( {"Content-Type"=>{"type"=>"string"}}) end end amazon_apigateway_integration do responses do default do statusCode 200 responseParameters( {"method.response.header.Content-Type"=>"'text/html'"}) responseTemplates( {"text/html"=> "<html></html>"}) end end requestTemplates( {"application/json"=>"{\"statusCode\": 200}"}) passthroughBehavior "when_no_match" type "mock" end end end end definitions do Empty do type "object" end end end
実装について
基本的にはAWS APIをゴニョゴニョしているという形なんですが、一番面倒そうなAPI Gateway上ではJSONとして扱われるSwagger定義をRuby DSLと相互変換するのは、kumogata
を含め、AWS等の設定をコード化するCodenize.toolsの作者であるid:winebarrelさんが公開しているdslh
というgemを使ってます。
ということで、偉大な先人へ感謝をしつつ締めたいと思います。よろしくお願いします。
*1:普段、こんなことを言ったりしてるけど、これはServerless自体を否定してるんじゃなくて「サーバのお守りをしたくないだけならPaaSで良いんじゃないの?Serverlessはそこがコアじゃないよね?」って意味である
*2:参考→ Swagger に対する API Gateway 拡張 - Amazon API Gateway
*3:他のフォーマットもサポートしてる
*4:そもそもAPI Gatewayのデプロイの概念がよく分からんという方はコチラを→Amazon API Gateway での API のデプロイ - Amazon API Gateway
LamveryにSwaggerベースのちょっとリッチな機能付きAPI Gateway integrationを追加しました
経緯
API Gatewayの"x-amazon-apigateway-integration"っていう独自要素に色々突っ込んでるSwagger記述サンプルを見て複雑な気持ちになってる
— Masashi Terui (@marcy_terui) April 11, 2016
書いたコードをサクッと上げてサクッとWebから叩ける用にしたいだけなのに何故こんなにJSONを書かないといけないのか
— Masashi Terui (@marcy_terui) April 11, 2016
ということでサクッとAPIが定義できるようにしました。
ここで説明しないインストール方法や使い方の詳しい情報はGitHubのREADMEやQiitaの記事でご確認ください。
使い方(コマンド)
lamvery api [-d] [-n] [-r] [-s <stage-name>] [-w]
-d
は恒例のDry run!!-n
が後述の自動オプション付加の無効化-r
で削除-s
はAPI Gatewayで言うステージ(dev,prod環境使い分けるとかに使う)-w
で新規作成時に設定ファイルにAPIを識別する番号を保存(更新する時に指定しなくて良いようにする)
設定
こんな感じで設定を書きます。
api_id: myipugal74 stage: dev cors: origin: '*' methods: - GET - OPTION headers: - Content-Type - X-Amz-Date - Authorization - X-Api-Key configuration: swagger: '2.0' info: title: Sample API schemes: - https paths: /: get: produces: - application/json parameters: - name: sample in: query required: false type: string responses: '200': description: 200 response schema: $ref: '#/definitions/Sample' definitions: Sample: type: object
ちなみにこれとほぼ同じ雛形は以下のコマンドで生成できます。
lamvery init
で、本来ならこれをAPI Gateway
でLambda
backendによって動かすためには x-amazon-apigateway-integration
っていう要素に色々突っ込まないといけないわけですが、その辺は同じくLamvery
でデプロイしたFunctionに向くように自動でよしなにやってくれるという感じです。
差分表示
こんな感じでDiffっぽくSwagger定義の差分が見れます。Dry runにすれば事前に確認だけすることが可能。
最後に
これぐらいサクッと書いてサクッとAPI公開できると「ああ、サーバレスっていいなあ」って思えそうな感じ。
ただ、認証の定義とかは未対応だし、自動オプション付加のやり方とかもうちょっとスマートに出来ないか悩み中で、もしアイデアあればいただけると嬉しいです。
-n
(x-amazon-apigateway-integration
の自動付加をしないオプション)をつければ単純に差分表示&Dry run対応のSwagger importerとしても使えるので、良かったら使ってみてご意見ください。
明日、ぺちかん北海道なのに俺、何やってんだ。。。
各社のサービスから見えるServerlessの本質とは何か
前置き
ポエム系です。以下は私の見解ですが、異論は大いに認めます。
あと、エイプリルフールは全く関係ありません。ごめんなさい。
まず、本日2016.04.01、MicrosoftがAzure Functions
というサービスを発表しました。
これで、AWS Lambda
・GCPのCloud Functions
・Azure Functions
という、三大(?)クラウドの所謂Serverless
と呼ばれるジャンルのサービスが出揃ったわけです。
AWS Lambda (サーバーレスでコードを実行・自動管理) | AWS
Google Cloud Functions Documentation | Cloud Functions | Google Cloud Platform
ドキュメントを読んで分かったAzure Functionsの実体
とりあえず、気になるサービスが出てきたらドキュメントを読んでみるようにしているのですが、そこでAzure Functions
がどんなものなのかなんとなく窺い知ることができました。
ランタイムとしてはC#
, Node.js
, Python
, F#
, PHP
, batch
, bash
, Java
等をサポートするようです。
「おお、多いなスゲー」とか思ったんですが、読み進めてみるとAzureのPaaS系サービスであるApp Service
の一機能であるWebJobs
と関連しているような記述が出てきます。
バックグラウンドジョブを行うWebJobs
にスケジュール実行だけではないStorage
やQueue
からのイベント実行を追加したようなものがAzure Functions
の今のところの実体のようです。
ちなみにCloud Functions
は今のところ基盤としてContainer Engine
を使用しており、コンテナクラスタからオンデマンドで実行環境(コンテナ)を割り当てていくような実装のようです。今はGKEインスタンスがユーザから見えちゃってるんですが、これは無くなってユーザは意識せずに使えるようになる予定のこと。
Lambda
は中身が全然見えないのですが、上記のCloud Functions
完成形って感じの雰囲気ですよね。
さて、ここで考えてみたいのは以下です。
PaaSとServerlessって何が違うの?
よく言われる、ユーザが管理しなくて良いマネージドサービスを使って運用フリーなシステムを作るっていうのがありますが、
それって(狭義の)PaaSでも一緒じゃね?*1
っていう話なんですね。
ここで注目したいのが、Azureが今までPaaSとして提供してきたものにEvent Drivenな要素を足してServerlessなサービスと銘打って出してきたということです。
つまり、"PaaS(狭義) + Event Driven = Serverless"であるという一つの定義が見いだせるわけです。
あとは、課金体系ですね。PaaSは基本的にアイドル状態でも課金が発生しますが、Serverless系のサービスは真に動いている分しか課金が発生しません。
Serverlessの本質とは
これは私の見解なので異論は大いに認めます(2回目)
まず、最近話題のServerless
(Architecture)と呼ばれているものについて、ずっと違和感を感じていました。
「API Gateway
+ Lambda
でAPIシステム作るのがCoolだ」みたいな話ですね。
こんなことを言うとたぶん誰かに怒られる気がするのですが、
いや、普通にPaaS使った方が良いんじゃない?
っていう。全部がそうだとは言いませんが、けっこうそういうケースが多いんじゃないかなと。
扱いやすさを求めるならHeroku
でRails
とか、性能を求めるならApp Engine
でGolang
とかで良いと思うんですよね。
最近なら、AWSにこだわりたいならAWS上でのライフサイクルを自動化してPaaSのように使わせてくれるMobingi
という手もあります。
https://mobingi.co.jp/mobingi.co.jp
ただ単に「インフラ運用したくない!!1」ってだけなら、そっちの方が管理も楽だし制約も少ないので良いと思うんです。
(管理が大変だからこういうツールを作りたくなるわけで)
じゃあ、何が本質でどんな場面でServerless
系のサービスが良いのかっていうと、そこで出てくるのがやっぱりEvent Driven
じゃないかと。
その中でAPI Gateway
がどんな存在になるかというと、Lambda
に対してWeb hook
だったりとか、ユーザの行動イベントをHTTPリクエストとして別システムから伝えるためのインターフェースだと思うわけです。
AWSはその辺り別サービスにして徹底的に疎結合になってるのがさすがって感じですね。だからこそ色んな使い方ができているというのはあると思います。(他はHTTPが単にトリガーの一つの扱いのはず)
クラウドのサービスとサービスの間をイベント連携する、あるいは他システムやユーザの行動を絡めたりもして、システムをイベント駆動で作り上げていく、それがServerlessの本質というか最大のメリットなのではないかと。
そういう風に考えると、多様なイベントに対応し、これからもどんどん増やしていくであろうAWS Lambda
がやっぱり一日の長があるといった印象です。
つまり何がいいたいかっていうと
っていうか、Lambdaのマイクロサービスとかサーバレスの話はもういいから、イベントドリブンコンピューティングの話しようぜ
— Masashi Terui (@marcy_terui) March 23, 2016
あと、もう一つ
App Engineを昔のCPU時間課金に戻して、Event Driven要素足せばそれだけで最強のServerless実行環境になるので、Google先生におかれましては是非ご検討のほどよろしくお願いします
— Masashi Terui (@marcy_terui) April 1, 2016
*1:広義のPaaSはIaaSの上に乗るマネージドサービス全般、狭義のPaaSはHeroku,App Engine等のアプリケーション実行環境を指すと思ってます
Lamveryが速攻でLambdaのVPCサポートに対応したぞ!
本題
念願の(?)LambdaのVPCサポートが来ましたね!
これはもうすぐにでも使いたいやつなので、速攻で対応しました。
v0.12.0~対応済みとなっております。
他にも随時機能が増えたりしてるので、以下の記事やREADMEをご確認ください。
設定ファイルはこんな感じ
vpc_config
以下が該当部分です。
今後、SecurityGroupとかIDじゃなくて名前で解決できるようにしたい。
profile: private region: us-east-1 versioning: true default_alias: test configuration: name: lamvery-test runtime: python2.7 role: {{ env['AWS_LAMBDA_ROLE'] }} handler: lambda_function.lambda_handler description: This is sample lambda function. timeout: 10 memory_size: 128 vpc_config: subnets: - subnet-cadf2993 security_groups: - sg-4d095028
補足
VPC内でのLambdaの起動(や削除等も含めた諸々)にはENIに関する権限が必要になります。
以下の様なIAM Role Policyの設定が必要です。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "ec2:DescribeNetworkInterfaces", "ec2:CreateNetworkInterface", "ec2:DeleteNetworkInterface", "ec2:AttachNetworkInterface", "ec2:DetachNetworkInterface" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "kms:Decrypt" ], "Resource": [ "arn:aws:kms:<region>:<account-number>:key/<key-id>" ] } ] }
最速だろコレは!
Lambda(Python)のスケジュール実行をコード(YAML)化してコマンド一発で設定!LamveryのCloudWatch Events対応とその他アップデートまとめ。
以前、QiitaやCloud RoadshowのLTで、AWS Lambda for Pythonのデプロイを便利にする拙作のツール(OSS)をご紹介しました。
その後もちょっとずつ改善を重ね、以下の様な機能追加・変更を行いました。
- 差分表示を整えた
- Lambdaの設定だけ変更するコマンドを追加 *1
- デプロイパッケージ(zip)の容量削減
- アーカイブ*2にライブラリを含まないオプションの追加
- リージョン毎にLambdaの容量に制限があるので合計容量も差分表示するようにした(下記参照)
下2つは @ijin さんにインスパイアされた機能です。ありがとうございます。
そして今回、一つ目玉的な機能として、CloudWatch Events対応をリリースしました。
これは、主な用途としては兼ねてよりAmazonらしからぬコンソールの画面先行でAPI待ちだった Scheduled Events
に対応するものです。
つまり、Lambda functionのスケジュール実行がコマンド一つで設定できるようになります。
定義もテンプレートエンジン付きのYAMLで簡潔かつ柔軟に記述できます。
最近、こんなのが話題になりましたが、
Python限定でFunction毎の管理という面で少し方向性は異なりますが、こっちの方が手軽だし便利で高機能なので、是非使ってみてください。 *3
使い方・設定の解説などはREADMEに書いていますが、後日Qiitaあたりに日本語でまとめようと思います。
今回のアップデート以外の部分については以下にまとめてます。
ざっくり使い方
Functionを実装してデプロイした上で、以下のような設定ファイルを記述(lamvery init
で雛形生成可)します。
profile: private region: us-east-1 configuration: name: lamvery-test runtime: python2.7 role: {{ env['AWS_LAMBDA_ROLE'] }} handler: lambda_function.lambda_handler description: This is sample lambda function. timeout: 10 memory_size: 128 events: - rule: foo description: bar schedule: 'rate(5 minutes)' targets: - id: test-target-id input: this: - is: a - sample: input
コマンドを叩きます。
lamvery events
これだけ!
もちろん、Dry runをサポートしているので -d
を付けて事前に更新内容だけ確認することもできます。
また、これを作る過程と使っていてLambda(Python)及び、CloudWatch Eventsについてかなりの知見や想定が溜まっているので、それもどこかで放出したいと思います。 *4
以上です。
是非使ってみてフィードバックをいただければ嬉しいです。
*1:それまではdeploy時と一緒にやる選択肢のみ
*2:アップロードするためのZIPアーカイブ
*3:正直、アレで1400 Starとか、やっぱり「何ができるか」よりも「誰が作ったか」が大事なんだな感あって、ちょっと悔しい
*4:JAWS Days 2016のタイムテーブルでLambda枠がまだ埋まってない(2015-01-23現在)んだけど、入れてくれたりしないかなー|д゚)チラッ
色々あって書ききれてない2015年を振り返ってみる
2015年の前半は割りと残しておきたいことはちゃんと文章に残しておけてたんだけど、後半は色々あって書けてないので、補完する意味も込めて振り返ってみる。 今年は副業としてフリーランス的な活動を始めたこともあり、普段の本業とそれ以外(副業・自学・勉強会やイベントなど)の活動で分けてまとめてみる。とはいえ、全く仕事の役に立たないことはあんまりしないので境目は曖昧な感じです。
あと、最後の方に来年に向けた割りと大事めなお話が書いてあります。
1~2月
本業
まず、この前の12月の転職しているので、基本的には軽めのタスクをこなしつつ色々新しい環境の把握やらなんやらしてた感じ。 特に大きな理想と現実のギャップみたいのはなかった。そもそもごく一部の企業を除いて地方でそんな恵まれた環境なんてないことは知っていたし、それでもクラウド案件はそれなりに多いにもかかわらず、思ってたよりオンプレ依存が強かったくらい。それもある程度は織り込み済みだったので、クラウドシフトやフロー改善その他も含めて色々展開していくことでバリューを出せたら良いなという気持ちを新たにした。
本業外
AWS SDK for Golangがベータリリースされたり、札幌でもGolangのMeetupが開催されたりでさすがにそろそろ触ってみないと不味いかなと思い、所謂イベント駆動開発してみたりとか、なんか作ってみたりとかした。あと、Azureに興味を持ち始めて、クラウドを組み合わせて使うことを本気で考え始めたのがこの辺。
www.slideshare.net
3月
本業
この辺りからAWSに詳しい人的な印象が社内に広く広まってきた感がある。色んな人から質問されたり、オブザーバとして打ち合わせに駆りだされたり、営業支援で東京に出張する場面が増えてきた(そして気がついた月3,4回とかで東京に行ってたw)
本業外
JAWS Days 2015に北海道組でありながら東北勢の温かいバックアップを受けて登壇させてもらった。ついでに会社としてもスポンサーさせてもらったり、Auroraのネタ話すのに5日前までプレビュー来なかったりとかトラブルも色々あったけど今までと違う関わり方でとても有意義な時間だった。来年のJAWS Daysも既にアナウンスされてましたが、はちょっと色々あってどうするか考え中です。。。
www.slideshare.net
4月~5月
本業
所属する会社がマザーズに上場した。そもそもこれを知ってたから入社したみたいな所はあった。上場企業に勤めたいとかそういうのはどうでも良いんだけど、札幌発のテクノロジー企業で上場は少なくとも自分がこの業界を志してからは聞いたことがなかったし、しかもそれがインフラメインの会社で、傍から見るにクラウドを本当の意味で使いこなしているようには見えなかった。だから、そこに自分が入ることで生み出せる価値がきっとあるはずだと思ったのが大きい。それに、良い流れが来始めていたので、より頑張ろうという気持ちになった。
本業外
業務でIoTの機運が高まってきたこともあり、IoTあるじゃんという勉強会に顔を出して、クラウド・サーバサイドエンジニアとして分からないなりにちょっとお話したり。
GCPに興味を持って触り始めたのもこの辺な気がする。
www.slideshare.net
6月
本業
IoT関連の仕事の話が出始める。色々と首を突っ込んで巻き込まれる形で色々やっていたようであまりやっていないような、よく覚えていないw
イベントに登壇・参加するために東京に行くと抱き合わせでAWS案件で色々営業について回るとかで出張は楽しかったけどツラい感じだった。
本業外
これは会社として回ってきた話なのでどちらかと言うと本業に近いのだけど、ニフティさん主催のWebセミナーに出演させてもらった。
あと、AWS Summit 2015に参加して、昼食ついでに一杯引っ掛けた状態で新しいDevOps Proの試験に受かるという快挙(?)を成し遂げたw
7月
本業
IoT関連の仕事が具体化し始める。というか、うん、いややめとく。
とりあえずそういった関係でかなり忙しくなり始めた。
本業外
July Tech Festaにプロポーザルが通ったので、マルチクラウド的な話をした。あと、東京めっちゃ暑かった。
マルチクラウドについては未だにだいぶ荒削りだけど、いくつか確信を得る体験はこの前後含めあったので、上手く伝えられるようにしていきたい。
www.slideshare.net
一方、YAPCとPyConも行かせてもらえそうだったので出したけど、落ちた。。。
PyConは札幌でやったイベント(後述)のネタ使い回しだったのでまあ良いとして、YAPCの方のネタは少し発展してクラウドも絡めて「クラウドがフレームワークに見える」とか「インフラをモデリングする」とかそういう概念を言語化する機会を求めていて、文章だけじゃ伝えきれなそうなので、どこかそういう場がないかな・・・ってずっと思ってるけど、未だに出会えてない。
あと、去年に一回関西・東京に混ぜてもらってChefのやつをやったきり、やるやる詐欺になってたInfra as Codeの勉強会というかカジュアルなイベントをやった。上述のYAPCのネタをここでやろうかとも思ったんだけど、自分の持ち時間は短めにしてできるだけ色んな人に話してもらいたかったので自粛した。これは参加者からまたやってほしいと嬉しい声を沢山いただいていて、自分でも楽しかったのでまたやりたい気持ちはあったんだけど、また延び延びになってて申し訳ない・・・やりたい気持ちはもちろんあるので、今色々抱えてる問題が解消されたらやります。
8~9月
本業
とにかくめっちゃ忙しかった。忙しすぎてYAPCもPyConもいけなくなったけど、Kinesis、LambdaとかOpsWorksとかDynamoDBとか、コアなプロダクト使ってガッツリ開発する経験ができたので、それはそれで良かったのかなと思ってる。
本業外
忙しさのピークとdb tech shocase、PyCon Mini Sapporoというイベント登壇2連チャンが重なるという不運だったけど、どちらも札幌発開催の大きめのイベントで絶対外したくなかったので気合で乗り切った。
www.slideshare.net
www.slideshare.net
特にAuroraの方は話題のサービスであることも相まって今年一番のヒットになりました。色々犠牲にして用意した甲斐があった。ありがとうございます。
この後個人事業になる副業の方が、ピークではないものの忙しい期間と被ってしまい疲れたのもあるけど、それよりも期限のないタスクがそれに甘えて遅くなったり、クライアントさんに気を遣わせてしまったりということが少しあったので、ちょっとこの辺のコントロールは考えなきゃなと思った。
10~11月
本業
忙しさが落ち着いてきた。で、落ち着いた所で色々これからの話をしていたのだけど、詳しくは色々問題があるので省くが、モチベーションが激落ちする出来事というか扱いを受けた。
本業外
個人事業主になった。正直、これがあったおかげでやりきれない想いを収めることができていたと思う。本当にありがたい。詳しくは以下から。
AWS Cloud Roadshow 2015でLTをしたけど、客層の見通しが甘すぎた上に途中の画面切り替えに失敗して過去最高レベルでスベった(ウケ狙いじゃないので盛り上がらなかった・響かなかったという意味で)反省しか無い。。。
www.slideshare.net
GCPUG札幌の立ち上げと第一回勉強会をやった。この時の資料は主観たっぷりの比較ネタなので口頭のフォロー無しの資料だけ公開すると問題がありそうなので自粛しました・・・w
こっちもそろそろ2回目に向けて動き出さなくては・・・誰かモチベーションください。。。
12月
本業
モチベーション激落ち継続中。仕事はそれなりにちゃんとやってます(当然ですがw)
本業外
こっちは頑張った。AWS×Kintone勉強会でBigQueryをぶっ込むとか(メインはあくまでAWSです!)
アドベントカレンダーは3つ参加した。
まとめ的と来年に向けて
本当に色々な経験をさせてもらった。コミュニティにも会社にもその他関わった皆様に感謝の念は付きない。ありがとうございます。
ただ、それとこれとは別問題で、本業(会社)の方についてはこのままのモチベーションでダラダラ行くのだけは誰も得しないので、来年の早い段階で何かしら決着付けないとと思ってます。
正直、今は副業の方を頑張ろうという気持ちです。そのまま独立するというのもアリかなと思ってる。というわけで、やる気出してウェブサイト作った!
何かあればよろしくお願いします!
副業フリーランス活動を認めてもらうこと・札幌(リモートでも可)勤務が必須条件ですが、色々な選択肢を考えたいので転職オファーでもOKです。
ちなみに会社の人に見られる可能性大ですが、それでも問題はないので大丈夫です。
それも含めて来年早々に決着付けたいという意思表示と受け取ってもらえれば。
ということで、来年もよろしくお願いします!
AWS Price List APIから欲しい情報だけ抜き取るAPIをAPI Gateway + Lambdaで作った
この記事はAWS Advent Calendar 2015の11日の記事です。
経緯
それは昨日(2015-12-10)の出来事でした。
全世界待望(?)の料金を取得するための公式APIが公開されました。
過去にこんなのやこんなのを作って、公式HPで使っているデータソースのJSONのURLやフォーマットが変わる度に(´・ω・`)ショボーンとしてきた身としては、「これは!!」となったわけです。
で、喜び勇んで試しに叩いてみたら
@marcy_terui RDSで26MB。。でけぇよ!
— Michael H. Oshita (@ijin) 2015, 12月 10
100万行超えのJSONやばすぎでしょw
— Masashi Terui (@marcy_terui) 2015, 12月 10
そんなこんなで
@ayakomuro たしかに。ほしいやつだけ返してくれる簡易APIでラップするの良いですね!
— Masashi Terui (@marcy_terui) 2015, 12月 10
みたいな話になったので勢いで作ってみましたよと。
成果物
ソース
APIドキュメント(swagger-ui)
フィードバックはGitHubの方からお願いします :-)
エラー処理とか雑なんでエラー時に普通にスタックトレースとか返ってくるので、Issueに貼り付けてやってくださいw
使い方
APIドキュメント見れば大枠はわかると思うので、ここでは各属性の指定方法を説明したいと思います。
とりあえずコマンドからのサンプルを貼っておきます。これをベースに説明したいと思います。
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '[{ "key": "instanceType", "value": "m4.4xlarge" }, { "key": "location", "value": "US West (Oregon)" }, { "key": "operatingSystem", "value": "Linux" }] ' 'https://eaoftu7rfi.execute-api.us-east-1.amazonaws.com/public/v1/offer/AmazonEC2?term=OnDemand'
Method
POSTのみに対応します(CORS対応のためにOPTIONも叩くことはできます)
URL
まず、ベースとなるのが以下の部分です。
https://eaoftu7rfi.execute-api.us-east-1.amazonaws.com/public/v1/offer/
次に、その後の AmazonEC2
の部分がサービスを示します。それぞれ何が使えるかは本家のAPIに準拠します。
なので、以下の offerCode
で何が使えるか確認できます。
https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/index.json
そして、クエリストリングの term
で購入方式を指定します。ここは、確認した範囲では OnDemand
or Reserved
しかないようです。EC2やRDS等以外の Reserved
の概念が存在しないサービスについては OnDemand
を指定してください。
Body
JSONフォーマットで各プロダクトの属性名が key
、その内容を value
で指定します。それぞれの内容は公式APIのデータが以下のようになっており、その中の attributes
の内容がそのまま該当します。
{ "formatVersion" : "v1.0", "disclaimer" : "This pricing list is for informational purposes only. All prices are subject to the additional terms included in the pricing pages on http://aws.amazon.com. All Free Tier prices are also subject to the terms included at https://aws.amazon.com/free/", "offerCode" : "AmazonRDS", "version" : "20151001000000", "publicationDate" : "2015-11-15T04:02:20Z", "products" : { "FNR4GZ675EW5UXJW" : { "sku" : "FNR4GZ675EW5UXJW", "productFamily" : "Database Instance", "attributes" : { "servicecode" : "AmazonRDS", "location" : "US West (Oregon)", "locationType" : "AWS Region", "instanceType" : "db.t2.small", "currentGeneration" : "Yes", "instanceClass" : "Burstable performance instances", "vcpu" : "1", "memory" : "2", "piopsOptimized" : "No", "networkPerformance" : "Low", "engineCode" : "10", "databaseEngine" : "SQL Server", "databaseEdition" : "Express", "deploymentOption" : "Single-AZ", "usagetype" : "USW2-InstanceUsage:db.t2.small", "operation" : "CreateDBInstance:0010" } },
複数の条件は全て AND
で繋がります。指定された条件を全て満たすデータが返却されます。
結果
上記コマンドの結果は以下のようになります。
[ { "product": { "sku": "8YGPZRQEKSSY8VWV", "productFamily": "Compute Instance", "attributes": { "enhancedNetworkingSupported": "Yes", "currentGeneration": "Yes", "operation": "RunInstances", "instanceType": "m4.4xlarge", "vcpu": "16", "storage": "EBS only", "location": "US West (Oregon)", "memory": "64 GiB", "processorFeatures": "Intel AVX; Intel AVX2; Intel Turbo", "networkPerformance": "High", "usagetype": "USW2-HostBoxUsage:m4.4xlarge", "processorArchitecture": "64-bit", "tenancy": "Host", "servicecode": "AmazonEC2", "dedicatedEbsThroughput": "2000 Mbps", "instanceFamily": "General purpose", "locationType": "AWS Region", "licenseModel": "No License required", "preInstalledSw": "NA", "clockSpeed": "2.4 GHz", "physicalProcessor": "Intel Xeon E5-2676 v3 (Haswell)", "operatingSystem": "Linux" } }, "price": [ { "sku": "8YGPZRQEKSSY8VWV", "termAttributes": {}, "effectiveDate": "2015-12-01T00:00:00Z", "offerTermCode": "JRTCKXETXF", "priceDimensions": { "8YGPZRQEKSSY8VWV.JRTCKXETXF.6YS6EN2CT7": { "description": "$0.000 per Linux m4.4xlarge Dedicated Host Instance hour", "pricePerUnit": { "USD": "0.0000000000" }, "rateCode": "8YGPZRQEKSSY8VWV.JRTCKXETXF.6YS6EN2CT7", "endRange": "Inf", "beginRange": "0", "appliesTo": [], "unit": "Hrs" } } } ] }, { "product": { "sku": "ZPAH28S2QQZ64QB5", "productFamily": "Compute Instance", "attributes": { "enhancedNetworkingSupported": "Yes", "currentGeneration": "Yes", "operation": "RunInstances", "instanceType": "m4.4xlarge", "vcpu": "16", "storage": "EBS only", "location": "US West (Oregon)", "memory": "64 GiB", "processorFeatures": "Intel AVX; Intel AVX2; Intel Turbo", "networkPerformance": "High", "usagetype": "USW2-DedicatedUsage:m4.4xlarge", "processorArchitecture": "64-bit", "tenancy": "Dedicated", "servicecode": "AmazonEC2", "dedicatedEbsThroughput": "2000 Mbps", "instanceFamily": "General purpose", "locationType": "AWS Region", "licenseModel": "No License required", "preInstalledSw": "NA", "clockSpeed": "2.4 GHz", "physicalProcessor": "Intel Xeon E5-2676 v3 (Haswell)", "operatingSystem": "Linux" } }, "price": [ { "sku": "ZPAH28S2QQZ64QB5", "termAttributes": {}, "effectiveDate": "2015-12-01T00:00:00Z", "offerTermCode": "JRTCKXETXF", "priceDimensions": { "ZPAH28S2QQZ64QB5.JRTCKXETXF.6YS6EN2CT7": { "description": "$1.109 per Dedicated Usage Linux m4.4xlarge Instance Hour", "pricePerUnit": { "USD": "1.1090000000" }, "rateCode": "ZPAH28S2QQZ64QB5.JRTCKXETXF.6YS6EN2CT7", "endRange": "Inf", "beginRange": "0", "appliesTo": [], "unit": "Hrs" } } } ] }, { "product": { "sku": "BMEYUTP658QKQRTP", "productFamily": "Compute Instance", "attributes": { "enhancedNetworkingSupported": "Yes", "currentGeneration": "Yes", "operation": "RunInstances", "instanceType": "m4.4xlarge", "vcpu": "16", "storage": "EBS only", "location": "US West (Oregon)", "memory": "64 GiB", "processorFeatures": "Intel AVX; Intel AVX2; Intel Turbo", "networkPerformance": "High", "usagetype": "USW2-BoxUsage:m4.4xlarge", "processorArchitecture": "64-bit", "tenancy": "Shared", "servicecode": "AmazonEC2", "dedicatedEbsThroughput": "2000 Mbps", "instanceFamily": "General purpose", "locationType": "AWS Region", "licenseModel": "No License required", "preInstalledSw": "NA", "clockSpeed": "2.4 GHz", "physicalProcessor": "Intel Xeon E5-2676 v3 (Haswell)", "operatingSystem": "Linux" } }, "price": [ { "sku": "BMEYUTP658QKQRTP", "termAttributes": {}, "effectiveDate": "2015-12-01T00:00:00Z", "offerTermCode": "JRTCKXETXF", "priceDimensions": { "BMEYUTP658QKQRTP.JRTCKXETXF.6YS6EN2CT7": { "description": "$1.008 per On Demand Linux m4.4xlarge Instance Hour", "pricePerUnit": { "USD": "1.0080000000" }, "rateCode": "BMEYUTP658QKQRTP.JRTCKXETXF.6YS6EN2CT7", "endRange": "Inf", "beginRange": "0", "appliesTo": [], "unit": "Hrs" } } } ] } ]
制限事項
ざっくり構築方法
1. ソースを取得
git clone git@github.com:willyworks/aws-price-api.git
2. Lambda functionをデプロイ
virtualenv -p /path/to/python2.7 .venv . .venv/bin/activate pip install -r requirements.txt lamvery deploy
デプロイは拙作のこちらを使ってます。詳しくはLambda縛り Advent Calendar 2015の16日で書きたいと思ってます。
3. Amazon API Gateway Swagger ImporterでAPIを定義する
Amazon API Gateway Swagger ImporterでAPIを一発で定義する | Developers.IO
4. Lambda functionの紐付けとMapping Templates設定
こんな感じ。
Mapping Templates↓
{ "offer" : "$input.params('offer')", "term": "$input.params('term')", "condition": $input.json('$') }
4. CORS設定
5. Deploy API!!
所感など
- Price List API生で使うのツラい
- 変更通知がSNSで受けれるらしいし、データストアに突っ込んで通知をトリガーに更新させることを想定してる?
- LambdaもAPIのデータ受け取るのに一番時間かかってる。Lambdaから叩ける低レイテンシなキャッシュほしい。*2
- Reservedで期間指定できるようにしたり、もうちょっとAPIの改善もしたいかも
というわけで
以上です!当初は以下のどちらかにしようと思ってましたが、予定を変更してお送りしました!
この辺はまたの機会に!