kashinoki38 blog

something like tech blog

文章を早く読む≒速読のためのメモ

ちょっと文書を早く読まないといけない気がし始めている。

結論

日本語

漢字読み(でサブボーカリゼーション防止)+逆行防止でFeedlyと本読む

英語

SpritzでFeedlyの記事読む(1日最低1本)

メモ

読書速度の計測ページ

https://www.pc-sokudoku.co.jp/books/index.html

  • 大体1000文字強/分だった

文章の面白さを捨てずに、本を早く読む4つの方法とコツ

https://wakarukoto.com/?p=15340

  • 助詞や動詞の後半は読まない
  • 文字ではなく単語や熟語の塊で読む
  • 意味が理解できるまで頭の中で音読する行為はやめる →これが苦手

    文章の中には、実は次の文を読まなければ全体の意味がわかりにくい表現手法もあります。そのため、1文字ずつ、1単語ずつ、1文ずつ意味を理解しながら読むのではなく、後追いで理解しながら読み進めるようにします。 イメージとしては、腹話術の「…声が…遅れて…聞こえるよ。」のような感じです。

  • 語彙力をつけるためにやっぱり読書は必要

読むスピードを上げる方法

https://www.wikihow.jp/%E8%AA%AD%E3%82%80%E3%82%B9%E3%83%94%E3%83%BC%E3%83%89%E3%82%92%E4%B8%8A%E3%81%92%E3%82%8B

  • 読む速度を上げる
    • 毎日少しずつ練習
      • 15~20分/日
    • 簡単な文書を読むことから始めましょう
    • 読むペースを保つには、指や索引カードを使いましょう
      • 自分の目を、ページ上のポインターに吸い付く磁石のようなものだというイメージを持ちましょう。ポインターが動く先へ、あなたの目も付いていきます。
    • 集中力を改善するためにより長い時間読みましょう。
      • 一度に少なくとも15分
    • 「読む」ことに対する考え方を変えましょう
      • 楽しい「機会」
    • ゆっくりと読むべき場合を見極めます。
      • →技術書の重要な部分
  • 悪い習慣を断ち切る
    • 頭の中で単語を発音するのをやめましょう(サブボーカリゼーション)
      • ガムを噛んだり鼻歌を歌ったりするなどして口を忙しく動かし
    • 単語を一語ずつ読むのをやめましょう。
      • まとまりごとに読む
    • 非効率的な目の動きを制御
      • 顔の筋肉を楽にして視野を広く保つ →一度に取り込めるページの内容を多くする
        • 一度に少なくとも4語は吸収してから、次のまとまりへ目を移すように努めましょう。
    • 「逆行運動」をやめましょう
      • ポインターを、いま読んでいる場所の目印にすれば、こうした後戻りを避けることができる
      • どんな文章でも最初の段階からしっかりと集中して読めば、再び読み返す必要はなくなる
      • その文章や段落の基本的な内容をつかめたのであれば、もう一度読み返すのは時間の無駄
    • 気が散る原因となるものを排除
      • 話し声や音
  • 読み方を変える
    • 文章にひととおり目を通す
      • 最初の段落の全文とそれに続く各段落の最初の一文、最後の段落の全文を読んでみる
      • この技術は、内容にあまり詳しくない場合や、長くて難しい文章の概要をつかみたいときに効果的
    • 最も重要な単語を探す
    • 各段落の最初と最後の文章を読む
      • 新しい情報の収集だけを目的として読む記事や本、レポートなどは、各段落の最初と最後の一文だけを読むのが便利
      • 新聞や雑誌の記事にも通じる
  • 既知の内容が書かれている部分は飛ばす
    • これに関連して、面白くない、何の勉強にもなっていないと感じるような本なら、途中で読むことをやめてしまっても一切気にする必要はない
  • 最も重要な情報を覚えておく
    • 重要な情報に蛍光ペンで印を付け、要約を書きましょう
      • 本を読み終えたら印を付けておいた場所に戻り、その情報を元にして本の内容を数百字程度にまとめる

1日500件の英語ニュースを読むための5つの方法

https://www.itmedia.co.jp/makoto/articles/1210/03/news008_3.html

  • RSSリーダーの高速読み(1日500件)
    • 3段階優先度
    • まずはざっと見て星をつける
  • 英語の速読方法をマスター
    • サブボーカリゼーション(subvocalization)と言われる。これが、英語速読の最大の障壁
    • 最後にとっておきのプレゼントがある。その名も「readfa.st」。このツールは自分が読みたい英語の記事をクリッピングして、「強制的に」早く読むことができるサービスだ。
      • 普通の音読のスピード……150wpm
      • 超早口の人の音読スピード……250wpm
      • 通常の読書スピード……300wpm
      • 早い人の読書スピード……1000wpm 1.RSSリーダーで読みたい英語の記事を見つける 2.Readfa.stで超高速リーディング(意味は分からなくていい) 3.元の記事に戻って流し読みをする(頭の中で音読をしないように。あくまで流し読み。つまみ読み)

        僕は通常の読書スピードは500wpmだが、このReadfa.stで強制的に1500wpmにして読む。その後、記事を普通に読むのだが、一度、単語を目で追っているため、ずっとずっと読むスピードが上がることに気付く。

読書スピードを超高速にする2つのテクニック

https://the-owner.jp/archives/580

  • 漢字だけリーディング → これかなりいいかも
    • ◎本を速く読むために重要になる接続詞。
      • 逆接の接続詞 ところが、しかし、だが、けれども、いっぽう
      • 理由の接続詞 つまり、なぜなら、要するに、というわけで
  • つまり読み
    • 「つまり何?」とつぶやきながら本を読む

瞬間速読〜名作の高速表示〜

https://play.google.com/store/apps/details?id=com.syunkansokudoku&hl=ja&gl=US

  • 日本語速読はこのアプリで練習か
  • Spritzを日本語でしたかったらしい

単語が目に飛び込んできてすごい速度で文章を読めるようになる「Spritz」

https://gigazine.net/news/20140228-spritz/

  • Spritz超いいかんじ

Spritz

https://spritz.com/

  • SpritzとFeedlyの相性最強なのだが →しばらくこれで英語速読鍛えよう(いったん1000wpmはきつすぎたので450wpmくらいから) f:id:kashionki38:20210405032834p:plain

日本語対応「Spritzもどき」をTwitter上で体験するブックマークレットを試作

https://memo.furyutei.work/entry/20140325/1395741983

  • こんな感じでいつか自分で作りてえ

2020年を振り返る

今更だが2020年を振り返る。
今更と思ったけど、去年も3末に振り返っていてそんなもん。 むしろ年度替わりに書くスタイル。

kashionki38.hatenablog.com

今更だが2020年を振り返る

  • 1月:スペイン本格化
    • 日本→インド(2週間)→スペイン(1週間)→日本という旅程を組む

      • エミレーツで行くとトランジットがトルコでこの謎の食べ物が美味しい

        f:id:kashionki38:20210405024336j:plain

      • もちろんスペインではパエリア

        f:id:kashionki38:20210405024353j:plain

      • Limeの電動キックボードにチャレンジするけど、思ってるより電源切れるの早くて会社からホテルまでたどり着けず、徒歩

      • WASABIで仲間のインド人と将来語ったなあ

        f:id:kashionki38:20210405024411j:plain

    • SRE Nextに参加してCloudNativeに興味持ち始める

    • Kubernetes Meetupにも参加し始めて、種々のMeetupに興味持つ
  • 2月:Kubernetes Day 1

    • 日本ではスノボしたり(かぐら

      f:id:kashionki38:20210405024424j:plain

    • 日本→インド(1週間)→スペイン(2週間)→インド(1週間)→日本という旅程にチャレンジ

      • 思えば自由に旅程を組ませてもらっていたな
      • 結果として提案系の案件ががんばれそうだったのでスペインを3週間に伸ばした
      • とにかくスペイン人についていって、提案資料作ったり問題解決トークしたり色々した
        • Kubernetesを使ったアーキのObservability支援みたいな提案ができそうだったので、色々勉強してBookinfoでObservabilityのデモしたのがとても印象的
      • 毎朝、サラミやら生ハムやらパンに挟んで食ってうまかったな
      • トレドに観光にいった

        f:id:kashionki38:20210405024441j:plain

  • 3月:コロナ本格化

    • そもそも2月の時点でスペイン人からお前日本から来たんなら2週間は空けないと客先行けないぞとか言われてた
    • 言っている間にインドがビザを停止。まさかの自体にインドへ帰れなくなったので、スペインから日本に直帰する旅程に急遽変更。ANAには大変感謝しています。
      • diamond.jp
      • 以降、インドにもスペインにも戻ることはできてない、
      • すべてリモートで動くしかなくなる
    • 塾活動としてKubernetesと性能について1割くらいの稼働で勉強し始める
  • 4月:引き継ぎ、半分日本の人
    • インドのロールは引き継ぐ。すごいチームだ、やっていることが高度だという話があり少し嬉しかった。
    • AWS使ったシステムの問題解決案件
    • 下旬はおそらく過去イチ忙しかった某案件で忙殺
  • 5月:記憶がない、、
    • 4下旬の忙しさを引きずり突入、GWは無かった
    • 後半は暇だったっけ
    • 仕事暇なのでMeetupいっぱい聞いてた気がする
  • 6月:サービスカタログ
    • グローバル向けサービスのカタログを試行錯誤しながら作っていた
      • 暗闇の荒野だった
  • 7月:初登壇

  • 8月:レベルアップ

  • 9月:悲しい
    • 悲しいことがあった
  • 10月:沖縄
    • 沖縄にGOTOで

      f:id:kashionki38:20210405024532j:plain

    • なんか振り返ると毎月どっか行ってる感じになってて、巣篭もりでストレス溜まっていたのかなんなのか
  • 11月:グローバル展開本格化
    • 満を持してサービスのカタログをグローバル各所に放出
    • 鬼滅の刃 無限列車編を見に行く
      • 煉獄さんの最後のシーンでおしっこ死ぬほど我慢してた
      • 昨年末にこの動画で鬼滅を見ることを決めたのを思い出したわ
  • 12月:Next Phase
    • 引っ越しの家さがしたり
    • 性能試験案件と問題解決案件の両持ち

登壇等のまとめ

P.S. 退職

2021年3月31日付けで4年間勤めた某SIerを退職した。入社以来性能プロフェッショナルな部署で実支援ベースの経験を積み、性能を中心に大変多くのことを学ばせてもらい、やりたかったグローバル含め多くのことにチャレンジさせてもらった。最後の一年はKubernetes等のCNCF系のOSSに触れながら好きに検証する機会をもらい、自身の技術志向に大きな影響があったと思う。

そして、4月1日付でAWSのSAにジョインすることになった。培った性能周りの知見を活かしながら、より広範にアーキテクチャに関わりたいと思っている。

別添1として、読んだ本

別添2として、YouTube遍歴

  • 霜降りチューブ
  • レインボーコントチャンネル
  • egg Channel
  • 土佐兄弟
  • ぽきぽき動画
    • あすわ整体
    • Dr Joseph
    • HAIR-CRACKING
    • Dr. Doug Willen
    • Chiropractor YUTO
  • マネーの虎
  • towaco
  • 東京03リモート単独公演 隔たってるね。
  • Abema Prime(ひろゆき
  • 晦日に108回もジャルってんじゃねえよ
    • まじ作業用
  • ニューヨークの漫才
  • よしログのGAG

別添3として、買ったもの

  • Mi Band 4

【日本正規代理店品】Xiaomi Mi Smart Band 4 スマートバンド 活動量計

【日本正規代理店品】Xiaomi Mi Smart Band 4 スマートバンド 活動量計

  • 発売日: 2019/12/23
  • メディア: エレクトロニクス

  • Gaming Chair GTRACING

  • Anker Type C Hub

  • キーボード:Majestouch Convertible 2 Tenkeyless 赤軸・テンキーレス・日本語かなあり

CloudNative Days 2021登壇 継続的な性能担保、DevPerfOpsという考え方

CloudNative Days Spring 2021 ONLINEというイベントに登壇した。

大変遅くなってしまったが書いておく。

event.cloudnativedays.jp

ちょっと登壇資料がまだ社内で手続き中でSlideShareアップロード待ちです。。

継続的な性能担保は必要だが難しい

まず継続的に性能を担保するのはかなり骨の折れることなのだと思っている。

リリースが何度も走るなかで性能品質を追いつかせていくにはちゃんとアプローチを決めて取り組んでいかないといけない。

DevPerfOpsとは

DevOpsの中でどうやって継続的に性能を担保するのだろうという疑問に対して、性能試験とリリース方式の2通りでアプローチを考えてみた。

とりあえずDevPerfOpsという単語を部署で唱え始めているところです。

f:id:kashionki38:20210330193341p:plain

こんなイメージを考えてみた。

f:id:kashionki38:20210330193357p:plain

Progressive Delivery

リリース時の性能リスク低減のアプローチとして期待できるのはProgressive Delivery。

Progressive DeliveryはCDの次のステップとして位置づけられた比較的新しいリリース方式で、従来のリリースに①リリース中の評価と②自動ロールバックを追加したもの。

カナリーリリースで少しずつトラフィックを流していき、問題があれば勝手に切り戻してくれるので、リリース時のリスク低減が可能というイメージ。

具体的なデプロイ時の流れは以下のFlaggerのドキュメントがわかりやすい。

docs.flagger.app

また以下の記事もわかりやすい

speakerdeck.com

qiita.com

medium.com

そして、CNDOでもFlagger, Argo Rolloutsで登壇されている方がいて興味深い。

event.cloudnativedays.jp

ツールとしては以下あたりが俎上に上がる理解。

PipeCDはどうか知らないが、FlaggerとArgo RolloutsはSevice Meshの機能を使ってトラフィック制御を実現している(要はIstioのVirtualService)。 なので、デプロイのされ方自体の機能差分に大きな差はなく、CDツール(FluxなのかArgoCDなのか)との連携やWebUIありなし(Flaggerはない)で選ぶことになると思う。

あとは、ArgoCDだとプライマリ昇格がローリングアップデートではなくServiceのEndpoint切り替えになるという話をCNDOの上記講演で聞いた。

諸々聞くと、Argo Rolloutsが良さそうに見えるが、なぜかFlaggerを最初に知ってしまい、Flaggerで検証してしまったw

結論、以下のようにカナリーリリースと最中の評価(Canary Analysisと呼ぶ)ができるので、ちゃんと事前に評価すべきメトリクスとその閾値を決めておきさえすればリスク低減の防衛戦として機能してくれそうとわかった。

f:id:kashionki38:20210330193518p:plain

もう少し細かいことが以下の記事にある(Podinfoというサンプルを使ったハンズオンを実施してみたの)

kashionki38.hatenablog.com

Progressive Deliveryの課題感

一方でなかなかうまく使うには考えることもあるなあと思っている。

妥当なSLI/SLOに基づいたしきい値使わないとね

サービスごとのSLI/SLOはもちろん事前に決めておく必要がある。

さらにそれは全体のSLAを考慮した上で妥当である必要がある。

これは結構難しいことなのでは、と思っている。

つまり、サービス全体とし決めたSLAを守るため、その構成要素として各サービスが他のサービスとの依存関係や用途を考慮した上で、どれくらいのSLOでないといけないのかを考えておく必要があるということ。

以下の記事が参考になるなと思いつつ、ここでは手に余るトピックなので議論のポイントとしてそっと置いておく笑

blog.newrelic.co.jp

engineering.mercari.com

いずれにしても、なんとなく決めたしきい値でリリースしてProgressive Deliveryの中でOKって出ても妥当じゃないよね、と思うので妥当感は何かしらに根付いて決める必要があるのかなと思った。

カバレッジ見ないとね

カナリーリリースをする際に、よく気になっていたのがいつどれくらいの時間かけてリリースするんですかね、である。

私の会社は大規模エンプラなので、結局本番はBlue/Greenでしょっていう感覚が強く、本番の日中帯にカナリーリリースするイメージがなかなか掴めない。

一方で、夜間帯の使われてないタイミングにカナリーリリースしてもなんの意味もないし、多少使われている時間帯でも数分でリリースしてしまったらそれって結局あんまりカナリーである意味ないのかな(ユーザフィードバック評価できたのかとか)と思うわけである。

ガスで苦しくなる前にカナリア引き上げてきましたwみたいな

Progressive DeliveryだとCanary Analysisが自動化されてしまうので、このリリースタイミングと期間の妥当性についても評価しておかないと、Canary AnalysisしましたOKです!って言われても信用ならないと思った。

CNDOの登壇の中でNewRelicの方がカナリーリリースを活用してリリースリスクを軽減するという話をObservabilityの管理力という文脈で説明されていたので、DIscordで質問してみた。

カバレッジの評価といういい単語をいただけた。なるほど、カバレッジはたしかに評価しないといけない。トラフィック量とURLやサービスベースでのカバレッジProgressive Delivery時の評価指標として取れているとさらに良さそうと思った。またどれくらいの期間かけてリリースしていくのかも普段のトラフィック量に応じて柔軟に決めるのだろう。

event.cloudnativedays.jp

f:id:kashionki38:20210330193548p:plain

Kubernetesリソースデプロイ時の自動負荷試験

さてもう一つのアプローチ自動負荷試験について入っていく。

こちらのブログや

amaya382.hatenablog.jp

こちらのブランチ戦略に関するポスト参考に、

qiita.com

GitOpsのブランチ戦略上のどのタイミングに負荷試験を自動で挟むかの想定を以下のように考えた。

f:id:kashionki38:20210330193623p:plain

つまり、機能試験担保済みのブランチでGitOpsのSyncがされたタイミングで自動で負荷試験が走るというイメージ。

で、こういったサンプルを作ってみた。

f:id:kashionki38:20210330193641p:plain

sock-shop をサンプルアプリとして、Observability と負荷試験自動化スタックを追加したもので、若干雑ながらも以下リポジトリに手順含めて置いたのでぜひ使ってみもらえれば。

github.com

残念ながらGitOpsは入れてないので、kubectl等でデプロイした段階からの開始イメージ。(Flux入れたとしても同じ用に動くはず)

フロートしては以下のように動いてくれる。

f:id:kashionki38:20210330193711p:plain

言ってもほとんどFlaggerががんばってくれるのだが、Jmeter化する部分は多少色々やった。

configMapGenerator:
  - name: jmeter-scenario-load-test
    files:
      - scenario.jmx
webhooks:
  ...
  - name: load-test
    url: http://jmeter-flagger-loadtester.jmeter/
    timeout: 5s
    metadata:
      # /jmeter/apache-jmeter-*/bin/jmeter -n -t $1 -Dserver.rmi.ssl.disable=true -JServerName=$2 -JNumOfThreads=$3 -JRampUp=$4 -JDuration=$5 -JTPM=$6
      cmd: '/bin/bash /load_test /scenario.jmx "front-end-canary.sock-shop" "50" "180" "600" "3000"'

これにより、事前にJmeterのシナリオを作っておけばリソースデプロイ後に自動で負荷試験が走って評価も自動で実施してくれるようになった。

実際に、2秒のスリープを仕込んだ上で、2秒しきい値として設定しておくと以下のように失敗(Halt)のメッセージがでて、

f:id:kashionki38:20210330193808p:plain

Slackにも失敗のメッセージが。(そっけないw)

f:id:kashionki38:20210330193816p:plain

これをベースにprdブランチへのマージを判断するようにすれば良い。

自動負荷試験の課題

こちらも同様に課題や考慮すべき点は多い。

リソース効率が悪い

試験環境が一時的にBlue/Greenで更新されたターゲットのPodが2倍用意されてしまうので、更新リソースが多いとリソースを多く消費してしまう。

定期的にどばっとリリースするというユースケースの場合、これだとあまりフィットしないなという率直な感想。その場合は、2週間に1回とかで性能試験用のクラスタを再作成して、そこで負荷試験するというのが自動化されているほうが便利なのではなかろうか、、

そうすると、今回のFlaggerを用いた方式は、リリース頻度が日単位未満でがんがんリリースされるようなユースケースではないか。クラスタをいちいち作るのは時間がかかるので、更新差分があるリソースだけBlue/Greenで立てて性能試験するという感じ。

さらなる自動化が不可欠

上記のそっけないSlackからわかるように、試験結果連携や整理には高度化が必須である(重要グラフ添付、結果のアップロード)

むしろそういった部分をなしにして自動化と歌ってしまっている今回のセッションは乱暴である。。。

また、負荷試験には実施や評価だけでなく、データ準備、負荷モデル、シナリオ作成が非常に重要なウェイトを占めており、この部分をなんとか自動化していかないことには、本質的に性能担保を継続的に回帰的に実施していくことは難しいと思う。

SwaggerによるAPI Documentからシナリオを自動で作る、普段の監視から負荷モデルを自動でつくる(Progressive Deliveryの部分におけるカバレッジと被るだろう)、試験のたびにDBのデータをあるスナップショットにする、といった周辺自動化も合わせて実施してやっと自動負荷試験と呼べる気がしている。

そんなOperator落ちてないですかね、

他のフェーズでの性能担保対応

セッション中の質問でもいただいたが、性能試験は負荷試験だけじゃなく、単体性能試験や長時間負荷試験などのバリエーションがある。

これらにも対応してまるっと性能担保を継続化するというのが最理想なのかなとは思う。

難しくなく実施できそうなのは、CIのコンテナイメージビルド時に単体性能試験(単API試験)をするとかだけど、よく考えるとUnit Test時に時間も測定しておくということのほうがよほど大事なのかもしれないと書きながら思ってしまった。

まとめ

まあ、そんなこんなで相当乱暴ながらDevPerfOpsというものを考えて、アプローチを検討してみた。

まとめると、

といったところ。

上述してきたように課題や考えるべき点はまだまだあるが、継続的な性能担保という考え方(ついでにDevPerfOpsも)が重要なポイントとして議論される日を祈って、その一助となれば嬉しい。

皆さん現場でうまく工夫されていることと思うのであれですが、一部でも参考にしてDevPerfOpsしてもらえると嬉しいです。

FlaggerでProgressive Derivery試してみた

Flaggerにずっと興味があるものの中々触れてなかった。
が、そろそろなにかしないと感とやっと時間が取れてきたということで触り始めた。
Flaggerすごいかっこいい。

github.com

Flaggerとは

  • Istio の VirtualSerice うまくつかって、Progressive Derivery を実現できる模様。AWS App Mesh や Linkerd とかにも対応してる。
  • Progressive Derivery は Canary Relase をしながら、Cnary Analysis を自動でして、Fail であれば Roll Back するデプロイ方法。
    • Canary Release は新しくデプロイした APP バージョンに少しずつトランザクションを割合で 10%→20%→30%と増やしていくようなリリース。増やしていく過程で問題がないかを見ながら段階的に増やすことに意義がある。
    • Canary Analysis は段階的に増やしていく過程の解析も指定したしきい値で自動評価していくような考え方。
      • Canary Analysis のメトリクスとして Prometheus が使える(PromQL でカスタム作れるっぽい)
  • Slack 通知も簡単

f:id:kashionki38:20210129034032p:plain

Flagger のセットアップ

Helm でデプロイ

prometheus, Slack の向き先とか設定。

$ helm upgrade -i flagger flagger/flagger \
 —namespace=istio-system \
 —set metricsServer=http://prometheus.istio-system:9090 \
 —set slack.url=https://hooks.slack.com/services/YOUR-WEBHOOK-ID \
 —set slack.channel=general \
 —set slack.user=flagger

Helm 設定値確認

$ helm get values flagger
USER-SUPPLIED VALUES:
metricsServer: http://prometheus.monitoring:9090
slack:
  channel: '@kashinoki38'
  url: https://hooks.slack.com/services/YOUR-WEBHOOK-ID
  user: flagger

サンプルアプリ、podinfo デプロイ

testnamespace にpodinfoを kustomize でデプロイ。

github.com

$ kubectl create ns test
$ kubectl label namespace test istio-injection=enabled
$ kubectl apply -k github.com/stefanprodan/podinfo//kustomize

kustomize の結果、Deployment, Service, HPA ができる。

$ kg all
NAME                           READY   STATUS    RESTARTS   AGE
pod/podinfo-7fdfdbd99c-4vc6n   2/2     Running   0          45s
pod/podinfo-7fdfdbd99c-nfsg7   2/2     Running   0          52s

NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
service/podinfo   ClusterIP   10.179.15.136   <none>        9898/TCP,9999/TCP   4m47s

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/podinfo   2/2     2            2           53s

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/podinfo-7fdfdbd99c   2         2         2       54s

NAME                                          REFERENCE            TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/podinfo   Deployment/podinfo   <unknown>/99%   2         4         2          6d18h

Flagger の Canary 設定 canary.yaml

Flagger の Canary 設定ファイルcanary.yaml 以下を設定

  • 対象となる deployment (.spec.targetRef)
  • Canary analysis の条件(.spe.analysis)
    • リトライ間隔(interval), rollback するまでののリトライ回数(threshold), トランザクションを割り振る

canaly.yaml

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: podinfo
  namespace: test
spec:
  # deployment reference
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  # the maximum time in seconds for the canary deployment
  # to make progress before it is rollback (default 600s)
  progressDeadlineSeconds: 60
  # HPA reference (optional)
  autoscalerRef:
    apiVersion: autoscaling/v2beta2
    kind: HorizontalPodAutoscaler
    name: podinfo
  service:
    # service port number
    port: 80
    # container port number or name (optional)
    targetPort: 9898
    # Istio gateways (optional)
    gateways:
      - ingressgateway.istio-system
    # Istio virtual service host names (optional)
    hosts:
      - "*"
      # - app.example.com
    # Istio traffic policy (optional)
    trafficPolicy:
      tls:
        # use ISTIO_MUTUAL when mTLS is enabled
        mode: DISABLE
    # Istio retry policy (optional)
    retries:
      attempts: 3
      perTryTimeout: 1s
      retryOn: "gateway-error,connect-failure,refused-stream"
  analysis:
    # schedule interval (default 60s)
    interval: 1m
    # max number of failed metric checks before rollback
    threshold: 5
    # max traffic percentage routed to canary
    # percentage (0-100)
    maxWeight: 50
    # canary increment step
    # percentage (0-100)
    stepWeight: 10
    metrics:
      - name: request-success-rate
        # minimum req success rate (non 5xx responses)
        # percentage (0-100)
        thresholdRange:
          min: 99
        interval: 1m
      # - name: request-duration
      #   # maximum req duration P99
      #   # milliseconds
      #   thresholdRange:
      #     max: 500
      #   interval: 30s
    # testing (optional)
    webhooks:
      - name: acceptance-test
        type: pre-rollout
        url: http://flagger-loadtester.test/
        timeout: 30s
        metadata:
          type: bash
          cmd: "curl -sd 'test' http://podinfo-canary:9898/token | grep token"
      - name: load-test
        url: http://flagger-loadtester.test/
        timeout: 5s
        metadata:
          cmd: "hey -z 1m -q 10 -c 2 http://podinfo-canary.test:9898/"
$ kubectl apply -f canary.yaml

以下のように Service と Deployment と VirtualService が作成される。

  • Services
    • podinfo
    • podinfo-primary ★new
    • podinfo-canary ★new
  • Deployment
    • podinfo
    • podinfo-canary ★new
  • VirtualService
    • podinfo ★new

podinfo の replicas は 0 になっている。

$ kg all
NAME                                   READY   STATUS    RESTARTS   AGE
pod/podinfo-primary-78cc86fbdb-csljl   2/2     Running   0          110s
pod/podinfo-primary-78cc86fbdb-wkzqj   2/2     Running   0          110s

NAME                      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/podinfo           ClusterIP   10.179.15.136   <none>        9898/TCP   16m
service/podinfo-canary    ClusterIP   10.179.1.5      <none>        9898/TCP   111s
service/podinfo-primary   ClusterIP   10.179.4.82     <none>        9898/TCP   111s

NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/podinfo           0/0     0            0           12m
deployment.apps/podinfo-primary   2/2     2            2           112s

NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/podinfo-7fdfdbd99c           0         0         0       12m
replicaset.apps/podinfo-primary-78cc86fbdb   2         2         2       112s

NAME                                                  REFERENCE                    TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/podinfo           Deployment/podinfo           <unknown>/99%   2         4         0          6d18h
horizontalpodautoscaler.autoscaling/podinfo-primary   Deployment/podinfo-primary   4%/99%          2         4         2          82s

NAME                         STATUS        WEIGHT   LASTTRANSITIONTIME
canary.flagger.app/podinfo   Initialized   0        2021-01-21T20:28:57Z

service の定義

$ kg svc -o yaml
apiVersion: v1
items:
- apiVersion: v1
  kind: Service
  metadata:
    annotations:
      cloud.google.com/neg: '{"ingress":true}'
      kubectl.kubernetes.io/last-applied-configuration: |
        {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"podinfo","namespace":"test"},"spec":{"ports":[{"name":"http","port":9898,"protocol":"TCP","targetPort":"http"},{"name":"grpc","port":9999,"protocol":"TCP","targetPort":"grpc"}],"selector":{"app":"podinfo"},"type":"ClusterIP"}}
    creationTimestamp: "2021-01-21T20:13:56Z"
    name: podinfo
    namespace: test
    resourceVersion: "133574186"
    selfLink: /api/v1/namespaces/test/services/podinfo
    uid: cd719bd9-9ccb-4ccd-948b-9272f3e8789e
  spec:
    clusterIP: 10.179.15.136
    ports:
    - name: http
      port: 9898
      protocol: TCP
      targetPort: 9898
    selector:
      app: podinfo-primary
    sessionAffinity: None
    type: ClusterIP
  status:
    loadBalancer: {}
- apiVersion: v1
  kind: Service
  metadata:
    creationTimestamp: "2021-01-21T20:28:27Z"
    labels:
      app: podinfo-canary
    name: podinfo-canary
    namespace: test
    ownerReferences:
    - apiVersion: flagger.app/v1beta1
      blockOwnerDeletion: true
      controller: true
      kind: Canary
      name: podinfo
      uid: ed4f3184-4789-49bd-8eec-5c62bdda3682
    resourceVersion: "133574170"
    selfLink: /api/v1/namespaces/test/services/podinfo-canary
    uid: c318abd8-6450-4d1e-8637-cd780525798e
  spec:
    clusterIP: 10.179.1.5
    ports:
    - name: http
      port: 9898
      protocol: TCP
      targetPort: 9898
    selector:
      app: podinfo
    sessionAffinity: None
    type: ClusterIP
  status:
    loadBalancer: {}
- apiVersion: v1
  kind: Service
  metadata:
    creationTimestamp: "2021-01-21T20:28:27Z"
    labels:
      app: podinfo-primary
    name: podinfo-primary
    namespace: test
    ownerReferences:
    - apiVersion: flagger.app/v1beta1
      blockOwnerDeletion: true
      controller: true
      kind: Canary
      name: podinfo
      uid: ed4f3184-4789-49bd-8eec-5c62bdda3682
    resourceVersion: "133574171"
    selfLink: /api/v1/namespaces/test/services/podinfo-primary
    uid: 10a8651c-4465-42d8-8f6b-386721fd5381
  spec:
    clusterIP: 10.179.4.82
    ports:
    - name: http
      port: 9898
      protocol: TCP
      targetPort: 9898
    selector:
      app: podinfo-primary
    sessionAffinity: None
    type: ClusterIP
  status:
    loadBalancer: {}
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

virtual service の定義
podinfo-primaryに 100%流す設定。

$ kg vs -o yaml
apiVersion: v1
items:
- apiVersion: networking.istio.io/v1alpha3
  kind: VirtualService
  metadata:
    creationTimestamp: "2021-01-21T20:42:27Z"
    generation: 1
    name: podinfo
    namespace: test
    ownerReferences:
    - apiVersion: flagger.app/v1beta1
      blockOwnerDeletion: true
      controller: true
      kind: Canary
      name: podinfo
      uid: 1fd42bd1-e477-4af8-8120-fa54d9be0f86
    resourceVersion: "133580636"
    selfLink: /apis/networking.istio.io/v1alpha3/namespaces/test/virtualservices/podinfo
    uid: 00cfc642-ccfa-4933-b3be-90a2fdcc7d00
  spec:
    gateways:
    - ingressgateway.istio-system.svc.cluster.local
    hosts:
    - app.istio.example.com
    - podinfo
    http:
    - route:
      - destination:
          host: podinfo-primary
        weight: 100
      - destination:
          host: podinfo-canary
        weight: 0
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

service と Deployment のマッピング

graph LR;
  a([service/podinfo])-->deploy/podinfo-primary;
  b([service/podinfo-canary])-->deploy/podinfo;
  c([service/podinfo-primary])-->deploy/podinfo-primary;
  deploy/podinfo-canary

tester の作成

Flagger の Webhook で負荷試験を実施するコンポーネント

$ kubectl apply -k https://github.com/fluxcd/flagger//kustomize/tester?ref=main
service/flagger-loadtester created
deployment.apps/flagger-loadtester created

webhook 設定

受け入れテストとしてhttp://podinfo-canary:9898/tokenへの curl
load-test としてhttp://podinfo-canary:9898/への hey

webhooks:
  - name: acceptance-test
    type: pre-rollout
    url: http://flagger-loadtester.test/
    timeout: 30s
    metadata:
      type: bash
      cmd: "curl -sd 'test' http://podinfo-canary:9898/token | grep token"
  - name: load-test
    url: http://flagger-loadtester.test/
    timeout: 5s
    metadata:
      cmd: "hey -z 1m -q 10 -c 2 http://podinfo-canary.test:9898/"

デプロイ:成功 ver

webhooks の定義にしたがって、acceptance-test と load-test が走る f:id:kashionki38:20210129034130p:plain

image のバージョンを変えてみる。

$ kubectl -n test set image deployment/podinfo podinfod=stefanprodan/podinfo:3.1.1
$ watch "kubectl describe canary podinfo -n test|tail"
Every 2.0s: kubectl describe canary podinfo -n test|tail  DESKTOP-NTAMOVN: Mon Jan 25 00:42:58 2021

  Normal   Synced  8m22s (x5 over 6h45m)  flagger  New revision detected! Scaling up podinfo.test  ★ターゲットの変更を検知
  Normal   Synced  7m22s (x5 over 6h44m)  flagger  Advance podinfo.test canary weight 10 ★virtualserviceで10%をpodinfoに流す(1分ごとに10%増加)
  Normal   Synced  7m22s (x5 over 6h44m)  flagger  Pre-rollout check acceptance-test passed  ★受け入れテストクリア
  Normal   Synced  7m22s (x5 over 6h44m)  flagger  Starting canary analysis for podinfo.test
  Normal   Synced  6m22s                  flagger  Advance podinfo.test canary weight 20
  Normal   Synced  5m22s                  flagger  Advance podinfo.test canary weight 30
  Normal   Synced  4m22s                  flagger  Advance podinfo.test canary weight 40
  Normal   Synced  3m22s                  flagger  Advance podinfo.test canary weight 50
  Normal   Synced  2m22s                  flagger  Copying podinfo.test template spec to podinfo-pr
imary.test
  Normal   Synced  22s (x2 over 82s)      flagger  (combined from similar events): Promotion comple
ted! Scaling down podinfo.test

検証用に podinfo が立ち上がる。

Every 2.0s: kubectl get po                                     DESKTOP-NTAMOVN: Mon Jan 25 15:39:58 2021

NAME                                  READY   STATUS    RESTARTS   AGE
flagger-loadtester-597d7756b5-xhcdq   2/2     Running   0          21h
podinfo-7b96774c87-d5n4s              2/2     Running   0          19s ★新しく起動
podinfo-7b96774c87-prnlv              1/2     Running   0          14s ★新しく起動
podinfo-primary-b49dbb9dc-8jgq4       2/2     Running   0          14h
podinfo-primary-b49dbb9dc-jslz4       2/2     Running   0          14h

Canary Analysis が通ってpodinfo-primary入れ替え

Every 2.0s: kubectl get po                                     DESKTOP-NTAMOVN: Mon Jan 25 15:56:57 2021

NAME                                  READY   STATUS            RESTARTS   AGE
flagger-loadtester-597d7756b5-xhcdq   2/2     Running           0          22h
podinfo-5788b6c694-f954v              2/2     Running           0          6m8s
podinfo-5788b6c694-kjzv8              2/2     Running           0          6m18s
podinfo-primary-67484dd774-lkxdf      2/2     Running           0          18s
podinfo-primary-67484dd774-xvnbj      0/2     PodInitializing   0          6s
podinfo-primary-b49dbb9dc-8jgq4       2/2     Running           0          15h
podinfo-primary-b49dbb9dc-jslz4       2/2     Terminating       0          15h

Kiali

load-testはIngressGateway通さない設定なので、直接podinfoに100%かけてる。
IngressGatewayから来ている負荷については、canary weightの増加にしたがって少しずつpodinfo-canaryに流れる比率が上がっていくのが見える。
確認し忘れていたが、おそらくVirtual Serviceのweightが変化していっているはず。

f:id:kashionki38:20210129034158p:plain

f:id:kashionki38:20210129034150p:plain

Canary Analysisが完了すると、podinfo-primaryが更新されて100%流れる。
f:id:kashionki38:20210129034153p:plain

画面

変更前
何回やっても v3.1.0
f:id:kashionki38:20210129034402p:plain

canary weight 10
何回かクリックすると v3.1.2 になる
f:id:kashionki38:20210129034416p:plain

slack 連携

1. 開始
f:id:kashionki38:20210129034430p:plain

2. デプロイ完了
f:id:kashionki38:20210129034440p:plain

デプロイ:失敗 ver

acceptance-test 失敗

Every 2.0s: kubectl describe canary podinfo -n test|tail                    DESKTOP-NTAMOVN: Mon Jan 25 15:45:50 2021

  Last Transition Time:    2021-01-25T06:45:38Z
  Phase:                   Failed
Events:
  Type     Reason  Age                  From     Message
  ----     ------  ----                 ----     -------
  Normal   Synced  6m15s (x6 over 21h)  flagger  New revision detected! Scaling up podinfo.test
  Normal   Synced  75s (x10 over 21h)   flagger  Starting canary analysis for podinfo.test
  Warning  Synced  65s (x5 over 5m5s)   flagger  Halt podinfo.test advancement pre-rollout check acceptance-test fail ★curlが通らず失敗
ed command curl -sd 'test' http://podinfo-canary:9898/token | grep token failed: : exit status 1
  Warning  Synced  15s (x5 over 21h)    flagger  Rolling back podinfo.test failed checks threshold reached 5
  Warning  Synced  15s (x5 over 21h)    flagger  Canary failed! Scaling down podinfo.test

load-test 失敗

request-duration がうまく取れないっぽく、canary.yaml.spec.analysis.metricsがそのままだと load-test 中に失敗する。 (metrics の request-duration をコメントアウトすると動く。Istio version によるメトリクス名変更のため?)

metrics:
  - name: request-success-rate
    # minimum req success rate (non 5xx responses)
    # percentage (0-100)
    thresholdRange:
      min: 99
    interval: 1m
  # - name: request-duration
  #   # maximum req duration P99
  #   # milliseconds
  #   thresholdRange:
  #     max: 500
  #   interval: 30s
$ kubectl -n test set image deployment/podinfo podinfod=stefanprodan/podinfo:3.1.1
$ watch "kubectl describe canary podinfo -n test|tail"
Every 2.0s: kubectl -n test describe canary/podinfo|tail -n 20                                                                                                                                                      DESKTOP-NTAMOVN: Sun Jan 24 18:05:01 2021

    Last Update Time:      2021-01-24T09:04:37Z
    Message:               Canary analysis failed, Deployment scaled to zero.
    Reason:                Failed
    Status:                False
    Type:                  Promoted
  Failed Checks:           0
  Iterations:              0
  Last Applied Spec:       5f8fd4f546
  Last Transition Time:    2021-01-24T09:04:37Z
  Phase:                   Failed
Events:
  Type     Reason  Age                  From     Message
  ----     ------  ----                 ----     -------
  Normal   Synced  7m30s                flagger  New revision detected! Scaling up podinfo.test
  Normal   Synced  6m30s                flagger  Starting canary analysis for podinfo.test
  Normal   Synced  6m30s                flagger  Pre-rollout check acceptance-test passed
  Normal   Synced  6m30s                flagger  Advance podinfo.test canary weight 10
  Warning  Synced  90s (x5 over 5m30s)  flagger  Halt advancement no values found for istio metric request-duration probably podinfo.test is not receiving traffic ★定義したmtricsであるrequest-durationが取れないので失敗
  Warning  Synced  30s                  flagger  Rolling back podinfo.test failed checks threshold reached 5
  Warning  Synced  30s                  flagger  Canary failed! Scaling down podinfo.test

request-duration はデフォルトで以下のような PromQL。
https://docs.flagger.app/faq#metrics

analysis:
  metrics:
    - name: request-duration
      # maximum req duration P99
      # milliseconds
      thresholdRange:
        max: 500
      interval: 1m

histogram_quantile(0.99,
  sum(
    irate(
      istio_request_duration_seconds_bucket{
        reporter="destination",
        destination_workload=~"$workload",
        destination_workload_namespace=~"$namespace"
      }[$interval]
    )
  ) by (le)
)

所感

  • .spe.analysisをうまく定義すればリリース後の Canary Analysis だけじゃなく、リリース後の負荷試験もうまく自動化できそう
  • DB のスキーマが変わってしまう場合は適応外?
  • Canary Analysis 周り
    • load-test と実際のトラフィック分割が同時に走るっぽいので、本番の負荷量考えないと load-test で本気だすと本番+ load-test なる?
    • Canary Analysis を走らせるタイミングがピーク時だと良いけど、そうじゃない場合にいは 50%まで担保しても微妙臭い
      • 目標スループットまで load-test で足してくれるような感じにできない?
    • Analysis を毎回全部通すのはきつい、うまくバリエーション持たせてコントロールできないか(開発は受け入れテスト、単性能のみ。ステージングは負荷試験も)
  • load-test 周り
    • 更新系の load-test 流したいと思うとどうすべきか
    • load-test のシナリオやデータを最新の取ってくるようにしたい
  • Slack 投稿内容とかカスタムしたい(グラフつけたり)

参考サイト

【暫定版】 Kubernetesの性能監視で必要なメトリクス一覧とPrometheusでのHowTo

2021/03/01 追記

記載していたリポジトリにあるマニフェスト系があまりに不親切だったので、ちゃんとまとめてみました。
後日、もうちょっとちゃんと記事書こうとは思いますが、大体はREADMEにあるので読んでみてください。
sock-shopをベースにObservability(Prometheus, Loki, Istio(Jaeger, Kiali))とProgressive Delivery&自動負荷試験スタック(Flagger, Jmeter, influxdb)をHelmとKustomizeで詰め込みました。
今回はちゃんと誰もが入れれるようにがんばってみたので、どうぞ。

github.com

この内容でCloudNativeDaysOnline2021に登壇することにしています。

event.cloudnativedays.jp

後、随分前ではありますが、本投稿に関連してKubernetes meetup tokyo #33で「Kubernetesでの性能解析 ~なんとなく遅いからの脱却~」というタイトルで登壇をしました。

www.slideshare.net


GitHubKubernetesの性能監視で必要なメトリクス一覧をまとめた。
また、それに伴って必要なPrometheusのExporter、それらのmetrics endpointに対するScrapeの方針とyamlのサンプル、GrafanaのダッシュボードJsonもまとめた。
改善余地はまだまだあると思うのでPRやコメント等大歓迎です。

監視すべき項目

監視すべき項目はUSE×REDだと認識している。
それを各コンポーネントの粒度でまとめている。
Cluster, Node, Pod/Container, MW(Java, Go, Nodejs, etc), Kubernetesコンポーネント自体

サービス監視(RED)

  • Rate : =Throughput, 秒間リクエスト数, 秒間 PV 数
  • Error Rate : エラー率, 5xx とか
  • Duration : =ResponseTime, %ile 評価が一般的

リソース監視(USE)http://www.brendangregg.com/usemethod.html

  • Utilization : 使用率 E.g. CPU 使用率
  • Saturation : 飽和度, どれくらいキューに詰まっているか
    E.g. ロードアベレージ
  • Errors : エラーイベントの数

前提条件

以下のバージョンを前提に設定のサンプルは用意している。

  • Kubernetes : v1.16.11-gke.5
  • Istio : 1.4.10-gke.4
  • Prometheus : prom/prometheus:v2.18.0
  • Grafana : grafana/grafana:7.0.1
  • NodeExporter : prom/node-exporter:v1.0.0

メトリクス一覧

以下のGitHubにも同様のReadme.mdをおいてます。 github.com

サービス監視(RED)

Jmeter

Grafana Dashboard

性能試験時のクライアント
Jmeter のメトリクスを収集
BackendListner->InfluxDB->Grafana

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/jmeter-metrics-dashboard.json

メトリクス USE x RED
Throughput R
ResponseTime D
Error% E

システムサイド  Istio Telemet

Istio のテレメトリ機能で各 service のメトリクスを収集

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/Istio-Mesh-Dashboard.json
https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/Istio-Workload-Dashboard.json
https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/Istio-Service-dashboard.json

メトリクス USE x RED Prometheus
Throughput R o
ResponseTime D o
Error% E o

システムサイド  Prometheus クライアントライブラリを利用

• 各言語のクライアントライブラリ使って Prometheus にメトリクスとして送る(request_duration_seconds をヒストグラム集計) https://github.com/devopsdemoapps/sockshop/search?q=request_duration_seconds&unscoped_q=request_duration_seconds

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus Grafana Dashboard Prometheus metrics
Throughput request_duration_seconds をヒストグラム集計 R o TBD
ResponseTime D o
Error% E o

OS リソース監視(USE)

クラスタ全体

NodeExporter と cAdvisor にて収集

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/kubernetes-cluster-dashboard.json

メトリクス USE x RED Prometheus
Node Availability ノード全体の稼働率
各ノードの Ready 時間合計/(集計期間 × ノード数)
Availability
Node 数 Availability o
unschedulable Node 数 Availability o
Node の詳細
kubernetes.node.name,各リソース量
Conf o
Pods Availability Available Pods Availability o
Pods status
Running / Pending / Failed / Unknown
Availability o
Container Availability Containers status
Ready / Terminated / Waiting / Running
Availability o
Deployment Count Deployment Count Availability o
StatefulSet Count StatefulSet Count Availability o
DaemonSet Count DaemonSet Count Availability o
Job Count Job Count Availability o
Failed Job Count Availability o

Node

Node Exporter で収集

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/node-exporter-dashboard.json

メトリクス USE x RED Prometheus
Node Availability ノード全体の稼働率
各ノードの Ready 時間合計/(集計期間 × ノード数)
Availability o
Node 数 Availability o
unschedulable Node 数 Availability o
Node の詳細
kubernetes.node.name,各リソース量
Conf o
pods Pods Allocatable Conf o
Pods Capacity Conf o
Pods Allocation o
CPU CPU 使用率 U o
CPU 使用率コアごと U o
ロードアベレージ S o
CPU Core Capacity Conf o
CPU Core Limits Conf o
CPU Core Requests Conf o
CPU Core Allocatable Conf o
メモリ メモリ使用量 U o
スワップイン量 S o
スワップアウト量 S o
スワップ使用率 S o
スワップサイズ S o
Memory Capacity Conf o
Memory Limits Conf o
Memory Requests Conf o
Memory Allocatable Conf o
ディスク ディスクビジー U o
ディスク I/O 待ち数 S o
ディスク I/O 待ち時間 S o
ディスク読込み量 U o
ディスク書込み量 U o
ディスク読込み回数 U o
ディスク書込み回数 U o
パーティション使用率 U o
パーティションサイズ U o
inode 総数/使用率 U o
ネットワーク 送信トラフィック U o
受信トラフィック U o
ポート/Socket U
Drops E o
Errs E o
ping Availability
ファイルディスクリプタ U o
プロセス プロセス数 U
プロセス数(ゾンビ) U
占有プロセス状況(プロセスキューサイズ) U

Pod/Container

cAdvisor にて収集 (Kubelet バイナリに統合されているので scrape の設定のみで OK)

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/pod_detail-dashboard.json

メトリクス USE x RED Prometheus
Pods Availability Available Pods Availability o
Pods Restarts Availability o
Pods status
Running / Pending / Failed / Unknown
Availability o
Container Availability Restarts Availability o
Errors
Terminated Reason
Waiting Reason
Restart Reason
E o
Containers status
Ready / Terminated / Waiting / Running
Availability o
CPU CPU 使用率 U o
ロードアベレージ S o
Throttle S o
CPU Core Limits Conf o
CPU Core Requests Conf o
メモリ メモリ使用量 U o
スワップイン量 S x
スワップアウト量 S x
スワップ使用量 S o
スワップサイズ S x
Memory Limits Conf o
Memory Requests Conf o
ディスク ディスクビジー U o
ディスク I/O 待ち数 S o
ディスク I/O 待ち時間 S o
ディスク読込み量 U o
ディスク書込み量 U o
ディスク読込み回数 U o
ディスク書込み回数 U o
パーティション使用率 U o
パーティションサイズ U
inode 総数/使用率 U o
ネットワーク 送信トラフィック U o
受信トラフィック U o
ポート/Socket U
Drops E o
Errs E o
ping Availability
ファイルディスクリプタ U

Persistent Volume

kubelet の metics エンドポイントから収集

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/pv-dashboard.json

メトリクス USE x RED Prometheus
ファイルシステム ディスク領域使用量 U o
inode 総数/使用率 U o

MW リソース監視

Nginx

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus
コネクション数 Active / Dropped S
スループット request per sec R
HTTP レスポンスコード E
レイテンシ Response Time D
Network bytes

Java (Jetty on SpringBoot)

SpringBoot2 系以降から実装の、Micrometer Actuator を使用
(pom.xml 変更のみで良いはず)

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/jmx-exporter-dashboard.json

メトリクス USE x RED Prometheus
ヒープメモリ 全体ヒープメモリ使用量 U o
Young U o
Old U o
Metaspace U o
Code Cache U o
GC 頻度(Full/Young) S o
時間(Full/Young) S o
レスポンスタイム レスポンスタイム D ?
レスポンスコード レスポンスコード E ?
スレッド数 スレッド数 S o
空きスレッド数 空きスレッド数 Conf ?
スレッドプール使用率 スレッドプール使用率 S ?
コネクションプール使用数 コネクションプール使用数 S ?

Go

golang クライアントライブラリの promhttp を使用
https://github.com/prometheus/client_golang/tree/master/prometheus/promhttp

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/go-process-dashboard.json

メトリクス USE x RED Prometheus
Process Memory U o
Memory Stats U o
Goroutines S o
GC duration S o | ##### Grafana Dashboard

Nodejs

nodejs クライアントライブラリの prom-client を使用
https://github.com/siimon/prom-client

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/nodejs-dashboard.json

メトリクス USE x RED Prometheus
Process Memory U o
Active Handlers S o

MySQL

Grafana Dashboard

mongodb

Grafana Dashboard

Redis

Grafana Dashboard

Kubernetes コンポーネント

kube-api-server

kube-api-server の metrics エンドポイントから収集

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/kube-apiserver-dashboard.json

メトリクス USE x RED Prometheus
API コール REST リクエスト数 R o
API リクエストレイテンシ D o
API リクエストエラー E o
Controller Manager から ワークキューの追加率 o
ワークキューの待ち時間 o
ワークキューの深さ o
etcd から etcd キャッシュエントリ x
etcd キャッシュのヒット/ミス率 x
etcd キャッシュ期間 x
リソース メモリ使用量 o
CPU 使用量 o
Go routine o

kube-controller-manager

Controller manager の metrics エンドポイントから収集
デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus
インスタンス kube-controller-manager インスタンスの数
ワークキュー情報 ワークキューのレイテンシー
ワークキューレート
ワークキューの深さ
kube-api kube-api リクエストレート
kube-api リクエストレイテンシ
リソース メモリ使用量
CPU 使用量
Go routine

etcd

kube-scheduler の metrics エンドポイントから収集
デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus
Leader Leader 変更回数
Database 系 DB サイズ
Disk 同期レイテンシ
Disk 操作 (fsync, commit)
Network Client Trafic
Peer Trafic
Raft Proposal
Proposal Committed
Proposal Pending
grpc
snapshot snapshot レイテンシ

Grafana Dashboard

kube-scheduler

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus
Scheduling Scheduling レート
Scheduling レイテンシ
kube-api kube-api リクエストレート
kube-api リクエストレイテンシ
リソース メモリ使用量
CPU 使用量
Go routine
Leader Leader 変更回数

kube-proxy

kube-proxy の metrics エンドポイントから収集
デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus
Proxy ルール Sync Proxy ルール Sync レート R
Proxy ルール Sync レイテンシ D
Network Programming Network Programming レート R
Network Programming レイテンシ D
kube-api kube-api リクエストレート
kube-api リクエストレイテンシ
リソース メモリ使用量
CPU 使用量
Go routine

kubelet

各ノードの 10255 ポート

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/kubelet-dashboard.json

メトリクス USE x RED Prometheus
インスタンス kubelet インスタンスの数 Availability o
ボリュームの数 Availability o
error error E o
オペレーション 各タイプのランタイムオペレーションの総数 U o
オペレーションのエラーの数
※コンテナランタイムの問題など、ノード内の低レベルの問題を示す良い指標
E o
オペレーションの間隔時間 S o
Pod の管理 ポッドのスタートレートと間隔時間
コンテナのランタイムまたはイメージへのアクセスの問題を示している可能性がある
S o
ポッドスタートオペレーションの数 U o
ストレージ ストレージオペレーション数 U o
ストレージオペレーションエラー E o
ストレージオペレーション時間 S o
Cgroup マネージャ Cgroup マネージャのオペレーション数 U o
Cgroup マネージャのオペレーション時間 S o
ポッドライフサイクルイベントジェネレータ ポッドライフサイクルイベントジェネレーター(PLEG):
relist レート、relist インターバル、relist 間隔時間。これらの値のエラーまたは過度の遅延は、ポッドの Kubernetes ステータスに問題を引き起こす可能性があ
U o

Prometheus

Grafana Dashboard

以下のGitHubにも同様のReadme.mdをおいてます。 github.com

必要な Exporter

Exporter Link
Node Exporter NodeExporter
https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-monitoring/node-exporter-ds.yml
kube-state-metrics kube-state-metrics
https://github.com/kubernetes/kube-state-metrics/tree/master/docs

各 Exporter に対する Scrape 方針

Exporter Scrape Target Endpoint Scrape Config Sample の job name
cadvisor apiserver の以下 metrics パス
https://kubernetes.default.svc:443/api/v1/nodes/gke-cn-horiuchiysh-s-cn-horiuchiysh-s-2b141725-5coq/proxy/metrics/cadvisor
kubernetes-cadvisor
NodeExporter 各 pod のコンテナポートの/metrics へ投げる
nodexporter/metrics
kubernetes-pods
go 各 pod のコンテナポートの/metrics へ投げる
go/metrics
kubernetes-service-endpoints
nodejs 各 pod のコンテナポートの/metrics へ投げる
nodejs/metrics
kubernetes-service-endpoints
mongodb 各 pod のコンテナポートの/metrics へ投げる
mongodb/metrics
kubernetes-pods
Istio Mesh istio-telemetry サービスの endpoint port name が prometheus
http://10.48.2.14:42422/metrics
istio-mesh
kubelet 各ノードの 10255 ポート
http://10.30.3.20:10255/metrics10255
kubernetes-nodes
kube-apiserver default namespace に api server 向けの svc と endpoint がある
https://104.198.95.200:443/metrics
kubernetes-service-endpoints
kube-state-metrics 各サービスの/metrics へ投げる
http://kube-state-metrics:8080/metrics
kubernetes-service-endpoints
prove /api/v1/nodes/gke-cn-horiuchiysh-s-cn-horiuchiysh-s-2b141725-5coq/proxy/metrics/probes
ベット job が必要
kube-controll-manager デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする
/metrics
kube-proxy デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする
/metrics
kube-scheduler デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする
/metrics

Scrape Config Sample

kubernetes-pods

- job_name: kubernetes-pods
  honor_timestamps: true
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: http
  kubernetes_sd_configs:
  - role: pod
  relabel_configs:
  - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
    separator: ;
    regex: ""true""
    replacement: $1
    action: keep
  - source_labels: [__meta_kubernetes_pod_node_name]
    separator: ;
    regex: (.*)
    target_label: node
    replacement: $1
    action: replace
  - source_labels: [__meta_kubernetes_namespace]
    separator: ;
    regex: (.*)
    target_label: namespace
    replacement: $1
    action: replace
  - source_labels: [__meta_kubernetes_pod_name]
    separator: ;
    regex: (.*)
    target_label: pod_name
    replacement: $1
    action: replace

kubernetes-nodes

各ノードの 10255 ポート

- job_name: kubernetes-nodes
  honor_timestamps: true
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: http
  kubernetes_sd_configs:
    - role: node
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  tls_config:
    insecure_skip_verify: true
  relabel_configs:
    - separator: ;
      regex: (.*)
      target_label: __scheme__
      replacement: https
      action: replace
    - source_labels: [__meta_kubernetes_node_label_kubernetes_io_hostname]
      separator: ;
      regex: (.*)
      target_label: instance
      replacement: $1
      action: replace
    - source_labels: [__address__]
      separator: ;
      regex: ^(.+?)(?::\d+)?$
      target_label: __address__
      replacement: $1:10255
      action: replace

kubernetes-cadvisor

apiserver の以下 metrics パス
/api/v1/nodes/gke-cn-horiuchiysh-s-cn-horiuchiysh-s-2b141725-5coq/proxy/metrics/cadvisor

- job_name: kubernetes-cadvisor
  honor_timestamps: true
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: https
  kubernetes_sd_configs:
    - role: node
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: false
  relabel_configs:
    - separator: ;
      regex: __meta_kubernetes_node_label_(.+)
      replacement: $1
      action: labelmap
    - separator: ;
      regex: (.*)
      target_label: __address__
      replacement: kubernetes.default.svc:443
      action: replace
    - source_labels: [__meta_kubernetes_node_name]
      separator: ;
      regex: (.+)
      target_label: __metrics_path__
      replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
      action: replace

istio-mesh

istio-telemetry サービスの endpoint port name が prometheus の port

- job_name: istio-mesh
  honor_timestamps: true
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: http
  kubernetes_sd_configs:
    - role: endpoints
      namespaces:
        names:
          - istio-system
  relabel_configs:
    - source_labels:
        [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      separator: ;
      regex: istio-telemetry;prometheus
      replacement: $1
      action: keep

kubernetes-service-endpoints

- job_name: kubernetes-service-endpoints
  honor_timestamps: true
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: http
  kubernetes_sd_configs:
    - role: endpoints
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: false
  relabel_configs:
    - source_labels: [__meta_kubernetes_service_label_component]
      separator: ;
      regex: apiserver
      target_label: __scheme__
      replacement: https
      action: replace
    - source_labels:
        [__meta_kubernetes_service_label_kubernetes_io_cluster_service]
      separator: ;
      regex: "true"
      replacement: $1
      action: drop
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
      separator: ;
      regex: "false"
      replacement: $1
      action: drop
    - source_labels: [__meta_kubernetes_pod_container_port_name]
      separator: ;
      regex: .*-noscrape
      replacement: $1
      action: drop
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
      separator: ;
      regex: ^(https?)$
      target_label: __scheme__
      replacement: $1
      action: replace
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
      separator: ;
      regex: ^(.+)$
      target_label: __metrics_path__
      replacement: $1
      action: replace
    - source_labels:
        [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
      separator: ;
      regex: ^(.+)(?::\d+);(\d+)$
      target_label: __address__
      replacement: $1:$2
      action: replace
    - separator: ;
      regex: ^__meta_kubernetes_service_label_(.+)$
      replacement: $1
      action: labelmap
    - source_labels: [__meta_kubernetes_namespace]
      separator: ;
      regex: (.*)
      target_label: namespace
      replacement: $1
      action: replace
    - source_labels: [__meta_kubernetes_pod_name]
      separator: ;
      regex: (.*)
      target_label: pod_name
      replacement: $1
      action: replace

prometheus.yaml の relabel_config

  • https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
  • relabel_configs で取得すべき項目のラベルを作っている

    • source_labels:元ネタ
    • regex正規表現抽出した項目について replace、keep、drop、labelmap、labeldrop,labelkeep でアクションする
    • replace:regex 連結され source_labels たと照合します。次に、設定 target_label に replacement 一致グループの参照(と、${1}、${2}、...)で replacement、その値によって置換されました。regex 一致しない場合、置換は行われません。
      → 一致した部分を target_label に挿入
    • keep:regex 連結に一致しないターゲットをドロップします source_labels。
    • dropregex 連結に一致するターゲットを削除し source_labels ます。
    • hashmod:連結されたハッシュのに設定さ target_label れ modulus ます source_labels。
    • labelmap:regex すべてのラベル名と照合します。その後で与えられたラベル名に一致するラベルの値をコピー replacement 一致グループの参照を(${1}、${2}中、...)replacement その値によって置換されています。
    • labeldrop:regex すべてのラベル名と照合します。一致するラベルは、ラベルのセットから削除されます。
    • labelkeep:regex すべてのラベル名と照合します。一致しないラベルは、ラベルのセットから削除されます。
  • 元ネタには以下のような meta タグを使用する

__meta_kubernetes_namespace: The namespace of the service object.
__meta_kubernetes_service_annotation_<annotationname>: Each annotation from the service object.
__meta_kubernetes_service_annotationpresent_<annotationname>: "true" for each annotation of the service object.
__meta_kubernetes_service_cluster_ip: The cluster IP address of the service. (Does not apply to services of type ExternalName)
__meta_kubernetes_service_external_name: The DNS name of the service. (Applies to services of type ExternalName)
__meta_kubernetes_service_label_<labelname>: Each label from the service object.
__meta_kubernetes_service_labelpresent_<labelname>: true for each label of the service object.
__meta_kubernetes_service_name: The name of the service object.
__meta_kubernetes_service_port_name: Name of the service port for the target.
__meta_kubernetes_service_port_protocol: Protocol of the service port for the target.
__meta_kubernetes_service_type: The type of the service.

検討必要事項

  • メモリを食うので VictoriaMetrics とかで工夫するかメトリクスを減らす必要がある
  • バージョンによって設定項目が変わってしまうので、設定を Code として git 上に残していくことが重要

Jmeter との連携

https://github.com/kubernauts/jmeter-operator

CKA合格した話

先日 CKA を合格しました。
せっかくなので少しだけメモ。
f:id:kashionki38:20200713025427p:plain

事前準備

細かい部分はもう細かく書いている人がいるので、そちらに任せるとしてざっくり把握しておきたのは以下。

出題範囲

  • Application Lifecycle Management (8%)
  • Installation, Configuration & Validation (12%)
  • Core Concepts (19%)
  • Networking (11%)
  • Scheduling (5%)
  • Security (12%)
  • Cluster Maintenance (11%)
  • Logging / Monitoring (5%)
  • Storage (7%)
  • Troubleshooting (10%)

設問数、時間、合格ライン

  • 設問数:24
  • 試験時間:3 時間
  • 合格ライン:74%

勉強方法

基礎知識+修行+当日ドキュメント見ながらで割となんとかなる感じ。

基礎知識

Kubernetes 完全ガイドで基礎知識は OK

www.amazon.co.jp

修行

udemy の Certified Kubernetes Administrator (CKA) with Practice Tests がおすすめ。
私は会社でタダだったけど、ちょくちょくセールしているという噂も聞く。
www.udemy.com

これに Katacoda 上でのハンズオンが付随しており、出題範囲を網羅的にカバーしてくれてるので、Katacoda をひたすら修行することが良かった。
解いている間はできるだけ Document のみを参照するようにして本番と同じような状況を再現してみた。その際に参照するような Document は本番でも参照する可能性が高いので、出題範囲の項目にフォルダ分けして当日参照用のブックマークにしておいた。

ただ一つだけ玉にキズなのが、Katacodaの起動後の準備シェルが遅い+キー反応がかなり悪くてイライラするところ。当日の試験もこんな感じなんだろうかと思っていたら、普通にレスポンス良くて当日はサクサク快適だった。
(逆にそういった意味でも修行なのかもしれない。)
f:id:kashionki38:20200713025817p:plain

受験場所

自宅で受験した。
もともとは WORKSTYLING で受けたかったが、日曜朝 10 時からにしてしまったので空いている場所がなく自宅での受験を余儀なくされた。。
机の上は PC+スクリーン+キーボード+マウスのみにして、周辺のものはブランケットで隠した。
f:id:kashionki38:20200713025043p:plain

始まってから試験官にカメラで周辺を見せるように指示され、無事 OK もらい安心した。

Tips

効率化のために alias と vim の設定はしておいた。

よく使う yaml 元ネタづくり

Pod
$ kubectl run nginx --image=nginx --dry-run=client -o yaml > nginx-pod.yaml
Deployment
$ kubectl create deploy nginx --image=nginx --dry-run=client -o yaml > nginx-dep.yaml
$ kubectl scale deploy nginx --replicas=4

alias

~/.bash_profile
alias k='kubectl'
alias kg='kubectl get'
alias kd='kubectl describe'
source ~/.bashrc

vim

~/.vimrc
:set number
:set autindent
:set expandtab

KubernetesNoviceTokyo で「Kubernetes 環境に対する性能試験」を発表した

今やっていることをとりあえずアウトプットしなければ、外部発表しなければ、と思いちょうど KubernetesNovice が良いタイミングだったので応募してみた。
運営の方々ありがとうございました。皆さんのおかげで私のような小心者な初心者でも外部発表を経験する良い機会を得ることができました。

k8s-novice-jp.connpass.com

speakerdeck.com

一応さらっと中身の説明を書きます。

モチベーション

そもそも私の身の回りの Kubernetes なプロジェクトでは、あまりちゃんと性能評価できている節がないように見える。
それが私の気のせいなのか、一部例しか見れてないのかわからないが、少なくとも弊部署にはナレッジがないので、性能に携わる者として Kubernetes× 性能のベストラプラクティスをまずは整理しておきたいと思った。
本当は性能試験を自動化して開発パイプラインに組み込む DevPerfOps という世界観がこうあるべき、という話までたどり着けると良いなあと思っていたのだが、現時点ではまず性能評価だけでも当たり前のように奥が深く、その深淵の先なのかなと思っている。。。

デモアプリ Sock Shop について

Weaveworks が公開している MSA デモアプリの Sock Shop を K8s v1.16 へ対応させた人の Fork してきて使っている。

github.com

多岐に渡るデプロイ方法が提供されているが、今の所はただ yaml の Manifest を kubectl apply -f しているだけ。
したがって更新しているディレクトリも/deploy/kubernetes/のみ。
ゆくゆくは Helm での管理に倒したいと思っているけど、知識と時間がまだない。

この靴下の EC サイトである Sock Shop を GKE にデプロイして、性能試験っぽいこと(後述)をして、実施 → 評価 → 解析といういわゆる性能改善の営みを回しながらベストラプラクティスを整理している。同時に性能問題事例も収集したい。

アーキテクチャ

f:id:kashionki38:20200706004457p:plain

  • Prometheus & Loki & Jager & Kiali でオブザーバビリティ実装

Prometheus でのメトリクス監視

f:id:kashionki38:20200706004512p:plain

RED + USE を Prometheus で実現
具体的な Prometheus の yaml はこちら(Scrape 設定)
https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-monitoring/prometheus-configmap.yaml

以下 Scraping の設定を列挙するけど、書きながら全然理解できてないことに気づく、、、
要勉強。

今、実装できている部分は最低限の OS リソース系の USE のみ。
本来は MW のリソースについても確認したいし、管理リソースについても監視していきたいので今後の課題である。

prometheus.yaml の relabel_config について

まだまとまってないし翻訳ほぼ貼っただけくらいのやつ。 https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
relabel_configs で取得すべき項目のラベルを作っている

  • source_labels:元ネタ
    • regex正規表現抽出した項目について replace、keep、drop、labelmap、labeldrop,labelkeep でアクションする
  • replace:regex 連結され source_labels たと照合します。次に、設定 target_label に replacement 一致グループの参照(と、${1}、${2}、...)で replacement、その値によって置換されました。regex 一致しない場合、置換は行われません。
    • → 一致した部分を target_label に挿入
  • keep:regex 連結に一致しないターゲットをドロップします source_labels。
  • dropregex 連結に一致するターゲットを削除し source_labels ます。
  • hashmod:連結されたハッシュのに設定さ target_label れ modulus ます source_labels。
  • labelmap:regex すべてのラベル名と照合します。その後で与えられたラベル名に一致するラベルの値をコピー replacement 一致グループの参照を(${1}、${2}中、...)replacement その値によって置換されています。
  • labeldrop:regex すべてのラベル名と照合します。一致するラベルは、ラベルのセットから削除されます。
  • labelkeep:regex すべてのラベル名と照合します。一致しないラベルは、ラベルのセットから削除されます。

元ネタには以下のような meta タグを使用する

__meta_kubernetes_namespace: The namespace of the service object.
__meta_kubernetes_service_annotation_<annotationname>: Each annotation from the service object.
__meta_kubernetes_service_annotationpresent_<annotationname>: "true" for each annotation of the service object.
__meta_kubernetes_service_cluster_ip: The cluster IP address of the service. (Does not apply to services of type ExternalName)
__meta_kubernetes_service_external_name: The DNS name of the service. (Applies to services of type ExternalName)
__meta_kubernetes_service_label_<labelname>: Each label from the service object.
__meta_kubernetes_service_labelpresent_<labelname>: true for each label of the service object.
__meta_kubernetes_service_name: The name of the service object.
__meta_kubernetes_service_port_name: Name of the service port for the target.
__meta_kubernetes_service_port_protocol: Protocol of the service port for the target.
__meta_kubernetes_service_type: The type of the service.

cAdvisor

Pod/Conatiner のリソース使用量は Kubelet バイナリに統合されている cAdvisor に対して Scrape する。
したがって特に Exporter とかは不要。

prometheus.yaml

https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-monitoring/prometheus-configmap.yaml

# Scrape config for Kubelet cAdvisor.
- job_name: "kubernetes-cadvisor"
  scheme: https

  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token

  kubernetes_sd_configs:
    - role: node

  relabel_configs:
    - action: labelmap
      regex: __meta_kubernetes_node_label_(.+)
    - target_label: __address__
      replacement: kubernetes.default.svc:443
    - source_labels: [__meta_kubernetes_node_name]
      regex: (.+)
      target_label: __metrics_path__
      replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
Grafana ダッシュボード

Namespace 内の全 Pod を俯瞰するpod_allと各 Pod とその中の Container を詳細に見るpod_detailを用意した。

node exporter

Node のリソース使用量は NodeExporter を利用。

NodeExporter

https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-monitoring/node-exporter-ds.yml

node exporter を DaemonSet としてデプロイ

prometheus.yaml

https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-monitoring/prometheus-configmap.yaml

- job_name: kubernetes-pods
  kubernetes_sd_configs:
    - role: pod
  relabel_configs:
    - source_labels:
        - __meta_kubernetes_pod_annotation_prometheus_io_scrape
      action: keep
      regex: "true"
    # - source_labels:
    #     - __meta_kubernetes_namespace
    #     - __meta_kubernetes_pod_label_name
    #   separator: /
    #   target_label: job
    - source_labels:
        - __meta_kubernetes_pod_node_name
      target_label: node
    - source_labels: [__meta_kubernetes_namespace]
      action: replace
      target_label: namespace
    - source_labels: [__meta_kubernetes_pod_name]
      action: replace
      target_label: pod_name
Grafana ダッシュボード

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/node-exporter.json

istio-mesh

各サービスごとの RED を見ようと思うと Istio のテレメトリ収集が有用。
APM 使ったり AP で独自にログを出すことでもサービスごとの RED を収集できるとは思うが、APM 使用量や AP 実装についてコストがかかるのでメリデメある印象。
もちろん Istio を入れることでもデメリットはあるはずで、そこを許容してでもマイクロサービスにオブザーバビリティやトラフィックコントロール柔軟性、セキュリティをもたせたいと思うかどうかがポイントになる。
(例えば、Istio のコントロールプレーンや Envoy のデプロイによるリソース使用量増加、すべてのトラフィックを Envoy 経由にすることによるレスポンスへのオーバヘッド増加など)
マイクロサービスを入れておきながら、各依存関係間の RED がわからないと性能評価できるわけないので、実装できないなら Istio 入れるしかないという所感 Istio を入れてしまえば、後は Prometheus の Scrape を設定すればテレメトリ情報は収集可能。

prometheus.yaml

https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-monitoring/prometheus-configmap.yaml

# Mixer scrapping. Defaults to Prometheus and mixer on same namespace.
#
- job_name: "istio-mesh"
  kubernetes_sd_configs:
    - role: endpoints
      namespaces:
        names:
          - istio-system
  relabel_configs:
    - source_labels:
        [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      action: keep
      regex: istio-telemetry;prometheus
Grafana ダッシュボード

以下、Istio-Mesh-DashboardIstio-Workload-Dashboardが今の所わかりやすい。
Istio-Mesh-Dashboardはリアルタイムな RED 把握によく、Istio-Workload-Dashboardは試験後の時系列での RED 把握によい。
とくにIstio-Workload-Dashboardでは、IncomingDuration と OutgoingDuration が見れるので、それにより後続のマイクロサービスからの影響を確認することが可能。
Istio-Mesh-Dashboardは、もし各マイクロサービスについて SLO を設けることができているのであれば、それと比較することができるので Jmeter の結果以外の評価もできるのではないだろうか。

トラシュー

kube-state-metrics

Pod/Container の Status や数を取得するためにkube-state-metricsも導入。
これを入れることで READY な数や、RESTART しているタイミングなどの状況把握が可能。
クラスター内に 1Deployment あれば良い。 https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-monitoring/prometheus-exporter-kube-state-dep.yaml

ものすごい量の情報が取れるのでまずは Doc を読んでみるのもよい。
https://github.com/kubernetes/kube-state-metrics/tree/master/docs

StatefulSet 化+ PersistentVolume

Prometheus に死なれるとリソース情報が全く残らなくてポストモーテムもクソもないので、さすがに Prometheus はせめて PV ででも永続化したほうが良い。
よりメモリ使用量削減や冗長構成を意識して、Victoria Metrics とか Thanos を使った永続化方法もあるようで、今後の課題ではある。
無邪気に Scrape していると Prometheus は結構メモリを食うので、急に OOME なったりするのでそうなってくると Victoria Metrics 付加を検討したい。
https://kashionki38.hatenablog.com/entry/2020/03/06/153039#Prometheus%E3%81%AF%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%A0%E3%81%A8%E3%82%81%E3%81%A3%E3%81%A1%E3%82%83%E3%83%A1%E3%83%A2%E3%83%AA%E9%A3%9F%E3%81%86%E3%82%88

※Victoria Metrics についてはこちら
www.youtube.com

prometheus statefulset

securityContext を付与しないと pv へのアクセス権限がなくエラーが出る

$ k logs prometheus-deployment-0
level=info ts=2020-06-21T22:35:42.534Z caller=main.go:337 msg="Starting Prometheus" version="(version=2.18.0, branch=HEAD, revision=a12e96299dcd159ea09b260f1a21e7e4b86e011d)"
level=info ts=2020-06-21T22:35:42.534Z caller=main.go:338 build_context="(go=go1.14.2, user=root@7fbcff55abdb, date=20200505-14:26:04)"
level=info ts=2020-06-21T22:35:42.534Z caller=main.go:339 host_details="(Linux 4.19.109+ #1 SMP Mon Mar 16 06:27:01 PDT 2020 x86_64 prometheus-deployment-0 (none))"
level=info ts=2020-06-21T22:35:42.534Z caller=main.go:340 fd_limits="(soft=1048576, hard=1048576)"
level=info ts=2020-06-21T22:35:42.535Z caller=main.go:341 vm_limits="(soft=unlimited, hard=unlimited)"
level=error ts=2020-06-21T22:35:42.535Z caller=query_logger.go:87 component=activeQueryTracker msg="Error opening query log file" file=data/queries.active err="open data/queries.active: permission denied"
panic: Unable to create mmap-ed active query log

goroutine 1 [running]:
github.com/prometheus/prometheus/promql.NewActiveQueryTracker(0x26b4395, 0x5, 0x14, 0x2e940a0, 0xc0003d8e40, 0x2e940a0)
        /app/promql/query_logger.go:117 +0x4cd
main.main()
        /app/cmd/prometheus/main.go:368 +0x4ed8

https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-monitoring/prometheus-dep.yaml

prometheus-sts.yaml

template:
  spec:
    securityContext:
      runAsUser: 1000
      runAsGroup: 3000
      fsGroup: 2000
persistent volume

https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-monitoring/prometheus-pv.yml

作成した PV を prometheus-sts 側でマウント

prometheus-sts.yaml

(略)
      containers:
      - name: prometheus
        image: prom/prometheus:v2.18.0
        args:
        - --web.enable-lifecycle
        - --storage.tsdb.no-lockfile
        - --storage.tsdb.retention.time=6h
        - --config.file=/etc/prometheus/prometheus.yml #重要
        volumeMounts:
        - name: config-volume
          mountPath: /etc/prometheus
        - name: alertrules-volume
          mountPath: /etc/prometheus-rules
        - name: prometheus-pv #重要
          mountPath: /prometheus/data
      volumes:
      - name: prometheus-pv #重要
        persistentVolumeClaim:
          claimName: cn-horiuchiysh-prometheus-pvc-prometheus-deployment-0
      nodeSelector:
        beta.kubernetes.io/os: linux
  volumeClaimTemplates: #重要
    - metadata:
        name: cn-horiuchiysh-prometheus-pvc
      spec:
        storageClassName: manual
        selector:
          matchLabels:
            objective: prometheus
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 40Gi

Loki

Loki は Promtail を DaemonSet として各 Node で走らせて標準出力を収集
Grafana の Explore でログを見れるので、Prometheus + Grafana と併用するのに向いている
まだあまり使用検証できてないので今後詳しい話を書いていければ。

取り急ぎ Helm で導入。
https://github.com/kashinoki38/prometheus-sample-yaml/tree/master/loki-helm/loki-stack

$ helm repo add loki https://grafana.github.io/loki/charts #リポジトリの追加
$ helm repo list
$ helm inspect chart loki/loki-stack
$ helm inspect values loki/loki-stack
$ helm install -n monitoring loki/loki-stack --generate-name #リポジトリで公開されているChartを使ってアプリケーションをインストール(デプロイ)する
$ helm list -n monitoring #デプロイされたReleaseの一覧
NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
loki-stack-1591529810   monitoring      1               2020-06-07 20:36:59.2916867 +0900 JST   deployed        loki-stack-0.37.3       v1.5.0

Jaeger & Kiali

Istio を入れることで Jaeger と Kiali も簡単に入れることが可能。

Sock Shop には Kiali が入っていなかったので、以下シェルで Kiali を有効化。
https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/jaeger-kiali/istioctl-jaeger-kiali.sh

Jaeger は以下

$ istioctl manifest apply --set values.tracing.enabled=true

Jaeger でトレーシングさせるためには環境変数に Jaeger の向き先を ZIPKIN として登録する必要があるっぽい。 以下 catalogue,user,payment の deploy に追加

      containers:
      - name: catalogue
        image: weaveworksdemos/catalogue:0.3.5
        env:
         - name: ZIPKIN
           value: http://zipkin.istio-system.svc.cluster.local:9411/api/v1/spans
        command: ["/app"]
        args:
        - -port=80

これもあんまり Sock Shop 検証では使いこなせてないので、今後詳しい話を述べていければ。 Bookinfo サンプルに対しての使いごごちはこちら。 kashionki38.hatenablog.com

今の所言えるのは、マイクロサービスサービス全体の把握をしたい場合は Kiali を眺めるのが一番可視性が良さそうということ

Jmeter

Deployment

以下 Jmeter と InnfluxDB を Deployment としてデプロイ

もとは JmeterOperator をデプロイしてみようとしてたけど、オペレータのリソース使用量が高くやめた。
https://github.com/kubernauts/jmeter-operator

Grafana

InfluxDB に格納された Jmeter 試験結果データ参照用のダッシュボード

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/jmeter-metrics.json

シナリオ

以下のように Jmeter のシナリオを作成。
事前に会員登録しておいたユーザを使って、ログイン → 商品閲覧 → カート投入 → 決済 → オーダ確認のシナリオ。

JmeterDeployment への実行方法はstart_test.shを実行して、シナリオ名を指定すれば良い。
https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-loadtest/start_test.sh

kashinoki38@DESKTOP-NTAMOVN:/mnt/c/Users/motim/sockshop/manifests-loadtest$ sh start_test.sh
Enter path to the jmx file scenario.jmx
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/jmeter/apache-jmeter-5.0/lib/log4j-slf4j-impl-2.11.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/jmeter/apache-jmeter-5.0/lib/ext/pepper-box-1.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Creating summariser <summary>
Created the tree successfully using scenario.jmx
Starting the test @ Sun Jun 28 20:33:48 UTC 2020 (1593376428758)
Waiting for possible Shutdown/StopTestNow/Heapdump message on port 4445
summary +     95 in 00:00:09 =   10.2/s Avg:    81 Min:     5 Max:  2773 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0
summary +    788 in 00:00:30 =   26.3/s Avg:    66 Min:     2 Max:  2589 Err:     0 (0.00%) Active: 3 Started: 3 Finished: 0
summary =    883 in 00:00:39 =   22.5/s Avg:    68 Min:     2 Max:  2773 Err:     0 (0.00%)
summary +   1400 in 00:00:30 =   46.7/s Avg:    73 Min:     2 Max:  3147 Err:     0 (0.00%) Active: 4 Started: 4 Finished: 0
summary =   2283 in 00:01:09 =   32.9/s Avg:    71 Min:     2 Max:  3147 Err:     0 (0.00%)
summary +   1839 in 00:00:30 =   61.3/s Avg:    81 Min:     3 Max:  3719 Err:     0 (0.00%) Active: 6 Started: 6 Finished: 0
summary =   4122 in 00:01:39 =   41.5/s Avg:    75 Min:     2 Max:  3719 Err:     0 (0.00%)
summary +   2065 in 00:00:30 =   68.8/s Avg:    85 Min:     2 Max:  3654 Err:     0 (0.00%) Active: 8 Started: 8 Finished: 0
summary =   6187 in 00:02:09 =   47.9/s Avg:    79 Min:     2 Max:  3719 Err:     0 (0.00%)
summary +   2144 in 00:00:30 =   71.5/s Avg:    87 Min:     2 Max:  4162 Err:     0 (0.00%) Active: 9 Started: 9 Finished: 0
summary =   8331 in 00:02:39 =   52.3/s Avg:    81 Min:     2 Max:  4162 Err:     0 (0.00%)
summary +   2092 in 00:00:30 =   69.7/s Avg:    97 Min:     3 Max:  4235 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary =  10423 in 00:03:09 =   55.1/s Avg:    84 Min:     2 Max:  4235 Err:     0 (0.00%)
summary +   2218 in 00:00:30 =   73.9/s Avg:    91 Min:     2 Max:  3895 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary =  12641 in 00:03:39 =   57.6/s Avg:    85 Min:     2 Max:  4235 Err:     0 (0.00%)
summary +   2035 in 00:00:30 =   67.8/s Avg:   104 Min:     3 Max:  4724 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary =  14676 in 00:04:09 =   58.9/s Avg:    88 Min:     2 Max:  4724 Err:     0 (0.00%)
summary +   2148 in 00:00:30 =   71.6/s Avg:    98 Min:     2 Max:  4252 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary =  16824 in 00:04:39 =   60.2/s Avg:    89 Min:     2 Max:  4724 Err:     0 (0.00%)
summary +   2156 in 00:00:30 =   71.8/s Avg:    96 Min:     2 Max:  4133 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0
summary =  18980 in 00:05:09 =   61.4/s Avg:    90 Min:     2 Max:  4724 Err:     0 (0.00%)
command terminated with exit code 137

試験実施について

このへんで力尽きたし、試験実施の流れはスライドのほうが見やすいのでそちらを見てください mm(_ _)mm