1. 序章

このチュートリアルでは、Kubernetesプラットフォームにサーバーレスワークロードをデプロイする方法について説明します。 このタスクを実行するためのフレームワークとしてKnativeを使用します。 その過程で、サーバーレスアプリケーションのフレームワークであるKnativeを使用する利点についても学びます。

2. KubernetesとKnative

私たちを助けるツールなしでサーバーレスアプリケーションを開発するのは楽しいことではありません! DockerとKubernetesの組み合わせにより、クラウドネイティブアプリケーションの管理がマイクロサービスアーキテクチャでどのように構築されたかを思い出してください。 確かに、サーバーレススペースでもフレームワークとツールの恩恵を受けることができます。 さて、Kubernetesがここで私たちを助けられない理由はありません。

2.1. サーバーレス向けKubernetes

Kubernetes は、CNCFの卒業プロジェクトとして、コンテナ化されたワークロードのオーケストレーションの分野で最有力候補の1つになりました。 DockerBuildahなどの一般的なツールを使用して、 OCIイメージとしてパッケージ化されたアプリケーションの展開、スケーリング、および管理を自動化できます。

明らかな利点には、最適なリソース使用率が含まれます。 しかし、それはサーバーレスでも同じ目的ではありませんか?

もちろん、コンテナオーケストレーションサービスとサーバーレスサービスで達成しようとしていることに関しては、いくつかの重複があります。 ただし、Kubernetesは多くのものを自動化するための優れたツールを提供してくれますが、それを構成および管理する責任は引き続きあります。 サーバーレスはそれさえも取り除くことを目指しています。

ただし、Kubernetesプラットフォームを活用して、サーバーレス環境を実行することはできます。 これには多くの利点があります。 まず、特定のクラウドベンダーに縛られているベンダー固有のSDKやAPIから逃れるのに役立ちます。 基盤となるKubernetesプラットフォームは、サーバーレスアプリケーションをあるクラウドベンダーから別のクラウドベンダーに比較的簡単に移植するのに役立ちます。

さらに、アプリケーションを構築するための標準のサーバーレスフレームワークのメリットを享受できます。 Ruby on Railsのメリットを忘れないでください。また、SpringBootが遅くなります。 最も初期のそのようなフレームワークの1つはAWSから出てきて、サーバーレスとして有名になりました。 これは、Node.jsで記述されたオープンソースのWebフレームワークであり、サーバーレスアプリケーションを複数のFaaSサービスプロバイダーにデプロイするのに役立ちます。

2.2. Knativeの紹介

Knative は、基本的にオープンソースプロジェクトであり、Kubernetes でサーバーレスアプリケーションをデプロイ、実行、管理するためのコンポーネントを追加します。 サービスまたは機能をコンテナイメージとしてパッケージ化し、Knativeに渡すことができます。 Knativeは、必要な場合にのみ、特定のサービスのコンテナーを実行します。

Knativeのコアアーキテクチャは、基盤となるKubernetesインフラストラクチャ上で実行されるServingとEventingの2つの広範なコンポーネントで構成されています。

ネイティブサービングを使用すると、必要に応じて自動的にスケーリングできるコンテナーを展開できます。 オブジェクトのセットをカスタムリソース定義(CRD)としてデプロイすることにより、KubernetesとIstioの上に構築されます。

Knative Servingは、主に 4つのオブジェクト、Service、Route、Configuration、およびRevisionで構成されます。 Serviceオブジェクトは、ワークロードのライフサイクル全体を管理し、RouteやConfigurationなどの他のオブジェクトを自動的に作成します。 サービスを更新するたびに、新しいリビジョンが作成されます。 トラフィックを最新またはその他のリビジョンにルーティングするようにサービスを定義できます。

Knative Eventing は、アプリケーションのイベントを消費および生成するためのインフラストラクチャを提供します。 これは、イベント駆動型アーキテクチャとサーバーレスアプリケーションを組み合わせるのに役立ちます。

Knative Eventing は、Source、Broker、Trigger、Sinkなどのカスタムリソースで機能します。 次に、トリガーを使用してイベントをフィルタリングし、サブスクライバーに転送できます。 サービスは、ブローカーにイベントを発行するコンポーネントです。 ここでのブローカーは、イベントのハブとして機能します。 トリガーを使用して任意の属性に基づいてこれらのイベントをフィルタリングし、シンクにルーティングできます。

Knative Eventingは、HTTP POSTリクエストを使用して、CloudEventsに準拠するイベントを送受信します。 CloudEventsは、基本的にイベントデータを標準的な方法で記述するための仕様です。 目的は、サービスとプラットフォーム間でのイベントの宣言と配信を簡素化することです。 これは、CNCFサーバーレスワーキンググループの下のプロジェクトです。

3. インストールとセットアップ

前に見たように、Knativeは基本的に、IstioのようなサービスメッシュとKubernetesのようなワークロードオーケストレーションクラスター上で実行されるServingやEventingのようなコンポーネントのセットです。 次に、操作を簡単にするためにインストールする必要のあるコマンドラインユーティリティがあります。 したがって、Knativeのインストールを続行する前に確認する必要のある依存関係はほとんどありません。

3.1. 前提条件のインストール

Kubernetesをインストールするためのオプションはいくつかありますが、このチュートリアルではそれらの詳細については説明しません。 たとえば、 Docker Desktop には、ほとんどの目的を果たす非常にシンプルなKubernetesクラスターを有効にする可能性があります。 ただし、簡単なアプローチの1つは、Docker(kind)でKubernetesを使用して、DockerコンテナノードでローカルKubernetesクラスターを実行することです。

Windowsベースのマシンでは、kindをインストールする最も簡単な方法は、Chocolateyパッケージを使用することです。

choco install kind

Kubernetesクラスターを操作する便利な方法の1つは、コマンドラインツールkubectlを使用することです。 ここでも、Chocolatyパッケージを使用してkubectlをインストールできます。

choco install kubernetes-cli

最後に、 Knativeには、knというコマンドラインツールも付属しています。 Knative CLIは、Knativeリソースを作成するための迅速で簡単なインターフェースを提供します。 また、自動スケーリングやトラフィック分割などの複雑なタスクにも役立ちます。

Knative CLIをWindowsマシンにインストールする最も簡単な方法は、互換性のあるバイナリを公式リリースページからダウンロードすることです。 次に、コマンドラインからバイナリの使用を開始できます。

3.2. Knativeのインストール

すべての前提条件が整ったら、Knativeコンポーネントのインストールに進むことができます。 ネイティブコンポーネントは、基盤となるKubernetesクラスターにデプロイするCRDの集まりにすぎないことはすでに見てきました。 これは、コマンドラインユーティリティを使用した場合でも、個別に行うのは少し複雑な場合があります。

幸い、開発環境では、クイックスタートプラグインを利用できます。 このプラグインは、Knativeクライアントを使用してKindにローカルKnativeクラスターをインストールできます。 以前と同様に、このクイックスタートプラグインをWindowsマシンにインストールする最も簡単な方法は、公式リリースページからバイナリをダウンロードすることです。

quickstartプラグインは、ロールする準備をするためにいくつかのことを行います! まず、Kindがインストールされていることを確認します。 次に、knativeというクラスターを作成します。 さらに、デフォルトのネットワーク層として Kourier を使用し、DNSとしてnio.ioを使用してKnativeServingをインストールします。 最後に、Knative Eventingをインストールし、メモリ内のブローカーとチャネルの実装を作成します。

最後に、クイックスタートプラグインが正しくインストールされていることを確認するために、Kindクラスターにクエリを実行し、knativeというクラスターがあることを確認できます。

4. Knativeを実際に体験する

これで、Knativeが提供する機能のいくつかを実際に試すのに十分な理論を実行しました。 まず、コンテナ化されたワークロードで遊ぶ必要があります。 JavaでシンプルなSpringBootアプリケーションを作成し、Docker を使用してそれをコンテナー化することは、非常に簡単なことです。 これについては詳しく説明しません。

興味深いことに、Knativeは、アプリケーションの開発方法を制限していません。 したがって、以前と同じように、お気に入りのWebフレームワークを使用できます。 さらに、フルサイズのアプリケーションから小さな機能まで、さまざまなタイプのワークロードをKnativeにデプロイできます。 もちろん、サーバーレスの利点は、より小さな自律機能を作成することにあります。

コンテナ化されたワークロードを作成したら、主に2つのアプローチを使用してこれをKnativeにデプロイできます。 すべてのワークロードが最終的にKubernetesリソースとしてデプロイされるため、はリソース定義を使用してYAMLファイルを作成し、kubectlを使用してこのリソースをデプロイできます。 または、Knative CLIを使用して、これらの詳細に立ち入ることなくワークロードをデプロイすることもできます。

4.1. ネイティブサービングを使用した展開

まず、ネイティブサービングから始めます。 KnativeServingが提供するサーバーレス環境にワークロードをデプロイする方法を理解します。 前に見たように、 Serviceは、アプリケーションのライフサイクル全体の管理を担当するKnativeServingオブジェクトです。 したがって、このオブジェクトをアプリケーションのYAMLファイルとして説明することから始めます。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: my-service
spec:
  template:
    metadata:
      name: my-service-v1
    spec:
      containers:
        - image: <location_of_container_image_in_a_registry>
          ports:
            - containerPort: 8080

これは、アクセス可能なレジストリで利用可能なアプリケーションのコンテナイメージの場所を示す非常に単純なリソース定義です。 ここで注意すべき唯一の重要なことは、spec.template.metadata.nameに提供した値です。 これは基本的にリビジョンに名前を付けるために使用され、後でそれを識別するのに役立ちます

このリソースのデプロイは、KubernetesCLIを使用すると非常に簡単です。 YAMLファイルにmy-service.yamlという名前を付けたと仮定して、次のコマンドを使用できます。

kubectl apply -f my-service.yaml

このリソースをデプロイすると、Knativeはアプリケーションを管理するために私たちに代わっていくつかの手順を実行します。 まず、このバージョンのアプリケーションの新しい不変のリビジョンを作成します。 次に、ネットワークプログラミングを実行して、アプリケーションのルート、入力、サービス、およびロードバランサーを作成します。 最後に、必要に応じてアプリケーションポッドを拡大および縮小します。

YAMLファイルの作成が少し不器用に思える場合は、KnativeCLIを使用して同じ結果を得ることができます。

kn service create hello \
  --image <location_of_container_image_in_a_registry> \
  --port 8080 \
  --revision-name=my-service-v1

これははるかに単純なアプローチであり、同じリソースがアプリケーションにデプロイされます。 さらに、Knativeは、要求に応じてアプリケーションを利用できるようにするために同じ必要な手順を実行します。

4.2. ネイティブサービングを使用したトラフィック分割

サーバーレスワークロードを自動的に上下にスケーリングすることだけが、KantiveServingを使用する利点ではありません。 サーバーレスアプリケーションの管理をさらに簡単にする他の多くのパワー満載の機能が付属しています。 このチュートリアルの限られた範囲では、これを完全にカバーすることはできません。 ただし、そのような機能の1つは、このセクションで焦点を当てるトラフィック分割です。

Knative Servingのリビジョンの概念を思い出すと、デフォルトでKnativeがすべてのトラフィックを最新のリビジョンに転送することに注意してください。 ただし、以前のすべてのリビジョンがまだ利用可能であるため、特定またはすべてのトラフィックを古いリビジョンに転送することはかなり可能です。

これを実現するために必要なのは、サービスの説明があった同じYAMLファイルを変更することだけです。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: my-service
spec:
  template:
    metadata:
      name: my-service-v2
    spec:
      containers:
        - image: <location_of_container_image_in_a_registry>
          ports:
            - containerPort: 8080
  traffic:
  - latestRevision: true
    percent: 50
  - revisionName: my-service-v1
    percent: 50

ご覧のとおり、リビジョン間のトラフィックの分割について説明する新しいセクションを追加しました。 Knativeに、トラフィックの半分を新しいリビジョンに送信し、残りのトラフィックを以前のリビジョンに送信するように依頼しています。 このリソースをデプロイした後、すべてのリビジョンをリストすることで分割を確認できます。

kn revisions list

Knativeを使用すると、トラフィック分割を非常に簡単に実現できますが、実際に何に使用できるでしょうか。 この機能にはいくつかのユースケースがあります。 たとえば、青緑色やカナリアなどの展開モデルを採用する場合、Knativeでのトラフィック分割は非常に便利です。 A / Bテストのような信頼醸成措置を採用したい場合も、この機能を利用できます。

4.3. ネイティブイベントを使用したイベント駆動型アプリケーション

次に、 KnativeEventingについて見ていきましょう。 以前に見たように、Knative Eventingは、イベント駆動型プログラミングをサーバーレスアーキテクチャにブレンドするのに役立ちます。 しかし、なぜイベント駆動型アーキテクチャを気にする必要があるのでしょうか。 基本的に、イベント駆動型アーキテクチャは、イベントの生成、検出、消費、およびイベントへの反応を促進するソフトウェアアーキテクチャパラダイムです

通常、イベントは状態の重要な変化です。 たとえば、注文が受理から発送される場合です。 ここでは、イベントのプロデューサーとコンシューマーが完全に切り離されています。 現在、どのアーキテクチャでも分離されたコンポーネントにはいくつかの利点があります。 たとえば、分散コンピューティングモデルの水平スケーリングを大幅に簡素化します。

Knative Eventingを使用するための最初のステップは、ブローカーを利用できるようにすることです。 これで、通常、標準インストールの一部として、クラスターメモリ内ブローカーを使用できるようになります。 利用可能なすべてのブローカーを一覧表示することで、これをすばやく確認できます。

kn broker list

現在、イベント駆動型アーキテクチャは非常に柔軟性があり、単一のサービスから数百のサービスの複雑なメッシュまで単純にすることができます。 Knative Eventingは、アプリケーションの設計方法に制限を課すことなく、基盤となるインフラストラクチャを提供します。

このチュートリアルのために、イベントの生成と消費の両方を行う単一のサービスがあると仮定します。 まず、イベントのソースを定義する必要があります。 以前にソースに変換するために使用したのと同じサービスの定義を拡張できます。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: my-service
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/minScale: "1"
    spec:
      containers:
        - image: <location_of_container_image_in_a_registry>
          env:
            - name: BROKER_URL
              value: <broker_url_as_provided_by_borker_list_command>

ここでの唯一の重要な変更は、ブローカーURLを環境変数として提供していることです。 これで、以前と同様に、kubectlを使用してこのリソースをデプロイするか、代わりにKnativeCLIを直接使用できます。

Knative Eventing は、HTTP POST を使用してCloudEventsに準拠するイベントを送受信するため、アプリケーションでこれを使用するのは非常に簡単です。 CloudEventsを使用してイベントペイロードを作成し、任意のHTTPクライアントライブラリを使用してブローカーに送信するだけです。

4.4. ネイティブイベントを使用してイベントをフィルタリングおよびサブスクライブする

これまでにイベントをブローカーに送信しましたが、その後はどうなりますか? さて、私たちが興味を持っているのは、これらのイベントをフィルタリングして特定のターゲットに送信できることです。 このために、トリガーを定義する必要があります。 基本的に、ブローカーはトリガーを使用してイベントを正しいコンシューマーに転送します。  これで、プロセスで、任意のイベント属性に基づいて送信するイベントをフィルタリングすることもできます。

前と同じように、トリガーを記述したYAMLファイルを簡単に作成できます。

apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
  name: my-trigger
  annotations:
    knative-eventing-injection: enabled
spec:
  broker: <name_of_the_broker_as_provided_by_borker_list_command>
  filter:
    attributes:
      type: <my_event_type>
  subscriber:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: my-service

これは、イベントのシンクとしてもソースとして使用したのと同じサービスを定義する非常に単純なトリガーです。 興味深いことに、このトリガーでフィルターを使用して、特定のタイプのイベントのみをサブスクライバーに送信しています。 より複雑なフィルターを作成できます。

これで、以前と同様に、kubectlを使用してこのリソースをデプロイするか、KnativeCLIを使用してこれを直接作成できます。 さまざまなサブスクライバーにイベントを送信するために、必要な数のトリガーを作成することもできます。 このトリガーを作成すると、サービスは任意のタイプのイベントを生成できるようになり、そのうちの特定のタイプのイベントを消費します。

ネイティブイベントでは、シンクはアドレス可能または呼び出し可能リソースにすることができます。 アドレス可能なリソースは、HTTPを介して配信されるイベントを受信して確認します。 呼び出し可能なリソースは、HTTPを介して配信されるイベントを受信してイベントを変換し、オプションでHTTP応答でイベントを返すことができます。 これまで見てきたサービスとは別に、チャネルとブローカーもシンクになることができます。

5. 結論

このチュートリアルでは、Kunativeを使用してサーバーレス環境をホストするための基盤となるインフラストラクチャとしてKubernetesを活用する方法について説明しました。 Knativeの基本的なアーキテクチャとコンポーネント、つまりKnativeServingとKnativeEventingについて説明しました。 これにより、Knaitiveなどのフレームワークを使用してサーバーレスアプリケーションを構築するメリットを理解する機会が得られました。