オンプレKubernetesでメリクリを叫ぶ

はじめに 
-
最近業務でGCP＋Kubernetes上にアプリを構築しています。
これまでブラックボックスだったKubernetesについて基本的な構造や利用方法を勉強したのでハンズオンを交えて記事にしてみました。
ざっとKubernetesの特徴や使い方を知りたい人向けです。
初投稿なので何か不備などあればコメントいただけると幸いです。

Dockerとは
-
Kubernetesの基盤をなす技術要素としてコンテナ仮想化があげられます。そのツールのデファクトスタンダードと言えるのがDockerです。
コンテナ仮想化とはアプリケーションをホストマシンの環境から切り離してパッケージ化する技術のことで、
アプリを「どこでも」「すぐに」「同じように」動かすことができます。
ローカル環境の構築で「あの人の端末では動くのに、自分の端末では動かないぃぃぃ！開発始められなぃぃぃぃ！」と頭を抱えることがなくなります。
参考：[【連載】世界一わかりみが深いコンテナ & Docker入門 〜 その1:コンテナってなに？ 〜](https://tech-lab.sios.jp/archives/18811)

Kubernetesとは
-
多数のコンテナ運用管理を自動化（コンテナオーケストレーション）するツールで、デファクトスタンダードとなっています。
多数のコンテナのデプロイ、起動、監視、スケーリング、停止、削除といった運用管理を自動化することができます。
参考：[Kubernetes道場 1日目 - Kubernetesの概要](https://cstoku.dev/posts/2018/k8sdojo-01/)

Kubernetesの基本
-
以下、Kubernetesの主要な構成要素とManifestについての概要です。
それぞれの役割がなんとなく頭に入っていれば次のハンズオンも理解しながらすすめることができるのではないかと思います。

- 構成要素
    - Cluster
        - Kubernetesの全ての構成要素を含むコンポーネント。
    - Master（Control Plane）
        - クラスタ内のWorkerやリソースの制御を主に行う。
    - Worker（Data Plane）
        - コンテナの起動・監視やKubernetesの実行環境を提供する。
    - Pod
        - 最小単位。1つ以上のコンテナが配置される。
    - Replicaset
        - Podを指定の数に増減させる。
    - Deployment 
        - Replicasetを管理することで間接的にPod数の調整を行う。
    - Service
        - 内部もしくは外部からのPodに対する通信の制御を行う。L4ロードバランサー。
        - clusterIP、nodePort、loadBalance、externalNameの4つのタイプがある。
    - Ingress
        - IngressはHTTPやHTTPSの外部アクセスを制御する。L7ロードバランサー。
        - パスベースのロードバランシングやSSLターミネーションを行うことができる。
        - Ingressを利用するにはIngress Controllerが必要。


#### MasterとWorker、DeploymentとReplicaset、Podの関係図
※MasterとWorkerにも細かい構成要素が存在しますが、ここでは割愛します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436737/671a4032-8450-6c55-102b-476bb8f4542a.png)


#### Ingress-Service-Podの構成、通信の流れの概念図
※実際にはIngress Controllerの上流にはロードバランサーが配置されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436737/bcb0acf7-6053-217c-2d41-4bac07ffe408.png)


- Manifest
    - Kubernetes上のリソースを管理するyamlやJsonで記述された定義ファイル。
    - Manifestを適用することでCluster上のリソースの更新を行うことができます。

# ハンズオン
ブラウザ上でメリクリとだけ表示するアプリをオンプレKubernetes上にデプロイし、ローカルで確認するハンズオンです。

### 環境
Windows10 Pro

### 利用ツール
node v10.22.0
yarn 1.22.4
Docker 19.03.13
kubernetes v1.19.3
minikube v1.15.1


### 手順
####1. Dockerのインストール
まずはDockerを利用できるようにしていきましょう。バックエンドにはHyper-Vを使用しています。
参考：[【Docker】第9回　Windows 10 Pro へ Docker Desktop for Windows をインストールする](https://www.public.ne.jp/2020/06/02/%E3%80%90docker%E3%80%91%E7%AC%AC9%E5%9B%9E%E3%80%80windows-10-pro-%E3%81%B8-docker-desktop-for-windows-%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B/)

####2. Kubernetes・minikubeのインストール
kubectlはKubernetesを操作するためのコマンドラインツールです。　
minikubeはローカルで簡単にKubernetesを実行できるツールです。
参考：
[kubectl 公式インストール手順](https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/)
[minikube 公式インストール手順](https://minikube.sigs.k8s.io/docs/start/)

####3. Hyper-Vマネージャの設定（外部ネットワーク用仮想スイッチの追加）
ローカルminikubeクラスタと通信できるよう仮想スイッチを追加します。
参考：
[初めてのkubernetes（Minikube） Windows環境構築編](https://qiita.com/comefigo/items/f7bc852a63797934d641)


####4. Manifestのダウンロード
下記リポジトリからクラスターに適用するManifestをダウンロードし、任意のディレクトリに保存して下さい。
https://github.com/nmotoki-dev/christmas-apps-infra.git

####5. minikubeの起動
コマンドプロンプトを管理者権限で起動し、仮想マシンドライバを'hyperv'、仮想スイッチに先ほど追加した仮想スイッチ名（ここでは'minikube'）を指定して起動します。
'--vm-driver'は無指定だとvirtualboxのドライバになります。

```
> minikube start --vm-driver=hyperv --hyperv-virtual-switch=minikube
```
クラスタが起動しているか確認

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

ブラウザにダッシューボードを表示。クラスター上のリソースを確認することができます。

```
> minikube dashboard
```


####6. クラスタに各リソースデプロイ
#####1. Deployment
DeploymentのManifestを適用しDeploymentをデプロイします。
Deploymentの設定に従って順次Replicaset, Podもデプロイされます。


```deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: christmas-apps-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: christmas-apps-front
  template:
    metadata:
      labels:
        app: christmas-apps-front
    spec:
      containers:
      - name: christmas-apps-front
        image: ghcr.io/nmotoki-dev/christmass-apps-container-registry/christmas-apps:latest
        ports:
        - containerPort: 80
```
DeploymentのManifestを適用。

```
> kubectl apply -f C:\~\christmas-apps-infra\deployment.yml --validate=false
deployment.apps/christmas-apps-deployment created
```
Pod一覧を表示し起動確認。

```
> kubectl get pod
NAME                                       READY   STATUS    RESTARTS   AGE
christmas-apps-deployment-d9cdcf6f-2crfm   1/1     Running   0          6m46s
christmas-apps-deployment-d9cdcf6f-zkmr4   1/1     Running   0          6m46s
```

#####2. Service
ServiceのManifestを適用しServiseをデプロイします。
クラスタ外部からアクセスできるようTypeはNordPortを指定しています。

```service.yml
apiVersion: v1
kind: Service
metadata:
  name: christmas-apps-service
spec:
  selector:
    app: christmas-apps-front
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
```

ServiceのManifestを適用。

```
> kubectl apply -f C:\~\motoki\react\christmas-apps-infra\service.yml --validate=false
service/christmas-apps-service created
```

Service一覧を表示し起動確認。TYPEが'NordPort'となっているものが作成したServiceです。

```
> kubectl get service
NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
christmas-apps-service   NodePort    10.106.189.11   <none>        80:30195/TCP   7m6s
kubernetes               ClusterIP   10.96.0.1       <none>        443/TCP        27m

```


####7. アプリをブラウザで表示
下記コマンドで公開したいServiceを指定するとPodへアクセスしブラウザで表示することができます。

```
> minikube service christmas-apps-service
|-----------|------------------------|-------------|------------------------------|
| NAMESPACE |          NAME          | TARGET PORT |             URL              |
|-----------|------------------------|-------------|------------------------------|
| default   | christmas-apps-service |          80 | http://192.168.100.124:30195 |
|-----------|------------------------|-------------|------------------------------|
* Opening service default/christmas-apps-service in default browser...```
```

ブラウザ表示画面
![2020-12-20_19h17_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436737/f314ff5a-c51f-2f00-6b0c-bf3a169b05bf.png)

####8. Podの自動起動を確認
Podを削除する前に現在のPodを確認。

```
> kubectl get pod
NAME                                       READY   STATUS    RESTARTS   AGE
christmas-apps-deployment-d9cdcf6f-2crfm   1/1     Running   0          58m
christmas-apps-deployment-d9cdcf6f-zkmr4   1/1     Running   0          58m
```

Podを一つ削除。

```
> kubectl delete pod christmas-apps-deployment-d9cdcf6f-2crfm
pod "christmas-apps-deployment-d9cdcf6f-2crfm" deleted
```

Podの起動を確認。
'christmas-apps-deployment-d9cdcf6f-2crfm'が削除され'christmas-apps-deployment-d9cdcf6f-zkmr4'に置き換わっていることがわかります。


```
> kubectl get pod
NAME                                       READY   STATUS    RESTARTS   AGE
christmas-apps-deployment-d9cdcf6f-r7xwx   1/1     Running   0          20s
christmas-apps-deployment-d9cdcf6f-zkmr4   1/1     Running   0          59m
```

####9. Pod数を変えてみる
Podの複製数（replicas）を2から4に増やします。

```deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: christmas-apps-deployment
spec:
  replicas: 4
  selector:
    matchLabels:
      app: christmas-apps-front
  template:
    metadata:
      labels:
        app: christmas-apps-front
    spec:
      containers:
      - name: christmas-apps-front
        image: ghcr.io/nmotoki-dev/christmass-apps-container-registry/christmas-apps:latest
        ports:
        - containerPort: 80
```
DeploymentのManifestを適用。

```
> kubectl apply -f C:\~\christmas-apps-infra\deployment.yml --validate=false
deployment.apps/christmas-apps-deployment configured
```
Pod一覧を表示し起動確認。Podが4つに増えたのが確認できればOKです。

```
> kubectl get pod
NAME                                       READY   STATUS    RESTARTS   AGE
christmas-apps-deployment-d9cdcf6f-4mbp2   1/1     Running   0          37s
christmas-apps-deployment-d9cdcf6f-89blb   1/1     Running   0          77m
christmas-apps-deployment-d9cdcf6f-9jr82   1/1     Running   0          77m
christmas-apps-deployment-d9cdcf6f-nfkqr   1/1     Running   0          37s
```



#minikubeがうまく立ち上がらない時
- minikubeを一度停止・削除してから再度起動するとうまくいくことがあります。

```
minikube削除
> minikube delete

minikube起動
> minikube start --vm-driver=hyperv --hyperv-virtual-switch=minikube
```

- minikubeがメモリ不足で立ち上がらない場合は、他のVMを停止するか、minikube用のメモリ割り当て数を減らし再起動してみましょう。



# まとめ
今回のハンズオンでは、Kubernetes上にアプリをデプロイする手順とPodの自動機能、Pod数の変更を行いました。
ローリングアップデートやロールバック、Ingressの利用については今回実現することができなかったので次回以降チャレンジしたいと思います。
また、コンテナイメージはローカルでビルドしてGithub Container Registryに手動でプッシュしているので、Github Actionで自動化したいとなと考えています。


# 参考

- [Kubernetesドキュメント(公式)](https://kubernetes.io/ja/docs/home/)
- [Kubernetes道場 1日目 - Kubernetesの概要](https://cstoku.dev/posts/2018/k8sdojo-01/)
- [Hello Minikube(公式チュートリアル)](https://kubernetes.io/ja/docs/tutorials/hello-minikube/)
- [kubectlチートシート](https://kubernetes.io/ja/docs/reference/kubectl/cheatsheet/)
- [初めてのkubernetes（Minikube） Windows環境構築編](https://qiita.com/comefigo/items/f7bc852a63797934d641)
- [GitHub Container Registry(ghcr.io)にDockerイメージをpushする手順](https://qiita.com/zembutsu/items/1effae6c39ceae3c3d0a)