Minikubeでk8sの基本操作を学ぶ

コンテナ初学者の新人社員でk8sを勉強しています。

今回はAWSのEC2にMinikubeをインストールして、nginxのテストページが見れるまでの手順を記したいと思います。

#開発環境
* AWS EC2 t3.small

今回、Minikubeを利用する環境として、EC2のt3.smallを選択しました。
2GB以上のメモリや20GB以上のディスクスペースがないとMinikubeをうまくインストールできないようです。

多少料金がかかってしまいます。試す場合は注意しましょう。

#準備

EC2インスタンスを起動する手順までは省きます。私はやりなれているUbuntuをインストールしたEC2を選択しました。

以下のように入力して起動したEC2に接続します。

```
$ ssh -i test-key.pem ubuntu@xxx.xxx.xxx.xxx
```

test-key.pem はEC2を作成した際にダウンロードした鍵のファイル名です。
xxx.xxx.xxx.xxx はEC2のパブリックIPを指定します。


###Dockerのインストール
無事EC2に接続できたらDockerをインストールしましょう。
ほぼ[公式の手順通り](https://docs.docker.com/engine/install/ubuntu/)です。

```terminal:Dockerのインストール
# Ubuntuのパッケージをアップデート
$ sudo apt-get update

# 必要なパッケージのインストール
$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

# Dockerの公式GPGキーの追加
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

# Dockerのダウンロードサイトをaptレポジトリに追加
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

# Docker Engineのインストール
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

# バージョンが表示されればインストール成功
$ sudo docker --version
```

###Minikubeのインストール
続いてMinikubeをインストールしましょう。

```terminal
# minikubeのダウンロードと実行権限の付与
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \
  && chmod +x minikube

# minikubeバイナリの移動
$ sudo mv minikube /usr/local/bin/

# バージョンが表示されればインストール成功
# minikube version
```

###kubectlのインストール
Kubernetesはkubectlコマンドを使って操作するので、kubectlコマンドをインストールしていきます。
[公式の手順](https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/)通りです。

```terminal
# 必要なパッケージのインストール
$ sudo apt-get update && sudo apt-get install -y apt-transport-https gnupg2

# kubectlのパッケージを追加
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - 
  echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list

# kubectlのインストール
$ sudo apt-get update
$ sudo apt-get install -y kubectl

# バージョンが表示されればインストール成功
$ kubectl version --client
```

最後にMinikubeを起動します。
エラーがなければ無事起動できています。

```terminal
$ sudo minikube start --vm-driver=none
・
・
・
💡  This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true
🔎  Verifying Kubernetes components...
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" by default
```

#マニフェストファイルの作成
kubectlを用いてリソースの操作をするわけですが、リソースの設定値が多いので、kubectlの引数で細かく設定するのはあまり現実的ではありません。
そのため、リソースの情報はファイルに記述しておいて、作成したファイルをkubectlに読み込ませるというやり方が一般的なようです。

リソースの情報を「マニフェスト」と呼び、それを記述したファイルのことを「マニフェストファイル」と呼びます。
マニフェストファイルはJSON形式またはYAML形式で記述するのですが、読みやすいYAML形式で記述されているものがほとんどです。

###Pod作成
それでは nginx のPodを作っていきましょう。
Podのマニフェストファイルは以下のように記述しました。

```yaml:nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-nginx 
spec:
  containers:
    - name: my-nginx-container
      image: nginx:latest
      ports:
        - containerPort: 80
```
Podをつくりたいので、kindにはPodと指定しておきます。
metadataには、Podの名前を指定します。test-nginxとしました。
specでは、Podの詳細情報を記します。
containerの項目では、nameにコンテナ名、imageにはイメージ名、portsではコンテナが使用するポート番号を指定します。

```terminal
# Pod作成
$ kubectl create -f nginx.yaml
pod/test-nginx created

# Podの状態を確認
$ kubectl get pods
NAME         READY   STATUS    RESTARTS   AGE
test-nginx   1/1     Running   0          8s

# Podの詳細情報の取得
$ kubectl describe pods my-pod
Name:         test-nginx
Namespace:    default
Priority:     0
Node:         ip-10-0-1-23/10.0.1.23
Start Time:   Sat, 14 Nov 2020 10:28:37 +0000
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           172.17.0.3
IPs:
  IP:  172.17.0.3
Containers:
  my-nginx-container:
    Container ID:   docker://a580525cc1eb22f7a237b2d3424f8899ba04cf17ec71a1c2810c6d7e9700ebfc
    Image:          nginx:latest
    Image ID:       docker-pullable://nginx@sha256:aeade65e99e5d5e7ce162833636f692354c227ff438556e5f3ed0335b7cc2f1b
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 14 Nov 2020 10:28:42 +0000
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-5qpwm (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-5qpwm:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-5qpwm
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  2m16s  default-scheduler  Successfully assigned default/test-nginx to ip-10-0-1-23
  Normal  Pulling    2m16s  kubelet            Pulling image "nginx:latest"
  Normal  Pulled     2m13s  kubelet            Successfully pulled image "nginx:latest" in 3.237396456s
  Normal  Created    2m13s  kubelet            Created container my-nginx-container
  Normal  Started    2m12s  kubelet            Started container my-nginx-container
```

`kubectl describe` でPodのIPアドレスは `172.17.0.3`だということがわかりました。
curlコマンドを実行してみると、nginxが起動していることがわかります。
ただこのままだとテストページを見ることができません。

```terminal
$ curl 172.17.0.3
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```

#テストページの確認
今度はテストページが見れるようにするための設定をしていきましょう。
あまり意味はないですが、複数Podの起動も合わせてやっていきましょう。

###Deplymentの作成
Deploymentを使って複数Podを作成できるようにします。
Deploymentのマニフェストファイルは以下のように記述しました。

```yaml:deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deploymnet
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-nginx
  template:
    metadata:
      labels:
        app: my-nginx
    spec:
      containers:
        - name: test-nginx
          image: nginx:latest
          ports:
            - containerPort: 80
```
DeploymentのAPIGROUPはappsなので、apiVersionを `apps/v1` とします。`kubectl api-resources` と実行すると確認できます。
metadataでは、Deploymentの名前を指定します。
specでは、Deploymentの詳細情報を記述していきます。
ReplicaSetでは、レプリカ数を指定します。このファイルの場合、同じ構成のPodを2つ作成するという意味になります。
selectorでは、どのようなPodを作成するのかを指定します。app: my-nginxと指定しますが、すぐ下のtemplateで定義されたものを使用するという意味です。
templateで具体的なPodの情報を記述します。selectorで選択してもらえるようにapp: my-nginx と設定します。
それ以外は `nginx.yaml` と同じように記述します。

###Serviceの作成
次はServiceを使って外部からアクセスできるようにします。
Serviceのマニフェストファイルは以下のように記述しました。

```yaml:service.yaml
apiVersion: v1
kind: Service
metadata: 
  name: nginx-service
spec:
  type: NodePort
  ports:
    - nodePort: 30000
      port: 8080
      targetPort: 80
      protocol: TCP
  selector:
    app: my-nginx 
```
apiVersionでは、`kubectl api-resources`で確認したところ空欄なので`v1`とします。
metadataでは、Serviceの名前を指定します。
specでは、Serviceの詳細を記述していきます。
typeはServiceの種類を指定します。ここでは、ノード（今回だとEC2）のIPアドレスを通じてアクセスできるNodePortとしました。試してないですが、ほかの種類にしてもできるかもしれません。
portsでは、ポートの設定を行います。
nodePortはノードのポート番号、portはServiceのポート番号、targetPortはPodのポート番号です。
ノードがポート30000で通信を待ち受け、そこからServiceのポート8080に転送、最後にPodのポート80に転送というような流れとなります。

###Serviceを使ってnginxのテストページを確認する
DeploymentとService オブジェクトを用いて、nginxのテストページを確認していきます。
Serviceのポートは8080、ノードのポートには30000が割り当てられていることがわかります。

```terminal
# Deploymentオブジェクトの作成
$ kubectl create -f deployment.yaml
deployment.apps/my-deploymnet created

# Serviceオブジェクトの作成
$ kubectl create -f service.yaml
service/nginx-service created

# Serviceの状態を確認
$ kubectl get services
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes      ClusterIP   10.96.0.1       <none>        443/TCP          11d
nginx-service   NodePort    10.110.191.26   <none>        8080:30000/TCP   82s
```

まだやることがあります。
EC2のセキュリティグループの設定で30000ポートを許可してあげないとテストページが見れません。
※初めてやったときにここでつまりました笑

AWSにログインして、EC2 > セキュリティグループでEC2に割り当てたセキュリティグループ名を選択し、インバウンドルールを編集というボタンがあるのでそのボタンをクリックします。

私は以下のように設定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379397/7c1d0d02-cf16-9eea-ae1a-fa3c2242673b.png)

ブラウザで `xxx.xxx.xxx.xxx:30000`（xxx.xxx.xxx.xxxはEC2のパブリックIP）に接続するとnginxのテストページを確認できました。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379397/ad6d30bc-7b6f-d3b6-8f2e-ad4eb976ab64.png)

#感想
今回の検証を通して、Kubernetesの基本的な使い方をなんとなく知ることができました。
手を動かしたほうが、理解が進んだような気がします。

今度は以前やったBIND, Unboundのマニフェスト化に取り組んでいけたらと思います。