Knative(v1.7)を触ってみる(インストール・チュートリアル)
Kubernetes上でサーバーレスを実行するためのOSSである、Knativeを触ったときのメモ。 GKEのStandardクラスタにインストールし、チュートリアルをやった。
環境
- Knative:v1.7
- GKE:v1.25.1-gke.500 ※GKEクラスタの作成については以下記事を参照。 tk-ch.hatenablog.com
Knativeとは
Knativeは、Kubernetesを拡張して、サーバーレスアプリケーションのデプロイと管理のプロセスを簡素化するOSS。
GCPのCloudRunの基盤にも使用されているらしい。
公式ドキュメントのConceptによると、KnativeはServingとEventingという2つのコンポーネントで構成されている。
- Serving:Kubernetes上でサーバレスコンテナを簡単に実行できるようにする機能。ネットワーク、オートスケーリング(ゼロスケールも可)、リビジョンのトラッキングなどの詳細を管理する。
- Eventing:アプリケーションでイベント駆動型アーキテクチャを使用できるようにする API のコレクション。これらの API を使用して、イベント プロデューサーから、イベントを受信するシンクと呼ばれるイベント コンシューマーにイベントをルーティングするコンポーネントを作成できる。
それぞれの概要は以下スライドを参照(バージョンは少し古いので注意)。
インストール
インストール方法
Installing Knativeによると、各ベンダのマネジメントKnativeを除くと、以下3つのインストール方法がある。
- Knative Quickstart pluginというツールを使って、minikubeかkindでKnativeがインストールされたkubernetesクラスタを手軽に構築できる。開発・検証目的に使うもので、本番環境では非推奨。
- YAMLファイルを使ってインストールする。本番環境へ対応可能。
- Knative Operatorを使ってインストールする。本番環境へ対応可能。
→今回はGKEにインストールするので、Kubernetesクラスタから作成するKnative Quickstart pluginは適さない。
また、Operaterを使うとインストール時作成されたリソースの内容が分かりづらくなりそうなので、今回は2つ目のYAMLファイルを使うインストールで進める。
Knative CLIのインストール
Knativeのインストール前に、こちらに従い、Knativeのリソースを簡単に操作できるようになるKnative CLIをインストールしておく。
バイナリをダウンロード $ wget https://github.com/knative/client/releases/download/knative-v1.7.1/kn-linux-amd64 バイナリをPATHが通るディレクトリに移動、リネームする $ sudo mv kn-linux-amd64 /usr/local/bin/kn 実行権限を付与する $ sudo chmod +x /usr/local/bin/kn Knative CLIのバージョン確認 $ kn version Version: v1.7.1 Build Date: 2022-10-11 10:18:30 Git Revision: e2f6caf3 Supported APIs: * Serving - serving.knative.dev/v1 (knative-serving v1.7.0) * Eventing - sources.knative.dev/v1 (knative-eventing v1.7.1) - eventing.knative.dev/v1 (knative-eventing v1.7.1)
Knative Servingのインストール
「Installing Knative Serving using YAML files」を参考に、Servingをインストールする。
Knative Serving コンポーネントをインストールする
以下を実行する。
カスタムリソースのYAMLファイルをダウンロードする $ wget https://github.com/knative/serving/releases/download/knative-v1.7.2/serving-crds.yaml カスタムリソースを作成 $ kubectl apply -f serving-crds.yaml customresourcedefinition.apiextensions.k8s.io/certificates.networking.internal.knative.dev created customresourcedefinition.apiextensions.k8s.io/configurations.serving.knative.dev created customresourcedefinition.apiextensions.k8s.io/clusterdomainclaims.networking.internal.knative.dev created customresourcedefinition.apiextensions.k8s.io/domainmappings.serving.knative.dev created customresourcedefinition.apiextensions.k8s.io/ingresses.networking.internal.knative.dev created customresourcedefinition.apiextensions.k8s.io/metrics.autoscaling.internal.knative.dev created customresourcedefinition.apiextensions.k8s.io/podautoscalers.autoscaling.internal.knative.dev created customresourcedefinition.apiextensions.k8s.io/revisions.serving.knative.dev created customresourcedefinition.apiextensions.k8s.io/routes.serving.knative.dev created customresourcedefinition.apiextensions.k8s.io/serverlessservices.networking.internal.knative.dev created customresourcedefinition.apiextensions.k8s.io/services.serving.knative.dev created customresourcedefinition.apiextensions.k8s.io/images.caching.internal.knative.dev created ServingのコアコンポーネントのYAMLファイルをダウンロードする $ wget https://github.com/knative/serving/releases/download/knative-v1.7.2/serving-core.yaml Servingのコアコンポーネントを作成 $ kubectl apply -f serving-core.yaml namespace/knative-serving created clusterrole.rbac.authorization.k8s.io/knative-serving-aggregated-addressable-resolver created clusterrole.rbac.authorization.k8s.io/knative-serving-addressable-resolver created clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-admin created clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-edit created clusterrole.rbac.authorization.k8s.io/knative-serving-namespaced-view created clusterrole.rbac.authorization.k8s.io/knative-serving-core created clusterrole.rbac.authorization.k8s.io/knative-serving-podspecable-binding created serviceaccount/controller created clusterrole.rbac.authorization.k8s.io/knative-serving-admin created clusterrolebinding.rbac.authorization.k8s.io/knative-serving-controller-admin created clusterrolebinding.rbac.authorization.k8s.io/knative-serving-controller-addressable-resolver created customresourcedefinition.apiextensions.k8s.io/images.caching.internal.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/certificates.networking.internal.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/configurations.serving.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/clusterdomainclaims.networking.internal.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/domainmappings.serving.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/ingresses.networking.internal.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/metrics.autoscaling.internal.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/podautoscalers.autoscaling.internal.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/revisions.serving.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/routes.serving.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/serverlessservices.networking.internal.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/services.serving.knative.dev unchanged secret/serving-certs-ctrl-ca created secret/knative-serving-certs created image.caching.internal.knative.dev/queue-proxy created configmap/config-autoscaler created configmap/config-defaults created configmap/config-deployment created configmap/config-domain created configmap/config-features created configmap/config-gc created configmap/config-leader-election created configmap/config-logging created configmap/config-network created configmap/config-observability created configmap/config-tracing created Warning: autoscaling/v2beta2 HorizontalPodAutoscaler is deprecated in v1.23+, unavailable in v1.26+; use autoscaling/v2 HorizontalPodAutoscaler horizontalpodautoscaler.autoscaling/activator created poddisruptionbudget.policy/activator-pdb created deployment.apps/activator created service/activator-service created deployment.apps/autoscaler created service/autoscaler created deployment.apps/controller created service/controller created deployment.apps/domain-mapping created deployment.apps/domainmapping-webhook created service/domainmapping-webhook created horizontalpodautoscaler.autoscaling/webhook created poddisruptionbudget.policy/webhook-pdb created deployment.apps/webhook created service/webhook created validatingwebhookconfiguration.admissionregistration.k8s.io/config.webhook.serving.knative.dev created mutatingwebhookconfiguration.admissionregistration.k8s.io/webhook.serving.knative.dev created mutatingwebhookconfiguration.admissionregistration.k8s.io/webhook.domainmapping.serving.knative.dev created secret/domainmapping-webhook-certs created validatingwebhookconfiguration.admissionregistration.k8s.io/validation.webhook.domainmapping.serving.knative.dev created validatingwebhookconfiguration.admissionregistration.k8s.io/validation.webhook.serving.knative.dev created secret/webhook-certs created
※以下のようにRole関連の設定に失敗する場合は、kubectlを実行しているユーザに割り当てられている権限が不足している。
「Kubernetes Engine 管理者」ロールを割り当てるなど、必要な権限を付与して再実行する。
Error from server (Forbidden): error when creating "serving-core.yaml": clusterroles.rbac.authorization.k8s.io is forbidden: User "117530911732356708839" cannot create resource "clusterroles" in API group "rbac.authorization.k8s.io" at the cluster scope: requires one of ["container.clusterRoles.create"] permission(s).` Error from server (Forbidden): error when creating "serving-core.yaml": clusterrolebindings.rbac.authorization.k8s.io is forbidden: User "117530911732356708839" cannot create resource "clusterrolebindings" in API group "rbac.authorization.k8s.io" at the cluster scope: requires one of ["container.clusterRoleBindings.create"] permission(s).
ネットワーク層をインストールする
ネットワーク層の選択肢はKourier、Istio、Contourがあるが、「Choose this if you are not sure」となっているKourierを使うことにする。
KourierコントローラーのYAMLファイルをダウンロード $ wget https://github.com/knative/net-kourier/releases/download/knative-v1.7.0/kourier.yaml このまま使うとKourierの外部IPアドレスがインターネットに公開されるので、ソースIP制限の設定を入れておく。 $ cp -pr kourier.yaml kourier_restrictip.yaml $ vim kourier_restrictip.yaml (略) apiVersion: v1 kind: Service metadata: name: kourier namespace: kourier-system labels: networking.knative.dev/ingress-provider: kourier app.kubernetes.io/component: net-kourier app.kubernetes.io/version: "1.7.0" app.kubernetes.io/name: knative-serving spec: ports: - name: http2 port: 80 protocol: TCP targetPort: 8080 - name: https port: 443 protocol: TCP targetPort: 8443 selector: app: 3scale-kourier-gateway type: LoadBalancer loadBalancerSourceRanges: #追加 - {接続を許可するグローバルIP}/32 #追加 (略) Knative Courier コントローラーを展開 $ kubectl apply -f kourier_restrictip.yaml namespace/kourier-system created configmap/kourier-bootstrap created configmap/config-kourier created serviceaccount/net-kourier created clusterrole.rbac.authorization.k8s.io/net-kourier created clusterrolebinding.rbac.authorization.k8s.io/net-kourier created deployment.apps/net-kourier-controller created service/net-kourier-controller created deployment.apps/3scale-kourier-gateway created service/kourier created service/kourier-internal created デフォルトで Kourier を使用するようKnative Servingに設定 $ kubectl patch configmap/config-network \ --namespace knative-serving \ --type merge \ --patch '{"data":{"ingress-class":"kourier.ingress.networking.knative.dev"}}' configmap/config-network patched Kourierの外部IPアドレスを取得 $ kubectl --namespace kourier-system get service kourier NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kourier LoadBalancer 10.96.13.13 34.145.106.59 80:31786/TCP,443:30679/TCP 2m6s GKEクラスタに設定されているFirewallルール名を確認 $ gcloud compute firewall-rules list --format="value(name)" | grep "^k8s-fw-" k8s-fw-a9dc27ac31fb24e4c9d8abcb85332173 IP制限設定がFirewallに反映されていることを確認 $ gcloud compute firewall-rules describe k8s-fw-a9dc27ac31fb24e4c9d8abcb85332173 --format="value(sourceRanges)" {接続を許可するグローバルIP}/32
インストールされたことを確認する
以下のように確認する。
ServingコンポーネントのPodがRunningとなっていることを確認 $ kubectl get pods -n knative-serving NAME READY STATUS RESTARTS AGE activator-76b68c57-8kzk7 1/1 Running 0 10m autoscaler-6786666674-sqp6v 1/1 Running 0 10m controller-dc889b65b-jshdk 1/1 Running 0 10m domain-mapping-7579b59cd8-bm4vh 1/1 Running 0 10m domainmapping-webhook-6c89c965bd-vggpj 1/1 Running 0 10m net-kourier-controller-77776d79dc-hglgf 1/1 Running 0 3m16s webhook-85ccb78947-sgvkw 1/1 Running 0 10m KourierコントローラーのPodがRunningとなっていることを確認 $ kubectl get pods -n kourier-system NAME READY STATUS RESTARTS AGE 3scale-kourier-gateway-77665f8968-zhwl4 1/1 Running 0 14m
DNSの構成
Knativeが作成するエンドポイントにDNS名で接続できるように、デフォルトDNSサフィックスとしてsslip.ioを使う設定をする。
マジックDNS設定ジョブのYAMLファイルをダウンロード $ wget https://github.com/knative/serving/releases/download/knative-v1.7.2/serving-default-domain.yaml マジックDNS設定ジョブを作成 $ kubectl apply -f serving-default-domain.yaml job.batch/default-domain created service/default-domain-service created
Knative Eventingのインストール
「Installing Knative Eventing using YAML files」を参考に、Eventingをインストールする。
Knative Eventing コンポーネントをインストールする
以下を実行する。
カスタムリソースのYAMLファイルをダウンロードする $ wget https://github.com/knative/eventing/releases/download/knative-v1.7.3/eventing-crds.yaml カスタムリソースを作成 $ kubectl apply -f eventing-crds.yaml customresourcedefinition.apiextensions.k8s.io/apiserversources.sources.knative.dev created customresourcedefinition.apiextensions.k8s.io/brokers.eventing.knative.dev created customresourcedefinition.apiextensions.k8s.io/channels.messaging.knative.dev created customresourcedefinition.apiextensions.k8s.io/containersources.sources.knative.dev created customresourcedefinition.apiextensions.k8s.io/eventtypes.eventing.knative.dev created customresourcedefinition.apiextensions.k8s.io/parallels.flows.knative.dev created customresourcedefinition.apiextensions.k8s.io/pingsources.sources.knative.dev created customresourcedefinition.apiextensions.k8s.io/sequences.flows.knative.dev created customresourcedefinition.apiextensions.k8s.io/sinkbindings.sources.knative.dev created customresourcedefinition.apiextensions.k8s.io/subscriptions.messaging.knative.dev created customresourcedefinition.apiextensions.k8s.io/triggers.eventing.knative.dev created EventingのコアコンポーネントのYAMLファイルをダウンロードする $ wget https://github.com/knative/eventing/releases/download/knative-v1.7.3/eventing-core.yaml Eventingのコアコンポーネントを作成 $ kubectl apply -f eventing-core.yaml namespace/knative-eventing created serviceaccount/eventing-controller created clusterrolebinding.rbac.authorization.k8s.io/eventing-controller created clusterrolebinding.rbac.authorization.k8s.io/eventing-controller-resolver created clusterrolebinding.rbac.authorization.k8s.io/eventing-controller-source-observer created clusterrolebinding.rbac.authorization.k8s.io/eventing-controller-sources-controller created clusterrolebinding.rbac.authorization.k8s.io/eventing-controller-manipulator created serviceaccount/pingsource-mt-adapter created clusterrolebinding.rbac.authorization.k8s.io/knative-eventing-pingsource-mt-adapter created serviceaccount/eventing-webhook created clusterrolebinding.rbac.authorization.k8s.io/eventing-webhook created rolebinding.rbac.authorization.k8s.io/eventing-webhook created clusterrolebinding.rbac.authorization.k8s.io/eventing-webhook-resolver created clusterrolebinding.rbac.authorization.k8s.io/eventing-webhook-podspecable-binding created configmap/config-br-default-channel created configmap/config-br-defaults created configmap/default-ch-webhook created configmap/config-ping-defaults created configmap/config-features created configmap/config-kreference-mapping created configmap/config-leader-election created configmap/config-logging created configmap/config-observability created configmap/config-sugar created configmap/config-tracing created deployment.apps/eventing-controller created deployment.apps/pingsource-mt-adapter created Warning: autoscaling/v2beta2 HorizontalPodAutoscaler is deprecated in v1.23+, unavailable in v1.26+; use autoscaling/v2 HorizontalPodAutoscaler horizontalpodautoscaler.autoscaling/eventing-webhook created poddisruptionbudget.policy/eventing-webhook created deployment.apps/eventing-webhook created service/eventing-webhook created customresourcedefinition.apiextensions.k8s.io/apiserversources.sources.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/brokers.eventing.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/channels.messaging.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/containersources.sources.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/eventtypes.eventing.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/parallels.flows.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/pingsources.sources.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/sequences.flows.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/sinkbindings.sources.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/subscriptions.messaging.knative.dev unchanged customresourcedefinition.apiextensions.k8s.io/triggers.eventing.knative.dev unchanged clusterrole.rbac.authorization.k8s.io/addressable-resolver created clusterrole.rbac.authorization.k8s.io/service-addressable-resolver created clusterrole.rbac.authorization.k8s.io/serving-addressable-resolver created clusterrole.rbac.authorization.k8s.io/channel-addressable-resolver created clusterrole.rbac.authorization.k8s.io/broker-addressable-resolver created clusterrole.rbac.authorization.k8s.io/flows-addressable-resolver created clusterrole.rbac.authorization.k8s.io/eventing-broker-filter created clusterrole.rbac.authorization.k8s.io/eventing-broker-ingress created clusterrole.rbac.authorization.k8s.io/eventing-config-reader created clusterrole.rbac.authorization.k8s.io/channelable-manipulator created clusterrole.rbac.authorization.k8s.io/meta-channelable-manipulator created clusterrole.rbac.authorization.k8s.io/knative-eventing-namespaced-admin created clusterrole.rbac.authorization.k8s.io/knative-messaging-namespaced-admin created clusterrole.rbac.authorization.k8s.io/knative-flows-namespaced-admin created clusterrole.rbac.authorization.k8s.io/knative-sources-namespaced-admin created clusterrole.rbac.authorization.k8s.io/knative-bindings-namespaced-admin created clusterrole.rbac.authorization.k8s.io/knative-eventing-namespaced-edit created clusterrole.rbac.authorization.k8s.io/knative-eventing-namespaced-view created clusterrole.rbac.authorization.k8s.io/knative-eventing-controller created clusterrole.rbac.authorization.k8s.io/knative-eventing-pingsource-mt-adapter created clusterrole.rbac.authorization.k8s.io/podspecable-binding created clusterrole.rbac.authorization.k8s.io/builtin-podspecable-binding created clusterrole.rbac.authorization.k8s.io/source-observer created clusterrole.rbac.authorization.k8s.io/eventing-sources-source-observer created clusterrole.rbac.authorization.k8s.io/knative-eventing-sources-controller created clusterrole.rbac.authorization.k8s.io/knative-eventing-webhook created role.rbac.authorization.k8s.io/knative-eventing-webhook created validatingwebhookconfiguration.admissionregistration.k8s.io/config.webhook.eventing.knative.dev created mutatingwebhookconfiguration.admissionregistration.k8s.io/webhook.eventing.knative.dev created validatingwebhookconfiguration.admissionregistration.k8s.io/validation.webhook.eventing.knative.dev created secret/eventing-webhook-certs created mutatingwebhookconfiguration.admissionregistration.k8s.io/sinkbindings.webhook.sources.knative.dev created
インストールされたことを確認する
以下のように確認する。
EventingコンポーネントのPodがRunningとなっていることを確認 $ kubectl get pods -n knative-eventing NAME READY STATUS RESTARTS AGE eventing-controller-56847b8877-6tgvp 1/1 Running 0 95s eventing-webhook-5477db5854-glhg8 1/1 Running 0 95s
デフォルトのChannelレイヤーをインストール
Channelレイヤー(実装)は以下の3つがあるが、とりあえず一番シンプルなInMemory Channelをインストールする。
- Apache Kafka Channel
- InMemory Channel ※本番環境では非推奨
- NATS Channel
InMemoryChannel実装のYAMLファイルをダウンロードする $ wget https://github.com/knative/eventing/releases/download/knative-v1.7.3/in-memory-channel.yaml InMemoryChannel実装をインストールする $ kubectl apply -f in-memory-channel.yaml serviceaccount/imc-controller created clusterrolebinding.rbac.authorization.k8s.io/imc-controller created rolebinding.rbac.authorization.k8s.io/imc-controller created clusterrolebinding.rbac.authorization.k8s.io/imc-controller-resolver created serviceaccount/imc-dispatcher created clusterrolebinding.rbac.authorization.k8s.io/imc-dispatcher created configmap/config-imc-event-dispatcher created configmap/config-observability unchanged configmap/config-tracing unchanged deployment.apps/imc-controller created service/inmemorychannel-webhook created service/imc-dispatcher created deployment.apps/imc-dispatcher created customresourcedefinition.apiextensions.k8s.io/inmemorychannels.messaging.knative.dev created clusterrole.rbac.authorization.k8s.io/imc-addressable-resolver created clusterrole.rbac.authorization.k8s.io/imc-channelable-manipulator created clusterrole.rbac.authorization.k8s.io/imc-controller created clusterrole.rbac.authorization.k8s.io/imc-dispatcher created role.rbac.authorization.k8s.io/knative-inmemorychannel-webhook created mutatingwebhookconfiguration.admissionregistration.k8s.io/inmemorychannel.eventing.knative.dev created validatingwebhookconfiguration.admissionregistration.k8s.io/validation.inmemorychannel.eventing.knative.dev created secret/inmemorychannel-webhook-certs created 作成されたPod、Serviceを確認 $ kubectl -n knative-eventing get pod | grep imc imc-controller-74cd59685d-44964 1/1 Running 0 3m56s imc-dispatcher-848587f767-xkpmw 1/1 Running 0 3m56s $ kubectl -n knative-eventing get svc | grep imc imc-dispatcher ClusterIP 10.96.1.73 <none> 80/TCP,9090/TCP 4m
こちらによると、デフォルトで使用されるチャンネルはdefault-ch-webhook Configmapに設定されているので、確認しておく。
確認すると、デフォルトはInMemoryChannelになっている $ kubectl get -n knative-eventing cm default-ch-webhook -o yaml apiVersion: v1 data: default-ch-config: | clusterDefault: apiVersion: messaging.knative.dev/v1 kind: InMemoryChannel namespaceDefaults: some-namespace: apiVersion: messaging.knative.dev/v1 kind: InMemoryChannel (略)
こちらを参考に、channelを作成してみる
yamlの作成 $ cat <<EOF > example-channel.yaml apiVersion: messaging.knative.dev/v1 kind: Channel metadata: name: example-channel EOF $ kubectl apply -f example-channel.yaml channel.messaging.knative.dev/example-channel created channelが作成されていることを確認(READYがTrueになっていればOK) $ kubectl get channels NAME URL AGE READY REASON example-channel http://example-channel-kn-channel.default.svc.cluster.local 29s True channelの種類ごとに確認することもできる。 デフォルト設定だったInMemoryChannelとして作成されていることがわかる $ kubectl get inmemorychannels NAME URL AGE READY REASON example-channel http://example-channel-kn-channel.default.svc.cluster.local 36s True knコマンドでも確認する $ kn channel list NAME TYPE URL AGE READY REASON example-channel InMemoryChannel http://example-channel-kn-channel.default.svc.cluster.local 59s True 一旦channelを消しておく $ kubectl delete -f example-channel.yaml channel.messaging.knative.dev "example-channel" deleted
Brokerレイヤーをインストール
Brokerにも以下の複数の実装がある。
とりあえずインストールが一番簡単なMT-Channel-based Brokerをインストールする。
MT-Channel-based Brokerは内部的にchannelを使用することで、インストールを簡単にしているらしい。
- Apache Kafka Broker
- MT-Channel-based Broker
- RabbitMQ Broker
MT-Channel-based BrokerのYAMLファイルをダウンロードする $ wget https://github.com/knative/eventing/releases/download/knative-v1.7.3/mt-channel-broker.yaml MT-Channel-based Brokerをデプロイする $ kubectl apply -f mt-channel-broker.yaml clusterrole.rbac.authorization.k8s.io/knative-eventing-mt-channel-broker-controller created clusterrole.rbac.authorization.k8s.io/knative-eventing-mt-broker-filter created serviceaccount/mt-broker-filter created clusterrole.rbac.authorization.k8s.io/knative-eventing-mt-broker-ingress created serviceaccount/mt-broker-ingress created clusterrolebinding.rbac.authorization.k8s.io/eventing-mt-channel-broker-controller created clusterrolebinding.rbac.authorization.k8s.io/knative-eventing-mt-broker-filter created clusterrolebinding.rbac.authorization.k8s.io/knative-eventing-mt-broker-ingress created deployment.apps/mt-broker-filter created service/broker-filter created deployment.apps/mt-broker-ingress created service/broker-ingress created deployment.apps/mt-broker-controller created Warning: autoscaling/v2beta2 HorizontalPodAutoscaler is deprecated in v1.23+, unavailable in v1.26+; use autoscaling/v2 HorizontalPodAutoscaler horizontalpodautoscaler.autoscaling/broker-ingress-hpa created horizontalpodautoscaler.autoscaling/broker-filter-hpa created 作成されたPod、Serviceを確認 $ kubectl -n knative-eventing get pod | grep broker mt-broker-controller-58b8c559f6-nfr5b 1/1 Running 0 17s mt-broker-filter-6f897c95d-g24p9 1/1 Running 0 17s mt-broker-ingress-d69b8bcb9-7m9nb 1/1 Running 0 17s $ kubectl -n knative-eventing get svc | grep broker broker-filter ClusterIP 10.96.5.155 <none> 80/TCP,9092/TCP 28s broker-ingress ClusterIP 10.96.14.159 <none> 80/TCP,9092/TCP 28s
こちらによると、デフォルトで使用されるブローカーはconfig-br-defaults Configmapに設定されているので確認する。
確認すると、デフォルトはMT-Channel-based Brokerになっている $ kubectl get -n knative-eventing cm config-br-defaults -o yaml apiVersion: v1 data: default-br-config: | clusterDefault: brokerClass: MTChannelBasedBroker apiVersion: v1 kind: ConfigMap name: config-br-default-channel namespace: knative-eventing delivery: retry: 10 backoffPolicy: exponential backoffDelay: PT0.2S (略)
Brokerの作成を試す https://knative.dev/docs/eventing/brokers/create-mtbroker/
こちらを参考に、channelを作成してみる
yamlを作成 $ cat <<EOF > example-broker.yaml apiVersion: eventing.knative.dev/v1 kind: Broker metadata: name: example-broker EOF brokerを作成 $ kubectl apply -f example-broker.yaml broker.eventing.knative.dev/example-broker created brokerを確認 $ kubectl get broker NAME URL AGE READY REASON example-broker http://broker-ingress.knative-eventing.svc.cluster.local/default/example-broker 20s True knコマンドでも確認 $ kn broker list NAME URL AGE CONDITIONS READY REASON example-broker http://broker-ingress.knative-eventing.svc.cluster.local/default/example-broker 32s 6 OK / 6 True brokerを削除する $ kubectl delete -f example-broker.yaml broker.eventing.knative.dev "example-broker" deleted
Sugar Controllerのインストール
Eventingの拡張機能のひとつであるSugar Controllerをインストールしてみる。
namespaceに特定のラベルを付けると、brokerを自動作成してくれるというもの。
公式ドキュメントの手順ではYAMLファイルを使ってインストールすると記載されているが、以下のようにYAMLファイルが存在しない。
Sugar ControllerのYAMLファイルをダウンロードしようとしたが、エラー $ wget https://github.com/knative/eventing/releases/download/knative-v1.7.3/eventing-sugar-controller.yaml --2022-10-17 13:01:24-- https://github.com/knative/eventing/releases/download/knative-v1.7.3/eventing-sugar-controller.yaml github.com (github.com) をDNSに問いあわせています... 192.30.255.113 github.com (github.com)|192.30.255.113|:443 に接続しています... 接続しました。 HTTP による接続要求を送信しました、応答を待っています... 404 Not Found 2022-10-17 13:01:24 エラー 404: Not Found。
こちらにはconfig-sugar Configmapを変更してSugar Controllerを有効化すると書かれている。
最初の状態 $ kubectl get -n knative-eventing cm config-sugar -o yaml apiVersion: v1 data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ # This block is not actually functional configuration, # but serves to illustrate the available configuration # options and document them in a way that is accessible # to users that `kubectl edit` this config map. # # These sample configuration options may be copied out of # this example block and unindented to be in the data block # to actually change the configuration. # namespace-selector specifies a LabelSelector which # determines which namespaces the Sugar Controller should operate upon # Use an empty value to disable the feature (this is the default): namespace-selector: "" # Use an empty object as a string to enable for all namespaces namespace-selector: "{}" # trigger-selector specifies a LabelSelector which # determines which triggers the Sugar Controller should operate upon # Use an empty value to disable the feature (this is the default): trigger-selector: "" # Use an empty object as string to enable for all triggers trigger-selector: "{}" (略) 編集して有効化 $ kubectl edit -n knative-eventing cm config-sugar configmap/config-sugar edited 編集後 $ kubectl get -n knative-eventing cm config-sugar -o yaml apiVersion: v1 data: namespace-selector: | matchExpressions: - key: "eventing.knative.dev/injection" operator: "In" values: ["enabled"] trigger-selector: | matchExpressions: - key: "eventing.knative.dev/injection" operator: "In" values: ["enabled"]
ブローカーの自動作成を試してみる
default namespaceにbrokerはない $ kubectl get broker No resources found in default namespace. default namespaceのラベルを確認 $ kubectl get namespaces default --show-labels NAME STATUS AGE LABELS default Active 6h47m kubernetes.io/metadata.name=default default namespaceにラベルを付ける $ kubectl label namespace default eventing.knative.dev/injection=enabled namespace/default labeled default namespaceのラベルを確認 $ kubectl get namespaces default --show-labels NAME STATUS AGE LABELS default Active 6h48m eventing.knative.dev/injection=enabled,kubernetes.io/metadata.name=default ブローカーが自動作成されたことを確認 $ kubectl get broker NAME URL AGE READY REASON default http://broker-ingress.knative-eventing.svc.cluster.local/default/default 109s True knコマンドでも確認 $ kn broker list NAME URL AGE CONDITIONS READY REASON default http://broker-ingress.knative-eventing.svc.cluster.local/default/default 96s 6 OK / 6 True
Sugar Controllerによってbrokerが自動作成されたことを確認できた。
ちなみに、自動作成されたbrokerは「eventing.knative.dev/injection=enabled」ラベルがついている間は、削除してもすぐに再作成される。
brokerを削除 $ kubectl delete broker default broker.eventing.knative.dev "default" deleted すぐに再作成されている $ kubectl get broker NAME URL AGE READY REASON default http://broker-ingress.knative-eventing.svc.cluster.local/default/default 5s True
そのため、brokerを削除したい場合は、「eventing.knative.dev/injection=enabled」ラベルを消してから削除する。
ラベルの削除 $ kubectl label namespace default eventing.knative.dev/injection- namespace/default unlabeled 「eventing.knative.dev/injection=enabled」ラベルが消えたことを確認 $ kubectl get namespaces default --show-labels NAME STATUS AGE LABELS default Active 46h kubernetes.io/metadata.name=default ラベルが消えてもbrokerは残る $ kubectl get broker NAME URL AGE READY REASON default http://broker-ingress.knative-eventing.svc.cluster.local/default/default 2m39s True brokerを削除 $ kubectl delete broker default broker.eventing.knative.dev "default" deleted 再作成されていないことを確認 $ kubectl get broker No resources found in default namespace.
チュートリアルをやってみる
動作確認を兼ねて、Knative公式ドキュメントのチュートリアルをやってみる。
Serving
Servingのチュートリアルを実施する。
Knative Serviceを作成
Deploying a Knative Serviceを実施する。
Knative Serviceのyamlを作成 $ cat <<EOF > hello.yaml apiVersion: serving.knative.dev/v1 kind: Service metadata: name: hello spec: template: spec: containers: - image: gcr.io/knative-samples/helloworld-go ports: - containerPort: 8080 env: - name: TARGET value: "World" EOF Knative Serviceを作成 $ kubectl apply -f hello.yaml service.serving.knative.dev/hello created $ kubectl get ksvc NAME URL LATESTCREATED LATESTREADY READY REASON hello http://hello.default.34.145.106.59.sslip.io hello-00001 hello-00001 True
オートスケーリング
Autoscalingを実施する。
作成されたKnativeServiceのURLを確認する $ kubectl get ksvc NAME URL LATESTCREATED LATESTREADY READY REASON hello http://hello.default.34.145.106.59.sslip.io hello-00001 hello-00001 True この時点ではPodは存在しない。 $ kubectl get pod -l serving.knative.dev/service=hello No resources found in default namespace. KnativeServiceへ接続すると、レスポンスが返ってくる $ curl http://hello.default.34.145.106.59.sslip.io Hello World! Podを確認すると、作成されている。 暫く待つとPodが削除される。 $ kubectl get pod -l serving.knative.dev/service=hello -w NAME READY STATUS RESTARTS AGE hello-00001-deployment-868c87995d-5brhr 2/2 Running 0 15s hello-00001-deployment-868c87995d-5brhr 2/2 Terminating 0 62s hello-00001-deployment-868c87995d-5brhr 1/2 Terminating 0 90s hello-00001-deployment-868c87995d-5brhr 0/2 Terminating 0 93s 以下のコマンドを実行した状態で、別コンソールで「curl http://hello.default.34.145.106.59.sslip.io」を実行すると、Podが無い状態から作成されるところを確認できる $ kubectl get pod -l serving.knative.dev/service=hello -w NAME READY STATUS RESTARTS AGE hello-00001-deployment-868c87995d-7bcxv 0/2 Pending 0 0s hello-00001-deployment-868c87995d-7bcxv 0/2 Pending 0 0s hello-00001-deployment-868c87995d-7bcxv 0/2 ContainerCreating 0 0s hello-00001-deployment-868c87995d-7bcxv 1/2 Running 0 1s hello-00001-deployment-868c87995d-7bcxv 2/2 Running 0 1s
→Servingによって、Podのゼロスケールができている。
補足:NodePortで接続する場合
Knative ServiceのエンドポイントになっているServiceは、kourier namespaceに存在するkourier。
$ kubectl get svc -n kourier-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kourier LoadBalancer 10.96.13.13 34.145.106.59 80:31786/TCP,443:30679/TCP 4h57m kourier-internal ClusterIP 10.96.7.171 <none> 80/TCP,443/TCP 4h57m
今回kourier Serviceは上記のようにLoadBalancerタイプとなっているが、LoadBalancerタイプのServiceは、PORT(S)列のポートでNodePortタイプでも接続が出来る。
ただ、そのままアクセスしても以下のように404エラーとなる。
$ curl -I http://${K8sクラスタのワーカーノードのIP}:31484 HTTP/1.1 404 Not Found date: Mon, 14 Nov 2022 11:32:07 GMT server: envoy transfer-encoding: chunked
RedHatのkourierに関するブログ記事に以下の記載がある。
Hosts, paths, and headers: These elements are matched against the same elements included in incoming requests. When there's a match, we know that the request should be proxied to the Knative service associated with the ingress object.
→Knative ServiceがデプロイされたときにServingにより作成されるKnative Ingressに、ホスト、パスといった情報が含まれる。
kourierはこれら情報にマッチするアクセスを該当するKnative サービスにルーティングしている模様。
そのため、NodePortで接続する際には、以下のようにホストヘッダにホスト名を設定する必要がある。
hello Knative Serviceに対応するKnative Ingressの情報を参照し、ホスト名を確認する $ kubectl get ingresses.networking.internal.knative.dev hello -o jsonpath='{.spec.rules[?(@.visibility=="ExternalIP")].hosts}' ["hello.default.34.145.106.59.sslip.io"] 確認したホスト名をホストヘッダに含めてNodePortにアクセスすると、接続できる。 $ curl -HHost:hello.default.34.145.106.59.sslip.io http://${K8sクラスタのワーカーノードのIP}:31484 Hello Knative!
※NodePortとGKE Ingressを組み合わせて使いたい場合はこちらのブログが参考になりそう(実際には試していないので未確認)。
トラフィック分割
Traffic splittingを実施する。
hello.yamlを修正 $ cat <<EOF > hello.yaml apiVersion: serving.knative.dev/v1 kind: Service metadata: name: hello spec: template: spec: containers: - image: gcr.io/knative-samples/helloworld-go ports: - containerPort: 8080 env: - name: TARGET value: "Knative" EOF デプロイする $ kubectl apply -f hello.yaml service.serving.knative.dev/hello configured Knative ServiceのLATESTCREATED、LATESTREADYがhello-00002に変わっている。 URLは変化なし。 $ kubectl get ksvc NAME URL LATESTCREATED LATESTREADY READY REASON hello http://hello.default.34.145.106.59.sslip.io hello-00002 hello-00002 True KnativeServiceへ接続すると、レスポンスの文字列が変わっている $ curl http://hello.default.34.145.106.59.sslip.io Hello Knative! リビジョンを確認する $ kubectl get revisions NAME CONFIG NAME K8S SERVICE NAME GENERATION READY REASON ACTUAL REPLICAS DESIRED REPLICAS hello-00001 hello 1 True 0 0 hello-00002 hello 2 True 1 1 Knative CLIで確認すると、トラフィックの100%がhello-00002リビジョンに転送される状態になっている $ kn revisions list NAME SERVICE TRAFFIC TAGS GENERATION AGE CONDITIONS READY REASON hello-00002 hello 100% 2 13m 3 OK / 4 True hello-00001 hello 1 43m 3 OK / 4 True
新しいリビジョンを作成すると、Knative はデフォルトで 100% のトラフィックを最新リビジョンに転送する。
各リビジョンが受信するトラフィックの量を指定することで、このデフォルトの動作を変更できるらしい。
リビジョンのトラフィック割合を変更してみる。
hello.yamlを修正 $ cat <<EOF > hello.yaml apiVersion: serving.knative.dev/v1 kind: Service metadata: name: hello spec: template: spec: containers: - image: gcr.io/knative-samples/helloworld-go ports: - containerPort: 8080 env: - name: TARGET value: "Knative" traffic: - latestRevision: true percent: 50 - latestRevision: false percent: 50 revisionName: hello-00001 EOF デプロイする $ kubectl apply -f hello.yaml service.serving.knative.dev/hello configured yamlの記載通り、トラフィックが50%ずつhello-00001リビジョンとhello-00002リビジョンに分割されている $ kn revisions list NAME SERVICE TRAFFIC TAGS GENERATION AGE CONDITIONS READY REASON hello-00002 hello 50% 2 20m 3 OK / 4 True hello-00001 hello 50% 1 50m 3 OK / 4 True Knative Serviceに複数回アクセスすると、トラフィックが50%ずつhello-00001リビジョンとhello-00002リビジョンに分割されていることが確認できる $ curl http://hello.default.34.145.106.59.sslip.io Hello World! $ curl http://hello.default.34.145.106.59.sslip.io Hello Knative! $ curl http://hello.default.34.145.106.59.sslip.io Hello Knative! $ curl http://hello.default.34.145.106.59.sslip.io Hello World!
片付け
$ kubectl delete -f hello.yaml service.serving.knative.dev "hello" deleted
Eventing
Eventingのチュートリアルを実施する。
Brokerの確認
Sources, Brokers, and Triggersを実施する。
公式ドキュメントのチュートリアルは「kn quickstart」でインストールしたことを前提にしている。
この場合、example-brokerというbrokerが存在する。
今回はKnativeをYAMLファイルでインストールしたため、example-brokerは存在しない。
そのため、sugar controllerの機能でbrokerを作成する。
default namespaceにラベルを付与する $ kubectl label namespace default eventing.knative.dev/injection=enabled namespace/default labeled default namespaceにbrokerが自動作成される $ kubectl get broker NAME URL AGE READY REASON default http://broker-ingress.knative-eventing.svc.cluster.local/default/default 5s True
Brokerにイベントを送信する
Using a Knative Service as a sourceを実施する。
Knative EventingはCloudEventsという仕様に準拠してイベント情報をやり取りする。
CloudEvents Playerという、CloudEvents仕様でイベント情報を送信するアプリケーションを、イベントの送信元として作成する。
CloudEvents playerのyamlを作成 $ cat <<EOF > cloudevents-player.yaml apiVersion: serving.knative.dev/v1 kind: Service metadata: name: cloudevents-player spec: template: metadata: annotations: autoscaling.knative.dev/min-scale: "1" spec: containers: - image: ruromero/cloudevents-player:latest env: - name: BROKER_URL value: http://broker-ingress.knative-eventing.svc.cluster.local/default/default EOF 作成する $ kubectl apply -f cloudevents-player.yaml service.serving.knative.dev/cloudevents-player created 確認 $ kubectl get ksvc NAME URL LATESTCREATED LATESTREADY READY REASON cloudevents-player http://cloudevents-player.default.34.145.106.59.sslip.io cloudevents-player-00001 cloudevents-player-00001
KnativeServiceのURL(http://cloudevents-player.default.34.145.106.59.sslip.io)にアクセスすると、以下が表示される。
以下のように入力して「SEND EVENT」をクリックする
すると、以下のように送信したイベントが表示される。
(今はBrokerの先に受け取り手がいないため、送信のみが表示される。)
ちなみに、CloudEvents Playerにcurlすることでもイベントを送信できる。
$ curl -i http://cloudevents-player.default.34.145.106.59.sslip.io \ -H "Content-Type: application/json" \ -H "Ce-Id: 123456789" \ -H "Ce-Specversion: 1.0" \ -H "Ce-Type: some-type" \ -H "Ce-Source: command-line" \ -d '{"msg":"Hello CloudEvents!"}' HTTP/1.1 202 Accepted content-length: 0 date: Tue, 18 Oct 2022 12:46:57 GMT x-envoy-upstream-service-time: 5 server: envoy
Brokerからイベントを受信する
Using Triggers and sinksを実施する。
yamlを作成 $ cat <<EOF > ce-trigger.yaml apiVersion: eventing.knative.dev/v1 kind: Trigger metadata: name: cloudevents-trigger annotations: knative-eventing-injection: enabled spec: broker: default subscriber: ref: apiVersion: serving.knative.dev/v1 kind: Service name: cloudevents-player EOF 作成する $ kubectl apply -f ce-trigger.yaml trigger.eventing.knative.dev/cloudevents-trigger created 確認 $ kubectl get trigger NAME BROKER SUBSCRIBER_URI AGE READY REASON cloudevents-trigger default http://cloudevents-player.default.svc.cluster.local 81s True
CloudEvents Playerからまたイベントを送信してみると、今度は2行表示される。
1行目はBrokerに送信されたイベントで、2行目はBrokerから受信した内容の模様。
Triggerでイベントのフィルタリングができるので、それも試してみる。
TriggerYAMLのfilter設定は公式ドキュメントのこちら参照。
Triggerを削除 $ kubectl delete -f ce-trigger.yaml trigger.eventing.knative.dev "cloudevents-trigger" deleted フィルタリング条件を追加したTriggerのyamlを作成 $ cat <<EOF > ce-trigger-filter.yaml apiVersion: eventing.knative.dev/v1 kind: Trigger metadata: name: cloudevents-trigger annotations: knative-eventing-injection: enabled spec: broker: default filter: attributes: type: test-type subscriber: ref: apiVersion: serving.knative.dev/v1 kind: Service name: cloudevents-player EOF 作成 $ kubectl apply -f ce-trigger-filter.yaml trigger.eventing.knative.dev/cloudevents-trigger created 確認 $ kubectl get trigger NAME BROKER SUBSCRIBER_URI AGE READY REASON cloudevents-trigger default http://cloudevents-player.default.svc.cluster.local 11s True
この状態だと、EventTypeが「test-type」であるイベント以外はbrokerから受信されない。
EventTypeを「test-type」と入力して送信すると、Brokerからの受信含めイベントが2行表示される。
EventTypeを「some-type」と入力して送信すると、Brokerからの受信はされず、イベントは1行だけ表示される。
片付け
$ kubectl delete -f ce-trigger-filter.yaml trigger.eventing.knative.dev "cloudevents-trigger" deleted $ kubectl delete -f cloudevents-player.yaml service.serving.knative.dev "cloudevents-player" deleted
おまけ
Stern
ゼロスケールするKnativeServiceのPodのログを追いたい時、「kubectl logs」だとPodが再作成されるたびにPod名を確認して再実行する必要がある。
sternというツールを使えば、指定した文字列にマッチするPodのログを出力し続けてくれるので便利。
インストール時のメモは以下。
$ wget https://github.com/wercker/stern/releases/download/1.11.0/stern_linux_amd64 $ sudo mv stern_linux_amd64 /usr/local/bin/stern $ sudo chmod +x /usr/local/bin/stern $ stern --version stern version 1.11.0
使い方例:「hello」というKnativeServiceであれば、以下のように実行する。
Podが削除と再作成を繰り返しても、ログを出力し続けてくれる。
$ stern hello
Eventingのログレベル設定
デフォルトだとログレベルはinfo以上だが、イベント送受信時のBrokerやChannelのログは、debugレベルでないと出力されない。
調査などでdebugレベルに変更したい場合は、以下のようにconfig-loggin ConfigMapを修正すればよい。
編集前 $ kubectl -n knative-eventing get configmaps config-logging -o yaml apiVersion: v1 data: loglevel.controller: info loglevel.webhook: info zap-logger-config: | { "level": "info", "development": false, "outputPaths": ["stdout"], "errorOutputPaths": ["stderr"], "encoding": "json", "encoderConfig": { "timeKey": "ts", "levelKey": "level", "nameKey": "logger", "callerKey": "caller", "messageKey": "msg", "stacktraceKey": "stacktrace", "lineEnding": "", "levelEncoder": "", "timeEncoder": "iso8601", "durationEncoder": "", "callerEncoder": "" } } (略) 編集 $ kubectl -n knative-eventing edit configmaps config-logging configmap/config-logging edited 編集後 $ kubectl -n knative-eventing get configmaps config-logging -o yaml apiVersion: v1 data: loglevel.controller: debug loglevel.webhook: debug zap-logger-config: | { "level": "debug", "development": false, "outputPaths": ["stdout"], "errorOutputPaths": ["stderr"], "encoding": "json", "encoderConfig": { "timeKey": "ts", "levelKey": "level", "nameKey": "logger", "callerKey": "caller", "messageKey": "msg", "stacktraceKey": "stacktrace", "lineEnding": "", "levelEncoder": "", "timeEncoder": "iso8601", "durationEncoder": "", "callerEncoder": "" } } (略)
まとめ
- GKE(v1.25.1)でKnative(v1.7)が正常に動作することを確認した。
- Servingを使うことで、Knative Serviceとして簡単にPodをクラスタ外公開できる。また、Podのゼロスケールを行える。
- Eventingを使うことで、brokerを介してイベント情報をやり取りできた。