kubeadm-dindでローカルにkubernetesを構築してknativeをデプロイする

# kubeadm-dindでローカルにkubernetesを構築してknativeをデプロイする

この記事は[信州大学 kstm Advent Calendar 2018](https://qiita.com/advent-calendar/2018/kstm)の7日目です


##  kubeadm-dindとは
[kubeadm-dind](https://github.com/kubernetes-sigs/kubeadm-dind-cluster) とはkubernetesをローカル環境に構築するツールの一つです。minikubeみたいな用途(個人用pcでの検証環境とか)に使います。

docker in dockerで構築するため、仮想マシンを使うminikubeよりも軽いという利点があります[^1]。  
また、事前準備がdockerをインストールするだけでなので構築もより簡単です。

[^1]: ソースは私の体感です

##  knativeとは
kubernetes上で動くServerlessのプラットフォームです。[^2]

[^2]: 正直良く分かってないです

##  kubeadm-dindのインストール
最初にdockerをインストールしてユーザを`docker` groupに追加[^3]してから一度ログアウトして再度ログインします

```
$ sudo groupadd docker
$ sudo usermod -aG docker $USER
$ logout
```

次にkubeadm-dindを構築するスクリプトをダウンロードして実行可能にします  
なるべく新しいversionで構築したいので現在の最新である`v1.12`を使用します

```
$ curl -sOL https://cdn.rawgit.com/kubernetes-sigs/kubeadm-dind-cluster/master/fixed/dind-cluster-v1.12.sh
$ chmod +x dind-cluster-v1.12.sh
```

knativeに必要なオプションを付けてスクリプトを実行し、kubernetesをデプロイします  
私の環境では4m25sで完了しました

```
$ ./dind-cluster-v1.12.sh up \
  --admission-control=LimitRanger,NamespaceExists,NamespaceLifecycle,ResourceQuota,ServiceAccount,DefaultStorageClass,MutatingAdmissionWebhook


real	4m25.099s
user	0m12.092s
sys	0m3.212s
```

設定ファイルが`~/.kube`に生成されているのでkubectlをインストールするか  
もしくは、`~/.kubeadm-dind-cluster/kubectl`に適合したversionがインストールされるのでそちらに`$PATH`を通して下さい

```
$ export PATH="$HOME/.kubeadm-dind-cluster:$PATH"

$ kubectl get nodes
NAME          STATUS   ROLES    AGE     VERSION
kube-master   Ready    master   3m53s   v1.12.1
kube-node-1   Ready    <none>   2m48s   v1.12.1
kube-node-2   Ready    <none>   2m48s   v1.12.1

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                    READY   STATUS    RESTARTS   AGE
kube-system   etcd-kube-master                        1/1     Running   1          2m36s
kube-system   kube-dns-cc8d86694-5dvwq                3/3     Running   0          66s
kube-system   kube-proxy-nhswh                        1/1     Running   1          2m4s
kube-system   kube-proxy-wkt82                        1/1     Running   1          2m14s
kube-system   kube-proxy-zjmwd                        1/1     Running   1          2m14s
kube-system   kubernetes-dashboard-667474557b-rtplv   1/1     Running   0          66s
```

これでkubeadm-dindを用いたkubernetesの構築は完了です  
kubectlコマンドでkubernetesの操作ができます

また、以下のコマンドでクラスタの停止や削除が行えます

```
# クラスタを停止
$ ./dind-cluster-v1.12.sh stop

# コンテナやボリュームの削除
$ ./dind-cluster-v1.12.sh clean
```

[^3]: あまり良くなんですが、他に良い方法が無いので....

## knativeのインストール
まずIstioをデプロイし、ラベルを付けます
```
$ kubectl apply --filename https://raw.githubusercontent.com/knative/serving/v0.2.2/third_party/istio-1.0.2/istio.yaml

$ kubectl label namespace default istio-injection=enabled
```

Istioのデプロイが完了するまで待ちます  
`--watch`オプションを付けることで変更を監視することができるのでこれを使用して待ちます

```
＄ kubectl get pods --namespace istio-system --watch

# 完了した
$ kubectl get pods --namespace istio-system
NAME                                        READY   STATUS      RESTARTS   AGE
istio-citadel-6959fcfb88-466cj              1/1     Running     0          2m30s
istio-cleanup-secrets-r2rvs                 0/1     Completed   0          2m31s
istio-egressgateway-5b765869bf-mbh52        1/1     Running     0          2m30s
istio-galley-7fccb9bbd9-ds6w4               0/1     Running     0          2m30s
istio-ingressgateway-69b597b6bd-k64kc       1/1     Running     0          2m30s
istio-pilot-7b594977cf-nzsjw                2/2     Running     0          2m30s
istio-policy-59b7f4ccd5-wg69k               2/2     Running     0          2m30s
istio-sidecar-injector-5c4b6cb6bc-m7vbp     0/1     Running     0          2m30s
istio-statsd-prom-bridge-67bbcc746c-nrfxx   1/1     Running     0          2m30s
istio-telemetry-7686cd76bd-8r8xt            2/2     Running     0          2m30s
```

Istioのデプロイが完了後、knativeをデプロイします

```
kubectl apply --filename https://github.com/knative/serving/releases/download/v0.2.2/release.yaml
```

podのステータスが全て`Running`になったら完了です

```
$ kubectl get pods --namespace knative-serving
NAME                          READY   STATUS    RESTARTS   AGE
activator-5d4b58b86d-cm5m9    2/2     Running   0          2m22s
activator-5d4b58b86d-hjx2m    2/2     Running   0          2m22s
activator-5d4b58b86d-snbcl    2/2     Running   0          2m22s
autoscaler-59f694cbfc-dr5kt   2/2     Running   0          2m22s
controller-c657b6496-bpk94    1/1     Running   0          2m22s
webhook-6f9bd9d9d7-lsxrf      1/1     Running   0          2m22s

$ kubectl get pods --namespace knative-build
NAME                                READY   STATUS    RESTARTS   AGE
build-controller-7b58f7cd8c-vh5sj   1/1     Running   0          2m26s
build-webhook-db9fc4d97-r6wh8       1/1     Running   0          2m26s
```

## 実際に動かす
実際に公式ドキュメント[^4]のsampleを動かしてみます  
以下の内容を`service.yaml`という名前で保存します

```
$ cat <<EOF > service.yaml
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"
EOF
```

kubectlで実行します

```
$ kubectl apply --filename service.yaml

$ kubectl get pods
NAME                                              READY   STATUS    RESTARTS   AGE
helloworld-go-00001-deployment-67c58c64db-g4rgt   3/3     Running   0          7s
```

knative-ingressgatewayで接続を受け付けているので内部的なIPアドレスとポート番号を調べます  

```
$ export IP_ADDRESS=$(kubectl get node  --output 'jsonpath={.items[0].status.addresses[0].address}'):$(kubectl get svc knative-ingressgateway --namespace istio-system   --output 'jsonpath={.spec.ports[?(@.port==80)].nodePort}')
```

また、ingressはバーチャルホストで接続を受けつけるのでサービスに割り当てられているdomainが接続に必要です  
今回の場合は`default`ネームスペースに`helloworld-go`という名前で作成したので以下のようになります

```
$ kubectl get ksvc helloworld-go
NAME            DOMAIN                              LATESTCREATED         LATESTREADY           READY   REASON
helloworld-go   helloworld-go.default.example.com   helloworld-go-00001   helloworld-go-00001   True
```

確認しましょう

```
$ curl -H "Host: helloworld-go.default.example.com" http://${IP_ADDRESS}
Hello Go Sample v1!
```

成功しました

### knativeについての追記

ちなみにknativeは自動的にスケールするためサービスを作成後、最後に接続して何分か経過するとpodが停止されます

```
$ kubectl get pods
No resources found.
```

接続しようとするとpodが再度作成されて応答を返してくれます

```
$ time curl -H "Host: helloworld-go.default.example.com" http://${IP_ADDRESS}
Hello Go Sample v1!

real	0m9.561s
user	0m0.006s
sys	0m0.010s

$ kubectl get pods
NAME                                              READY   STATUS    RESTARTS   AGE
helloworld-go-00001-deployment-67c58c64db-75p2l   3/3     Running   0          17s
```

やはりpodの作成にはかなり時間がかかるようですね


[^4]: https://github.com/knative/docs/blob/master/install/getting-started-knative-app.md

## おわりに
kubeadm-dindはminikubeよりも簡単に構築できる上環境も軽いので個人的におすすめです  
knativeは自動スケールやバーチャルホストを良い感じにやってくれるのはすごいですね  

kubernetesやknativeのことはまだあまり詳しくないので今後も頑張りたいです


### 参考
- [kubeadm-dind-cluster/config.sh](https://github.com/kubernetes-sigs/kubeadm-dind-cluster/blob/master/config.sh)
- [Knative-with-any-k8s](https://github.com/knative/docs/blob/master/install/Knative-with-any-k8s.md)
- [getting-started-knative-app](https://github.com/knative/docs/blob/master/install/getting-started-knative-app.md)