ローカルでサクッと試す Kubernetes ハンズオン

# 初めに

Kubernetes の学習をはじめ、なんとか一通り触ったので記事にします。

この記事では Kubernetes の概要からデプロイメントまでを扱います。
概念チックな内容を前半にまとめ、後半で手を動かすことで理解を深める構成になっています。

# Kubernetes とは

Kubernetes とは、コンテナ化されたサービスを管理するためのプラットフォームです。
主に効率的なリソース活用、柔軟なスケールなどを提供します。

Kubernetes は開発面での課題ではなく運用面の課題を解決するためのツールです。
普段アプリケーション開発を主に行っており、インフラは触らないこともないけど作業の比重は低い、
という人には手を出しにくい存在かと思います。（まさに筆者がそうです）
更に追い打ちをかけるように、Kubernetes 自体が巨大なシステムであるため、とっつきにくさが増します。

学ぶ目的は人それぞれかと思いますが、共に気合い入れて頑張っていきましょう 💪（根性論）

### アーキテクチャ

以下が Kubernetes のアーキテクチャです。
※画像は [Think IT さんの記事](https://thinkit.co.jp/article/18188) よりお借りしました

![cl_kubernetes_study02_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547464/8379f6a0-53dc-14d6-8341-c231e4efb72f.png) 

今回はアーテクチャの中の個別のプロセス郡（ `kube-api-server` など）には踏み入りません。
重要な要素ではあるのですが、はじめから意識すると訳がわからなくなります。

### 構成要素

初歩で抑えておくべき Kubernetes の構成は以下です。

- kubectl
  - クラスター
    - コントロールプレーン
    - ワーカー1
      - コントローラー
        - ポッド
          - コンテナ1
          - コンテナ2
    - ワーカー2
      - ...

図には書かれていない要素もありますが、説明します。

kubectl とは、kubenetes を操作するための CLI です。
この CLI 1つでローカル環境でも本番環境でも kubernetes を操作するとこが可能です。

コントロールプレーンとワーカー郡をまとめてクラスタと呼びます。
kubernetes にははじめにクラスタがあり、その中に様々なコンポーネントが入っているという構成になっています。

コントローラーとは、ポッドを制御するオブジェクトです。
コントローラーにはいくつか種類があります。
今回紹介するのはデプロイメントという名前のコントローラーです。
このコントローラーは目標維持数に応じてポッドの数を自動で維持しようとします。

ポッドと呼ばれるものが存在します。
ポッドとはコンテナの最小実行単位のことであり、ポッドの中に複数のコンテナが存在します。

以下、個別に説明します。

### kubectl

kubectl とは、kubernetes を操作するための CLI です。

厳密には kubernetes は API を通して操作可能であり、kubectl は　CLI から API を叩けるツールです。
kubectl 以外に kubernetes の API を叩く方法としては、各プログラミング言語の SDK などがあります。

### コントロールプレーン

コントロールプレーンとは、ワーカーを監視するためのコンポーネントです。
コントロールプレーンはクラスタ内に1つのみです。

クライアント（開発者、運用者、CIツールなど）はコントロールプレーンに対してリクエストを送り、Kubernetes を操作します。
例えば開発者や運用者であれば、kubectl を通してコントロールプレーンに対してリクエストを送ります。

### ワーカー

ワーカーとは、アプリケーションを実行するためのコンポーネントです。
ワーカーはクラスタ内に1つ以上存在できます。

ワーカーはコントロールプレーンによって操作されます。
ワーカーはポッドとコンテナを操作します。

### コントローラー

コントローラーとは、ポッドを制御するオブジェクトです。
いくつか種類があり、アプリケーションのワークロードに応じて適切なコントローラーを選択する必要があります。

### デプロイメント

デプロイメントとは、クライアント・サーバーモデルに適したコントローラーです。
ポッドの目標維持数を設定し、目標数を維持しようとします。

### ポッド

ポッドとは、コンテナの最小実行単位です。
ポッドの中に複数のコンテナが存在します。

例えばポッドの中にアプリケーションサーバー、バッチアプリケーションを一緒に含めるといったことが可能です。

### コンテナ

言わずと知れた Docker のコンテナです。
詳細は割愛します。

# minikube とは

minikube とは、単一ノードの kubernetes 環境を構築するためのツールです。
主にローカル環境でサクッと kubernetes を試用するために使用されます。

まさに今回のようなユースケースにピッタリであり、試しに触って見るにはもってこいのツールです。

### インストール

詳しい手順は [minikube start](https://minikube.sigs.k8s.io/docs/start/)に載っています。
OS などを選択するだけで環境ごとのインストール手順を参照できるようになっています。

MacOS の場合、homebrew でインストールできます。

```shell
$ brew install minikube
😄  minikube v1.25.2 on Darwin 12.2.1 (arm64)
✨  Automatically selected the docker driver
👍  Starting control plane node minikube in cluster minikube
...
```

絵文字が可愛らしいですね ✨

### start

`start` コマンドで単一ノードの kubernetes クラスタを作成できます。

```shell
$ minikube start
```

### status

`status` コマンドで minikube の稼働状況を見ることができます。
`Running` になっていれば起動に成功しています。

```shell
$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
```

### stop

`stop` コマンドでクラスタを停止できます。

```shell
$ minikube stop    
✋  Stopping node "minikube"  ...
🛑  Powering off "minikube" via SSH ...
🛑  1 node stopped.
```

ここでも絵文字は正義です。
停止できているか確認してみましょう。

```shell
$ minikube status
minikube
type: Control Plane
host: Stopped
kubelet: Stopped
apiserver: Stopped
kubeconfig: Stopped
```

無事に停止しています。

### delete

`delete` コマンドでクラスタの削除ができます。

```shell
$ minikube delete
🔥  Deleting "minikube" in docker ...
🔥  Deleting container "minikube" ...
🔥  Removing /Users/hiroto.ohira/.minikube/machines/minikube ...
💀  Removed all traces of the "minikube" cluster.
```

こちらも確認してみましょう。

```shell
$ minikube status
🤷  Profile "minikube" not found. Run "minikube profile list" to view all profiles.
👉  To start a cluster, run: "minikube start"
```

良さそうですね　💪

# kubectl とは

kubbectl とは、kubernetes を操作するための CLI です。
主に Docker を扱う操作感に近くなっています。

## 事前準備

### インストール

より詳細なインストール手順は [kubectlのインストールおよびセットアップ](https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/) に記載されています。

こちらも MacOS であれば homebrew でインストールできます。

```shell
$ brew install kubectl
```

### 構文

kubectl の構文は以下になります。
動作指向で設計されているため直感的に操作しやすくなっています。

```shell
$ kubectl <command> <resource-type> [name] [option]
```

## ポッドの直接起動

### ノードの確認

`get node` コマンドでノードの情報を確認することができます。
試しに minikube を起動したあとでコマンドを実行してみましょう。

```shell
kubectl get node
NAME       STATUS   ROLES                  AGE     VERSION
minikube   Ready    control-plane,master   8m27s   v1.23.3
```

minikube は単一ノード構成のため、表示されるノードは1つのみです。

### クラスタの確認

`cluster-info` コマンドでクラスタの情報を確認することができます。
コントロールプレーンのドメイン情報などが表示されます。

```shell
$ kubectl cluster-info 
Kubernetes control plane is running at https://127.0.0.1:49925
CoreDNS is running at https://127.0.0.1:49925/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
```

### ポッドの起動

ポッドをコントローラーを通さずに起動してみます。

`run <name>` コマンドでポッドを起動する事ができます。
`--restart=Never` オプションを指定する事により、コントローラーを介さずにポッド単体で起動できます。

- `--image`: ポッド内で実行するコンテナのイメージを指定します
- `-it`: 対話的に起動します。`--restart=Never` が付与されている場合のみに有効。
- `--restart`: コントローラーの種類を指定します。

```shell
kubectl run hello-world --image=hello-world -it --restart=Never

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (arm64v8)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
```

ポッドが起動し、`hello-world` コンテナが実行されました。

### ポッドの確認

`get pod` コマンドでポッドの情報を確認できます。

```
$ kubectl get pod 
NAME          READY   STATUS      RESTARTS   AGE
hello-world   0/1     Completed   0          101s
```

STATUS が `Completed` の場合、ポッドは正常終了しています。

### ポッドの削除

Docker コンテナと同じ用に、ポッドは実行終了した後も残ります。
`delte pod <name>` コマンドでポッドを削除できます。

```shell
$ kubectl delete pod hello-world
pod "hello-world" deleted
```

ポッドが削除できたか確認してみましょう。

```shell
$ kubectl get pod               
No resources found in default namespace.
```

### ポッドをバックグラウンドで起動


`-it` を指定しないことにより、ポッドをバックグラウンドで起動できます。

```shell
$ kubectl run hello-world --image=hello-world --restart=Never     
pod/hello-world created
```

バックグラウンドで起動した場合、コンソールにログは出力されません。

### ポッドのログの確認

`logs <name>`　コマンドで、ポッドのログを確認できます。

```shell
$ kubectl logs hello-world                                   

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (arm64v8)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
```

ログが確認できていますね。

## デプロイメントを通してポッドを起動

### デプロイメントの作成

`create deployment` コマンドでデプロイメントを作成できます。
これにより、デプロイメントを通してポッドを起動する事ができます。

1. デプロイメントを作成する
1. デプロイメントがポッドの目標数を維持しようとする
1. 目標数が1であれば、ポッドを1個作成する

```
$ kubectl create deployment --image=nginx server              
deployment.apps/server created
```

### デプロイメントとポッドの確認

`get deploy,pod` コマンドで、デプロイメントとポッドのみの情報を確認できます。

```shell
$ kubectl get deploy,pod                        
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/server   1/1     1            1           12s

NAME                          READY   STATUS    RESTARTS   AGE
pod/server-5f5dc45899-xxx8n   1/1     Running   0          12s
```

プレフィックスが `deployment.apps/` となっている方がデプロイメントで、
`pod/` となっている方がポッドです。

### ポッドの目標維持数を増やす

`sclae`　コマンドでデプロイメントのポッド目標維持数を変更することができます。
`--replicas` オプションで個数を指定することができます。

今回は試しに 5個 に増やしてみます。

```shell
$ kubectl scale --replicas=5 deployment/server
deployment.apps/server scaled
```

確認してみましょう。

```shell
$ kubectl get deploy,pod                      
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/server   2/5     5            2           46s

NAME                          READY   STATUS              RESTARTS   AGE
pod/server-5f5dc45899-jhv9c   0/1     ContainerCreating   0          3s
pod/server-5f5dc45899-k7bvg   0/1     ContainerCreating   0          3s
pod/server-5f5dc45899-pc6rv   0/1     ContainerCreating   0          3s
pod/server-5f5dc45899-qbf9n   1/1     Running             0          3s
pod/server-5f5dc45899-xxx8n   1/1     Running             0          46s
```

5個 のポッドが作成されていますね。

### ポッドの削除

`delete pod` コマンドでポッドを削除することができます。
今回は 2個 のポッドを削除してみます。

```shell
$ kubectl delete pod server-5f5dc45899-jhv9c server-5f5dc45899-k7bvg
pod "server-5f5dc45899-jhv9c" deleted
pod "server-5f5dc45899-k7bvg" deleted
```

削除されたか確認してみましょう。

```shell
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/server   3/5     5            3           113s

NAME                          READY   STATUS              RESTARTS   AGE
pod/server-5f5dc45899-md9j9   0/1     ContainerCreating   0          3s
pod/server-5f5dc45899-mt6zt   0/1     ContainerCreating   0          3s
pod/server-5f5dc45899-pc6rv   1/1     Running             0          70s
pod/server-5f5dc45899-qbf9n   1/1     Running             0          70s
pod/server-5f5dc45899-xxx8n   1/1     Running             0          113s
```

あれ、5個 のままですね。
しかしよく見ると上2個のポッドの識別子が異なります。

この場合、ポッドは無事に 2個 削除されています。
確認した結果 5個 表示されているのは、デプロイメントのポッド維持機能によりポッドが新しく再作成されたためになります。

デプロイメントがきちんと仕事をしていることがわかります。

### デプロイメントの削除

`delete deployment` コマンドでデプロイメントを削除することができます。
デプロイメントを削除した場合、ポッドも削除されます。

```shell
$ kubectl delete deployment server
deployment.apps "server" deleted
```

確認してみましょう。

```shell
$ kubectl get deploy,pod          
No resources found in default namespace.
```

良さそうですね！🎉

# 最後に

いかがでしたでしょうか。
正直システムの規模が大きく、いきなり全体を理解してからの作業は無理な気がします。
ある概念を抑えたらとりあえず手を動かすことが、kubernetes を効率よく学習する近道なように思います。

誰かのお役に立てましたら幸いです。

# 参考文献

- [15Stepで習得 Dockerから入るKubernetes](https://www.amazon.co.jp/dp/B08221TFBH)
- [Kubernetes環境を構築して、実際にコンテナを動かしてみよう](https://thinkit.co.jp/article/18188)