OpenStackDays2018で登壇

去年はセッションを聞くだけだったけど、今年は応募したら通ったので話してきた。タイトルは「大規模ウェブサービスの成長に伴うデプロイ手法の変化から見る技術と文化」というもの。

過去の取り組み、自分がやった取り組みなどをベースにして、そこから学べることは何か?を考えるよい機会になった。また、スライド作成中にCNCF Overviewを知り、歴史の流れから技術選択を見直すということもでき、視野が多少は広がったと思う。

セッション、予想よりもたくさんの人に見に来ていただき、ほぼ満席に近いくらいだったので非常にうれしい。今後も、応募して登壇にチャレンジしていくぞ!

Knativeが目指すもの、考え方を見てみよう

初めてKnativeを触ると、これServerlessなのかな…PaaS…FaaS…?と感じることがありました。このモヤモヤをすっきりさせるべく、コアコンポーネントの1つであるKnative Servingが何をゴールとしているのか、どういう思想なのかを見てみます。

Knative Servingのゴール、対象とするワークロードは何か

motivation.mdに、Servingがどのようなゴールを目指しているのか、対象としてるワークロードは何か、ということが書かれています。これを知ることで、なぜそのような挙動となるのかを理解する助けになります。

まずServingプロジェクトのゴールですが、「サーバーレスなワークロードのための、コモンツールキットとAPIフレームワークを提供すること」と書かれています。そして、Servingが定義するサーバーレスワークロードが以下の3つです。

  1. ステートレス
  2. プロセスのスケールアウトモデルが適用可能
  3. 主にアプリケーションレベル(L7、例えばHTTP)からリクエストされるトラフィックによって駆動

Kubernetesはこのワークロードをサポートする機能(DeploymentやService)を持っています。Knativeはさらに上位レイヤの機能を提供することで開発者がリッチな体験をできるようにする、ということのようですね。ここまで、ゴールとワークロードを見てみると、「PaaS」「FaaS」というキーワードが登場していません。でも、触ってみるとPaaSっぽいな…と感じたりします。ファンクションも扱える…Knativeはいったい何なのでしょうか?

重要なのはワークロードの3つめである、「クライアントからのリクエストによって駆動する」という点じゃないか、と考えました。ここではKnative上で動くコードがRailsやHTTPサーバーのような従来のアプリケーションなのか、FaaSで扱われるファンクションなのかは区別していません。ここを抽象化することで、どちらも使えるようになっています。逆に、これによってServerless…?PaaSなのかFaaSなのか…?と、わかりにくいと感じたのかもしれません。

Knative Servingの考え方とFastContainer

Knativeのサンプルを触っていた時、リクエストをしばらく投げないでいたらデプロイしたアプリケーションのPodが勝手に終了して、1台もいなくなってしまいびっくりした。Knativeを触った人なら同じ体験があるかもしれません。この挙動について、おいおいアプリケーションが動いてないのにユーザーからのリクエストをどう処理するのだ!と疑問に思っても、モチベーション(ゴール、ワークロード)を知っていると理解できます。

要は、1プロセスも動いていない状態だとしても、ユーザーからリクエストが届いたらそれをトリガーとして起動すればよい、という考え方なんですね(最小起動台数のようなものも設定できるのじゃないかなあとは思っています)。これはFaaSではなじみのある考え方ですが、従来のアプリケーションではそうではないので、混乱するのではないでしょうか。

僕が割とすんなり理解できたのはゴールとワークロードを読んだから、というのもありますが、FastContainerアーキテクチャを知っていたから、というのも大きいと思います。このアーキテクチャも、「リクエスト単位でスケールアウト」「一定時間経過・リクエスト処理がなければコンテナを停止」という、Servingと似た思想を持っています。

Knativeという新しいソフトウェアが登場した時、そのアーキテクチャについて既にモデル化されていたことで割とすんなり理解できました。コンテナオーケストレーションツールとしてデファクトスタンダードとなりつつあるKubernetes上に同じようなアーキテクチャで作られたことから、このアーキテクチャが今後重要になる可能性がある、といえるかもしれません。

Knativeのゴール、対象とするワークロード、考え方について見てきましたが、触り始めたばかりの時は既存の概念に引きずられて見てしまっていたなあと実感しました。Serverlessについてもあまり追えていないので、そちらもキャッチアップすることで、さらにKnativeが目指すものが見えてくるのではないか、と考えています。なお次はより詳細について、フローやServing内部のコンポーネントを見ていく予定です。

Knative EventingがGCP PubSubからメッセージを受け取る様子を観察する

Knative EventingはGCP PubSubをバスとして使用することができる。他にも、Kafkaを使ったりもできるようだ。Knativeのオートスケール機能をminikubeで試したメモと同様動く様子を観察してみて、Serverless的な機能だということを確認できた。なお、今回はGKEを使います。

まずはGKE上にクラスタを構築し、IstioとKnative Servingをインストールする。ドキュメントに従って進めればOKなので省略します。

Kevent Eventingのインストール

これも基本的にはドキュメントに従って進めればいい。コマンド一発でできる。

GCP PubSub

ここからが本題。GCP PubSubと連携するための準備を行う。ドキュメントはの通りに進めるとハマった所があったので手順を記録しておく。

以下のコマンドでGCP PubSubのイベントソースをインストールする。

しかし、以下のようなエラーが出る場合がある。

インストール時にGCRにイメージをプッシュしようとしていて、権限がなくてエラーとなっているようであった。高度な認証方式を見つつ、以下のコマンドでクレデンシャルを設定し、再度 ko applyすればよい。

次に、GCP PubSubのトピックを作成。

最後にクラスターバスを作成する。stub-bus.yaml内のkindをClusterBusに変更する必要があります。最初読み飛ばしていていた…

ko applyします。

サービスアカウントの作成

これはドキュメントの通りコマンド実行すればよかった。

Route、Configurationの設定

これもドキュメント通りでOK。RouteはどのConfigurationにトラフィックを流すかを決定して、Configurationは実行するFunction(サンプルではGithub上のコードをapply時にビルド、レジストリに保存しているのでコンテナイメージを意識しなくてもよさそう)を決定しているようだ。

Flowの作成

Flowオブジェクトを作ることで、GCP PubSubに送ったメッセージを受け取れるようになる。TrigerでGCP PubSubのトピックを指定して、Actionでメッセージを流すRouteを指定している。なお、flow.yaml内のresourceを、自分のプロジェクトIDやトピック名に書き換える必要がある。

diffの様子。

applyだ!!!

うまくいくと、GCP PubSubのサブスクリプションが作られる。

次はgcloudコマンドを使ってトピックへメッセージを送る。

Podのログを見てみると、データを受信していることが確認できる。ドキュメントだと送ったメッセージが表示されているけど、なんだかちゃんと表示されていないね。

動作しているコードはfunction.go。メッセージを受け取ってあれこれできそうで、FaaSらしさがでてきたな。なお、gcp-pubsub-functionのPodはしばらくメッセージを受け取らないと終了しているようで、これもFaaSらしいね。(条件は確認しておきたい)。終了した場合でも、メッセージを送るとPodがちゃんと再度作成される。

感想

準備がいろいろ必要だったけど、ある程度形にしてしまえばfunctionとマニフェスト書いて適用、でPubSubとやりとりできるようになるのかな。Knativeのオートスケール機能をminikubeで試したメモを試した時はPaaS的な機能が主だったけど、今回はFaaS的な動きを見ることができておもしろかった。

Knativeのオートスケール機能をminikubeで試したメモ

Knativeが発表されたので、GKEや手元のminikubeで遊んでいた。オートスケール機能について試したよ。autoscale-go/README.mdをminikubeでやった、という記録です。

GKEでもいいけど、今回はminikubeを使う。Mac上にhyperkitを使って構築するので、kubernetes/minikubeを参考にしてminikubeをhyperkitで使えるようにしておく必要があります。

Knative servingのインストール

基本的にドキュメントに従って進めればよいので割愛。

autoscale-goを試す

さて、autoscale-goを試してみる。サンプルアプリをビルドしてコンテナイメージをレジストリに置くのだけど、今回はhub.docker.comに置くことにした。minikubeの場合、minikube上でビルドしてしまえばレジストリに置く必要もないかも。

プッシュ

autoscale-go用のマニフェストを書き換えて、レジストリにプッシュしたイメージを使用する必要がある。公式ドキュメントを真似して、perlで書き換え。

diffを確認…

マニフェストができたのでapplyしましょう。

これで、Knative servingによってPodが作られる。最初は1台しかない。

minikubeの場合、ここから先少しやり方が変わる。スケールアウトのために大量にリクエストを投げるのだが、そこでアクセス用のアドレス・ポートを指定しておく。test.goのオプションで、ipとportを指定します。それぞれの値はMinikube用のインストールドキュメントを見ると確認方法が記載されている。fishの場合だと以下のようにする。

さて、アクセス先の情報も分かったので、test.goでリクエストを投げまくる。

すると…1台だったPodが増えていることが確認できる。minikubeだからか、なかなかRunningにならないのだけどGKEなどで試すと全てRunningになると思う。

test.goの実行を止めると、Podが減っていくことも確認できる。

仕組み

スケールアウト・スケールインすることはわかったが、どういうロジックだろう?と思いドキュメントを眺めると、書かれていた。Pod毎の、完了していないリクエスト平均数(in-flight requestってこういう意味であってるかな)をベースとしているようだ。デフォルトは1.0なので、Podが処理しているリクエストが常に1.0となるようにPodの数を増減している、ということかな?また、より詳細な情報はDEVELOPMENT.mdにあれこれかかれているので読むと良さそう。

感想

スケールアウト機能がServingをインストールするだけでパッと使えたので手軽でよいと思いました(HPAもHeapsterをいれればすぐ使えるか)。おもしろそうなので触ってくぞー。

Rubotyで作ったbotをkubernetes上で動かす

Botを作る方法の一つに、/rubotyがある。これをKubernetes上で動かしたかったので、メモをとっておく。今回は、ruboty-slack_rtmを使ったSlackBotとする。

環境変数としてSLACK_TOKENを指定してrubotyコマンドを実行すればSlack Botとなる。

さて、これをKubernetes上で動かしたい。まずはDockerfile。

次にKubernetesのマニフェスト。

これでOK。RubotyでこれまでBotをいろいろ作ってきて、Kubernetesに載せ替えたい時はこんな感じでOKであろう。

ref: https://github.com/takaishi/hello2018/tree/master/ruboty-on-k8s