続 カッコの付け方

AWSを始めとしたクラウドコンピューティング全般と、唯一神emacsにおける()の付け方についてだらだら書きます

わかったつもりのCloudWatch

CloudWatchのプリセット(ビルトイン)メトリックスに関する記事です。カスタムメトリックスには殆ど触れません。

世の中には2つのタイプの製品があると思います。

  • 説明書を読まなくても使える
  • 説明書を読まないとハナから使えない

AWS CloudWatchは 明らかに前者ですが、この手のプロダクトはテキトーに触りだけ覚えてわかったつもりになるケースが極めて多いです。このエントリで わかったつもり から ちゃんと理解した の橋渡しをします。

重要なポイントの先出し

  • メトリックが定時観測型なのか、随時記録型なのか見極める
  • メトリックスの 1サンプルの値 は必ず1なのか確認する
  • EC2のMC(マネージメントコンソール)の特徴と落とし穴

定時観測型? 随時記録型?

両方共私の造語です。

定時観測型とは、RDS Auroraの qps 等を指します。
このタイプの特徴は、統計の種類 Average, Max, Min が必ず全て同じ値 になります。くわしくは後述

随時記録型とは、ELBの Request数、レイテンシ、各HTTPコードなどのメトリックスです。これはすごく雑に書くと、何時いつの値がNだった というデータを1個1個格納しています。周期的に格納しているのではなく、実際にその現象が発生した都度となります。特徴は、統計の種類 Average, Max, Min が異なる値となりうる です。

定時観測型の説明

特定の周期で、その時の値をCloudWatchのストレージが記録しています。
単純な話ですね、直感的にわかると思います。つまり、1分間隔であれば

  • 10:00 に 10.0
  • 10:01 に 15.0
  • 10:02 に 9.0

のように記録しています。よって、集計間隔を1分, 統計方法SampleCount とすれば、常に1です。 1分ごとに1個データが入っている という意味です。
上記を踏まえると

集計間隔を1分, 統計方法 Average, Max, Min とした場合、全て同じ値になります。だって1分毎に1個しかデータが入っていないから。 また、パーセンタイルも Sumも意味ないですね。だって1分毎に1個しかデータが入っていないから

勿論、データの間隔よりも大きな集計間隔を取った場合は異なります。データは1分間隔で入っている、5分間隔での集計なら、各々の集計間隔に5個データがあるからです。

随時記録型の説明

上記で大事なことなので2回言いました的に だって1分毎に1個しかデータが入っていないから と書いたのは随時記録型は 1分毎に1個以上のデータが入っている との対比のため。

取り敢えず ELB の Latecyを挙げます。Latencyはこんな感じでデータが入ります

  • 10:00:01 に 10
  • 10:00:02 に 12
  • 10:00:09 に 9
  • 10:00:23 に 4
  • 10:00:31 に 11
  • 10:00:42 に 3
  • 10:01:06 に 5

上記のように間隔はバラバラで、その現象が発生した時間 = リクエストが発生した(レスポンスを返した?)タイミング で随時・都度書かれます。つまり 10:00:00 - 10:00:59.xxx の間に 100個リクエストがあれば、100個データを持っていることになります。これ、インフラ屋ならわかると思いますが、ゲージ型と較べて全然データ量が違いますよね。これがタダって凄い太っ腹ですよね!
1分毎に1個以上のデータが入っている だから Average,Max,Min も異なってくるし、パーセンタイルも意味ある。

定時型・随時型の見分け方

長いので 定時型 随時型 と書き分けます。 正確な見分け方は、統計としてSampleCountを使うと一発でわかります。もうわかると思いますが、定時型なら集計間隔を何に変更しようとも常に一定です。(Demenstionで複数のリソースが混ざる場合は?とか意地悪なことは言わないで)

そもそも AWSのプリセット?ビルトイン? つまりカスタムじゃないメトリックスはほぼ全て定時型です
例外はELB(ALB/NLB含)ぐらいです。

ELBのメトリックス

ELBの随時型メトリックスを個別に掘り下げます。

Latency

前述しているので、軽く追加情報。
Latencyは、各リクエストに掛かった時間を値として書いています。 (敢えて を強調します、伏線です。) ですので、Max,Min,Average およびパーセンタイルは基本全部違いがあります。勿論Sumも

では、SampleCount ですが、これが 別メトリックスのRequest数:Sum とは一致します。AWS的には個別メトリックスとしていますが、実は1メトリックスで賄えるのです。

f:id:iga-ninja:20171104030250p:plain

線が丸かぶりしているので1本に見えますが、一致しています。

ではRequest数:Sumはなんでリクエスト数を表しているのでしょうか?LatencyでSumをやると、これまでの知識でわかると思いますが、その単位時間に発生したリクエストレスポンスの合計値となります。当たり前ですがとんでもなくデカイ値になります。では Requests:Sum はなんでバカでかい値にならないのでしょう?

単純な話です。伏線回収 = 1サンプルの値 が常に1だからです。

  • 10:00:01 に 1
  • 10:00:02 に 1
  • 10:00:09 に 1
  • 10:00:23 に 1
  • 10:00:31 に 1
  • 10:00:42 に 1
  • 10:01:06 に 1

とデータが格納されている場合、当然1分等の集計間隔で Sumすれば、その時間のリクエスト合計になります。ま、SampleCountを使ってもおなじですが。

2xx,4xx,5xx 系のカウント数

これらは常に1サンプルの値が1 です。なので Max,Min,Average は常に1です、パーセンタイルも意味ありません。 よって使える統計は Sum か SampleCount だけです。

HealtyHostsCount

これは結構特殊ですので、先に答えを書きます。

  • 定点型
  • データのサンプル数 = ELBを配置するAZの数 (正確にはELBのノードが増えた場合はその台数?)
  • 1サンプルの値 は healtyなホストの数 だが、それは最低でもAZ毎に出している。

前提知識を先に記載。
ELBはマネージメントコンソール上は1台ですが、実際は複数台で動いています。複数AZに配置する場合、最低でもそのAZに1台となります。暖気申請や、自動スケールアウトによりELB自身もスケールアウト・インします。つまりELBを構成する台数は常に一定ではない。

まず定点型 これについては素直に理解出来るはず。
データのサンプル数 = ELBを配置するAZの数 は直前に書いた前提知識の通りです。おそらくELBを構成する実ノード(私達は見れない、AWSが管轄しているリソース)の数になります。
最後に 1サンプルの値 は healtyなホストの数ですが、試すのが早いです。AZ2つで、EC2を2台ぶら下げて、Sumを出して下さい、ちゃんと healtyなら 4となるはずです。

今EC2が2台ぶら下がっていて * AZが2つ(=ELBを構成するノードが2つ) = 4

この点、もうちょっと掘り下げます。ELBと言えど、実体は恐らくただのEC2です。上記のケースで 例として A,B という2台のELBノードがあった場合

Aは 2台 healty Bは 0台 healty

と返す場合もありえます。つまりELB自身の片方であるBに障害があった場合の話です。この場合 Sumすると2となります。
殆どの場合、Average,Max,Min は一定になりますが、ELB側で障害があった場合、これらの値が一定でなくなります。監視屋としてどの値を使うかは検討した方がよいです。
妥当なのは Average、 Minだとつまり悪いとこ取りするので、さっきのA,Bの話だと0となります。これをもってNGとしてもAは生きているのでELB全体としては全滅ではないので厳しすぎとも言えます。逆にMaxだといいとこ取りなので、A,Bともに0になって始めて0になります。緩すぎな感じもします。

ManagementCosole @EC2 と @Cloudwatch の違い

メトリックスを見る時にEC2からみたほうが纏まっていてわかりやすいですが、EC2側で確認するのと、CloudWatchで直接確認するのと随分異なることがあります。

  • このメトリックスはSumがいいだとか、Averageがいいとか、予め空気読んでくれている
  • IOPSとかは予め計算してくれている(そのせいでCloudWatchの値と合わない)

1つ目の空気読んでくれている点ですが、たしかに便利は便利ですが、私はこれが学習を妨げる原因の1つになってしまったように思います。なんでこのメトリックスはAverageが全部1になるの? とか気づきを奪っているようにも感じます。
2つ目も詳しく書きますが、@EC2 と @CloudWatchは同じ物が出ているという間違った頭があると危険です。データーソースは同じですが、見せ方が違う。EC2側は一手間勝手に掛けてくれている

EBS Volume Write&Read Ops and Bytes

EC2側はいい感じに計算済みの値が入っています。試しに SampleCountに変えるとおかしな値が出ます。

f:id:iga-ninja:20171104024810p:plain

CloudWatch側は生の値です。

f:id:iga-ninja:20171104025258p:plain

言いたいことは、EC2とCloudWatchで値違うので、ちゃんとCloudWatchで調べなおしてね。

まとめ

  • メトリックが定時観測型なのか、随時記録型なのか分かっていると、統計のどれを使えば良いのか自ずとわかる
  • 1サンプルの値 は必ず確認すること。1の場合 随時記録型 で ずっと値が一定なものに監視を掛けたりしかねない
  • EC2のマネジメント ≠ CloudWatchの正規の値

監視屋として、どの統計を使っていいかわからないければ、 ELB Cloudwatchのようにググって

http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-cloudwatch-metrics.html

にある推奨を使えば大抵OK

Google Cloud Storage (gcs) IAM対応でACL設定がより簡単に

Google版 S3である Google Cloud Storage (gcs) ですが、もう随分前になるもののIAM対応となり、アクセス・ユーザー管理が非常に楽になりました。
ここでのIAMは勿論 GCPのIAMです。名前は同じですが、AWS の IAMとは、全く異なるものです。 今のところgcsのIAMはAWSに比べて機能面で大きく劣ります。

2019追加機能について下記エントリを作成しました。もっと楽になっているので合わせて参照してください。

iga-ninja.hatenablog.com

f:id:iga-ninja:20171023195140p:plain f:id:iga-ninja:20171023195105p:plain

IAMと、今までのACL

元々GCPにはIAMは存在せず、GCSはそれ単体で独自のACLを持っていました。今回の変更でこのACLレガシーACL と呼ばれるようになりました。レガシーと後述します。
対して今後はIAMによるGCSのアクセス制限・許可を使うようになります。
では、レガシーは今後どうなるのかですが、恐らく無くなることはないと思います。が、Developsers Console(ブラウザから)のレガシーACL設定は、もうできなくなりました。

IAMで出来るようになること

まず最初に、非常に語弊があるIAMという名称。先にAWS識者に言うことは S3に対するIAMと違って、リソース縛り(/pub/* は全員許可 /user1* は IAM user user1だけが通るとか、が一切できません。
制御出来るのは バケット単位のみです。 Prefix/Key単位では制御不能です。Denyのルールとかも書けません。

で、何が出来るようになったかと言うと バケット単位で IAM権限として付与した場合は、レガシーACLに頼らず(レガシーよりも強く) そのバケットの全てのオブジェクトに対して制御が可能です。

は?何いってんの?そんなの当たり前じゃねーか?

AWS識者は即反応しそうですが、この当たり前が、ほんのすこし前まで当たり前ではなかった。この記事は主にそれを書きます。

レガシーACL

S3のバケットACLやオブジェクトACLと同じで、バケット・オブジェクト1個1個単位でACLを設定します。このACLには、プロジェクトメンバだけではなく、Web公開する場合は allUsers に対する権限も含まれます。
大変なのは1個1個に指定しなければならないことです。極端な話、静的サイトをホスティングする場合、全部で100ファイルから成る場合は、その100個1つ1つに allUsers の閲覧権限が必要です。
...
そんなのやってられないですよね!そこで Default ACL と言うものをバケット単位で指定します。

Default ACL ?

バケット単位で指定する、DefaultでオブジェクトにつけるACLです。

例をあげるともしも、Default ACLを指定していなかったら。 バケットACLがあれば、ファイルのアップロードは可能です。つまり、XさんがAバケットに書き込み権限が付与されていると gs://a/hoge/fuga.txt など、好きな場所にファイル(オブジェクト)を upload可能です。 しかし、 gs://a/hoge/fuga.txt というファイル(オブジェクト)自体には ACLが何も付きません。勿論ACLの後付は可能です、が ACLが何も付いていないオブジェクトは、例え作成者であるXであっても`削除や移動や編集(上書きUpload)が一切できないオブジェクトになります。 対して、 Default ACL に AllUser に対して ReadOnly を指定していた場合。上記と同じ手順で、gs://a/hoge/fuga.txt がWeb公開された状態に自動でなります。

つまりは、オブジェクトをUploadする時に、ACLを何も指定しなかったら Default ACLの内容で、オブジェクトACLが付くということです。

バケット・オブジェクト ACLの問題点

一見問題なさそうに見える Default ACLですが、実に大きな問題を持っています。それは

バケットACLに新たにユーザーを追加した場合でも、既存オブジェクトのACLは変わらない、という点です。 つまりこういうことです。

  1. X さんが gs://hoge/a.txt を upload この時、 Default ACL は Xの編集権限のみ
  2. upload により a.txt に Xの編集権限が付く(仮に)
  3. Y さんがプロジェクトに参加、 gs://home にレガシーACLとしてユーザーを追加した Default ACL にも Yの編集権限を追加
  4. Y さんが gs://hoge/b.txt を upload これは問題ない
  5. Y さんが gs://hoge/a.txt を削除 or 上書き これができない、 だって a.txt は Yがいない時に生成されたので、 オブジェクトACLにXの編集権限しかないから

これに対する対処方は2つ

  1. 既存のオブジェクトのACLを全部変更する 具体的にはYの編集権限もオブジェクト全部につける
  2. そもそもユーザー個単位で権限を付与しない Google Group (G SuiteでなくてもOK)単位で許可をする

1) は根性です。全てのファイルのACL書き換えですので、それなりに時間もかかるリスキーな作業です。
2) はGroupという管理単位を1つかまして、ユーザー追加・削除の影響を最小限にする方法です。Google Gruop単位でACL設定した場合、もしもメンバを追加したいとなっても、GCS側はとくに変更無しで、Google Groupに該当するユーザーを追加 or 削除すればよいのです

Web公開とallUsers

注意
2019年にこの点に対する更新エントリを書いています。ぜひ参照してください。

2019年版 Google Cloud Storage (gcs) のアクセスコントロールがより簡単に - 続 カッコの付け方

GCSのオブジェクトをWeb公開する場合、AWSのような便利なバケットポリシーは存在せず、オブジェクトACL単位で管轄します。この、公開する時につかうユーザー(= 無認証ユーザーのアクセス)を allUsers という名前で指定します。回りくどく書きましたが、

Web公開したい なら allUsersでRead権限付ける しかもファイル一個一個に
だけどそんな面倒なことやってられないので、 Default ACLallUsers 足しとけ

となります。

レガシー or IAM

レガシーとIAMを比較して、じゃあこれからどうすればいいの?をまとめます

ユーザー・グループには IAMで権限付与

Object ACLの問題が発生しないため、レガシーを捨ててIAMにすることを強くおすすめします。 デメリットは私は思いつきません。

allUsers には レガシーで

ここは私の感覚をもろに出しているので、そうじゃないと思う人もいるかもしれません。

結論から言うと、 allUsers としてIAMで読み取り専用で権限付与は可能です。 が、1つ大きく問題があります。 詳しくは書きませんが、GCSはブラウザ上でバケット内のオブジェクトの一覧を確認できるGCPのツールがあります。AWSでいうマネージメントコンソールからのS3一覧画面のようなものですが、GCSはGCPの認証とは別にGCS単体での管理画面を持ちます。この画面が、何とallUsersとしてIAMでバケット許可していると、だれでも見えてしまいます。 つまりどう言うことかというと、所謂Apacheとかが自動生成する そのディレクトリに含まれるファイル一覧無認証で閲覧可能 になります。

結局Webで全部公開するなら、見れてもいいじゃないか?

という考えも有ると思いますが、「公開してはダメなものも意図せず置いちゃった。。」というのが二昔前の情報漏えいの基本だったと記憶しています。なので、私はIAMとして allUsers を読み込み専用とするのはかなり危険だと思います。このバケットには絶対に公開してOKのものしか置かない・置けないという仕掛けが無い限りは。

おまけ Default ACLの設定

今のDevelopers Console上から、 Default ACLを設定することはできません。gsutil のみとなります。 gsutil で Default ACLを設定する手順をざっくり書きます。

gsutil defacl get gs://[バケット名] > default.json

vim default.json 
# 編集する 下記を追記
  {
    "entity": "allUsers",
    "role": "READER"
  }

gsutil defacl set default.json gs://[バケット名]

まとめ

  • 今後はGCSのアクセス管理は基本IAMでいい
  • allUsers を IAMで ReadOnlyとするのは結構危険

Default ACLをブラウザ上から設定できないのは不便だなとおもう。

AWS NLB 初心者向け説明 (特にHealthCheck)

続々とELBに機能が追加されていますが、今更ですがNLBについて書きます。 今更NLBの記事を書くことに意味があるのか?と自問しましたが、一応 (初心者向け) と (HealthCheck) という切り口で、なるべく優しく書こうと思います。

NLBについて

先に言っておきたいこととして、NLBははっきり言って玄人好みで初見殺しです。いや、死ぬことは無いかも、そもそも思った通りに動かせない。

先にこの記事よりも遥かにレベルの高いものをエントリしておきます。下記を理解出来るレベルであればこのエントリは用済みです。

kanny.hateblo.jp

dev.classmethod.jp

dev.classmethod.jp

HealthCheckについて

早速本題です。 HealthCheck と ELB(TargetGroup)はセットで切り離せない存在ですが、NLBにSecurityGroupを当てることができません。

今までなら、ELBに X というSGを付けたら、バックエンドのサーバには X からのインバウンド 例えば TCP:80 とかを許可していました。SG設定できないなら、どうすんの? 答えは NLBの属するSubnetのIPレンジに対して許可するとなります。しかも上記の記事をちゃんと読んだ人ならわかるはずですが、NLBはバックエンドとの通信でAZを跨ぎません。よって、NLBが属するAZと同じAZにあるバックエンドに対して、設定すれば良いとなります。ここはAccess.logを見ても確認できます。

NLBの解説

なるべく簡単に

所謂リバースプロキシ型ではない

ALB, ELB (Classic ELB) は所謂リバースプロキシで、ロードバランサで一旦全てのリクエストを受けきって、ロードバランサのSourceIPでバックエンドにリクエストを飛ばします。当然レスポンスが戻って来るので、それを受け止めてリクエスタ(エンドユーザーのブラウザ等)に返します。雑に書くと、結構忙しい。だから暖気とか必要。 もっというと 複雑なこともできる となります。複雑なこととは SSL Terminate, Stickey Sessionなどです。

対して NLB はリバースプロキシではないです。厳密にはDSRとも違う?らしいですが、ロードバランサが一旦リクエストを受ける... の動きがなく、いきなりバックエンドのインスタンスにリクエストが来ます(来たように見えますが正しい)そして、ロードバランサを介さずレスポンスが戻ります。これまた雑に書くと、結構ヒマ、だけど複雑なことは無理

GCEの場合

敢えてGCEと比較します。 GCEが最初にだした、ネットワークロードバランサ(元々は単にローバランサ)はDSR方式です。ウチのLBは暖気要らずやで!どやぁ と言っていたのはこのためです。 これは私の感覚ですが何度も出している言葉ですが、 Google は IP, AWS は DNS という冗長のための仕組みの思想があるように思います。最初にDSRを作ったのもこの設計思想が強く反映されているように思います。しかしDSR型は機能が盛れない、SSL Terminateとかです。そこで HTTP(S) ロードバランサというリバースプロキシ型 + 地域分散型のLBを出しました。

話をHealthCheckに戻します。 GCEはHealthCheck、どうやってるのか? 答えは LB自身がヘルスチェックをせずに特定のIPアドレスからヘルスチェックが飛んでくる、です。この特定のIPとは、プロジェクト(AWSで言うところのアカウント)が異なっても同じです。なので、ヘルスチェックだけを通す・殺すは一応可能です。

NLBのHealthCheckは誰がやんの?

誰がHealthCheckするのかは、他のLBと変わらずNLB自身がやります。 で、SGが指定できない。なので、今のところバックエンド側のinbound SG ルールを絞りたいとなったら、(個人的にはこれはやだなというのも含みますが)

  • VPC の CIDRで妥協 (AWSドキュメントでおすすめとか言ってる)
  • Subnet の CIDRで行く (AZ跨がない考慮を入れる・入れないで2段階)
  • NLBだけを特定のSubnetに押し込めてそのCIDR (Subnetだらけになる、ただでさえ嫌いなのに)
  • 固定かどうか分からないが、アクセスログに出てくるIPだけ許可する。(変わらない保証はない)

今のところ、これぐらいです。

おまけ1. 従来のPrivate Subnetにバックエンドを引っ込めるは出来るのか?

結論から言うとできます。 この構成は CLB,ALBともよくやっていると思います。バックエンドにグローバルIPアドレスを持たせない。DSRは自力でクライアントにデータを届けなくてはならないので一見無理そうですが、できます、できました。 必要なものは

  • NLB は当然 Public Subnetにおく
  • バックエンドは Private Subnet & グローバルIP無し(あっても意味ない)
  • バックエンドが立つ Subnet は NAT-GatewayとかでOutboundが出来る
  • バックエンドにSG inbound TCP:80 0.0.0.0/0 とかを付ける

グローバルIPが無いインスタンスinbound TCP:80 0.0.0.0/0 を付けるんです!気になるのは、NAT経由で戻る点ですが、帯域的にもまあ問題ないかと。そもそもこの構成で本当に行くなら、全AZにNAT-GW必須と言えると思います。理由は?冒頭のエントリ見直してみてください。

おまけ2. ECSと組み合わせ可能?

可能です。ただし、普通にPublic Subnetにおいてしまうと、ポート全開で丸裸にせざるを得ないので、Privateに引っ込めるのはかなりいい手だと思います。NLBもターゲットグループを参照するので、普通にECSと連携できます、Drainingはできませんが、そもそもDSR方式(じゃないけど)なら原理的にはそんなもん必要ないです。

まとめ

  • healthcheck は VPC か Subnet のCIDRぐらいしか無い
  • NLB + Privateに引っ込んだバックエンドの構成は可能
  • ECS + NLB も一応イケる Privateに引っ込めるのがおすすめ

healthcheck はそのうち綺麗な方法がでるかも。一応、healthcheckにしか使わないよ!とUIで言って予防線張っても、ユーザーは NLBのSGに 0.0.0.0/0 とか絶対付けちゃうだろうし、NLBでIP制限出来るとか考えちゃうだろうから、NLBはSG無しとしたのは良い手だと思う。ただ、仕組み的にはhealthcheckだけSGは付けられるはず、だってhealthcheckするのは結局NLBだしローカルIPあるってことは、ENIがあるってこと、SGはインスタンスに付くのではなく、ENIに付くものなので仕組み上は絶対出来るはず。

結局あんまり初心者むけではなくなったような。。。

CloudWatchLogs データを入れてからのおたのしみ(概要編)

リリースから随分日が経っていますが、改めてCloudWatchLogsの良さを書きます。今回はLogs Agentや取り込みの話しは触れません。Logsに取り込んだは良いけど、どうしよう にフォーカスします。

その前にCWLogsの概要

長いのでCWLogsと略記。 CWLogsは文字通り、システムログやアプリケーションログ、Windowsはイベントログも含むを、CloudWatchLogs(AWS側の基版と言い換え可能)に投げます。CloudWatchはカスタムメトリックスといって、ユーザーが任意のメトリックスを送信することが出来ますが、CWLogsはそれのLog版となります。Logですので、メトリックス値(数値)ではなく、ログそのもの=文字列です。

ログをCWLogsに投げる処理は、CWL-Agent等を使います。前述の通りCWLogsに投げるまでの話しはこの記事では触れません。

CWLogsの代替

ここまでの 「Logを何処か一箇所に投げる」という機能だけみれば、fluentdや、同じくAWSkinesis、kafkaなどでも実現出来ます。逆に言うと、「Logを何処か一箇所にに投げる」という目的だけで使ってしまうと、ある程度の量を越えると割高で、kinesisの方がお得です。

これより、CWLogsの利点です。

用語説明

その前に用語説明を

ロググループ 後述のログストリームを束ねるものです。一般的にログの種類でロググループを分けます。
e.g. /var/log/messages や /var/log/http/access_log 毎に1ロググループ

ログストリーム 必ずどこかのロググループに所属します。一般的にはホスト毎に1ストリームとします。そうしない設計も可能ですが、その場合ログの中にホスト名を書くなど考慮が必要です。(どのホストのログか見かけが付けられないので)

The Log group has some Log streams .
A Log stream belong to one Log group.

CWLogsの利点

  1. マネジメントコンソールからログの検索
  2. メトリックスフィルタにより、ログをメトリックス(数値)化、そこからClowdWatch アラート発報
  3. ロググループをサブスクライブして、Lambdaでリアルタイム処理

マネジメントコンソールからログの検索

ロググループ単位で検索可能です。つまり複数のホストのログをまとめて、時間と検索文字列を指定して探すことができます。触ればわかる機能ですので、詳しく説明しませんが。これはこれで便利だと思います。

メトリックスフィルタについて

CWLogsがリリースされたすぐに使えた機能です。先の説明どうりですが、Log中の特定の値を含んだものをカウントし、Logを数値化します。 これを ClowdWatchで閾値を指定、アラーム発報とします。メトリックスフィルタは、ロググループ単位で指定します。

メトリックスフィルタの特徴

Pros
- 1つのロググループに対して、複数のメトリックスフィルタを指定可能
- フィルタルールは結構柔軟。複合条件に似たような記載も可能(後述)
- 検出・通知までプログラミングは一切不要

Cons
- ログ -> 数値化し、その数値に対してアラート発報をするだけなので、ログのアラート発報の原因となったレコード自体 はわからない

簡単に指定出来る点は有利ですが、ログそのものはアラートに含まれないという欠点があります。
つまり、
アラート飛んできたら、どのログ(種類)でアラートを検出したかや、発生の時間帯はわかるが、
どのノードで発生した?/一部なの?全体なの?
ログの中身は?
と言った利用者が本当に欲しいものはそのアラートだけでは得らず、わざわざマネージメントコンソールにログインしてログ検索する必要があります。
それでも最低限の監視、何かが起こっているの検知にはなると思います。

ロググループのサブスクライブの特徴

CWLogs出たてのころはlambdaは存在しなかったため、この機能は後発で実装されました。この機能もロググループ単位で指定出来ます。

Pros
- 生のログを処理出来るので、ログの内容をアラートに込めることが出来る
- フィルタルールだけでなく、lambdaで処理できるので、自由自在

Cons
- lambda必須 = プログラミング必須
- 1つのロググループに対して、1つののサブスクライバしか指定できない

メトリックスフィルタで出来ないことは実現できるのが強力です。が、ロググループ1つに付き1つのサブスクライバとなるので、この点は注意です。

1つの記事にまとめるつもりでしたが、結構な長編になってしまいました。 次回はメトリックスフィルタ編、次にサブスクライブ編と続けます。

AWS EBS SSD (gp2 general purpose) バーストクレジット計算式

「EBS (gp2) のクレジットの回復レートってどんなの?」の質問に即答できなかったので、書いておきます。 結論、数式としては

クレジット 0 -> Fullまでの時間 = 5,400,000(IO) ÷ ベースラインIOPS

となります。

概要と用語

簡潔に

  • EBSは 3000 IOPSまでのバーストクレジットがある
  • 1GBあたり 3 IOPSのベースラインIOPS ただし、 33.333GB ?(つまり 100IOPS以下)の場合でも最低100IOPS
  • バーストの継続時間は、 3000IOPS と、ベースラインのIOPSの差に反比例する 言い換えると ベースラインが 3000IOPSに近ければ長く、遠ければそれだけ短い
  • 1TB超の場合はベースラインが 3000IOPSとなるので、そもそもバーストしない

上記は理解できていると思います。 用語も改めて

  • ベースラインIOPS = バーストなしで利用可能なIOPS上限
  • バーストクレジット = ベースラインを越えるIOPSを利用した時に消費され、ベースライン以下のIOPSしか消費していなければ貯まる

公式ドキュメント

http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSVolumeTypes.html

http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/images/gp2-burst-bucket.png

解説もなにもありません、この絵の通りです。 EBSはOS起動時にIOPSが派手に発生することを見込んで、CPUクレジットとは異なり、いきなり 5,400,000 クレジットから始まります。このクレジットを消費することによって、バーストします。

Volume size (GiB) Baseline performance (IOPS) Maximum burst duration @ 3,000 IOPS (seconds) Seconds to fill empty credit balance
1 100 1862 54,000
100 300 2,000 18,000
214 (Min. size for max. throughput) 642 2,290 8,412
250 750 2,400 7,200
500 1,500 3,600 3,600
750 2,250 7,200 2,400
1,000 3,000 N/A* N/A*
3,334 (Min. size for max. IOPS) 10,000 N/A* N/A*
16,384 (16 TiB, max. volume size) 10,000 N/A* N/A*

上記抜粋表のの 1GB を見て下さい 単純な算数ですが 54,000 * 1000 = 5,400,000 となります。 100GBの場合、1GBの3倍のベースラインですので、54,000 / 3 = 18,000 となっています。

数学的な説明

5,400,000 という数字ですが、単位として示すなら 5,400,000 IO (英語的にはIOsが正しいですが、紛らわしいので IOとします) と読み替えられます。算数の 速さ・時間・距離(地方によっては、は・じ・き と言うらしい)の関係のように、単位変換を式で表すと

まずIOPSは文字通り1秒あたりのIO数ですので IOPS = IO / 1sec とします。そのあと、
Sec = 5,400,000 IO ÷ BaseLine IO / 1 sec 変換して
Sec = 5,400,000 IO × 1 sec / BaseLine IO

5,400,000 の IO と 掛け算の分母である BaseLine の IOが相殺されて
Sec = 5,400,000 / BaseLine
となります。

AmazonLinux や CentOS6 で upstart root以外で実行

もうオワコンである upstart で結構苦戦しました。やりたい事は単純に root以外のユーザーで実行したいということだけ

upstart ?

sysVと systemd の間にあったデーモン管理Tool(というか機構?)です。こいつは sysV とは違って systemdと共存出来ないので、オワコンです。が、残念なことにAmazonLinuxはこれに依存しているサービスが沢山あります。 AmazonLinuxのイケてないところは後述します。

やりたい事

root以外でデーモン起動

setuid / setgid があるじゃん!

残念ながら、 Cent6(RHEL6)をベースにしている AmazonLinuxは古すぎてsetuid/setgid に対応していません。その気になれば差し替えも出来るでしょうが、upstart のような根幹に関わる部分を差し替えるのは難しいはずです。少なくとも再起動は伴うと思いますので、やりません

方法

ubuntu - Running upstart jobs as unprivileged users - Super User

色々ありますが、単に su/sudo でやる方法でも、私の目的のスクリプト(中でデーモンプロセスが動く)は上手く動かなかった。挙動としてはsu コマンドの部分のみプロセスを見ているような動き。 コマンドその物に chmod コマンドで setuidもありですが、今回はシェルスクリプトなので不可能。シェルスクリプトで setuidが使えない理由はセキュリティー上の問題です。結構重要なことですが、詳しくはググって下さい。

結論 setuidgid コマンドを使う

daemon-tools の一部である setuidgid コマンドを使います。古いツールですが、パッチさえ当てればビルド出来ます。

ビルド

kaztr.hatenadiary.com

抜粋

wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz
tar zxvf daemontools-0.76.tar.gz
admin/daemontools-0.76
wget http://qmail.org/moni.csi.hu/pub/glibc-2.3.1/daemontools-0.76.errno.patch
patch -p1 < daemontools-0.76.errno.patch 
package/compile

使う

upstart のサービス毎の設定ファイルにて

exec setuidgid <ユーザ名> xxxx

AmazonLinuxのイケてないところ

他所のディストリビューションが 全て systemd に行ったのに、未だに sysV upstartなのは、centos6 をベースにしたから。 AmazonLinuxはkernelだけは上げていますが、grub, init系など は centos6 の古典時代のまま。 さらに悪い事に、ECS Agent 等は upstart で動かしているなど、この古い基版の上にAWS謹製のものを作っています。 思うに、今更 死んだ upstart に触りくないし、触ってほしくない。

なんでスパッと切り替えられないかの最大の要因は たぶんAmazonLinuxはローリング・リリースしているから。つまり yum updateだけでメジャーバージョンアップ完了。当然カーネルは無理だが、その他のものはこれで問題ない。しかし、 grub, init系を弄るとなると、結構怖い変更かつ、OS再起動は必須になるはず。だからやらなかったのだとおもうし出来る気がしない。

なので、次のバージョンから 最低でもベースを Cent7 か何かに切り替えた AmazonLinuxと、今のAmazonLinuxの2本立てとなるのが嬉しい。でもなんとなくそうしない気がする、2本立てのリソース裂きを嫌って。

まとめ

upstart root以外ユーザーなら setuidgidが良さげ、

AmazonLinuxへ一言 さっさと systemd化してくれ。。

Google API Client Library 入門

今まで、Cloud Monitoring のカスタムメトリックスを打つために、サンプルを改造する程度の理解しか無かったのですが、ある程度自分の頭で整理出来たので残します。GCP(Google)におけるAPIクライアントライブラリについて、入門からAWSとの違いについて。

Google API Client Library概要

Google(GCP) の各種サービスのAPIを呼び出すためのライブラリです。 ここで言うGCPには、GAE, GCEは勿論、G-Suite(旧Apps) や Mapsも含みます。

主に何をやってくれる?

まず、基本的な部分の説明ですが、APIを呼び出すためには

  1. 認証 (ヘッダなどに込める)
  2. https による RESTfulな操作

が必要です。といいますか、これだけあれば他は不要です。 つまり、AWSだろうがGoogleだろうが、 curl(にかぎらず httpsが喋れるクライアント) があれば、あとは認証情報さえどうにかすれば完了です。 Google API Client Library (API Clientと略) は、シンプルに 上記機能を提供します。特に面倒な 1. 認証 が大きな役目であり、それ以外の機能はとても 薄い実装 といえます。

理論よりさきに実装

書いていて先にコードを書いたほうがいいと思ったので晒します。(文章の流れは無視)

import httplib2
from apiclient import discovery
from oauth2client.client import GoogleCredentials

credentials = GoogleCredentials.get_application_default()
service = discovery.build('monitoring', 'v3', credentials=credentials)
req = service.projects().timeSeries().list(
        name=project_resource,
        filter=filter_strings,
        interval_endTime=end_time.isoformat(),
        interval_startTime=start_time.isoformat(),
        fields="timeSeries.points.value"
        )
ret = req.execute()

project_resource など、service.projects().timeSeries().list() の中の引数は実際のコードの抜粋なので参考程度にしてください。これはmonitoring.projects.timeSeries.listのコールとなります。

https://developers.google.com/apis-explorer/#search/monitoring.projects.timeseries.list/m/monitoring/v3/monitoring.projects.timeSeries.list

コード解説

credentials = GoogleCredentials.get_application_default() 特に触れなくていいいと思います、
service = discovery.build('monitoring', 'v3', credentials=credentials) これも問題無いでしょう、
req = service.projects().timeSeries().list(... がなんとも気持ち悪いコードだと思います(AWS脳には)。なんでわざわざメソッドになるの?ということですが、ここが Client APIの肝です。IPythonなどのREPLを使えばわかりますが、
service.projects(). まで打って 補完しても候補が出てきません。メソッドなので当たり前といえばそうですが、service.projects() を評価して初めて timeSeries リソース(クラス)が存在することが分かりのです。試しに().のチェーンをやめて、1つずつ変数に込めて見て下さい。
つまり、動的にAPIコールのためのクラスを生成しているのです。

また、メソッドの引数(APIパラメータと引数の名前マップ) を確認したいなら

 .__DOC__

を参照すればわかります。IPythonなら ? でも見えます。

Google API Client Library概要 再び

厚い実装・薄い実装

やり玉にAWSを上げると、AWSSDKは非常にぶ厚い実装です。上記で述べた認証は勿論、各種サービス毎に、1API毎に細かくclass-methodを実装し、各サービスを網羅しています。

それに対して GoogleAPI Client は API Clientのソースコード自体に、各サービスが持っている APIを細かく実装するということは行っておらず、classやresourceをダイナミックに取得・生成することにより、ものすごくコンパクトな実装になっています。

  1. 認証についてはどちらも同じ
  2. API操作部分については、 AWSが泥臭く全サービス毎に実装しているのに対して、GoogleAPI clientの中で自動生成している

優劣は一旦置いておいて、
AWS SDKAWS CLI とほぼ同じ領域をカバーする実装であるのに対し、
gcloudコマンド と Google API Client は 全くカバーする範囲が異なります。

gcloud に近い実装としては、 API Client ではなく Google Cloud Client Library というものが対応しています。

github.com

ただしこちらはまだ開発中であるためか、GCE等のサービスには対応していなかったりします。とりあえずAWS SDKに近いのはこちらで、AWS脳のひとはすんなり入れると思います。

薄い実装の利点

APIを作る側(この場合はGoogle)にとってはとてもメリットが大きいです。ここでもAWS SDKと比較しますが、APIの数だけSDKのclass-methodとして実装しているので、APIの仕様ドキュメントは勿論、AWS SDKでもほぼ同じ内容のドキュメントを用意、さらに各種言語毎に作成することになり、かなりのリソースを割くことになります。無論、潜在的なバグも多く含むことになります。
対して、API Clientのような実装の場合、各APIのドキュメントはありますが、API Client側にひとつひとつの対応class-methodに対応したドキュメントを用意する必要がありません。出来ないといったほうが正しいかもしれません。APIs Explorer を使えばOAuth2 で実際に打てるので、四の五の言わずに打って試せ!そしてそれをコードにしろ! というスタンスかもしれません。

また、API本体に仕様変更があっても、API Client側の実装はまず変更不要となるはずです。(使う側は堪ったもんではないですが)

この考え方・実装は、自分がAPIの提供側となった時、とても参考になると思う。

薄い実装の欠点

一言で言うと取っ付きにくい
私個人の感覚ですが、AWS SDKを使ったことがある人で、APIなんて curlさえあれば呼べると分かっていない人(つまりSDKなんて必須でないことをわかっている人以外)、SDKとは丁寧なドキュメントがあるのが正しいと思っている人は、まずそう感じると思います。それをGoogle自身も感じているため Google Cloud Client Library を作っているのだと思います。私も、取っ付きにくいと感じました。

また、根本的な話ですが、GCPは結構頻繁にAPIを弄ります。破壊的な変更は v1,v2 などと旧バージョンを残した上で、エンドポイントが変わる(増える)ことがほとんどですが、パラメータが増える等の対応があった場合、確かに API Client自体は影響受けないですが、API使う側の実装は当然変更となります。ただし、この点は 厚い実装 でも同じですし、厚い実装 と違って新機能のためにわざわざ API Clientのバージョンを上げる必要が無い点は利点に述べた通りです。

まとめ

  • Google API Client Library は主に認証の面倒を見てくれる
  • Google API Client Library の API を呼ぶ部分の実装はかなり 薄い
  • AWS SDK のような 厚い実装が良いなら Google Cloud Client Library を待つ?

自分がAPIを提供する側だったら、この薄い実装 の方がいいなとは思いました。最近は自動生成とかできますけどね。。