ほんと久しぶりの投稿です。
社内のタスクで、Knativeの技術調査をこの間まで実施していました。せっかくなので、備忘録として作業ログを何回かに分けて書いていきます。
Knativeとは
Google社やPivotal社、IBMが中心となって開発している、Kubernetesを基盤とした、Serverlessプラットフォーム構築のためのビルディング・ブロックです。ざっくりと言って、以下の3つの要素から構成されます:
- Builds
- イメージのビルドに必要な仕組みを提供する
- Serving
- リクエスト量に応じた動的なスケールアウト/インの仕組みの提供
- Istioを活用した賢いルーティングの仕組みの提供
- Eventing
- FaaSが必要とするイベント駆動のための仕組みを提供
Knativeが出てきた背景などは以下のリンクの記事が詳しいので、是非目を通していただければと思います。自分も最初何度も読みました。
最強のServerlessプラットフォーム? Knativeを動かしてみるぞい
Knativeってどこで使われてる?
例えば、IBMがオープンソースとして寄与したApache OpenWhiskはKnativeを基盤に据える新アーキテクチャーが検討されています。プロジェクトKwskという名前です。(にしても「くわしく」ってw)
Kwsk (Apache OpenWhisk on Knative)
また、Riffと呼ばれるKubernetesのためのFaaS構成基盤もKnativeベースで構成されるオープンソースです。RiffをベースにPivotal社はPivotal Function Servicesのアルファ版を2018年12月前半に公開しています。
他にも、CI/CDツールのJenkins XもKnativeを活用した構成をとるようです。
調べると色々あるもんですね。。他にもあるのかな?
Knative環境を用意しよう
では、実際にどんな環境なのかを構成して確認してみます。今回は普段使っているIKS (IBM Cloud Kubernetes Service)で構成してみます。
ただ、Knativeそのままだとやや使いにくい印象もあるので、今回はknctlコマンドライン・インターフェースを利用して導入・操作する手順をまとめておきます。
- Knative Install on IBM Cloud Kubernetes Service (IKS)
- Introducing Knctl: A simpler way to work with Knative
注意
- knctlコマンドライン・ツールは2018年12月時点ではKnative公式のコマンドライン・インターフェースではありません。
- 今回の手順で導入されるKnativeに関して、Eventingは未導入です。
0. コマンドライン・インターフェースを準備する
まずはIBM Cloudを操作するためのコマンドライン・インターフェースを導入します。
すでに導入済みの人は良いですが、導入済みでない場合は以下のリンクを参考に導入し、ibmcloud loginでIBM Cloudにログインしておきます。
IBM Cloud資料 - CLI と API のセットアップ
kubectlコマンドライン・インターフェースも以下のリンクを参考に導入しておきます。
1. Kubernetesクラスターを構成する
IBM Cloudのコンソール画面でも導入できますが、面倒なのでコマンドラインで導入します。以下は全てMac OSにて実施したログですので、Windowsの場合は参考程度に読み替えて実施してみてください。
まずはIBM Cloud上で利用可能なKubernetesのバージョンをibmcloud ks kube-versions
で確認します。
$ ibmcloud ks kube-versions
OK
バージョン
1.9.11 (推奨されておらず、13 日後にはサポート対象外)
1.10.11 (default)
1.11.5
1.12.3
バージョン間の差分を評価するには、https://console.bluemix.net/docs/containers/cs_versions.html#cs_versions を参照してください
上記より今回はデフォルトの1.10.11で導入します。
備考
1.11以降、コンテナー実行基盤がDockerdからContainerdに変更されています。
それが原因なのかはちゃんと調べきれてませんが、Istioに付属するPrometheus Serverの導入に失敗します(2018年12月14日確認時点)。
IBM CloudでKnativeを触ってみたい方は一旦1.10で試してもらった方が良いかもしれません。
続いて、デプロイ先のリージョンの指定やクラスター名を変数として設定します。
以下はIBM Cloudの東京リージョンにあるゾーンtok02を利用する例です。先ほど調べたバージョンはCLUSTER_K8S_VERSION
に設定します。クラスター名はknative
とします。
export CLUSTER_NAME=knative
export CLUSTER_REGION=ap-north
export CLUSTER_ZONE=tok02
export CLUSTER_K8S_VERSION=1.10.13
ibmcloud ks region-set
で操作対象のリージョンをap-north、つまりは東京に切り替えます。OK
と表示されたら先に進みます。
ibmcloud ks region-set $CLUSTER_REGION
デプロイの準備ができたので、ibmcloud ks cluster-create
コマンドでクラスターを作成します。マシンタイプに関しては、今回はKnativeのドキュメントにある最小要件b2c.4x16
(4 vCPU, 16GBメモリーの共有仮想サーバー)のワーカーノードを3台構成します。
ibmcloud ks cluster-create --name=$CLUSTER_NAME \
--zone=$CLUSTER_ZONE \
--kube-version=$CLUSTER_K8S_VERSION \
--machine-type=b2c.4x16 \
--workers=3
しばらく待てばクラスターが作成され、利用可能になります。ibmcloud ks clusters
で一覧表示し、状態がnormal
になっていることを確認しましょう。
$ ibmcloud ks clusters
OK
名前 ID 状態 作成日時 ワーカー ロケーション バージョン リソース・グループ名
knative xxxxxxx normal 52 minutes ago 3 Tokyo 1.10.11_1536 default
注意
最小要件を満たすクラスターを構成するためには利用しているIBM Cloudアカウントはクレジット登録しないとオーダーできませんのでご注意ください。今回の構成の場合、1時間ごとに約0.88ドルかかります。
2. Knative (Serving, Builds)を導入する
ここから本題のKnativeを導入していきます。
今回はKnctlコマンドライン・インターフェースで導入するのでシンプルです。
まずはibmcloud ks cluster-config <クラスター名>
でkubectlコマンドライン・インターフェースでアクセスするための構成情報をダウンロードします。
$ ibmcloud ks cluster-config knative
OK
knative の構成は正常にダウンロードされました。
環境変数をエクスポートして Kubernetes の使用を開始してください。
export KUBECONFIG=/Users/xxxx/.bluemix/plugins/container-service/clusters/knative/kube-config-tok02-knative.yml
表示されたexport ~
の部分をターミナルで実行し、kubectl get node
などでワーカーノード数などを確認し、問題なくアクセスできていることを確認します。
そうしたら、knctl install
を実行し、Knativeを導入します。特にエラーなく、Succeeded
と表示されればまずはOKです。
$knctl install
Installing Istio from 'https://github.com/knative/serving/releases/download/v0.2.1/istio.yaml'
namespace "istio-system" created
configmap "istio-galley-configuration" created
configmap "istio-statsd-prom-bridge" created
configmap "istio-security-custom-resources" created
configmap "istio" created
:
(中略)
:
Non-ready pods: activator-db79694db-bc2bv, autoscaler-86d954bffc-pwzjp
Non-ready pods: activator-db79694db-bc2bv, autoscaler-86d954bffc-pwzjp
Non-ready pods: autoscaler-86d954bffc-pwzjp
Non-ready pods: autoscaler-86d954bffc-pwzjp
Succeeded
念のため、ダウンしているPodがいないかkubectl get pods --all-namespaces
で確認します。
$kubectl get po --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
ibm-system ibm-cloud-provider-ip-161-202-148-10-f67dc95c4-pvm8x 1/1 Running 0 3h
ibm-system ibm-cloud-provider-ip-161-202-148-10-f67dc95c4-z6j62 1/1 Running 0 3h
ibm-system ibm-cloud-provider-ip-161-202-148-13-8655c5cd99-nr2pp 1/1 Running 0 3h
ibm-system ibm-cloud-provider-ip-161-202-148-13-8655c5cd99-w6zns 1/1 Running 0 3h
ibm-system ibm-cloud-provider-ip-161-202-148-14-5f9f5696db-fq4d2 1/1 Running 0 4h
ibm-system ibm-cloud-provider-ip-161-202-148-14-5f9f5696db-qq7nn 1/1 Running 0 4h
istio-system istio-citadel-84fb7985bf-tk76n 1/1 Running 0 3h
istio-system istio-cleanup-secrets-kqkt2 0/1 Completed 0 3h
istio-system istio-egressgateway-bd9fb967d-dqzxr 1/1 Running 0 3h
istio-system istio-galley-655c4f9ccd-ps4xs 1/1 Running 0 3h
istio-system istio-ingressgateway-688865c5f7-jxk5f 1/1 Running 0 3h
istio-system istio-pilot-6cd69dc444-6cvwk 2/2 Running 0 3h
istio-system istio-policy-6b9f4697d-p5r7n 2/2 Running 0 3h
istio-system istio-sidecar-injector-8975849b4-sr5zl 1/1 Running 0 3h
istio-system istio-statsd-prom-bridge-7f44bb5ddb-7px64 1/1 Running 0 3h
istio-system istio-telemetry-6b5579595f-7nrpw 2/2 Running 0 3h
istio-system istio-telemetry-6b5579595f-9bmkb 2/2 Running 0 3h
istio-system istio-telemetry-6b5579595f-lhnwm 2/2 Running 0 2h
istio-system knative-ingressgateway-76b7677587-cltpn 1/1 Running 0 3h
istio-system zipkin-7f4b7b4988-2jnkj 1/1 Running 0 3h
knative-build build-controller-747b8fd966-6f8nw 1/1 Running 0 3h
knative-build build-webhook-6dc78d8f6d-p64f9 1/1 Running 0 3h
knative-monitoring elasticsearch-logging-0 1/1 Running 0 3h
knative-monitoring elasticsearch-logging-1 1/1 Running 0 3h
knative-monitoring grafana-798cf569ff-xc4gc 1/1 Running 0 3h
knative-monitoring kibana-logging-6bf7d8784d-d5jgk 1/1 Running 0 3h
knative-monitoring kube-state-metrics-6d99fddb8d-lhbg4 4/4 Running 0 3h
knative-monitoring node-exporter-kw7jc 2/2 Running 0 3h
knative-monitoring node-exporter-prlbs 2/2 Running 0 3h
knative-monitoring node-exporter-ts6t5 2/2 Running 0 3h
knative-monitoring prometheus-system-0 1/1 Running 0 3h
knative-monitoring prometheus-system-1 1/1 Running 0 3h
knative-serving activator-6cd459647f-p6bfk 2/2 Running 0 3h
knative-serving activator-6cd459647f-sxhhd 2/2 Running 0 3h
knative-serving activator-6cd459647f-v27kw 2/2 Running 0 3h
knative-serving autoscaler-75b64694b-nxxpx 2/2 Running 0 3h
knative-serving controller-54ffbcdfd4-kbmzq 1/1 Running 0 3h
knative-serving webhook-5955555748-lmkvj 1/1 Running 0 3h
kube-system calico-kube-controllers-6b79555b7-n99xt 1/1 Running 0 4h
kube-system calico-node-fl7g5 2/2 Running 0 4h
kube-system calico-node-v8rss 2/2 Running 0 4h
kube-system calico-node-vnl8m 2/2 Running 0 4h
kube-system heapster-74547548dd-kwcdt 2/2 Running 0 4h
kube-system ibm-file-plugin-54b4ff5b8d-cdf7b 1/1 Running 0 4h
kube-system ibm-keepalived-watcher-hrrs2 1/1 Running 0 4h
kube-system ibm-keepalived-watcher-lsr2r 1/1 Running 0 4h
kube-system ibm-keepalived-watcher-psmjl 1/1 Running 0 4h
kube-system ibm-kube-fluentd-thsxp 1/1 Running 0 4h
kube-system ibm-kube-fluentd-vjww7 1/1 Running 0 4h
kube-system ibm-kube-fluentd-znpdn 1/1 Running 0 4h
kube-system ibm-master-proxy-static-10.129.180.104 2/2 Running 0 4h
kube-system ibm-master-proxy-static-10.129.180.76 2/2 Running 0 4h
kube-system ibm-master-proxy-static-10.129.180.78 2/2 Running 0 4h
kube-system ibm-storage-watcher-65c9657c94-rvshv 1/1 Running 0 4h
kube-system kube-dns-amd64-84454d78cf-dg7fn 3/3 Running 0 4h
kube-system kube-dns-amd64-84454d78cf-j4f8n 3/3 Running 0 4h
kube-system kube-dns-autoscaler-87c768b59-vs9xt 1/1 Running 0 4h
kube-system kubernetes-dashboard-66ddf6bfd-q2kbd 1/1 Running 0 4h
kube-system public-cr8ab804382e104dd5a576c00c2a8c9c9e-alb1-67d987f5f9-5ncxk 4/4 Running 0 4h
kube-system public-cr8ab804382e104dd5a576c00c2a8c9c9e-alb1-67d987f5f9-m95z5 4/4 Running 0 4h
kube-system vpn-7747668c4b-bxq7x 1/1 Running 0 4h
Knativeを試す (ざっくりと動作確認)
重要な機能やIBM Cloud固有の使い方の話は別途記載するとして、ざっくりとアプリがデプロイできるところを確認します。
knctl deploy
コマンドでKnativeのサンプル・イメージを用いてアプリをデプロイします。
$ knctl deploy --service hello \
--image gcr.io/knative-samples/helloworld-go \
--env TARGET=Taro
Name hello
Waiting for new revision to be created...
Tagging new revision 'hello-00001' as 'latest'
Tagging new revision 'hello-00001' as 'previous'
Annotating new revision 'hello-00001'
Waiting for new revision 'hello-00001' to be ready for up to 5m0s (logs below)...
hello-00001 > hello-00001-deployment-5b596c876c-6rxf7 | 2018/12/17 15:41:05 Hello world sample started.
Revision 'hello-00001' became ready
Continuing to watch logs for 5s before exiting
Succeeded
デプロイされたアプリケーションはKnativeとしてはServiceと呼ばれる単位で管理されます。knctl service list
でKnative Serviceの一覧を確認できます。
$ knctl service list
Services in namespace 'default'
Name Domain Annotations Conditions Age
hello hello.default.example.com - 3 OK / 3 2m
1 services
Succeeded
Kubernetesの視点で見ると、アプリケーションはDeploymentでデプロイされています。
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-00001-deployment 1 1 1 1 2m
$ kubectl get pods -n default
NAMESPACE NAME READY STATUS RESTARTS AGE
default hello-00001-deployment-5b596c876c-6rxf7 3/3 Running 0 2m
ここで、5分ほど放置すると、上記で確認したPodは削除されているのが確認できると思います。Servingのゼロ・スケーリングが発動したためです。
$kubectl get po
No resources found.
利用していない時はリソースの無駄遣いをしないようにするためにPodを落とす、なかなかに素敵な動きをします。この状態でアプリケーションにアクセスするとどうなるでしょうか? knctl curl --service <Knative Service名>
でアクセスしてみます。
$knctl curl --service hello
Running: curl '-sS' '-H' 'Host: hello.default.example.com' 'http://161.202.103.219:80'
Hello Taro!
Succeeded
体感的にやや時間がかかりましたが、きちんと応答が返ってきました。もう一度Podを確認すると、別のPodが作成されて稼働しているのが確認できます。
$kubectl get po
NAME READY STATUS RESTARTS AGE
hello-00001-deployment-5b596c876c-n682h 3/3 Running 0 18s
次にアプリケーションを更新します。再びknctl deploy
コマンドでデプロイします。
Knative Serviceであるhelloのリビジョンが上がったことが確認できます。
$ knctl deploy --service hello \
--image gcr.io/knative-samples/helloworld-go \
--managed-route=false \
--env TARGET=Jiro
Name hello
Waiting for new revision (after revision 'hello-00001') to be created...
Tagging new revision 'hello-00002' as 'latest'
Tagging older revision 'hello-00001' as 'previous'
Annotating new revision 'hello-00002'
Waiting for new revision 'hello-00002' to be ready for up to 5m0s (logs below)...
hello-00002 > hello-00002-deployment-66dccfb4c5-fhbdm | 2018/12/17 16:06:49 Hello world sample started.
Revision 'hello-00002' became ready
Continuing to watch logs for 5s before exiting
Succeeded
再びアプリケーションに対しデプロイすると、結果が変わっていることが確認できます。
(環境変数env
に合わせて出力が変わっていることが確認できます。)
$knctl curl --service hello
Running: curl '-sS' '-H' 'Host: hello.default.example.com' 'http://161.202.103.219:80'
Hello Jiro!
Succeeded
もう一度、デプロイしてみます。
$ knctl deploy --service hello \
--image gcr.io/knative-samples/helloworld-go \
--managed-route=false \
--env TARGET=Saburo
Name hello
Waiting for new revision (after revision 'hello-00002') to be created...
Tagging new revision 'hello-00003' as 'latest'
Tagging older revision 'hello-00002' as 'previous'
Annotating new revision 'hello-00003'
Waiting for new revision 'hello-00003' to be ready for up to 5m0s (logs below)...
hello-00003 > hello-00003-deployment-f956864b4-wg8hp | 2018/12/17 16:21:59 Hello world sample started.
Revision 'hello-00003' became ready
Continuing to watch logs for 5s before exiting
Succeeded
そしてknctl rollout
コマンドを実行します。下記の例はlatest(envがSaburo)のリビジョンとprevious(envがJiro)のリビジョンのルーティング比を20%, 80%に指定しています。すなわち5回に1回は「Hello Saburo!」、他は「Hello Jiro!」と結果が帰るようなルーティング動作がこのコマンドで実現できます。
$knctl rollout --route hello -p hello:latest=20% -p hello:previous=80% -n default
Succeeded
数回アクセスしてみましたが、以下の結果を見る限りだいたい合ってそうですね。いつも綺麗な結果が出るわけではないですが、こうしたロールアウトの設定を少しずつ変更してカナリア・リリースを実現できます、ということですね。
$ knctl curl --service hello
Running: curl '-sS' '-H' 'Host: hello.default.example.com' 'http://161.202.103.219:80'
Hello Jiro!
Succeeded
$ knctl curl --service hello
Running: curl '-sS' '-H' 'Host: hello.default.example.com' 'http://161.202.103.219:80'
Hello Jiro!
Succeeded
$ knctl curl --service hello
Running: curl '-sS' '-H' 'Host: hello.default.example.com' 'http://161.202.103.219:80'
Hello Jiro!
Succeeded
$ knctl curl --service hello
Running: curl '-sS' '-H' 'Host: hello.default.example.com' 'http://161.202.103.219:80'
Hello Jiro!
Succeeded
$ knctl curl --service hello
Running: curl '-sS' '-H' 'Host: hello.default.example.com' 'http://161.202.103.219:80'
Hello Saburo!
Succeeded
$ knctl curl --service hello
Running: curl '-sS' '-H' 'Host: hello.default.example.com' 'http://161.202.103.219:80'
Hello Jiro!
終わりに
まずは導入編ということで、IBM CloudのIKS(IBM Cloud Kubernetes Service)でのKnativeのセットアップと簡単な動作確認を行いました。特にServingの動作をざっくり見てみたわけですが、Buildsの利用については別記事で整理したいと思います。