Knativeとは
Knativeとは、Kubernetes上にサーバレスコンピューティングの基盤を構築する、オープンソースソフトウェアです。 イベントをトリガーにしてコンテナを起動して、負荷に応じコンテナ実行数を自由に増減させるスケーラビリティを提供します。KnativeはGoogle Cloud上の「Cloud Run」を構成する主要なソフトウェアになっています。
Knativeのメリットとして、アプリケーションの利用率に応じてゼロスケールできること、利用率の増加に伴って自動でスケールすること、Kubernetesの細かい部分を知らないでもサービスの作成ができることがメリットとして挙げられます。逆にデメリットは...色々な部分が抽象化されるので、動かなくなった場合は幅広い知識が要求されます。
Knative Servingについては「Knative Serving in Production」をご覧ください。かなり細かい部分についても書かれているので、非常に良い資料だと私は思います。
Knative EventingについてはKnative Eventingでイベント駆動なアプリケーションを体験するなどをご覧ください。
microk8sとは
microk8sとは開発者、クラウド、クラスター、ワークステーション、エッジ、IoT向けの最小構成のKubernetesを提供する、オープンソースソフトウェアです。Ubuntuの開発、サポートを提供するカノニカルが開発を主導しています。
割とハードウェアリソースが厳しいIoT機器から、一般のサーバー、クライアントなどで動かすことが可能です。Kubernetes環境のセットアップは時間や手間がかかって大変ですが、microk8sならsnapパッケージを使ってインストールするだけで簡単にクラスターを動かせるだけでなく、ワンライナーで豊富なアドオンを追加することで色々な環境を作ることができます。
周辺のソフトウェアなどの準備
それでは早速Knativeを触ってみようと思います。 Ubuntu Server 20.04最新版をインストールして、アップデート、再起動を実行します。
sudo apt update && sudo apt upgrade && sudo reboot
microk8sを入れます。Ubuntu Serverのインストーラーを使ってセットアップする際に、microk8sをインストールすることもできます。このオプションを選択すると、Ubuntu Serverのインストール後、初回起動時に最新のstableバージョンのmicrok8sがインストールされます。
sudo snap install microk8s --channel=stable --classic sudo snap install kubectl --channel=stable --classic sudo microk8s enable dns rbac
type:LoadBalancer
を使うため、MetalLBを有効化(オプション)します。
指定するIPアドレスはホストのIPアドレス(多くの場合一つしか設定されていないはずなので次のような指定方法)を設定しましょう。
microk8s enable metallb Enter each IP address range delimited by comma: 192.168.0.49-192.168.0.49
kubeconfigを書き込みます(snapコマンドを使ってmicrok8s.kubectlコマンドのエイリアスを張る方法もあるのですが、後述のKnative CLIを使うためにこんなことをする必要があります)。
mkdir ~/.kube/ && touch ~/.kube/config microk8s config > ~/.kube/config
Knative CLIであるkn
を次の手順でインストールします。
curl -Lo ./kn https://github.com/knative/client/releases/download/knative-v1.3.1/kn-linux-amd64 chmod +x ./kn sudo mv ./kn /usr/local/bin/kn
Knative のセットアップ
mictrok8sのアドオンにKnativeというアドオンがありますが、これはバックエンドにIstioを利用しています。最近のIstioはリソース要件が厳しいらしく、手元の環境では正常に動かすことができませんでした。現在のKnativeはIngressコントローラーとしてIstioの他、Gloo、Ambassador、Kourierが利用できます。
このうちKourierは、Red Hatが主導して開発が進められているKnativeのためのIngressであり、Istio Ingressの置き換えを目的としているようです。ミニマムなリファレンス実装を目指して開発されています。
今回はKourierを使ってみます。
Knative Servingのインストール
今回はKnative Serving 1.3.0をインストールする例です。バージョン1.0以降はバージョンが変わってもほぼ同じ流れで動かせるようです。
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.3.0/serving-crds.yaml kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.3.0/serving-core.yaml
ネットワークレイヤーのインストール
Knativeのネットワークレイヤとして軽量なKourier Ingressを使ってみます。
curl -Lo kourier.yaml https://github.com/knative/net-kourier/releases/download/knative-v1.3.0/kourier.yaml
以下の設定部分を書き換えます (MetalLB
を使う場合は設定書換えは不要)。
... 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.3.0" app.kubernetes.io/name: knative-serving serving.knative.dev/release: "v1.3.0" spec: ports: - name: http2 port: 80 protocol: TCP targetPort: 8080 nodePort: 31080 # 追加 - name: https port: 443 protocol: TCP targetPort: 8443 nodePort: 31443 # 追加 selector: app: 3scale-kourier-gateway type: NodePort # LoadBalancerから変更 ...
設定を適用
kubectl apply -f kourier.yaml
Knative ServingがKourierを使用するように構成
kubectl patch configmap/config-network --namespace knative-serving --type merge --patch '{"data":{"ingress-class":"kourier.ingress.networking.knative.dev"}}'
DNSの構成
ここではワイルドカードDNSサービスであるsslip.io
を使用するよう構成します(ファイル内に「args: ["-magic-dns=sslip.io"]」みたいな記述がある)。
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.3.0/serving-default-domain.yaml
config-domainに以下を追加して、カスタムドメイン*.192.168.0.49.sslip.io
を192.168.0.49
に解決します(IPアドレスは環境に合わせて置き換えるか、もしくは127.0.0.1
を設定してください)。
kubectl patch configmap/config-domain --namespace knative-serving --type merge --patch '{"data":{"192.168.0.49.sslip.io":""}}'
この設定により、例えばPodの名前がhello
で名前空間がdefault
のPodへはhttp://hello.default.192.168.0.49.sslip.io
のようなアドレスが払い出されます。
サービスの確認
サービスを確認します。NodePortでアクセスする場合は、URLにポート番号をつけてアクセスしてください。
kubectl get svc kourier -n kourier-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kourier NodePort 10.152.183.112 <none> 80:31080/TCP,443:31443/TCP 27m or NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kourier LoadBalancer 10.152.183.182 192.168.0.49 80:32083/TCP,443:31470/TCP 9m56s
これ以降では、MetalLBを使った場合の実行例と結果例を記述します。NodePortでアクセスする場合はhttpアクセスは31080ポートをつけてアクセスしてください。
Knative Servingを触ってみる
試しにこれを作ってみましょう。
kn service create hello --image gcr.io/knative-samples/helloworld-go --port 8080 --env TARGET=World Creating service 'hello' in namespace 'default': 0.010s The Route is still working to reflect the latest desired specification. 0.080s ... 0.096s Configuration "hello" is waiting for a Revision to become ready. 167.698s ... 167.970s Ingress has not yet been reconciled. 168.128s Waiting for load balancer to be ready 168.287s Ready to serve. Service 'hello' created to latest revision 'hello-00001' is available at URL: http://hello.default.192.168.0.49.sslip.io
(160秒もかかっていますが、もっと良いマシンで実行したら、もっと速く作られるはずです)
LBアクセス
curl
コマンドでアクセスしてみましょう。ブラウザでアクセスしても同じ結果になります。
curl http://hello.default.192.168.0.49.sslip.io Hello World!
Knative Servingのサービスリストは次のコマンドで確認できます。
kn service list NAME URL LATEST AGE CONDITIONS READY REASON hello http://hello.default.192.168.0.49.sslip.io hello-00001 26m 3 OK / 3 True
Scaling to Zero
デフォルトの設定ではおよそ数分経過すると、サービスが縮退します。
-w
オプションを使ってデプロイメントの状態を監視してみましょう。最終的にはPod数0としてアプリケーションが存在することがわかります(あくまで0にするだけで、サービスは削除されない)
kubectl get deployment -l serving.knative.dev/service=hello -w NAME READY UP-TO-DATE AVAILABLE AGE hello-00001-deployment 1/1 1 1 118s hello-00001-deployment 1/0 1 1 2m hello-00001-deployment 1/0 1 1 2m hello-00001-deployment 0/0 0 0 2m1s ...
アクセスがあるとPodが再作成され、サービスが復活します。
curl hello.default.192.168.0.49.sslip.io Hello World! kubectl get deployment -l serving.knative.dev/service=hello -w NAME READY UP-TO-DATE AVAILABLE AGE hello-00001-deployment 1/1 1 1 3m15s
Basics of Traffic Splitting
トラフィックの分割もKnativeはサポートしています。
まず、現在のサービスの状態を確認します。
kn service list NAME URL LATEST AGE CONDITIONS READY REASON hello http://hello.default.192.168.0.49.sslip.io hello-00001 47m 3 OK / 3 True
Knative Serviceの更新されたバージョンをデプロイします。
kn service update hello --env TARGET=Knative Updating Service 'hello' in namespace 'default': 0.067s The Configuration is still working to reflect the latest desired specification. 9.259s Traffic is not yet migrated to the latest revision. 9.461s Ingress has not yet been reconciled. 9.603s Waiting for load balancer to be ready 9.736s Ready to serve. Service 'hello' updated to latest revision 'hello-00002' is available at URL: http://hello.default.192.168.0.49.sslip.io
リビジョンが変わったことが確認できます。
kn service list NAME URL LATEST AGE CONDITIONS READY REASON hello http://hello.default.192.168.0.49.sslip.io hello-00002 8m30s 3 OK / 3 True
新しいリビジョンにアクセスしてみる(普通にcurlでアクセスしても良い)
echo "Accessing URL $(kn service describe hello -o url)" curl "$(kn service describe hello -o url)" Hello Knative!
リビジョンを確認すると、現在はhello-00002
のサービスに100%アクセスが振り分けられていることがわかります。つまり何度アクセスしてもリビジョンhello-00002
にアクセスされ、hello-00001
のサービスへはアクセスできません。
kn revisions list NAME SERVICE TRAFFIC TAGS GENERATION AGE CONDITIONS READY REASON hello-00002 hello 100% 2 2m59s 3 OK / 4 True hello-00001 hello 1 51m 3 OK / 4 True
リビジョン間でトラフィックを分割してみます。今回は50%の確率でhello-00001
かhello-00002
のサービスを表示できるように設定します。実行するコマンドは次のとおりです。
kn service update hello --traffic hello-00001=50 --traffic @latest=50 Updating Service 'hello' in namespace 'default': 0.059s The Route is still working to reflect the latest desired specification. 0.204s Ingress has not yet been reconciled. 0.335s Waiting for load balancer to be ready 0.432s Ready to serve. Service 'hello' with latest revision 'hello-00002' (unchanged) is available at URL: http://hello.default.192.168.0.49.sslip.io kn revisions list NAME SERVICE TRAFFIC TAGS GENERATION AGE CONDITIONS READY REASON hello-00002 hello 50% 2 4m58s 3 OK / 4 True hello-00001 hello 50% 1 53m 3 OK / 4 True
アクセスすると、大体半分の確率でhello-00001
とhello-00002
のサービスに振り分けられます。
curl http://hello.default.192.168.0.49.sslip.io Hello World! curl http://hello.default.192.168.0.49.sslip.io Hello Knative! ...
他のサービスを作成
他のサービスを作成して、そのコンテナアプリケーションにも引き続きアクセスできることを確認します。
kn service create hello2 --image gcr.io/knative-samples/helloworld-go --port 8080 --env TARGET=World Creating service 'hello2' in namespace 'default': ... Service 'hello2' created to latest revision 'hello2-00001' is available at URL: http://hello2.default.192.168.0.49.sslip.io kn service list NAME URL LATEST AGE CONDITIONS READY REASON hello http://hello.default.192.168.0.49.sslip.io hello-00002 33m 3 OK / 3 True hello2 http://hello2.default.192.168.0.49.sslip.io hello2-00001 5m41s 3 OK / 3 True curl http://hello.default.192.168.0.49.sslip.io Hello World! curl http://hello2.default.192.168.0.49.sslip.io Hello World!
問題ないようです。
サービスの削除
最後にサービスをクリーンアップしましょう。
kn service delete hello kn service delete hello2 kn service list
microk8sのおかげで、KubernetesとKnativeの理解がちょっとだけ深まりました。ありがとうございます。 この記事と同じ内容は、以下のGistで公開しています。そちらも合わせてご覧ください。