はじめに
Knativeをご存知でしょうか? 簡単に言うとCloud Build, Google AppEngine, Cloud FunctionをDocker/k8sベースで実現するための仕組み。
これは中々便利でスケーラブルなビルド環境まで含まれてるので、マネージドなKnative環境があれば自前でGCPっぽい環境が作れる訳ですね。
と言うわけ、Cloud Next 2019でなんか発表あるだろうから予習がてら現状のKnativeをGKEで動かしてみた備忘録です。
最新情報は公式ドキュメント参考で。
GKEでKubenetesクラスタの作成
まずはクラスタを作成するわけですが、KnativeはIstioやFluentd, Prometheus, Grafana, OpenZipkin, Kibanaなども含まれている大きなアセットです。
なので、最小構成といえどそれなりのソースを使います。ただ、たいしたもの動かさないのであまりお金かけたく無いと言うこともあり構成を試行錯誤してみました。
その結果以下の感じになりました。n1-standard-2が恐らく動かすために必要なノードあたりの最低スペックになります。ワーカーとしても用もf1-microだとリソース不足になりがちなのでg1-small以上が良いかと思います。
node type | node count | description |
n1-standard-2 | 3 | Knative環境一式を動かすのに使う |
g1-small | 1 | ワーカー用 |
ワーカー用と管理用を分ける必要は特に無いのですが、私の環境の場合ワーカーはほとんどリソースがいらないので別でg1-smallを追加のノードプールで作ることでコスト圧縮を狙ってみました。
まずは、以下のコマンドでクラスタの作成。
export CLUSTER_NAME=knative-cluster-01
export CLUSTER_ZONE=us-central1-f
gcloud beta container clusters create $CLUSTER_NAME \
--zone=$CLUSTER_ZONE \
--cluster-version=latest \
--machine-type=n1-standard-2 \
--preemptible \
--disk-type "pd-standard" --disk-size "10" \
--image-type "COS" \
--num-nodes=3 \
--enable-autorepair \
--no-enable-basic-auth \
--addons HorizontalPodAutoscaling,HttpLoadBalancing,KubernetesDashboard \
--enable-autoupgrade \
--enable-stackdriver-kubernetes \
--scopes "https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/compute.readonly","https://www.googleapis.com/auth/devstorage.read_write","https://www.googleapis.com/auth/taskqueue","https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/monitoring","https://www.googleapis.com/auth/pubsub","https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly","https://www.googleapis.com/auth/trace.append","https://www.googleapis.com/auth/source.read_write","https://www.googleapis.com/auth/cloud_debugger"
続いてアカウントの紐づけをします。
kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value core/account)
IstioとKnativeのインストール
次に構築したクラスタにIstioとKnativeのインストールを行います。
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.4.0/istio-crds.yaml
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.4.0/istio.yaml
kubectl label namespace default istio-injection=enabled
以下のコマンドでステータスが全てRunning
になってればインストール完了です。
kubectl get pods --namespace istio-system
引き続きKnativeをインストールします。
kubectl apply \
--filename https://github.com/knative/serving/releases/download/v0.4.0/serving.yaml \
--filename https://github.com/knative/build/releases/download/v0.4.0/build.yaml \
--filename https://github.com/knative/eventing/releases/download/v0.4.0/in-memory-channel.yaml \
--filename https://github.com/knative/eventing/releases/download/v0.4.0/release.yaml \
--filename https://github.com/knative/eventing-sources/releases/download/v0.4.0/release.yaml \
--filename https://github.com/knative/serving/releases/download/v0.4.0/monitoring.yaml \
--filename https://raw.githubusercontent.com/knative/serving/v0.4.0/third_party/config/build/clusterrole.yaml
こちらも以下のコマンドでステータスがRunningになれば成功です。
kubectl get pods --namespace knative-serving
kubectl get pods --namespace knative-build
kubectl get pods --namespace knative-eventing
kubectl get pods --namespace knative-sources
kubectl get pods --namespace knative-monitoring
ワーカーノードをクラスタへ追加
Knative関連のインストールが終わったのでワーカー向けのノードをクラスタに追加します。
特に設定を入れてるわけでは無いので常にこのノードにアプリがデプロイされるとは限りませんが、すでにKnative関連のPodは他に入ってるので確率的にはここに追加されるはず。
gcloud container node-pools create small-pool \
--zone $CLUSTER_ZONE --cluster $CLUSTER_NAME \
--machine-type=g1-small \
--preemptible \
--disk-type "pd-standard" --disk-size "10" \
--image-type "COS" \
--num-nodes=1
アプリのDeploy
続いてアプリのデプロイです。
service.yamlを作成し、以下の内容を記述します。
apiVersion: serving.knative.dev/v1alpha1 # Current version of Knative
kind: Service
metadata:
name: echo-server # The name of the app
namespace: default # The namespace the app will use
spec:
runLatest:
configuration:
revisionTemplate:
spec:
container:
image: koduki/echo-server
見た目通りecho-serverをKnativeのServiceとしてデプロイするシンプルな設定になっています。
echoサーバは8080で動くシンプルな構成。コンテナの詳細はこちらのDockerfileを確認してください。
echoサーバの実装はこちらのとおりです。Istioを経由するということでどういうI/Fを書けば良いのかと思ったのですがとりあえず普通にHTTPのrequest/responseを返しておけば後は良しなにしてくれるようです。便利!
kubectl apply --filename service.yaml
とりあえずデプロイできたら動作確認をしてみます。
export IP_ADDRESS=$(kubectl get svc istio-ingressgateway --namespace istio-system --output 'jsonpath={.status.loadBalancer.ingress[0].ip}')
curl -H "Host: echo-server.default.example.com" http://${IP_ADDRESS}/hello
hello%
引数で渡しているhello
が返ってるのがわかりますね。
クラスタのIPアドレスを確認してcurlでアクセスします。
ドメイン名としてecho-server.default.example.com
が振られているらしく、同一IPでもバーチャルホストとして動作しているようです。
ただ、default.example.com
がDNSに登録されているわけじゃ無いので-Hオプション
でホストを直接指定します。この辺の解消は後ほど。
もう一つ重要な点としてkoduki/echo-serverは8080
で動作してるのに、curlで接続するポートは80
です。これはリクエストをまず受け取ってるのはIstioでecho-serverはそこと通信をしているためかと思います。たぶん。
ドメインの設定
example.comはDNS登録されてないので、DNSに適切に登録されたドメインを設定します。そうしないとcurlはさておきブラウザでのアクセスは不便ですし。
とはいえ毎回ドメインを作るのも面倒なのでNIP.IOを使います。
これは、任意のIPアドレスをサブドメイン名に指定すると指定したIPで名前解決をしてくれるワイルドカードDNSと呼ばれるものです。
例えばecho-server.default.127.0.0.1.nip.io
は127.0.0.1
を返します。これを使うことで簡単にドメインが利用できます。
まずEXTERNAL-IPを確認します。
$ kubectl get svc istio-ingressgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.xxx.xxx.xxx 35.xxx.xxx.xxx 80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:31406/TCP,8060:32449/TCP,853:30097/TCP,15030:32188/TCP,15031:32016/TCP 7d3h
kubectl edit cm config-domain --namespace knative-serving
を実行して、ドメインの内容を下記のようにExternal IP + nio.io
に変更します。
apiVersion: v1
data:
35.xxx.xxx.xxx.nip.io: ""
kind: ConfigMap
metadata:
annotations:
これで準備は完了。今度は-H
オプションは不要でURLをホスト名で指定して接続します。
$ curl http://echo-server.default.35.xxx.xxx.xxx.nip.io/hello
hello
無事接続できましたね。
Knativeをモニタリングする
構築/デプロイと来たら次はモニタリングですね?
KnativeにはIstioと連携する形でOpenZipkin, Prometheus/Grafana, そしてKibanaが含まれています。
Grafana
Grafanaにアクセスするためにport-forwardのため以下のコマンドを実行します。
kubectl port-forward --namespace knative-monitoring \
$(kubectl get pods --namespace knative-monitoring \
--selector=app=grafana --output=jsonpath="{.items..metadata.name}") \
3000
3000
portにフォーワードしてるのでhttp://localhost:3000/
にアクセスします。
ノードやPodの状態、あるいはリクエスト数などの基本的なダッシュボードは既に用意されているのですぐに利用できるかと思います。
OpenZipkinを開く
また、Istioと連携する形でOpenZipkinも入っています。kubectl proxy
を実行して以下のURLにアクセスします。
http://localhost:8001/api/v1/namespaces/istio-system/services/zipkin:9411/proxy/zipkin/
Kibanaを開く
Kibanaを開くにはkubectl proxy
を実行して以下のURLにアクセスします。
http://localhost:8001/api/v1/namespaces/knative-monitoring/services/kibana-logging/proxy/app/kibana
現時点ではデフォルトにはあまり仕込みはいれて無いようなのでカスタマイズは自分でする必要がありそうです。
まとめ
Knativeを使って環境をGKE上にサーバレス環境を構築してみました。
Knativeの場合は単にFaaSのことをサーバレスと呼んでるのではなくPaaS/FaaS/Build含めてスケーラブルな環境を実サーバ台数を気にすることなく構築できるので、k8sよりかなり使いやすい抽象度になります。
とはいえ、これを使ってオレオレGCPやオレオレHerokuを運用したい人は実際はさほど多く無い気がするので、Knative自体のマネージドサービスが出て、それが今後のクラウドのベースラインになってくるのかな、と思います。
現在、α版やってるServerless add-on for Google Kubernetes Engine
とかがそんな感じでは無いかと期待。
いずれにしても常時稼働しておくと結構な費用なのでどこかマネージドknative早く頼むw
それではHappy Hacking!