minikube使ってみて、Kubernetesに入門してみた気分になる

この記事は富士通システムズウェブテクノロジーの社内技術コミュニティで、「イノベーション推進コミュニティ」
略して「いのべこ」が企画する、[いのべこ夏休みアドベントカレンダー 2020](https://qiita.com/jugemsan/items/5761773308fb1df0c23a)の11日目の記事です。
本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません。
ここまでお約束 :wink: 

# はじめに

この記事では、Dockerには触れたことがあって使うことはできるけど。
Kubernetes(通称K8s。どう発音するのだろう。けーはちえす？けーえいつ？）は難しそうだなーと思って
使ったことがない未経験者が、ふと`minikube`なるものを見つけ、これなら簡単に使える気になれるのでは？！

と思って思い立ったときに試した内容をシェアするための記事です。

以下の環境を想定して記事を作成しています。

* Windows10 2004 Update
* WSL2(ubuntu 20.04)
* docker(Docker Engine CE 19.03.12)

## minikubeとは

[公式リポジトリ](https://github.com/kubernetes/minikube)には、以下のような説明が書かれています。

> minikube implements a local Kubernetes cluster on macOS, Linux, and Windows. minikube's primary goals are to be the best tool for local Kubernetes application development and to support all Kubernetes features that fit.

ローカルでK8sクラスタを構築し、
ローカルでのアプリケーション開発におけるK8sを利用しやすくしたもの。ととらえればいいのかな？

## K8sクラスタとは？

ローカルでクラスタを構築と言っているが、K8sにおけるクラスタはどういうものなのか。
公式ページから引用します。
[Kubernetesのコンポーネント](https://kubernetes.io/ja/docs/concepts/overview/components/)より
![Kubernetesクラスターの図](https://d33wubrfki0l68.cloudfront.net/7016517375d10c702489167e704dcb99e570df85/7bb53/images/docs/components-of-kubernetes.png)

この図における、Kubernetes Nodesの部分を、ローカル環境で簡単に用意してくれるていうものらしい。

実際、Kubernetesクラスタを構築するにはいくつか方法があるようで・・・

* minikube
* kubeadm
* kops
* kubespray

などがあるようです。
公式ページでは、kubeadmを使用したプロダクション環境用のK8sクラスタ構築の[手順](https://kubernetes.io/ja/docs/setup/production-environment/tools/)が公開されていましたが、複雑でどれもローカル環境でのテスト用に準備するには手間がかかりそうです。

K8sクラスタを構築するような記事がインターネット上にあったりしますが、マスターノードを構築して、
非マスターノードの構築して・・・とやたらと手順が複雑でめげてしまいそうです。。。
それに比べて、簡単にシングルノードのクラスタを構築できるものが、minikubeのようです。

## インストール方法

導入方法は、Kubernetesの公式ドキュメントに詳しく書かれています。
[Minikubeのインストール](https://kubernetes.io/ja/docs/tasks/tools/install-minikube/)
私の環境には、WSL2とdocker（docker desktop経由ではなく、CLIでインストールしました）がインストールされているため、
その状態からの抜粋でお送りします。

```bash
# ローカル環境にkubectl/minikubeをインストールします
# kubectlを取得します
$ curl -Lo /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 41.9M  100 41.9M    0     0  32.2M      0  0:00:01  0:00:01 --:--:-- 32.2M
# kubectlに実行権限を付与します
$ chmod +x /usr/local/bin/kubectl

# minikubeのインストールを行います
$ curl -Lo /usr/local/bin/minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 55.7M  100 55.7M    0     0  29.6M      0  0:00:01  0:00:01 --:--:-- 29.5M
# 実行権限の付与
$ chmod +x /usr/local/bin/minikube
```

インストールができました。インストールしたツールが動作するか確認してみましょう。

```bash
$ docker version
Client: Docker Engine - Community
 Version:           19.03.12
 API version:       1.40
 Go version:        go1.13.10
 Git commit:        48a66213fe
 Built:             Mon Jun 22 15:45:44 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:44:15 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
$ minikube version
minikube version: v1.12.1
commit: 5664228288552de9f3a446ea4f51c6f29bbdd0e0-dirty
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.6", GitCommit:"dff82dc0de47299ab66c83c626e08b245ab19037", GitTreeState:"clean", BuildDate:"2020-07-15T16:58:53Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
```

## 公式サンプルを試してみる

minikube/kubectlのインストールができたら、公式サンプルを試してみましょう。
[公式のドキュメント](https://kubernetes.io/ja/docs/setup/learning-environment/minikube/)に、サンプルのコマンドが載っていますので、
確認しながら実施してみたいと思います。

### minikubeを使用したローカルクラスタの構築

```bash
# minikubeを使用して、ローカル環境にKubernetesクラスタを構築します。
$ minikube start 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280383/7c8ea743-aaf1-4413-a04f-ea57386ef0c6.png)

上記のようになれば、起動成功です！Windows Terminalを使用していると、絵文字があって楽しいですね。
WSLのデフォルトコンソールだと、`<?>`のようになって何が何だかという感じ。

デフォルト指定してminikubeでクラスタを起動した場合、`--vm-driver`フラグには`none`
いわゆる、dockerドライバーが選択されます。（ローカル環境にDockerがインストールされている必要があります）

また、ログを見る限りだと、`--cpus`は2、`--memory`は4gが割り当てられているようです。

### kubernetesのデプロイを実行します

```bash
$ kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.10
deployment.apps/hello-minikube created
$ kubectl expose deployment hello-minikube --type=NodePort --port=8080
service/hello-minikube exposed
```

以下のコマンドで、podが起動していることを確認できます。

```bash
$ kubectl get pod
NAME                              READY   STATUS    RESTARTS   AGE
hello-minikube-64b64df8c9-662hl   1/1     Running   0          90s
```


### デプロイされたコンテナの動作を確認する

公式ページでは`curl $(minikube service hello-minikube --url)`で、
動作しているコンテナにアクセスできるようですが、WSL2の環境では、以下のようになり実行できません。

```bash
$ minikube service hello-minikube --url
🏃  Starting tunnel for service hello-minikube.
|-----------|----------------|-------------|------------------------|
| NAMESPACE |      NAME      | TARGET PORT |          URL           |
|-----------|----------------|-------------|------------------------|
| default   | hello-minikube |             | http://127.0.0.1:41527 |
|-----------|----------------|-------------|------------------------|
http://127.0.0.1:41527
❗  Because you are using a Docker driver on linux, the terminal needs to be open to run it.
```

ただ、上記でURLが出ている、`http://127.0.0.1:41527`にアクセスすれば、動作は確認できますので、curlなどで覗いてみましょう。

```bash
$ curl curl http://172.17.0.3:30971


Hostname: hello-minikube-64b64df8c9-662hl

Pod Information:
        -no pod information available-

Server values:
        server_version=nginx: 1.13.3 - lua: 10008

Request Information:
        client_address=172.19.0.1
        method=GET
        real path=/
        query=
        request_version=1.1
        request_scheme=http
        request_uri=http://172.17.0.3:8080/

Request Headers:
        accept=*/*
        host=172.17.0.3:30971
        user-agent=curl/7.68.0

Request Body:
        -no body in request-
```

無事、動作確認できたのではないでしょうか。
最後に、作成したサービスとminikubeで作成したクラスタを削除し、動作確認は終了です。

```bash
$ kubectl delete services hello-minikube
service "hello-minikube" deleted
$ kubectl delete deployment hello-minikube
deployment.apps "hello-minikube" deleted
$ minikube service list # "hello-minikube"のサービスがなくなっています。
|----------------------|---------------------------|--------------|-----| 
|      NAMESPACE       |           NAME            | TARGET PORT  | URL |
|----------------------|---------------------------|--------------|-----|
| default              | kubernetes                | No node port |
| kube-system          | kube-dns                  | No node port |
| kubernetes-dashboard | dashboard-metrics-scraper | No node port |
| kubernetes-dashboard | kubernetes-dashboard      | No node port |
|----------------------|---------------------------|--------------|-----|
$ minikube stop # ローカルクラスタの停止
✋  Stopping "minikube" in docker ...
🛑  Powering off "minikube" via SSH ...
🛑  Node "minikube" stopped.
$ minikube delete # ローカルクラスタの削除
🔥  Deleting "minikube" in docker ...
🔥  Deleting container "minikube" ...
🔥  Removing /home/bash/.minikube/machines/minikube ...
💀  Removed all traces of the "minikube" cluster.
```

## minikubeを使ってできること

minikubeのコマンドラインには、kubernetesを使用するにあたり様々なものが用意されています。
helpの内容を見てみましょう。

```
minikube --help
minikube provisions and manages local Kubernetes clusters optimized for development workflows.

Basic Commands:
  start          Starts a local Kubernetes cluster
  status         Gets the status of a local Kubernetes cluster
  stop           Stops a running local Kubernetes cluster
  delete         Deletes a local Kubernetes cluster
  dashboard      Access the Kubernetes dashboard running within the minikube cluster
  pause          pause Kubernetes
  unpause        unpause Kubernetes

Images Commands:
  docker-env     Configure environment to use minikube's Docker daemon
  podman-env     Configure environment to use minikube's Podman service
  cache          Add, delete, or push a local image into minikube

Configuration and Management Commands:
  addons         Enable or disable a minikube addon
  config         Modify persistent configuration values
  profile        Get or list the the current profiles (clusters)
  update-context Update kubeconfig in case of an IP or port change

Networking and Connectivity Commands:
  service        Returns a URL to connect to a service
  tunnel         Connect to LoadBalancer services

Advanced Commands:
  mount          Mounts the specified directory into minikube
  ssh            Log into the minikube environment (for debugging)
  kubectl        Run a kubectl binary matching the cluster version
  node           Add, remove, or list additional nodes

Troubleshooting Commands:
  ssh-key        Retrieve the ssh identity key path of the specified cluster
  ip             Retrieves the IP address of the running cluster
  logs           Returns logs to debug a local Kubernetes cluster
  update-check   Print current and latest version number
  version        Print the version of minikube

Other Commands:
  completion     Generate command completion for a shell

Use "minikube <command> --help" for more information about a given command.
```

以下では、便利そうだなーと思ったコマンドを紹介します。


### dashboard

`minikube dashboard`で起動します。
起動するとコンソールに、
`🎉  Opening http://127.0.0.1:42011/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...`
のように表示されるので、ブラウザなどでアクセスしてみてください。
すると、kubernetesクラスタの状態を確認するためのダッシュボードにアクセスすることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280383/3fda250a-7c3e-2f6b-0ced-9164fa1dd6d4.png)

dashboardは素のK8sの場合デプロイされておらず、kubectlを使用してデプロイ～プロキシコマンドを実行することによって、ダッシュボードにアクセスできるようになります。それがワンコマンドで・複雑（？）なオプションなしで実行できるのは少し便利なのかな？と思います。

[WebUI(Dashboard)](https://kubernetes.io/ja/docs/tasks/access-application-cluster/web-ui-dashboard/)

### service

稼働しているserviceの一覧を表示します。

```bash
$ minikube service list
|----------------------|---------------------------|--------------|-------------------------|
|      NAMESPACE       |           NAME            | TARGET PORT  |           URL           |
|----------------------|---------------------------|--------------|-------------------------|
| default              | hello-minikube            |         8080 | http://172.17.0.3:30971 |
| default              | kubernetes                | No node port |
| kube-system          | kube-dns                  | No node port |
| kubernetes-dashboard | dashboard-metrics-scraper | No node port |
| kubernetes-dashboard | kubernetes-dashboard      | No node port |
|----------------------|---------------------------|--------------|-------------------------|
```

## 困りごと

`minikube start`してstop>deleteした後、またminikube startしてローカルクラスタを構築しようとするとエラーになります。

```bash
minikube start
😄  minikube v1.12.1 on Ubuntu 20.04
✨  Automatically selected the docker driver

❗  'docker' driver reported a issue that could affect the performance.
💡  Suggestion: enable overlayfs kernel module on your Linux

👍  Starting control plane node minikube in cluster minikube
🔥  Creating docker container (CPUs=2, Memory=2200MB) ...
🤦  StartHost failed, but will try again: creating host: create: creating: create kic node: create container: docker run -d -t --privileged --security-opt seccomp=unconfined --tmpfs /tmp --tmpfs /run -v /lib/modules:/lib/modules:ro --hostname minikube --name minikube --label created_by.minikube.sigs.k8s.io=true --label name.minikube.sigs.k8s.io=minikube --label role.minikube.sigs.k8s.io= --label mode.minikube.sigs.k8s.io=minikube --volume minikube:/var --security-opt apparmor=unconfined --cpus=2 --memory=2200mb -e container=docker --expose 8443 --publish=127.0.0.1::8443 --publish=127.0.0.1::22 --publish=127.0.0.1::2376 --publish=127.0.0.1::5000 gcr.io/k8s-minikube/kicbase:v0.0.10@sha256:f58e0c4662bac8a9b5dda7984b185bad8502ade5d9fa364bf2755d636ab51438: exit status 125
stdout:
8df93322265580c4510cb0a0e9d59bd4cc3f306aaadf73a1681e6d4c605a7dd5

stderr:
docker: Error response from daemon: cgroups: cannot find cgroup mount destination: unknown.

^@🤷  docker "minikube" container is missing, will recreate.
```

🤷🤷🤷

`docker run`も同様の理由でできなくなります。
`docker: Error response from daemon: cgroups: cannot find cgroup mount destination: unknown.`

一応、WSL2の再起動（shutdownからのWSLの起動）で治ります。

また、以下のコマンドでも治ります。(応急処置です）

```bash
sudo mkdir /sys/fs/cgroup/systemd
sudo mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd
```

[参考にしたIssue](https://github.com/microsoft/WSL/issues/4189)

原因は深くは追及してないので、わかりましたらここに残したいと思います。

## 感想

公式チュートリアルをなぞっただけですが、minikubeでローカルクラスタを構築することができました。
Kubernetesに入門する・Kubernetes環境をローカルマシンにもって動作確認環境にできるのはとても便利そうです。
これをきっかけに、皆さんも1人1Kubernetesクラスタを持って開発に勤しみましょう:muscle:（？）