Kubernetesのいろは。Kubernetesのいろは。Kubernetesのいろは。2018の14日目の記事です。本日(2018/12/26)の投稿になっているのは、空きがあったため埋めるために参加したからなのであって、決して遅刻などではありません!笑モチベーション私は学部3年生だった去年の2017年6月あたりにオンライン学習プラットフォームを一人で作っていました。ここでいうオンライン学習プラットフォームは、機械学習分野での「オンライン学習」を指します。簡単にいうとニア・リアルタイムで機械学習エンジンのパラメータを更新していく、なんとも難しいシステムです。当初は、単線的にニューラルネットワークでやろうと思っていましたが、そのアルゴリズム(誤差逆伝搬あたり)ゆえに、分散的に処理を実行するのは不可能でした。Cassandraなどを主に使っていましたが、何より一人で構築するのは大変でした。Kafkaという分散メッセージングシステムが出てきたわけですが、このときにメッセージングセマンティックスだったり考えることが多いなと思いました。ありとあらゆるメッセージングシステムがある今の時代に、知識なしでは選定するのは難しいなとその時は思いました。Flinkなどなどです。メッセージングセマンティックはat-least-onceat-most-onceexactly-onceとあるわけです。Pulsarをはじめとして「工夫してくる」セマンティックが登場してきているからです。PulsarでいうとEffectively-once(効率的に一つ)です。短絡的にこれで解決じゃないか!と思うかもしれません。メッセージングセマンティックだけでなくコミュニティの成熟度をはじめとしてAPIのサポート状態、運用の難しさ、障害点の有無など、差異が多少なりとも存在するので、設計要件にあった技術選定ができるかどうかは一概に言えません。話が変わりますが、私がいま専攻している工学という学問でも進学時に受けたガイダンスでは工学は、判断を下すために客観的資料を揃え、決定をする総合性をもつ科学技術である。このような経験を通じて、工学は社会における工業のあり方、工学の意義、役割を改めて問い直し、一層、総合的な視野、判断をもつ科学として脱皮しつづけている。工学は、人間が道具をつくり始めた技術の起源と共に長い歴史をもち、同時に絶えず脱皮、発展をつづける若い体質をもっていると言えよう。工学(英語でエンジニアリング)を実践する人が技師(エンジニア)であり、総合的な問題解決手段の術を知ることがより良いエンジニアリングになれるのではないかと思っています。ProjectであるNATSを使ってみて、自分の知識として消化することを目指しています。今までまとめた関連する備忘録的な記事は以下の通りです。www.1915keke.comwww.1915keke.comwww.1915keke.comwww.1915keke.comwww.1915keke.comwww.1915keke.comwww.1915keke.comwww.1915keke.com本記事のコンテンツ以下のコンテンツがありますので、興味のあるセクションだけでもご覧ください。Systemの略で、オープンソースなメッセージングシステムであるということができます。Streamingです。StreamingAt-least-onceの保証NATSストリーミングサーバーでストリーミングをするメッセージモデルNATSは以下の3つのメッセージモデルをサポートしています。Pub/SubSubjectに対してPublisherというメッセージを配信する人が、Subjectを購読する全ての人にメッセージを配信する配信機構で、Subject自体(NATSサーバー)がブローカーのような役割をする。HTTPリクエストなどと異なり、データを配信するPublisherはレスポンスを待つ必要がないため、非常に高速に、あとの処理をSubscriberに任せることができます。不可抗力ですが、その反面、レスポンスを必要とするようなもの(例えばユーザーデータ取得など)には向いておらず、一方的なデータ配信になります。Replyメッセージモデルを説明します。いくつものSubscriberはいるのですがPub/Subと違ってRequestに対してはReplyという形で返答をすることができます。対多の関係にもすることができます。Reply'などレスポンスを返すものをサポートしているのは珍しいため、NATSのユースケースとしてはメッセージングに限らないです。Queueこの図はあくまでもイメージ図なので気をつけてください。Kafkaと違って、あらかじめTopicを立てる必要がありません。ストリーム処理の中でのロードバランサーの役割を果たすものです。Nameを持つキューで構成するものを購読するSubscriberどれか一つに配信されます。どれか一つということが重要で、分散的に処理することができるというわけです。GroupのどれかのQueueに入ります。一つのSubscriberに配信されます。Serverでの話をします。Serverは一般的なWebサーバーとしても簡単な動作はすることはできるでしょう。ReplyメッゼージモデルによってレスポンスをReplyできるからです。恩恵としては、クライアントとサーバーが1対1である必要がない点だと思います。ストリームのメッセージに対して永続化を目的とするSubscriberと、Responceを高速化するためのSubscriberがあると、永続化とレスポンスを同時に並行的に行えたりします。Serverを使うことができます。ザーピングレイヤと呼ばれる高速なDBを用いて可視化に対して高速にレスポンスできるようにします。直近のメッセージはスピードレイヤでストリーム処理され、(ニア)リアルタイムで可視化できるようにリアルタイムビューにします。Kafkaに分散クエリを投げたりしていました。www.1915keke.comこのアーキテクチャのメリットとして、「ある確かさ」でのストリーム処理をできることでしょう。ストリーム処理の結果はバッジ処理によってより確かなものになるので、少し粗い(ニア)リアルタイムビューを表示しても問題は少ないです。これに対して、さらに発展したカッパアーキテクチャというものがあります。これはラムダアーキテクチャがバッジ処理とストリーム処理の両方を実装しなければならないところを指摘して、より開発効率のよいアーキテクチャになっています。これはメッセージブローカー(ここでいうNATSサーバー)がメッセージを一定期間保持して、過去のメッセージと現在のメッセージに対してストリーム処理をします。処理が冪等であるならば、適宜バッジ処理をするようになります。アーキテクチャはシンプルな一方で、ストリーム処理に対して過去のデータの流し込むとメモリ消費量の増加などをはじめとする負荷があがってしまうので気をつけなければなりません。構築編Helmを使ってインストールHelmが使える状態であることを前提にしています。本記事を書く前に、拝見させていただいた以下の記事があります。Chartがなかったのですが6月に登場し、簡単にKubernetesにデプロイできるようになっています。それでは始めていきましょう。Helmを使ってインストールします。stable/nats少しインストールまで待ちます。次にサービスを取得します。app=natsすると以下のようになります。6mこのようにサービスがあり、Podは以下のようにStatefulsetなものが一つあります。7mMonitoringサービスMonitoringサービスを使ってみましょう。NATSは以下のようなJSONを返すエンドポイントを持っています。クライアントの接続数やCPU使用率など。現在のコネクションについてvarzより詳しい情報を提供。クライアントそのものの情報。クラスタでアクティブなルーティングを提供。現在の購読について詳しい情報を提供。サブスクライバー数や、メッセージ数など。GUIでも確認できるのできます。8222:8222そして、以下のようにブラウザで情報を取得できればおっけいです。Terminalからも同様に取得できます。[]}GUIから見るとわかりやすいってこともないので、あまり使い勝手がよいとは言えません。サードパーティのDashboardを使ってみる以下のプロジェクトによってNATSのモニタリングを可視化するダッシュボードを構築することができます。github.comまず、以下のように取得します。natsboardそして起動するだけです。natsboard内容的には定期的にAPIから取得しているだけです。可視化をするには便利なものなので、あとから再度、使ってみます。実装編Pub/Subメッセージモデル使用するライブラリは公式のGoライブラリを使います。github.com以下のようにインストールしてください。github.com/nats-io/go-natsまた、今回はClientサーバーにアクセスするため、再度ポート転送しなければなりません。以下のようにメッセージを送る、上流の方のコードを実装します。図にすると以下のよう箇所に該当します。接続を確立させるチュートリアルにはnats.DefaultURLというようにnats.DefaultURLが割り当てられています。接続を確立するところまで書きましょう。nc.Close()}実行するとエラーが出ます。1これは認証に失敗して接続ができない状態だからです。NATSには二つの認証方法があり、UsernameとPasswordによるものTokenによるものの二つがあります。今回はHelmを使ってインストールしたのでデフォルトの前者を使っていきます。以下のように取得をすることができます。ここでNATSモニタリングサービスのログインに使うユーザー名とパスワードは以下のコマンドで確認することができます。$NATS_PASS"これで取得することができます。(10)になっています。各々で設定をする場合は以下のようにHelmのValueファイルを作るといいでしょう。EOFそしてHelmにデプロイするときに-fオプションをつけてこのファイルを指定するといいでしょう。stable/natsnats.Connectメソッドに第二引数であるOptionを渡すことができるので以下のように実装します。nc.Close()}そして実行すると無事エラーなく接続することができました。hoge.goだいたいは環境変数にて設定するので以下のようにします。.envには以下のように記述する。nc.Close()}です。Service(KMS)を使えばよいでしょう。www.1915keke.com今回は、本質的ではないのでこのまま進めます。再度、ダッシュボードでConnectionをみるとプログラムが実行中の間は以下のようにでます。最初のメッセージストリーム実装なので複数のSubscriberがSubjectからメッセージを受け取れることを確認しましょう。今回は試しに3つのSubscriberを動作させます。出力は以下の通りです。ダッシュボードは以下のようになっています。inよりoutが約3倍くらい大きな値となって正常でしょう。メッセージをPublishする以下のコードを付け足してメッセージをPublishします。Subjectgreetingに入れてみます。time.Millisecond)}1秒あたり10メッセージが含まれているはずです。今回は1000メッセージを逐次処理で入れてみます。ここで第一引数はsubjectです。実行してみると以下のようになります。標準出力は以下の通りです。times..そしてダッシュボードは以下のようになっています。オーバーヘッドがあるため完全に10メッセージ/秒ではありませんが、だいたいは届けられています。Subscriber側メッセージを受け取る方の実装です。対象箇所は以下の通りです。Subscribeをする接続するのはPublisherと同様なので省略します。以下のように先ほど定義したgreetingサブジェクトを購読します。三つの方法があります。非同期的(コールバック)で実装する以下のようにコールバックで実装します。!!!")これによって非同期的にメッセージがサブジェクトにPublishされると実行されます。今後のためにも簡単なシェルスクリプトを書きます。すると以下のようになりました。!!!Sleepしているはずなのに、Callbackで受けることができているのです。スクリプトの実行順序的に17からスタートしています。仮にmain関数のtime.Sleep()をなくすと即時に終了してしまうので注意が必要です。同期的に実装する同期的に実装するには以下のようにSubscribeSyncメソッドを使えばいいでしょう。string(m.Data))timeoutはその時間メッセージのPublishがなければ終了するような時間を指定します。このまま実行すると一つだけ取得して終了します。出力は以下の通りです。非同期的(コールバック)で実装する**では、time.Sleep()を取り除くとmain関数が何もすることがなくなるので即時終了されますが、同期処理はすぐ終わることはありません。うまく表現できないのですが、例えば以下のようなコードではメッセージを受け取るのにmain関数がブロックされてしまいます。!!!")とりあえず、同期を取らなければならないときは必要な機能です。チャネルで受け取るチャネルを使っても受け取ることができます。以下のようにSubscribeします。<-chメッセージが来るまで待ってしまっているので、同期処理のような実装になっています。わかりやすく、以下のようにするとメッセージがPublishされない状態だとmain関数はブロックされてしまいます。Publisherは何もPublishしていない状態です。🔥")何も動きません。何かメッセージをPublishしたときは動きます。完全に同期が取れています。msgで受けなくても<-chだけでやっても一緒です。これを非同期的にするには、並行処理ができればなんてことはありません。これはNATSに限らず、goのチャネルを使った並行処理実装では基本的な知識でしょう。!!!")実行すると以下のような結果になります。!!!ここまでSubscriberについてやってきて一通り終わりました。試しにダッシュボードでみてみようと思います。綺麗にoutがあって良いですね。購読を終了するにはUnsubscribeをします。Replyメッセージモデルを実装して確認してみます。Request側まずはメッセージを発信するRequest側の実装です。以下のようにRequestを配信します。1と出て、エラーになります。それはreplyを待っているのに何もこずにタイムアウトするからです。次にSubscriberを実装します。there?"(=だれかいますか?)っていうメッセージだったので、返事をしてみましょう。今回はここにいるよとreplyをするコードを書きます。here"))})そしてSubscriberを実行して、Publisherを実行すると以下のようになりました。hereこのようにRequestに対してResponceをすることができました。ここで仮に、普通のSubscriberがいたらどのようになるのでしょうか。Pub/Subのセクションで使った以下の機能をもつスクリプトを実行します。string(m.Data))})図としては以下のような状態になっています。普通のSubscriberの出力は以下のようになりました。!!!そしてReplyをするものは何もPrintしていないので、何も出ていません。Publisherですが、以下のようになっており、やり取りは正常にできている様子です。hereQueueメッセージモデル次はQueueのメッセージモデルを試してみます。以下のように簡単に実装できます。Groupの名前はキャメルケースでなければ動作しないことに気をつけてください。結果は以下のようになります。Groupを分けられれば以下のように構築することもできます。アドバンス編WildcardでSubjectを指定する方法とSubjectの階層設計Wildcardを使ってSubjectを指定することができ、.で区切られるトークンごとに使うことができます。*これはgreeting.*とすることでgreetinggreeting.afternoongreeting.morninggreeting.midnigth.quietなど何にでもマッチします。>これは>よりあとのトークンがあればマッチします。greeting.>とあればgreetingにはマッチしないもののgreeting.afternoongreeting.morninggreeting.midnigth.quietにはマッチをします。再度注意ですがgree*>ingなどとトークン内では使うことができないのです。逆にいうとSubjectが設計を満たすように設計をしなければなりません。オブジェクト指向言語で、ひたすらクラスやドメインを抽象化して、共通部分を抜き出しきたエンジニアなら分かりやすいと思います。(人間)という集合には(日本人)や、(米国人)などの集合があります。(東京都民)という集合があって、、、と概念ごとに積層化することがわかりやすいSubjectになるのではないかと思います。Serverが監視対象にアクセスして各種メトリクスなどデータを収集してくるアーキテクチャです。Serverからのアクセスポイントとして設定しているものをExporterといいます。node_exporterはここではGKEのKubernetesクラスタを構築するNodeのデータを提供しています。NATS自体のモニタリングもExporterを持って行うことができます。簡単に示すと以下のようになっています。Exporterがアプリケーションサーバーとどのような関係であるかは、実はSidecarの関係になっています。upgradeによってデプロイするようにします。実際には、以下のようにmetrics.enabledで設定します。stable/natsこれによってSidecarであるExporterがデプロイされています。確認までにPodをみてみましょう。Exporterの二つがあります。ローカルからアクセスするには以下のようにポート転送をしてください。7777:7777確認までに以下のようなリクエストを送ってください。gauge...とメトリクスのレスポンスが返ってきます。これからPrometheusが必要となるのでインストールをします。最初にモニタリングのためのnamespaceを作りましょう。monitorそしてHelmでPrometheusをインストールします。stable/prometheus次にGrafanaをインストールいます。stable/grafana最初にGrafanaのパスワードを取得します。ユーザー名はAdminです。echoそしてポート転送をしてログインをします。3000KubernetesクラスタのモニタリングPrometheusとGrafanaの全体像を掴んでほしいのでまずは簡単なKubernetesのNodeのモニタリングからやりましょう。全体の流れとしては以下のようになっています。ますは先ほどGrafanaのポート転送をしたと思いますが、そのURLにブラウザからアクセスしてください。最初に以下のような画面が見えると思います。Grafanaにログインできると以下のような画面が見えます。sourceをクリックすると以下の画面になるのでPrometheusを選択します。すると以下の画面になります。ここではKubernetesの内部DNSに問い合わせることになるのでHTTP.URLをhttp://prometheus-server.monitor.svc.cluster.localにすれば正しいです。Kubernetesにあまり詳しくない人は、内部DNSはよく使う項目なので調べておいても損はありません。ここまでで、以下の設定ができました。このまま使うとGrafanaでメトリクスを可視化するためにコードを書かないといけません。そのため既存のDashboardを使って構築します。Labsというサイトで探せて、今回は以下のものを使います。Dashboardを追加するボタンにImportというものがあるので選択をしてください。すると以下のように設定ができます。prometheusの箇所に先ほど定義したデータソースを指定します。これでKubernetesクラスタのモニタリングができるようになりました。常にクラスタノードのメトリクスをフィードバックしてもらえるのは非常によいですね。Exporterからメトリクスを取得するPrometheusはデフォルトではtarget(対象)は、KubernetesのNodeに対してのメトリクスを提供するnode_exporterだけです。以下の図のようにPrometheusからNATSのメトリクスを取得するURLにアクセスする必要があります。データを取得してくることをScrapeというのですが、PrometheusではScrape対象を記述するscrapes_configs[]に追加します。PrometheusのGUIで確認してみます。Targetにありました。Dashboardを使用します。先ほどと手順は同様です。最終的には以下のような監視をすることができます。これまでに作ったスクリプトを使って監視をしてみましょう。メッセージングなのでPrometheusのScrap時間が長いように感じました。デフォルトではPrometheusがメトリクスを取ってくるインターバルは1分なので変更します。Intervalを設定できます。Nativeにメッセージングシステムを構築できることがわかって、非常に面白かったです。メッセージングはエンジニアとしてデータベースなどの知識と同様に必要最低限であるので、さらに知識を広くすることができてよかったです。Experience(=開発経験)はよかったです。これからばしばし使って行こうと思います。NativeやKubernetesなどいろんな勉強会に出て、もっといろんな知識を蓄えたいと思います。カオスだった平成最後の日に。日本では未だ、マイクロサ...2018-12-23Concourseで継続的デリバリー。Concourseで継続的デリバリー。»プロフィール学生エンジニア。忘れてしまうので備忘録です。flaskでServerlessにホストするTelepresence概論スターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。