Minikubeを使ってローカルにkubernetes環境を構築

## 概要
Kubernetesを試したいが、環境構築はなかなか大変。そこで、Minikubeを使ってローカルに簡単にk8sの環境を構築する。
ここではCentOSに環境構築するが、Mac、Windowsにも構築可能。

ここでは、dashboardを起動してブラウザから閲覧可能にするところまで説明する。

## 目次
- [Kubernetesハンズオン目次](https://qiita.com/Esfahan/items/4fcf51622fed20dffb88)

## 環境
- CentOS 7.6
- Minikube v1.1.1
- Kubernetes v1.14.3

## Dockerのインストール
Dockerがインストールされていることが前提。(docker-composeは不要)
参考：[docker(docker-engine), docker-composeのインストール](https://qiita.com/Esfahan/items/aa5802548ee42d8a98de)

## Minikubeのインストール

```shell-session
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
```

## kubectlのインストール

```shell-session
$ curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/
```

環境変数などセット。方法はなんでもよいが、k8sをrootで利用するので、rootで読み込めるようにする。

```shell-session
$ sudo vi /etc/profile
export MINIKUBE_WANTUPDATENOTIFICATION=false
export MINIKUBE_WANTREPORTERRORPROMPT=false
export MINIKUBE_HOME=/root
export CHANGE_MINIKUBE_NONE_USER=true
export KUBECONFIG=/root/.kube/config
```

```shell-session
$ sudo mkdir -p /root/.kube || true
$ sudo touch /root/.kube/config
```

## Minikubeを起動
デフォルトではVirtualBoxのVMを作成してその上にkubernetes環境が構築される。
`--vm-driver=none` オプションを付けることで、minikubeを実行しているホスト上にkubernetesを構築されるようにできる。

```shell-session
$ sudo /usr/local/bin/minikube start --vm-driver=none
😄  minikube v1.1.1 on linux (amd64)
🔥  Creating none VM (CPUs=2, Memory=2048MB, Disk=20000MB) ...
🐳  Configuring environment for Kubernetes v1.14.3 on Docker 17.05.0-ce
❌  Unable to load cached images: loading cached images: loading image /root/.minikube/cache/images/gcr.io/k8s-minikube/storage-provisioner_v1.8.1: stat /root/.minikube/cache/images/gcr.io/k8s-minikube/storage-provisioner_v1.8.1: no such file or directory
💾  Downloading kubeadm v1.14.3
💾  Downloading kubelet v1.14.3
🚜  Pulling images ...
🚀  Launching Kubernetes ...
🤹  Configuring local host environment ...

⚠️  The 'none' driver provides limited isolation and may reduce system security and reliability.
⚠️  For more information, see:
👉  https://github.com/kubernetes/minikube/blob/master/docs/vmdriver-none.md

⚠️  kubectl and minikube configuration will be stored in /root
⚠️  To use kubectl or minikube commands as your own user, you may
⚠️  need to relocate them. For example, to overwrite your own settings:

    ▪ sudo mv /root/.kube /root/.minikube $HOME
    ▪ sudo chown -R $USER $HOME/.kube $HOME/.minikube

💡  This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true
⌛  Verifying: apiserver proxy etcd scheduler controller dns
🏄  Done! kubectl is now configured to use "minikube"
```

/root/.kube/configが生成される。
configの中身を確認する。

```shell-session
$ sudo kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /root/.minikube/ca.crt
    server: https://xxx.xxx.xxx:8443
  name: minikube
contexts:
- context:
    cluster: minikube
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: /root/.minikube/client.crt
    client-key: /root/.minikube/client.key
```

minikubeの起動を確認。

```shell-session
$ sudo minikube status
host: Running
kubelet: Running
apiserver: Running
kubectl: Correctly Configured: pointing to minikube-vm at xxx.xxx.xxx.xxx
```

kubectlがMinikubeのapi serverにアクセスできるようになるまで待つ。

```sh
# this for loop waits until kubectl can access the api server that Minikube has created
for i in {1..150}; do # timeout for 5 minutes
   sudo /usr/local/bin/kubectl get po &> /dev/null
   if [ $? -ne 1 ]; then
      break
  fi
  sleep 2
done && echo 'kubectl commands are now able to interact with Minikube cluster'
```

## port 8443を開ける

```shell-session
$ sudo firewall-cmd --add-port=8443/tcp --zone=public --permanent
success
$ sudo firewall-cmd --reload
success
$ sudo firewall-cmd --list-all
```

## dashboardのコンテナを作成、起動する
k8s.gcr.io/echoserver:1.4というイメージがあるので、そちらを利用してdashboardコンテナを作成する。

```shell-session
$ sudo docker images | grep 'k8s.gcr.io/echoserver'
k8s.gcr.io/echoserver                     1.4                 a90209bb39e3        3 years ago         140MB
```

### pod作成

```shell-session
$ sudo kubectl run hello-minikube --image=k8s.gcr.io/echoserver:1.4 --port=8080
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/hello-minikube created
```

nodeを確認

```shell-session
$ sudo kubectl get nodes
NAME       STATUS   ROLES    AGE   VERSION
minikube   Ready    master   63m   v1.14.3
```

podを確認

```shell-session
$ sudo kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
hello-minikube-78c9fc5f89-9whkn   1/1     Running   0          29s
```

デプロイのリストを表示します。インスタンスはDockerコンテナとしてノードで実行される。

```shell-session
$ sudo kubectl get deployments
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
hello-minikube   1/1     1            1           80m
```

### serviceを作成
`--type=NodePort`オプションを付けることで、ホストOSと、kubernetesのコンテナのIPアドレスを関連付ける。typeは、他にはLoadBalancerなどがある。

[Publishing services - service types - 公開サービス サービスタイプ](https://qiita.com/kouares/items/94a073baed9dffe86ea0#publishing-services---service-types---%E5%85%AC%E9%96%8B%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9-%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%97)

```shell-session
$ sudo kubectl expose deployment hello-minikube --type=NodePort
service/hello-minikube exposed
```

serviceを確認

```shell-session
$ sudo kubectl get services
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
hello-minikube   NodePort    10.98.185.37   <none>        8080:30525/TCP   25m
kubernetes       ClusterIP   10.96.0.1      <none>        443/TCP          103m
```

## dashboardにアクセスする
### dashboardのURLを取得
以下のコマンドでdashboardを起動し、URLが表示されるのでアクセスする。
ポートは毎回変わる。

```shell-session
$ sudo minikube dashboard --url
🔌  Enabling dashboard ...
🤔  Verifying dashboard health ...
🚀  Launching proxy ...
🤔  Verifying proxy health ...
http://127.0.0.1:36439/api/v1/namespaces/kube-system/services/http:kubernetes-dashboard:/proxy/
```

```shell-session
$ curl http://127.0.0.1:36439/api/v1/namespaces/kube-system/services/http:kubernetes-dashboard:/proxy/
```

### Kubernetesのプロキシ経由でアクセスする場合
デフォルトでは、podはkubernetesの中でprivateで動いており、同じKubernetes clusterの中からしかアクセスすることができない。
そこで、`kubectl proxy`でプロキシを立てることで、cluster間を超えたアクセスを可能にする。

[[第1回]Kubernetesの公式チュートリアルをやって基本を押さえる -アプリのデプロイ-](https://dev.classmethod.jp/cloud/kubernetes-tutorial-1/)
> KubernetesのAPIエンドポイント経由でアプリケーションにアクセスできます。kubectlがapiエンドポイントへのリバースプロキシとして動作します。 kubectl proxy(ローカル端末) > Kubernetesクラスターで起動しているAPIエンドポイント > Pod

以下の`kubectl proxy`コマンドを使うと、Kubernetes APIのエンドポイントを経由してdashboardにアクセスできる。つまり、Kubernetesがリバースプロキシとなり、dashboardにアクセスできる。

```sh
# まずはdashboardを起動
$ sudo minikube dashboard --url
# proxyを起動
$ sudo kubectl proxy
Starting to serve on 127.0.0.1:8001
```

こちらの場合は、ポートは8001固定。

```shell-session
$ curl http://localhost:8001
以下略
```

## 外部からdashboardにアクセス可能にする
`--vm-driver=none` オプションを付けてMinikubeを起動した場合、proxyを使ってもホストOSからしかアクセスできない。そのため、プロキシの設定を変更し、ホストOS外（ブラウザ）からアクセスできるようにする。

```sh
# まずはdashboardを起動
$ sudo minikube dashboard --url
# proxyを起動
$ sudo kubectl proxy --address=0.0.0.0 --accept-hosts='.*'
Starting to serve on [::]:8001
```

http://{YOUR_HOST_NAME}:8001/api/v1/namespaces/kube-system/services/http:kubernetes-dashboard:/proxy/#!/overview?namespace=default

![Screen Shot 2019-06-10 at 15.21.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105936/e44f574e-d10d-4f65-1ce2-2db0316cedc8.png)


## ログを確認

```shell-session
$ sudo kubectl logs hello-minikube-78c9fc5f89-9whkn
192.168.249.1 - - [10/Jun/2019:05:53:20 +0000] "GET / HTTP/1.1" 200 399 "-" "curl/7.29.0"
192.168.249.1 - - [10/Jun/2019:05:53:55 +0000] "GET / HTTP/1.1" 200 399 "-" "curl/7.29.0"
192.168.249.1 - - [10/Jun/2019:05:55:26 +0000] "GET / HTTP/1.1" 200 399 "-" "curl/7.29.0"
192.168.249.1 - - [10/Jun/2019:06:30:35 +0000] "GET / HTTP/1.1" 200 399 "-" "curl/7.29.0"
192.168.249.1 - - [10/Jun/2019:06:43:21 +0000] "GET / HTTP/1.1" 200 399 "-" "curl/7.29.0"
192.168.249.1 - - [10/Jun/2019:06:44:07 +0000] "GET /api/v1/namespaces/kube-system/services/http:kubernetes-dashboard:/proxy HTTP/1.1" 200 542 "-" "curl/7.29.0"
192.168.249.1 - - [10/Jun/2019:06:50:39 +0000] "GET /api/v1/namespaces/default/services/ HTTP/1.1" 200 470 "-" "curl/7.29.0"
192.168.249.1 - - [10/Jun/2019:06:53:47 +0000] "GET / HTTP/1.1" 200 769 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"
192.168.249.1 - - [10/Jun/2019:06:53:47 +0000] "GET /favicon.ico HTTP/1.1" 200 722 "http://xxx.xxx.xxx.xxx:30525/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"
192.168.249.1 - - [10/Jun/2019:06:56:53 +0000] "GET /version HTTP/1.1" 200 784 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"
192.168.249.1 - - [10/Jun/2019:06:56:53 +0000] "GET /favicon.ico HTTP/1.1" 200 729 "http://xxx.xxx.xxx.xxx:30525/version" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"
```

```shell-session
$ minikube logs -f 
```

## 色々削除
service削除

```shell-session
$ sudo kubectl delete services hello-minikube
```

deployment削除

```shell-session
$ sudo kubectl delete deployment hello-minikube
```

状態を確認

```sh
# nodeを確認
$ sudo kubectl get nodes
NAME       STATUS   ROLES    AGE   VERSION
minikube   Ready    master   20m   v1.14.3

# podを確認
$ sudo kubectl get pods
No resources found.

# serviceを確認
$ sudo kubectl get services
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   20m

# deploymentsを確認
$ sudo kubectl get deployments
No resources found.
```

クラスタの停止

```shell-session
$ sudo minikube stop
```

クラスタの削除

```shell-session
$ minikube delete
```

## トラブルシューティング
### kubectlで以下のエラーが出る場合はKUBECONFIGの内容がおかしい
> Get http://localhost:8080/apis/apps/v1?timeout=32s: dial tcp 127.0.0.1:8080: connect: connection refused

or

> The connection to the server localhost:8080 was refused - did you specify the right host or port?


**e.g.) 環境変数`KUBECONFIG`で設定されている`.kube/config`の場所or内容がおかしい**
sudo付けた場合とそうでない場合で取得されるconfigが異なる。

```
$ kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /home/username/.minikube/ca.crt
    server: https://xxx.xxx.xxx.xxx:8443
  name: minikube
contexts:
- context:
    cluster: minikube
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: /home/username/.minikube/client.crt
    client-key: /home/username/.minikube/client.key
```

sudoを付けた場合

```
$ sudo kubectl config view
apiVersion: v1
clusters: []
contexts: []
current-context: ""
kind: Config
preferences: {}
users: []
```

この例の場合は、/home/username/.kube/configが存在していて、/root/.kube/configが存在していない。kubectlをrootで実行する場合は、/root/.kube/の下に設定ファイルが存在している必要がある。


## 参考
- [GitHub: kubernetes/minikube](https://github.com/kubernetes/minikube/blob/v0.25.2/README.md)
- [Hello Minikube](https://kubernetes.io/ja/docs/tutorials/hello-minikube/)
- [CentOS7.5にminikubeをインストールする](https://qiita.com/okcoder/items/5381e5ad08ae5562c1dd)
- [CentOS7でminikubeを爆速で試す](https://qiita.com/chaspy/items/afe2009cea6180bd2fc5)
- [簡単にローカルKubernetes環境を構築できるツール「Minikube」](https://knowledge.sakura.ad.jp/15320/)
- [minikubeのvm-driver noneでk8sを構築したときに外部ホストからアクセスを許可する](http://thaim.hatenablog.jp/entry/2017/12/09/122520)
- [kubernetes初心者のための入門ハンズオン](https://qiita.com/mihirat/items/ebb0833d50c882398b0f)
- [Minikubeを使用してローカル環境でKubernetesを動かす](https://kubernetes.io/ja/docs/setup/minikube/)
- [minikubeでkubernetes cluster構築してdashboard開くまでやってみる](https://namionobkup.hatenablog.com/entry/2018/02/25/154350)
- https://gist.github.com/zaru/ae1d3294415fedbaec614137125e01c6
- [KubernetesにDashboardをインストールして、認証なしでアクセスする](https://qiita.com/sheepland/items/0ee17b80fcfb10227a41)