概要
Google Cloud Next '18において、「Knative」が発表されました。
Knativeは、コンテナのオーケストレーションツールであるKubernetes上でアプリを動かす際の手順(ビルド、デプロイ、サービスの管理)を簡略化してくれるツールとのことです。
このエントリでは、ローカルマシン(mac)1台で、Kubernetes環境構築用のツール「Minikube」を利用してKubernetes環境を作り、その上でKnativeを動かすまでについての手順を紹介します。

対象読者
- Knativeの動かし方を確認したい方
- Kubernetesが何をしてくれるものかの知識がある方
前提
このエントリでは、2018/7/25時点で利用可能な以下のバージョンを利用しています。
- Minikube : 0.28.2
- Knative : (2018/7/25時点の最新版)
- macOS : 10.13.2
- VirtualBox : 5.2.16
- Macbook Pro(15-inch, Mid 2014)
※Minikube上でサービスを動作させるにはそれなりにメモリが必要です。メインメモリが8GBのマシンの場合、Minikube用VMへの割り当てを変更するなどしてお試しください。(筆者はメモリ16GBのマシンでVMに8GBを割り当てて実行しています。)
Minikubeを動かすまで(Kubernetes環境準備)
まずは、Kubernetes環境をローカルマシン内に準備します。
基本的には、Minikubeのサイトに記載されている導入手順通りなのですが、このエントリで利用している方法について簡単に説明します。
ハイパーバイザ
このエントリでは、VirtualBoxを利用します。通常のインストールをした上で、「拡張機能パック」もインストールしています。
Kubernetes-cli
macOSでbrewを使ったインストールです。(brewの導入自体は、brewのタイト上にある通り、上で1行で終了します。)
$ brew install kubernetes-cli
こんな感じでKubernetes-cli 1.11.1が導入されます。
zsh completions have been installed to:
/usr/local/share/zsh/site-functions
==> Summary
🍺 /usr/local/Cellar/kubernetes-cli/1.11.1: 196 files, 53.7MB
</div>
## Minikube
リリースページから最新版(エントリ作成時点ではv0.28.2)を取得します。
macOSに対応した、「minikube-darwin-amd64」をダウンロードします。
Knativeのサイトに記載されたオプションでMinikubeを起動します。上と同じく、--vm-driverオプションにはvirtualboxを指定しています。
(うっかり、「minikube」コマンドを単独で実行すると、出来上がったVMがデフォルト設定でメモリが2GBytes程度となり、あとでサービスが増えた時にハマります。)
なお、コマンドが少し長いので筆者はスクリプトにして実行しました。
```bash
# !/bin/sh
minikube start --memory=8192 --cpus=4 \
--kubernetes-version=v1.10.5 \
--vm-driver=virtualbox \
--bootstrapper=kubeadm \
--extra-config=controller-manager.cluster-signing-cert-file="/var/lib/localkube/certs/ca.crt" \
--extra-config=controller-manager.cluster-signing-key-file="/var/lib/localkube/certs/ca.key" \
--extra-config=apiserver.admission-control="LimitRanger,NamespaceExists,NamespaceLifecycle,ResourceQuota,ServiceAccount,DefaultStorageClass,MutatingAdmissionWebhook"
Istio
サイトにあるとおりの手順でサービスメッシュのIstioを開始します。
curl -L https://storage.googleapis.com/knative-releases/serving/latest/istio.yaml \
| sed 's/LoadBalancer/NodePort/' \
| kubectl apply -f -
サービスが上がるまで待ちます。
状態を確認して、最初はこんなかんじで「ContainerCreating」状態のサービスを含んでいたものが
$ kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
istio-citadel-7bdc7775c7-2nqq6 0/1 ContainerCreating 0 1m
istio-cleanup-old-ca-vgg5g 0/1 ContainerCreating 0 1m
istio-egressgateway-795fc9b47-fkpw9 1/1 Running 0 1m
istio-ingress-84659cf44c-46rmd 0/1 ContainerCreating 0 1m
istio-ingressgateway-7d89dbf85f-vkgcw 0/1 ContainerCreating 0 1m
istio-mixer-post-install-4jgcb 0/1 Completed 0 1m
istio-pilot-66f4dd866c-f4kpt 0/2 ContainerCreating 0 1m
istio-policy-76c8896799-2lggq 0/2 ContainerCreating 0 1m
istio-sidecar-injector-645c89bc64-hgcbq 0/1 ContainerCreating 0 1m
istio-statsd-prom-bridge-949999c4c-9dzd7 1/1 Running 0 1m
istio-telemetry-6554768879-sz59r 0/2 ContainerCreating 0 1m
状態を確認して、全て「Running」か「Completed」となればOKです。
Knative Serving
Knative Servingを導入します。
サイトの通りに開始します。
curl -L https://storage.googleapis.com/knative-releases/serving/latest/release-lite.yaml \
| sed 's/LoadBalancer/NodePort/' \
| kubectl apply -f -
ログはこんな感じ。10秒程度。
$ time curl -L https://storage.googleapis.com/knative-releases/serving/latest/release-lite.yaml \
> | sed 's/LoadBalancer/NodePort/' \
> | kubectl apply -f -
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0namespace/knative-build created
clusterrole.rbac.authorization.k8s.io/knative-build-admin created
serviceaccount/build-controller created
clusterrolebinding.rbac.authorization.k8s.io/build-controller-admin created
customresourcedefinition.apiextensions.k8s.io/builds.build.knative.dev created
customresourcedefinition.apiextensions.k8s.io/buildtemplates.build.knative.dev created
service/build-controller created
service/build-webhook created
configmap/config-logging created
deployment.apps/build-controller created
deployment.apps/build-webhook created
namespace/knative-serving created
clusterrole.rbac.authorization.k8s.io/knative-serving-admin created
clusterrole.rbac.authorization.k8s.io/knative-serving-write created
serviceaccount/controller created
serviceaccount/autoscaler created
clusterrolebinding.rbac.authorization.k8s.io/knative-serving-controller-admin created
clusterrolebinding.rbac.authorization.k8s.io/knative-serving-autoscaler-write created
gateway.networking.istio.io/knative-shared-gateway created
service/knative-ingressgateway created
deployment.extensions/knative-ingressgateway created
horizontalpodautoscaler.autoscaling/knative-ingressgateway created
customresourcedefinition.apiextensions.k8s.io/configurations.serving.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/services.serving.knative.dev created
service/activator-service created
service/controller created
service/webhook created
deployment.apps/activator created
service/autoscaler created
deployment.apps/autoscaler created
configmap/config-autoscaler created
configmap/config-controller created
configmap/config-domain created
configmap/config-logging created
configmap/config-network created
configmap/config-observability created
deployment.apps/controller created
deployment.apps/webhook created
namespace/monitoring created
configmap/grafana-dashboard-definition-istio created
configmap/grafana-dashboard-definition-mixer created
configmap/grafana-dashboard-definition-pilot created
serviceaccount/kube-state-metrics created
role.rbac.authorization.k8s.io/kube-state-metrics-resizer created
rolebinding.rbac.authorization.k8s.io/kube-state-metrics created
clusterrole.rbac.authorization.k8s.io/kube-state-metrics created
clusterrolebinding.rbac.authorization.k8s.io/kube-state-metrics created
deployment.extensions/kube-state-metrics created
service/kube-state-metrics created
configmap/grafana-dashboard-definition-kubernetes-deployment created
configmap/grafana-dashboard-definition-kubernetes-capacity-planning created
83 485k 83 403k 0 0 167k 0 0:00:02 0:00:02 --:--:-- 167kconfigmap/grafana-dashboard-definition-kubernetes-cluster-health created
configmap/grafana-dashboard-definition-kubernetes-cluster-status created
configmap/grafana-dashboard-definition-kubernetes-control-plane-status created
configmap/grafana-dashboard-definition-kubernetes-resource-requests created
100 485k 100 485k 0 0 160k 0 0:00:03 0:00:03 --:--:-- 160k
configmap/grafana-dashboard-definition-kubernetes-nodes created
configmap/grafana-dashboard-definition-kubernetes-pods created
configmap/grafana-dashboard-definition-kubernetes-statefulset created
serviceaccount/node-exporter created
clusterrole.rbac.authorization.k8s.io/node-exporter created
clusterrolebinding.rbac.authorization.k8s.io/node-exporter created
daemonset.extensions/node-exporter created
service/node-exporter created
configmap/scaling-config created
service/fluentd-ds created
configmap/grafana-dashboard-definition-knative-efficiency created
configmap/grafana-dashboard-definition-knative created
configmap/grafana-datasources created
configmap/grafana-dashboards created
service/grafana created
deployment.apps/grafana created
logentry.config.istio.io/requestlog created
fluentd.config.istio.io/requestloghandler created
rule.config.istio.io/requestlogtofluentd created
metric.config.istio.io/revisionrequestcount created
metric.config.istio.io/revisionrequestduration created
metric.config.istio.io/revisionrequestsize created
metric.config.istio.io/revisionresponsesize created
prometheus.config.istio.io/revisionpromhandler created
rule.config.istio.io/revisionpromhttp created
service/kube-controller-manager created
service/prometheus-system-discovery created
configmap/prometheus-scrape-config created
serviceaccount/prometheus-system created
role.rbac.authorization.k8s.io/prometheus-system created
role.rbac.authorization.k8s.io/prometheus-system created
role.rbac.authorization.k8s.io/prometheus-system created
role.rbac.authorization.k8s.io/prometheus-system created
clusterrole.rbac.authorization.k8s.io/prometheus-system created
rolebinding.rbac.authorization.k8s.io/prometheus-system created
rolebinding.rbac.authorization.k8s.io/prometheus-system created
rolebinding.rbac.authorization.k8s.io/prometheus-system created
rolebinding.rbac.authorization.k8s.io/prometheus-system created
clusterrolebinding.rbac.authorization.k8s.io/prometheus-system created
service/prometheus-system-np created
statefulset.apps/prometheus-system created
logentry.config.istio.io/requestlog unchanged
fluentd.config.istio.io/requestloghandler unchanged
rule.config.istio.io/requestlogtofluentd unchanged
metric.config.istio.io/revisionrequestcount unchanged
metric.config.istio.io/revisionrequestduration unchanged
metric.config.istio.io/revisionrequestsize unchanged
metric.config.istio.io/revisionresponsesize unchanged
prometheus.config.istio.io/revisionpromhandler unchanged
rule.config.istio.io/revisionpromhttp unchanged
real 0m7.227s
user 0m0.604s
sys 0m0.154s
動作を確認します。
$ kubectl get pods -n knative-serving
NAME READY STATUS RESTARTS AGE
activator-5f78d674df-b7f2v 2/2 Running 4 17m
autoscaler-5787568ff8-5mg79 2/2 Running 4 17m
controller-c8dd5d467-8hnhx 1/1 Running 2 17m
webhook-78f58769cb-m5s7z 1/1 Running 2 17m
Knative上でサンプルを動かす
Knativeのサイト上のガイド「Getting Started with Knative App Deployment」の例を動かしてみます。
services.yamlの準備
このようなファイルを準備します。ガイドに示された、「gcr.io/knative-samples/helloworld-go」のイメージを使っています。
apiVersion: serving.knative.dev/v1alpha1 # Current version of Knative
kind: Service
metadata:
name: helloworld-go # The name of the app
namespace: default # The namespace the app will use
spec:
runLatest:
configuration:
revisionTemplate:
spec:
container:
image: gcr.io/knative-samples/helloworld-go # The URL to the image of the app
env:
- name: TARGET # The environment variable printed out by the sample app
value: "Go Sample v1"
動かします。(ここの簡単さがKnativeのいいところ)
$ kubectl apply -f service.yaml
service.serving.knative.dev/helloworld-go created
この1行で、Knativeは下記を担当してくれます。
- このアプリの普遍なリビジョンを作る
- route, ingress, load balancerを作る
- podのスケールアップ/ダウン
動作状況を確認します。
$
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
knative-ingressgateway NodePort 10.104.55.123 <none> 80:32380/TCP,443:32390/TCP,32400:32400/TCP 25m
サービスのURLを調べて、
$ kubectl get services.serving.knative.dev helloworld-go -o=custom-columns=NAME:.metadata.name,DOMAIN:.status.domain
NAME DOMAIN
helloworld-go helloworld-go.default.example.com
Knativeのサイトにある方法で接続先IPアドレスを調べて、
$ echo $(minikube ip):$(kubectl get svc knative-ingressgateway -n istio-system -o 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')
192.168.99.101:32380
このアドレスを変数にセットして、
export IP_ADDRESS=192.168.99.100:32380
接続してみます。
$ curl -H "Host: ${HOST_URL}" http://${IP_ADDRESS}
Hello World: Go Sample v1!
Goプログラムからの出力が確認できました。
services.yamlの内容を少し書き換えて
value: "Go Sample version2"
サービスを登録し直すと、
$ kubectl apply -f service.yaml
service.serving.knative.dev/helloworld-go configured
少し経つと、サービスの環境変数が新しい内容となり、コンソールの出力変わることが確認できます。
$ curl -H "Host: ${HOST_URL}" http://${IP_ADDRESS}
Hello World: Go Sample version2
$ minikube dashboard
を実行すると、サービスのデプロイの様子をWebのコンソールで確認できます(本エントリ冒頭の図)。
まとめ
本エントリでは、Knativeをローカルマシン1台で試す方法について説明しました。
Minikubeを使うと、マシン一台でお手軽に試すことができるのでおすすめです。