Kubernetes・FaaSをどのように提供しているか
西脇雄基氏:ここまでずっと抽象的なお話をしていたので少し退屈に感じられた方もいるかと思います。そこでここからは、ここまで出てきたお話について、僕たちは実際にどのように提供しているのか、ソリューションにマッピングをしてみたいと思います。
先ほど出てきたオーケストレーターについては、みなさんもKubernetesをご利用されているということなので想像がついていたかと思いますが、我々はマネージドなKubernetesクラスタをアプリケーション開発者にオーケストレーターとして提供しています。
なので、Kubernetesを通して、実際にはステートレスなアプリケーションに対して、スケールアウトやオートヒーリングの機能を提供しています。
もう1つ提供しているのが、Database as a Serviceなどのマネージドミドルウェアサービスです。これはなぜ提供しているかというと、Kubernetesを提供することで、ステートレスなアプリケーションについては、オートヒーリング・オートスケーリングのような実装はわりと簡単に実施できます。純粋にデプロイするソフトウェアの数を変えればいいだけです。
ただ、ステートフルなアプリケーションについては、オートヒーリング、いわゆる障害のときにどういった対応をするのか、また、「パフォーマンスを上げるためにスケールアウトしたい」みたいな時に、どうしてもミドルウェア独自のロジックが必要になってきてしまいます。
なので、そういったアプリケーションについては、オーケストレーターを使ってデプロイをするのではなく、我々が管理しているマネージドなミドルウェアを使ってください、と案内を出しています。
もう、1つ我々が現在提供しているのはFunction as a Serviceになります。ここまで、マネージドなKubernetesクラスタ・マネージドなミドルウェアを提供することで、デプロイやデプロイ後に起きるようなオペレーションはある程度自動化をすることができます。
ただ、我々がシステムを開発・運用しているなかで、まだまだこれらでカバーしきれないオペレーションはたくさんあると感じております。そのため、そういったオペレーションの自動化プラットフォームとして、Function as a Serviceを提供しています。
このFunction as a ServiceはKubernetesのさらにもう1枚上に抽象化レイヤーを噛ませたような実装になっています。
3つのミッションと注力ポイント
ここからは、Managed KubernetesとFunction as a Serviceが、個々のプロダクトに対して現在どういうことをやっていて、どういうかたちで実装されているのか。そして今後どういうことをやろうとしているのかという話をさせていただきます。
Managed Kubernetesでは現在3つのミッションを掲げています。
左から、1つ目は、HA(High Availbility)やパフォーマンス、またプライベートクラウドのほかの機能と密に連携されることが考慮されたKubernetesクラスタをプライベートクラウドユーザーに提供することと。
2つ目は、そのKubernetesクラスタを提供したあとに、継続的に安定稼働させるためにKubernetesクラスタを運用することと。
3つ目、最後はKubernetesクラスタを提供したものの、その上で「じゃあどういうアプリケーションを載せますか。このアプリケーションはまだ載せられないね」みたいなケースは多いです。なので、現在Kubernetesに載っていないようなアプリケーションをどうやったらKubernetesに載せられるかを検討しながら、Kubernetes自身を変えていくのか、アプリケーション自身を変えていくのか、両方のアプローチでKubernetes化を進めていく活動も3つ目のミッションとして入れています。
すべてのミッションを100パーセント達成できているのかというと、実はぜんぜんそういう状況ではなくて、現状は丸で囲っている部分がカバーできているだけです。現状できているのは、HAが考慮されているシンプルなKubernetesクラスタを提供することと、そのKubernetesクラスタで起きるオペレーションを自動化してあげることが現在できていることです。
実はここに最初注力をすると決めたのにはもう1つ背景があります。このサービスを始める前から、いくつかのチームではすでにKubernetesクラスタをプロダクションで運用していました。なので、まずはそういったKubernetesクラスタを我々で巻き取ることで、彼らのオペレーションを楽にしてあげるのことをターゲットとして置いているので、現在はここに注力しています。
API・Rancher・Add-on Managerの3つで構成
ここで我々のManaged Kubernetesのシステムの構成概要をご紹介したいと思います。大きく分けて3つのコンポーネントで成り立っています。
一番左から、APIサーバです。このAPIサーバは我々が独自で開発したものでして、このAPIサーバがユーザーのManaged Kubernetes Systemのインターフェースになります。ここではユーザーからのクラスタの作成リクエストや更新リクエスト、またはワーカーの追加リクエストなどをAPIとして受け付けます。
では、このAPIサーバ自身にKubernetesをデプロイする細かいビジネスロジックが実装されているかというとそうではなくて、実際にはそのようなロジックは真ん中に位置しているRancherと呼ばれるオープンソースのソフトウェアを利用しています。
このRancherは、我々がデプロイしているすべてのKubernetesクラスタのmanagement functionalityに責任を持っています。具体的には、クラスタのデプロイのあとのモニタリングからヒーリングに責任を持っています。
このAPIとRancherで、Kubernetesの基本的なmanagement functionalityはすべて完結しているのですが、Kubernetesをデプロイしたあとに追加でデプロイをしなければいけないミドルウェアは、別でAdd-on Managerという別のコンポーネントを動かしています。
このAdd-on Managerでは、すべてのデプロイされているKubernetesクラスタ上で動かなければいけないミドルウェアの管理をしています。例えば「あるミドルウェアが止まりました。あるミドルウェアをアップグレードしないといけないです。」というときに、このAdd-on Managerが責任を持って実施をしています。
Add-on Management機能でできること
ここからはManaged Kubernetesの特徴をご紹介させていただきたいと思います。1つ目は、先ほど出てきたAdd-on Managerが提供している、Add-on Managementの機能です。
みなさんKubernetesクラスタをすでにご利用されていると思うのであまり詳しいことはお話ししませんが、実際にKubernetesクラスタをデプロイをすると、Kubernetesのコンポーネント、Kubeletやkube-apiserverなどのほかに、追加でデプロイしなければならないミドルウェアは多々あると思います。
例えば、ログを集めるためのFluentdや、モニタリングをするためのPrometheusだったり、もしかしたらIngress Controllerみたいなものをデプロイして、Kubernetesクラスタに対してゲートウェイのような入り口を作るというお話だったり、ほかにもたくさんKubernetesのアドオンと呼ばれるものは、インターネット上にたくさん実装として置いてあります。
ただ、それらを使おうと思ったときには設定をする必要もありますし、それらにバグがあった場合は修正しなければいけません。なので、我々はシンプルなKubernetesクラスタをただ提供するだけではなく、その上で動かすために各プロダクションユーザーが使わなければいけないミドルウェアも追加でマネジメントすることにしています。
そのため、Add-on ManagerがAdd-on APIを提供していて、もしユーザーからログを1箇所に集めたくなりましたという話が出たときは、基本的にAdd-on APIでlog collectingのAdd-onをenableにします。すると、自動的に裏側でそのクラスタに対してログを集めるために必要なソフトウェアがデプロイされる。そんなAdd-onのマネジメント機能を提供しています。
たった5人で130のクラスタと2,000超のノードを運用・開発
また、Managed Kubernetes Systemの根幹部分であるKubernetesの構築や構築後の運用業務は、Rancherを用いて自動化を進めています。
RancherはKubernetesを運用する上で必要なオペレーションの自動化機能を提供しています。具体的には、ノードがハードウェア故障によって利用不可能になった場合、1 API Callでノードの入れ替えが実施可能です。また、クラスタが完全に故障した際も、1 API Callで定期的に取得しているetcdのスナップショットファイルから復旧することができる。
これらの自動化を進めることで、我々プライベートクラウドの開発者は、運用にかける時間を最小限にとどめながら、新規機能の開発ができるようになっています。
また、もう1つ重要な機能なのがモニタリング機能です。
たくさんのKubernetesクラスタをプロビジョニングしているので、モニタリング機能はとても重要です。モニタリングについては、現在は2種類のモニタリングを提供しています。
1つ目は、Rancherが提供しているシンプルなヘルスチェックです。これについては、基本的には各機能がちゃんと動いているのかどうか、0か1で判断するようなヘルスチェックになります。
実際にどんなところをチェックしているかというと、各クラスタのKubernetesのAPIがちゃんと動いているのかどうかというチェックだったり、各Kubernetesクラスタに管理用のエージェントをデプロイしているので、そのエージェントとTCPのコネクションが張れているかどうかのチェックだったり、各KubernetesクラスタのKubeletのステータスであったり、Component Status APIの結果もチェックしています。
もう1つモニタリングの取り組みとして実施しているのが、先ほど紹介したAdd-on Managementの仕組みを通してデプロイしている、PrometheusとGrafanaを利用したアドバンスドなヘルスチェックです。こちらは、基本的には各ミドルウェアのMetrics APIを通して内部的なステートデータを集めて、特定の閾値を決めて、その閾値をベースにこのクラスタがちゃんと動いているのか動いていないのかを判断するモニタリングになります。
これらの自動化や監視の仕組みを用いて、現在130ほどのクラスタと2,000を超えるノードを5名ほどの開発者で開発・運用をしております。
現在のマジョリティは開発環境で検証しているユーザーがほとんどなのですが、10月にプロダクションリリースをしたことから、これからプロダクションでのクラスタは増えることが想定されます。なので、このノード数はこれからもっと増えていくと予想しています。
Managed Kubernetesについての紹介の最後に、今どういうことができていて、これからどういうことに取り組んでいくのかを紹介したいと思います。
ここまでは冒頭紹介したとおり、デプロイやHAの部分、Kubernetesの運用の自動化というとても基本的なところに注力していました。そのため、今できているのはシンプルなHAクラスタの提供とAdd-on機能の提供、オペレーションの自動化についてです。
これらのおかげでいくつかのサービスは現在本番で利用していただいていますが、まだまだプロダクションでの利用事例は多くはありません。そのため、今後よりKubernetesクラスタの適用範囲をもっと広げていくことを軸に、これからの開発を進めていきたいと思っています。具体的には、パフォーマンスの強化やKubernetes利用のハードルを下げるためのAdd-on機能の提供を考えています。
FaaSを開発するモチベーション
続いて、現在企画開発中のFunction Serviceについてご紹介させていただきます。
おそらくみなさんもKubernetesクラスタを使っていらっしゃると思うので、「わざわざFunction Serviceを提供するモチベーションって何なんですか?」と思われる方もいらっしゃると思います。なので、Function Serviceを開発しているモチベーションについてご紹介させていただきたいと思います。
Kubernetesを利用することで、さまざまなオペレーションを自動化することができます。例えば、アプリケーションに障害が起きたときの自動的なアプリケーションのヒーリングであったり、アプリケーションのオートスケーリングやアプリケーションのローリングアップグレードなど、こういったオペレーションは確かに簡単に自動化することができます。
ただ、これらのオペレーション以外にも、アプリケーションを運用・開発しているとき、私たちはもっとさまざまなイベントや運用業務をしていると思います。
例えば、モニタリングシステムで特定のアラートが出たときは、特別なデータを取っておきたい、特別な処理をしたいという話があったり、依存しているシステムや依存しているプライベートクラウドのコンポーネントで、なにかしらの定期メンテナンスがあった、もしくはなにかしらのoutageの情報が出てきたときに、なにか特定の処理を実施したい。また、定期的にこういったバッチ処理を流したい。こういうオペレーションがあると思います。
これらのオペレーションも、もちろんモニタリングシステムであれば、「じゃあ、WebhookのAPIを通して、シンプルなAPIサーバを使って運用の自動化をしましょう」であったり「チャットボットを作りましょう」みたいなさまざまなソリューションがあるとは思いますが、やはりそれらの管理コストも無視することはできないですし、開発するコストもあるので、なんだかんだで自動化をせずにやってしまっている状況もあると思います。
僕たちはそういうユースケースに応えるために、Function Serviceを開発しています。このFunction Serviceは大きく分けて2つの概念で構成されます。
1つが、適切なタイミングで適切なイベントを生成するEvent Providerです。もう1つが、そのイベントを全部集めて、そのイベントに対してFunctionが紐づけられているかどうかをチェックして、Functionが紐づけられている場合はそのFunctionを実行してあげるようなFunction Serviceです。
FaaSの実装と仕組み
これが基本的なコンセプトになりますが、もう少し実装に目を向けて、どういうかたちになっているのかというと、こんな実装になっています。
すごいたくさんのブロックをここに記述をしているので、ここから何か読み取ってくださいといっても、「とくに何も読み取れないよ」というのが正直なところだと思います。ですので、一つひとつのブロックをご紹介したいと思います。
まずは、この左下のFunction Service用のAPIサーバとControllerです。
こちらはKubernetesのCustom Resource Definitionをふんだんに活用して実装しているので、このフロントのAPIサーバは、実際にはほかのKubernetesのAPIと同じように、リクエストに対してそのリクエストに紐づくリソースを裏側で生成して、Kubernetesに保存することだけが責任範囲です。
それをこのControllerという別のコンポーネントがウォッチしていて、生成されたリソースに対して、それをチェックしながら、Functionを新たにデプロイをしたり削除したりというオペレーションを実施しています。
実はこのAPIとControllerの裏側には、Knativeと呼ばれるオープンソースのソフトウェアが動いています。このKnativeと呼ばれるソフトウェアは、Googleが去年オープンソース化したサーバレスのフレームワークです。
Knative自身、中で3つのコンポーネントに分けられています。KnativeのservingとKnativeのbuilding、またはKnativeのeventingです。我々はこれらすべてを利用しています。
具体的にKnativeのbuildingでは何をしているかというと、ユーザーがFunctionを登録するときは、基本的にはソースコード、いわゆるただのPythonプログラムになっています。なので、そのPythonプログラムをもとにコンテナを生成するのがKnativeのbuildingになります。その後、コンテナイメージが作成されると、Knativeのservingによって、そのFunctionがデプロイされます。
また、Knativeのeventingは外部のEvent Providerから入ってくるイベントをウォッチしていて、そのイベントに紐づいているFunctionがあるかどうかというマッピング情報を持っており、そのマッピングが存在すれば、そのFunctionを実行する責任を持っています。
また、このKnativeのservingの実装はIstioに依存していて、IstioのIngress Gatewayを通して必ずFunctionが実行されるモデルになっているので、Istioも我々も環境では動いていて、すべてのFunctionはIstio経由でユーザーに提供されています。
ここまでがFunctionを実行するための仕組みの説明です。ではEventのProviderはどうなっているのかというと、EventのProviderはサポートするイベントによって実装がさまざまなので、今回はOpenStackを例にご紹介したいと思います。
OpenStackでは、各コンポーネントが担当しているリソースになにかしら変化があった場合に、その変化情報をRabbitMQと呼ばれるメッセージングバスに流してあげるような機能がすでに存在しています。
なので、ここで実施をしているのはKnativeのeventingというコンポーネントがRabbitMQのメッセージをコンシュームしていて、そのコンシュームされたデータをもとに、実際に紐づけられているFunctionがある場合はKafkaを通して実行するモデルになっています。
サポートするイベントをより強化したい
ここまでがFunction as a Serviceの実装の概要になります。
では、Function as a Serviceで何ができていて、これから何を取り組むのかというお話をさせていただきたいと思います。
現状できていることは、とてもシンプルなFunctionを実行する機能と、3つのイベントトリガーに現状はサポートしています。
1つ目がOpenStackのリソース変化のイベント。例えば「VMが作成されました」「VMが削除されました」みたいなイベントです。もう1つが、定期実行を支援するようなcronタイプのイベント。また、Functionをデプロイしたあとに、そのFunctionに対してHTTPでFunctionを実行できるようなHTTPイベント。この3つのトリガーを現在は提供しています。
ただ、これらのイベントでどれだけのオペレーションが自動化できるかというと、まだまだそれほど多いとは思っていません。なので、これからFunction Serviceをより意味のあるものにしていくために、プライオリティを上げて取り組もうと考えているのが、サポートするイベントをもっと強化していく部分についてです。
また、Functionのパイプラインであったり同時に実行できる数の制御といったFunctionの細かい挙動のコントロールも、これから取り組んでいこうとしています。
LINEにおけるCloud Nativeのこれから
ここまで、Cloud Nativeをどう捉えていて、どういった問題を解決したくて、どういうプロダクトをどういうかたちで提供しているのか、概要をご紹介させていただきました。最後に、各プロダクトごとのネクストステップではなく、Managed KubernetesやFunction as a Serviceなどを利用して今後どんなことに取り組んでいくのかというお話をさせていただきたいと思います。
今はKubernetesやFunction Serviceなど、直接サーバをユーザーに意識させないような仕組みをユーザーに提供するフェーズで、Managed KubernetesやFunction Serviceの企画・開発、また提供を実施しています。まだまだ導入フェーズなので、これからカバーするユースケースをどんどん増やすための活動や、機能開発により力を入れていく必要があると考えています。
また、もう少し長期的な目線では、KubernetesやFunction Serviceの利用範囲がある程度アプリケーション開発者の間に広まってきたら、その抽象化レイヤーの下側でインフラ利用効率をどうやって上げられるかという部分に、活動するエリアをスイッチしていこうと考えています。
では、インフラの利用効率を上げていくということをどんなオプションを考えているのかというと、2つ考えています。1つがショートタームで、もう1つがロングタームなオプションになります。
ショートタームのオプションについては、現在、Function as a Serviceの裏側も純粋なKubernetesクラスタになっているので、そのKubernetesクラスタを含めて、さまざまなKubernetesクラスタをユーザーに提供している状態です。なので、最初にとろうと思っているアクションは、そのクラスタのresource usageをベースに、クラスタの自動的なスケールインやスケールアウトを実装していこうと考えています。
そうすると、複数のクラスタを提供しているものの、各クラスタの利用usageに合わせてクラスタの大きさが変わってくるので、それを活かしてインフラの利用効率を上げることができるのではないかと考えています。
ただ、このショートタームのソリューションには、「スケールイン・スケールアウトに時間がかかってしまうよね」という課題であったり、これを簡単に実装するために裏側ではバーチャルマシンを使っているんですけど、そうすると「仮想化のオーバーヘッドが残っているよね」という課題が残っているので、ロングタームとしては、やはり1つのKubernetesのインターフェースをユーザーにまずは見せようと考えています。
もしかしたら、その裏側で複数のKubernetesクラスタがFederationのようなかたちで協調して動いているのかもしれませんし、1つの大きいKubernetesクラスタになるのかもしれません。そこはまだ言及はしていませんが、1つのインターフェースで、裏側でアプリケーションのスケジューリングを行ってインフラの利用効率を上げていくというアプローチも考えています。
ただ、まだまだアイソレーション的な課題やスケール的な課題がまだ残っているので、そういったところはKubernetesのupstreamのコミュニティを見ながら、今後継続的に改善していければと考えております。
これで本日のセッションは以上となります。これらのトピックに対して一緒に取り組んでくれる方をまだまだ募集していますので、もし興味がある方がいらっしゃったら、このあとのAsk the Speakerや懇親会で私に声をかけていただければと思います。
本日はありがとうございました。
(会場拍手)