Knative(ケイ・ネイティブ)は、IBM Cloud Kubernetesサービスの上で簡単に動作するので、セットアップして、サンプルアプリのコンテナビルドと、動作テストまでを実施して記録です。
Knativeとは
Knativeは、アプリケーション開発者にとっての最大の課題、「実行基盤の整備や運用に悩まされることなく、即にアプリケーション開発に集中したい」に対する一つのソリューションです。 つまり、サーバーレスのワークロードを、Kubernetesクラスタで実行できる様になります。しかも、Knativeは、HELMとISTIOをベースとして構築されるため、面倒なセットアップは最小ですみます。
Knativeの実行環境のセットアップ
設置アップ方法は、Knative Install on IBM Cloud Kubernetes Service (IKS)にあります。このページにあるボタンをクリックすると、自動的に環境をセットアップするようなのですが、Before you beginから順番に設置アップしました。
この中では、環境変数にセットして、コマンドを実行するので、筆者が使った環境変数を以下に列挙しておきます。
export CLUSTER_NAME=knative
export CLUSTER_REGION=jp-tok
export CLUSTER_ZONE=tok04
export CLUSTER_K8S_VERSION=1.11.5
コマンドの実行は、IBM Cloudにログインして、順番に実行します。
alias ic='ibmcloud'
ic login
CLUSTER_ZONEで既にVLANを使っていれば、VLANのリストを表示してVLAN番号を取得する。
ic sl vlan list -d $CLUSTER_ZONE
次のコマンドで、IKSのクラスタを作成する。vlan番号は、前述の結果で得たID番号で置き換えます。
ic cs cluster-create --name=$CLUSTER_NAME \
--zone=$CLUSTER_ZONE \
--kube-version=$CLUSTER_K8S_VERSION \
--machine-type=b2c.4x16 \
--workers=3 \
--private-vlan 244**** \
--public-vlan 244***
大体20分くらいで、クラスタが稼働するので、ISTIOをインストール
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.2.2/istio.yaml
ISTIOが介入するネームスペースを設定して、ポッドの動作を確認する。
kubectl label namespace default istio-injection=enabled
kubectl get pods --namespace istio-system
ISTIOのポッドが全部立ち上がる、または、処理が完了したら、Knativeをインストールする。
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.2.2/release.yaml
次は起動完了確認の結果です。
$ kubectl get pods --namespace knative-serving
NAME READY STATUS RESTARTS AGE
activator-6677bbc9d6-7jmzg 2/2 Running 0 2m
activator-6677bbc9d6-tvz57 2/2 Running 0 2m
activator-6677bbc9d6-vlkmm 2/2 Running 0 2m
autoscaler-5d87cc6b75-brfq6 2/2 Running 0 2m
controller-f4c59f474-tdm8q 1/1 Running 0 2m
webhook-5d9cbd46f7-ldmmx 1/1 Running 0 2m
$ kubectl get pods --namespace knative-build
NAME READY STATUS RESTARTS AGE
build-controller-79d6cc9d57-hg2t9 1/1 Running 0 2m
build-webhook-f97d479f9-m9bcz 1/1 Running 0 2m
以上で、Knative利用の準備完了です。 およそ 30分くらいという感じです。
Serverlessのアプリのコンテナビルド
サーバーレスのクライアントから呼び出すためのコンテナを開発します。と言っても、このアプリケーションは、PythonのFLASKフレームワークで開発したマイクロサービス相当のサンプルコードを利用します。
ディレクトリappを作成して、Pythonのアプリを作成します。
$ tree
.
├── app
│ ├── Dockerfile
│ └── app.py
└── service.yaml
app.pyのコードは、以下の通りで、curlなどで、ルート / をアクセスすると、Hello と 環境変数TARGETに設定された文字列を返すだけのシンプルなRESTサービスです。
import os
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
target = os.environ.get('TARGET', 'World')
return 'Hello {}!\n'.format(target)
if __name__ == "__main__":
app.run(debug=True,host='0.0.0.0',port=int(os.environ.get('PORT', 8080)))
次のコマンドのリストを順番に実行して、このアプリをコンテナにビルドして、Docker Hubに登録します。
docker build -t maho/helloworld-python .
docker login
docker push maho/helloworld-python
以上で、Serverlessのコンテナの準備は完了です。
次に進む前に、ここで利用したDockerfileは以下の通りです。環境変数が回りグドい感じがしますが、気にせず利用ください。
FROM python
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . .
RUN pip install Flask
ENV PORT 8080
EXPOSE $PORT
CMD ["python", "app.py"]
Knativeのサービス登録(アプリ機能の登録)
コンテナの準備ができたら、Knativeのサービスを登録していきます。このためのマニフェストは、以下の通りです。環境変数 TAGETに応答する文字列(Python Sample v1)をセットしておきます。
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: helloworld-python
namespace: default
spec:
runLatest:
configuration:
revisionTemplate:
spec:
container:
image: maho/helloworld-python
env:
- name: TARGET
value: "Python Sample v1"
マニフェストを適用することで、ロードバランサーと連携したサービスが生成されます。そして、アクセストラフィックは、ドメイン名 helloworld-python.default.example.com でルーティングされるようになります。
$ kubectl apply -f service.yaml
service.serving.knative.dev/helloworld-python created
$ kubectl get svc knative-ingressgateway --namespace istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
knative-ingressgateway LoadBalancer 172.21.63.101 ***.***.68.123 80:32380/TCP,443:32390/TCP,31400:32400/TCP,15011:31145/TCP,8060:30283/TCP,853:32466/TCP,15030:31171/TCP,15031:32012/TCP 48m
$ kubectl get ksvc helloworld-python --output=custom-columns=NAME:.metadata.name,DOMAIN:.status.domain
NAME DOMAIN
helloworld-python helloworld-python.default.example.com
アクセステスト
簡単な動作検証で、ドメイン名をDNSへ登録している訳にはいかないので、ヘッダーにドメイン名を設定して、サービスのEXTERNAL-IPに目がけて、アクセステストを実施します。
$ export IP_ADDRESS=***.***.68.123
$ curl -H "Host: helloworld-python.default.example.com" http://{$IP_ADDRESS}
Hello Python Sample v1!
RESTサービスの応答として、「Hello Python Sample v1!」がきました。
ここでは、検証のためにcurlでじかに利用しましたが、実際のアプリケーションからKnativeのサーバーレスを機能を呼び出す場合には、ベタにURLを書かずに、ラップ関数を設けて、コーディングし易いようにすると思います。というか、するべきだと思います。
どこが Serverlessなんだろう?
これじゃ、サーバーレスとしての動作が良くわからないですよね。
次の実行結果で、curlのアクセスが実行されるまで、Pythonで書いたコンテナのポッドは、存在していません。そして、アクセスが来ると、そのFQDNに対応するポッド(コンテナ)が起動して、要求を処理します。そして、要求が5分間を経過しても、要求がなければ、Pythonのサンプルアプリのポッドは終了させられ、リソースを解放します。
つまり、Knativeは、機能(アプリ)を利用しない場合は、資源を解放して待機しており、機能(アプリ)への要求があると、対応する機能(アプリ)のポッド(コンテナ)を起動して処理を実行しまます。
## サービスのFQDN helloworld-python.default.example.com を呼び出され前
$ kubectl get pod
No resources found.
## 呼び出され後
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
helloworld-python-00001-deployment-669888748b-gzzkq 3/3 Running 0 8s
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
helloworld-python-00001-deployment-669888748b-gzzkq 3/3 Running 0 56s
<省略>
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
helloworld-python-00001-deployment-669888748b-gzzkq 3/3 Running 0 5m
## 5分越えると自動クリーンナップ
$ kubectl get pod
No resources found.
オートスケールはしないのか?
IKSには、2018年12月末現在で、ノードレベルのオートスケールが実装されていません。2019年はじめには、リリースされると思います。(個人の意見です) そのため、現在は、Knativeのアプリケーションに負荷をかけても、ノードレベルではスケールしませんが、もう少しすれば、ポッド数=0から、最大ノード数設定値までスケールするようになると思います。
まとめ
IKSでも、Knativeは利用できました。セットアップはとても簡単でした。IKSのノードレベルのオートスケールの実装が待ち遠しいですね。しかし、スケールの必要がなければ、現在のIKSでもKnativeは十分使い始められそうです。