Kubernetes入門 〜ローカル環境で触ってからEKSへのデプロイまで〜

# この記事について
「Kubernetesを実際に触って勉強してみたい！」となって参考記事を探してみると、多くの記事がいきなりEKSやGKEといったクラウド上の本番環境を触るところからのスタートになっています。
「いきなり本番環境はちょっと……」「まずはローカル環境で軽く触って慣れてからクラウド上の環境を構築したい！」という方向けに、

1. Kubernetesのアーキテクチャの勉強
2. ローカルで実際に触ってみる
3. EKSにデプロイ

という流れで、Kubernetesってこんな感じなんだ！という雰囲気を紹介したいと思います。

## 使用する環境・バージョン

- OS : macOS Mojave 10.14.5
- Docker.app : 2.2.0.5
- Kubernetes : v1.15.5
- eksctl : 0.23.0
- aws-cli : 2.0.10

## 前提条件
Docker App, AWS CLIはインストール済みの状態からスタートします。

## 読者に求める前提知識
- コンテナをある程度扱えること
- コンテナオーケストレーションという概念について知っていること
- VPC, セキュリティグループといったAWSの用語がある程度わかること
- (ECSの知識があると所々の例え話がわかりやすくなりますが、必須ではありません)

# Kubernetesのアーキテクチャ
まず、Kubernetesの構成要素について詳しく説明します。
![k8s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/f2fe3b04-3a6d-549f-5779-2356e47915de.png)
画像出典:[Step by Step Introduction to Basic Concept of Kubernetes](https://medium.com/easyread/step-by-step-introduction-to-basic-concept-of-kubernetes-e20383bdd118)
参考:[順を追って学ぶKubernetesのキホン〜ローカル環境でKubernetesクラスターを作成してKubernetesの概念を理解する〜](https://qiita.com/baby-degu/items/ce26507bd954621d6dc5)

## Master
コンテナの起動・削除・カナリアデプロイといった、Kubernetesができるコンテナ管理・制御機能を担う頭脳部分です。
Masterを構成する主な要素は4つです。

- API Server
- etcd
- Scheduler
- Controller Manager

### API Server
Kubernetesが扱うリソース(コンテナやボリュームなど)を操作するためのAPIがここで公開されています。
開発者(Devops)は、ターミナルで`kubectl`コマンドを使うことでこのAPIを叩き、リソースの作成・削除・制御を行います。

### etcd
分散KVS(キーバリューストア)です。作成されたクラスター(コンテナを動かすサーバー群)の設定情報がここに保存されます。

### Scheduler
コンテナの適切な配置場所を決定する機能を持ちます。
この機能があるがゆえに、「開発者は円滑な運用のために、どこのサーバーにコンテナを作成すべきか？」という設定を手動で行う必要がなくなり、アプリ側の開発に集中することができます。

### Controller Manager
Kubernetesが扱うリソースの制御を行います。
例えば、「起動コンテナの数を保つ」「サーバーダウン時の通知・対応を行う」「PodとServiceの紐付け」などを行います。

参考:[Kubernetes公式ドキュメント Kubernetesのコンポーネント](https://kubernetes.io/ja/docs/concepts/overview/components/)

## Cluster(クラスター)
コンテナを動かすサーバー群のことをKubernetesではクラスターと呼びます。
AWSのECSにおけるクラスターとほぼ同義です。

## Node(ノード)
コンテナを動かすサーバー1つ1つのことをKubernetesではノードと呼びます。
クラスターとは「1つのクラスターの中に、任意の数のノードが含まれる」という関係になっています。
上記のMasterに管理される対象であることから、「Slave Node」と呼ばれることもあります。

ECSにおける、クラスター内のEC2インスタンスとほぼ同義です。
ローカルでKubernetesを動かす場合では、そのPCそのものが1つのノードという扱いになります。

ノードの中に作成されるリソースは主に4つです。

- Pod
- Kubelet
- Container Engine
- Kube Proxy

### Pod
ノード上で動かすコンテナ(組)のことです。
Podを構成するコンテナは複数個でもOKです。例えば、「nginxのコンテナとアプリコンテナの2つをセットにして1つのPodにする」ということができます(ECSでのタスクと同様です)。

### Kubelet
Masterからのリソース・スケジュール管理を受け付けるためのエージェントです。
ECSにおけるECS Container Agentとほぼ同義です。

### Container Engine
Dockerといった、コンテナの作成・削除等の処理を実際に実行するエンジンです。

### Kube Proxy
ノードが受け付けたユーザーからのリクエストを、適切なPodに割り当て転送するネットワークプロキシです。

参考:[Kubernetes公式ドキュメント Kubernetesのコンポーネント](https://kubernetes.io/ja/docs/concepts/overview/components/)

# 始める前の初期状態
Kubernetesを使っていない状態でも、MasterにあるAPIを叩くための`kubectl`コマンドは存在します。Docker Appインストール時に`kubectl`コマンドも同時にインストールされているからです。

```bash
# このように、kubectlコマンドの存在がwhichコマンドで確認可能
$ which kubectl
/usr/local/bin/kubectl
```
しかし、コマンドのバージョン確認を行うと、以下のような表示になります。

```bash
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}
Unable to connect to the server: EOF
```
これは、「開発者クライアントの準備(=`kubectl`コマンド)は存在するが、それを受け付けるMasterのAPI Serverに接続できない(まだ存在しない)」という状態だということです。

このままではKubernetesを利用できません。そのため、次にKuberbetesを有効化して、ローカルにKubernetes Serverを立ち上げる操作を行います。

# ローカルでのKubernetes有効化
## Kubernetes有効化設定の手順
MacのメニューバーにあるDockerアイコンをクリックすると、以下のようなメニューが表示されます。
<img width="248" alt="スクリーンショット 2020-07-04 18.33.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/2ed5ef17-0d27-66cc-5453-6d72b5ea8e57.png">
ここから"Preferences"を選択すると、以下のような画面になります。
<img width="1037" alt="スクリーンショット 2020-07-04 18.35.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/e0d69931-ff51-c917-ab2d-1838e84eab95.png">
左のバーから"Kubernetes"を選択します。すると、Docker AppにおけるKubernetesの設定画面が以下のように表示されます。
<img width="1038" alt="スクリーンショット 2020-07-04 18.35.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/0dea938b-2be8-15c5-85be-c95fa40dd059.png">
この中から、"Enable Kubernetes"のチェックボックスに印を入れ、"Apply & Restart"で設定を保存します。

<img width="1038" alt="スクリーンショット 2020-07-04 18.38.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/171eac3e-52c6-3281-4069-2501bcd8e4bc.png">
このような画面になるのでしばらく待機します。
<img width="1037" alt="スクリーンショット 2020-07-04 18.41.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/467a306f-c29a-c37d-5314-142115f4d17b.png">
ウィンドウ下部に「Kubernetes running」が表示されれば準備はOKです。

## 起動確認
本当にKubernetesのサーバーが立ち上がったかどうかをコマンドで確認します。

```bash
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:07:57Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}
```
先ほどは`Unable to connect to the server: EOF`と表示されていた部分にサーバーのバージョンが表示されています。無事に起動できたようです。

また、Kubernetesを有効化したことで、Masterを構成するAPI ServerやSchedulerといった機能を担うコンテナイメージがpullされていることも確認できます。

```bash
# 以下のイメージが新規にpullされた
$ docker images
docker/desktop-storage-provisioner                                           v1.0                605a0f683b7b        4 months ago        33.1MB
k8s.gcr.io/kube-apiserver                                                    v1.15.5             e534b1952a0d        8 months ago        207MB
k8s.gcr.io/kube-controller-manager                                           v1.15.5             1399a72fa1a9        8 months ago        159MB
k8s.gcr.io/kube-proxy                                                        v1.15.5             cbd7f21fec99        8 months ago        82.4MB
k8s.gcr.io/kube-scheduler                                                    v1.15.5             fab2dded59dd        8 months ago        81.1MB
docker/kube-compose-controller                                               v0.4.23             a8c3d87a58e7        13 months ago       35.3MB
docker/kube-compose-api-server                                               v0.4.23             f3591b2cb223        13 months ago       49.9MB
k8s.gcr.io/coredns                                                           1.3.1               eb516548c180        17 months ago       40.3MB
k8s.gcr.io/etcd                                                              3.3.10              2c4adeb21b4f        19 months ago       258MB
k8s.gcr.io/pause                                                             3.1                 da86e6ba6ca1        2 years ago         742kB
```
それなら、Masterを構成するコンテナがMac上で起動しているのか？と思ったのですが、`docker ps`では起動中のコマンドが確認できませんでした。

```bash
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```

# (おまけ)Kubernetes Dashboardの用意
「今のクラスターでは何が動いているのか？」「起動したPodはノードのリソース(CPUなど)をどれくらい食っているのか？」といった情報を、コマンドラインではなくGUIで確認できるようにするツールが存在します。それがKubernetes Dashboardです。
これはオプションツールなので、Kubernetesをインストールしただけの状態ではこれを持っていません。そのため、これを使いたい場合は個別にインストール・起動する必要があります。

## Dashboardのリソース作成(≒インストール)
Kubernetes Dashboardは、Kubernetesで作られたサービス(アプリ)という形で配布されています。
そのため、Dashboardを立ち上げるための設定ファイル(Kubernetesではマニュフェストファイルという)を参照して、その内容をローカルに展開・起動するという形をとります。

`kubetcl apply`というコマンドで、マニュフェストファイルからDashboardのリソース作成を行います。`-f`オプションで、インターネット上に公開されているDashboardのマニュフェストファイルを指定しています。

```bash
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml

namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created
```
参考:[Kubernetes公式ドキュメント Web UI (Dashboard)](https://kubernetes.io/ja/docs/tasks/access-application-cluster/web-ui-dashboard/)

## Dashboardログインのためのトークン取得
Dashboardにアクセスするためにはトークンによる認証が必要です。なので、そのトークンを確認します。
以下のコマンドを打って、`default-token-*****`という名前のものを探します。

```bash
$ kubectl -n kube-system get secret
NAME                                             TYPE                                  DATA   AGE
(略)
default-token-ss24c                              kubernetes.io/service-account-token   3      168m
(略)
```
ここでは`default-token-ss24c`というものが見つかりました。これを元に今度は以下のコマンドを打ちます。

```bash
$ kubectl -n kube-system describe secret default-token-ss24c
Name:         default-token-ss24c
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: default
              kubernetes.io/service-account.uid: 92b6b004-dbf3-4593-adf0-fe2a2eb253f4

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1025 bytes
namespace:  11 bytes
token:      *********************
```
ここに表示されているtokenをこの後利用するので、メモしておきましょう。

参考:[Docker for Mac で Kubernetes をちょっと試す](https://qiita.com/kitsuki00/items/d69edca9d6d9af38fc95)

## プロキシサーバの起動
Dashboardサービスにアクセスするために、プロキシサーバを起動する。
以下のコマンドを打つことで、プロキシがフォアグラウンド稼働をします。(そのため、止めたくなった場合はCtrl+Cで停止できます。)

```bash
$ kubectl proxy
Starting to serve on 127.0.0.1:8001
```

## ログイン
プロキシサーバを起動させた状態で、ブラウザで以下のアドレスにアクセスします。

```
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ 
```

<img width="1440" alt="スクリーンショット 2020-07-04 21.24.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/505a57e5-75a0-d856-ae25-b6953c2e207d.png">
Tokenを選択して、フォームに先ほど確認したトークンを入力します。

<img width="1440" alt="スクリーンショット 2020-07-04 21.33.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/0a0f8ea0-d14a-b3c5-925b-c86b6e21052d.png">
このようなダッシュボード画面が表示されれば成功です。

## 後片付け
Dashboardのリソースを削除したい場合は、以下のコマンドで行えます。

```bash
$ kubectl delete -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml

namespace "kubernetes-dashboard" deleted
serviceaccount "kubernetes-dashboard" deleted
service "kubernetes-dashboard" deleted
secret "kubernetes-dashboard-certs" deleted
secret "kubernetes-dashboard-csrf" deleted
secret "kubernetes-dashboard-key-holder" deleted
configmap "kubernetes-dashboard-settings" deleted
role.rbac.authorization.k8s.io "kubernetes-dashboard" deleted
clusterrole.rbac.authorization.k8s.io "kubernetes-dashboard" deleted
rolebinding.rbac.authorization.k8s.io "kubernetes-dashboard" deleted
clusterrolebinding.rbac.authorization.k8s.io "kubernetes-dashboard" deleted
deployment.apps "kubernetes-dashboard" deleted
service "dashboard-metrics-scraper" deleted
deployment.apps "dashboard-metrics-scraper" deleted
```

# contextの選択
Kubernetesを使う準備が整いました。これでクラスター上にPod等のリソースを作ってアプリを構築していくことができます。

しかし、ここで問題になるのが構築していく対象の設定です。
例えば、「クラスターAとクラスターBが現在存在していて、今はクラスターAを使いたい」という状況では、開発者が使う`kubectl`コマンドでクラスターAのみがいじれないといけないわけです。
また、「クラスターA上でアプリチームがいじれるリソースと、同じクラスターAでインフラチームがいじれるリソースという風に触れる範囲を制御したい」という場合では、同じ`kubectl`コマンドでも同じ権限(機能)を持たせてはいけないことになります。

この、「どのクラスターを、どの権限で`kubectl`コマンドで動かすのか」という設定集がcontextです。開発者は、手を入れたいリソースに合わせて、適切なcontextを選択・使用する必要があるわけです。

## contextの確認・変更
以下のコマンドで、現在存在するcontext一覧を確認することができます。

```bash
$ kubectl config get-contexts
CURRENT   NAME                 CLUSTER          AUTHINFO         NAMESPACE
*         docker-desktop       docker-desktop   docker-desktop   
          docker-for-desktop   docker-desktop   docker-desktop
```
現在選択されているcontextは"docker-desktop"です。
"docker-for-desktop"に切り替えたい場合は、以下のようなコマンドを打ちます。

```bash
$ kubectl config use-context docker-for-desktop
Switched to context "docker-for-desktop".

$ kubectl config get-contexts
CURRENT   NAME                 CLUSTER          AUTHINFO         NAMESPACE
          docker-desktop       docker-desktop   docker-desktop   
*         docker-for-desktop   docker-desktop   docker-desktop
```
以下、ローカル上でのKubernetes操作は、この"docker-for-desktop"で行うこととします。

参考:[[Kubernetes入門] kubectlのアクセス先(コンテキスト)を切り替える方法](https://www.skyarch.net/blog/?p=16631)

# ローカルで動いているクラスターの状態確認
Docker Appによって作られたクラスター(実態は、ローカルマシンというノード1台のみで構成)上には、デフォルトでどんな状態で作られているのかを確認してみましょう。

## クラスター情報の確認
クラスターのMaster,DNSサーバーがどのアドレスで動いているのかが確認できます。

```bash
$ kubectl cluster-info
Kubernetes master is running at https://kubernetes.docker.internal:6443
KubeDNS is running at https://kubernetes.docker.internal:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
```
クラスター内部からこれらのアドレスにアクセスすることによって、サービスを利用することができます。

## ノードの確認
### 一覧取得
クラスター上で動いているノード一覧は、`kubectl get node`コマンドで取得できます。

```bash
$ kubectl get node
NAME             STATUS   ROLES    AGE   VERSION
docker-desktop   Ready    master   24h   v1.15.5
```
### 詳細情報取得
特定ノードの詳細な状態が知りたい場合は、`kubectl describe node`で確認できます。

```bash
$ kubectl describe node <node-name>
```

## Podの確認
### 一覧取得
クラスター上で動いているPod一覧も、`kubectl get pod`コマンドで取得できます。

```bash
$ kubectl get pod -n kube-system
NAME                                     READY   STATUS    RESTARTS   AGE
coredns-5c98db65d4-qshvb                 1/1     Running   1          44h
coredns-5c98db65d4-zpbfq                 1/1     Running   1          44h
etcd-docker-desktop                      1/1     Running   0          44h
kube-apiserver-docker-desktop            1/1     Running   0          44h
kube-controller-manager-docker-desktop   1/1     Running   0          44h
kube-proxy-kd5kf                         1/1     Running   0          44h
kube-scheduler-docker-desktop            1/1     Running   0          44h
storage-provisioner                      1/1     Running   1          44h
```
注: オプション`-n`は、後述する「名前空間」を指定するコマンドです。上の例の場合、クラスター上のkube-systemという名前空間で動いているPod一覧が取得されています。

### 詳細情報取得
特定Podの詳細な状態が知りたい場合は、`kubectl describe pod`で確認できます。

```bash
$ kubectl describe pods <pod-name>
```

### ログ取得
Podででたログを確認したい場合は、以下のコマンドでログを標準出力に表示させることができます。

```bash
$ kubectl logs <pod-name>
```

## Serviceの確認
### Serviceとは
PodのIPアドレスは不定です。つまり、Pod起動のたびにIPアドレスが変化します。
そのため、そのPodを利用する側がIPアドレスの変化を気にすることなく、それらにアクセスするための単一エンドポイントが必要です。Kubernetesでその単一エンドポイントを作るための仕組みをサービスと呼びます。
(docker-composeにおいてコンテナのIPアドレスでアクセスするのではなく、サービスを作成してその名前でアクセスするのと同じです。)

### 一覧取得
`kubectl get service`コマンドで可能です。

```bash
$ kubectl get service -n default
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   24h
```
注: `-n`オプションの効果はPodのときと同じで、名前空間(後述)を指定するものです。

### 詳細情報取得
`kubectl describe service`で可能です。

```bash
$ kubectl describe service <service-name>
```

## 名前空間の確認
### 名前空間とは
名前空間とは、1つの物理クラスターを論理的に分割して仮想のクラスターを作成する機能のことです。

例えば、「クラスターA上でアプリBとアプリCを両方同時に、干渉しないように動かしたい」という場合は、クラスターA上にアプリB用、アプリC用の名前空間を作成し、その名前空間上にそれぞれのアプリのPodやサービスをデプロイすることで、クラスターAを仮想的に二つの別クラスター空間と扱うことができます。

### 一覧取得
`kubectl get namespace`コマンドで、現在のクラスター上に存在する名前空間を確認することができます。

```bash
$ kubectl get namespace
NAME                   STATUS   AGE
default                Active   24h
docker                 Active   24h
kube-node-lease        Active   24h
kube-public            Active   24h
kube-system            Active   24h
kubernetes-dashboard   Active   21h
```
デフォルトで作られる名前空間は以下の4つです。

- default
- kube-public
- kube-system
- kube-node-lease

また、Docker Appがある場合は"docker"名前空間が、Kubernetes Dashboardを入れている場合は"kubernetes-dashboard"名前空間があります。

#### default名前空間
デフォルトの名前空間です。
名前空間の指定が必要なリソース作成時にそれを指定しないと、自動的にdefault名前空間が使われます。`kubectl get`等のコマンド実行時に`-n`オプションをつけないときも、default名前空間上の情報が取得されます。
デフォルトでは1つのサービスが存在します。

```bash
$ kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   45h
```
このサービスは、Master(≒API Server)にリクエストを送るためのものです。
参考:[What's the purpose of the default kubernetes service?
](https://stackoverflow.com/questions/47523136/whats-the-purpose-of-the-default-kubernetes-service)

#### kube-public名前空間
全contextからアクセス可能なリソースを配置するための空間です。
作成初期にリソースは存在しません。

#### kube-system名前空間
Kubernetesシステムによって作成されたオブジェクト(API Serverなど)のための名前空間です。
ここに存在するリソースは以下の通りです。

```bash
$ kubectl -n kube-system get all
NAME                                         READY   STATUS    RESTARTS   AGE
pod/coredns-5c98db65d4-qshvb                 1/1     Running   1          44h
pod/coredns-5c98db65d4-zpbfq                 1/1     Running   1          44h
pod/etcd-docker-desktop                      1/1     Running   0          44h
pod/kube-apiserver-docker-desktop            1/1     Running   0          44h
pod/kube-controller-manager-docker-desktop   1/1     Running   0          44h
pod/kube-proxy-kd5kf                         1/1     Running   0          44h
pod/kube-scheduler-docker-desktop            1/1     Running   0          44h
pod/storage-provisioner                      1/1     Running   1          44h


NAME               TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
service/kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   44h

NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                 AGE
daemonset.apps/kube-proxy   1         1         1       1            1           beta.kubernetes.io/os=linux   44h

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/coredns   2/2     2            2           44h

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/coredns-5c98db65d4   2         2         2       44h
```

- **pod/coredns**: kube-dnsのサービスにアクセスがあったら、問い合わせが来るDNSサーバー 
- **pod/etcd**-docker-desktop: etcd本体
- **pod/kube-apiserver**-docker-desktop: API Serverの本体
- **pod/kube-controller-manager**-docker-desktop: Controller Managerの本体
- **pod/kube-proxy**: サービスに接続するプロキシ
- **pod/kube-scheduler**-docker-desktop: Schedulerの本体
- **pod/storage-provisioner**: ストレージの割り当てを行う
- **service/kube-dns**: クラスター内に内蔵されているDNSサービス

時折「-docker-desktop」と付いているのは、「クラスターdoccker-desktop用」という意味だと思われます。

参考:[Kubernetes公式ドキュメント Kubernetesのコンポーネント](https://kubernetes.io/ja/docs/concepts/overview/components/)

#### kube-node-lease名前空間
Kubernetes 1.13から導入。NodeLeaseが有効になっている場合、各ノードはこの名前空間にオブジェクトを一つ作って、それを更新し続けることで死活監視を行います。
参考:[Kubernetes公式ドキュメント ノード](https://kubernetes.io/ja/docs/concepts/architecture/nodes/)

#### docker名前空間
Kubernetesには、専用のマニュフェストファイルからだけではなく、`docker-compose.yml`からデプロイする機能が存在します。
この機能を提供するサービスはここに展開されているようです。
参考:[Docker for MacでKubernetes構築 #composeとの統合](https://qiita.com/nakayamam/items/a9855444cdc4310e0231#composeとの統合)

#### kubernetes-dashboard名前空間
Kubernetes Dashboardをデプロイするための名前空間です。

### 詳細情報取得
特定の名前空間の詳しい状態が知りたい場合は、`kubectl describe`を使用します。

```bash
$ kubectl describe namespace <name>
Name:         <name>
Labels:       <none>
Annotations:  <none>
Status:       Active

No resource quota.

No resource limits.
```

# マニュフェストファイルを用いてアプリをデプロイ
ここからは、マニュフェストファイルでアプリ・コンテナの設定を記述して、それをローカルのKubernetes上にデプロイしていきたいと思います。
デプロイするアプリが1つだけの場合、名前空間はdefaultを使用するのが楽でしょう。
以下、特筆しない限り名前空間はdefaultです。

## Podを作ってみる
まず手始めに、Podを単独で作ってみましょう。

### マニュフェストファイル作成
`pod.yml`という名前でマニュフェストファイルを作成し、以下のように記述します。
今回は、MySQLのコンテナPodを作ってみます。

```pod.yml
apiVersion: v1
kind: Pod
metadata:
    name: k8s-mysql
    labels:
      app: myapp
      tier: db
spec:
    containers:
    - name: k8s-mysql
      image: mysql:5.7
      volumeMounts:
      - name: k8s-mysql-storage
        mountPath: /var/lib/mysql
      ports:
      - containerPort: 3306
      env:
      - name: MYSQL_ROOT_USER
        value: root
      - name: MYSQL_ROOT_PASSWORD
        value: pass
      - name: MYSQL_DATABASE
        value: sampledb
    volumes:
    - name: k8s-mysql-storage
      hostPath:
        path: /Users/myname/Desktop/k8s
```
記述の意味は以下の通りです。

```pod.yml
# KubernetesのAPI Serverのバージョン
apiVersion: v1
# マニュフェストファイルで何を作ろうとしているか。
kind: Pod
# Podにつける識別子
metadata:
    # Pod名
    name: k8s-mysql
    # この場合「key:app, value:myapp」「key:tier, value:db」という2つのラベルが付く
    labels:
      app: myapp
      tier: db
# 作成するPodの定義
spec:
    # 所属するコンテナ
    containers:
      # コンテナの名前
    - name: k8s-mysql
      # 使用するイメージ
      image: mysql:5.7
      # マウントするボリュームの名前と、マウントさせるディレクトリパス(コンテナ内)
      volumeMounts:
      - name: k8s-mysql-storage
        mountPath: /var/lib/mysql
      # containerPortで、Podコンテナの何番ポートを開けるかを指定
      ports:
      - containerPort: 3306
      # コンテナに渡す環境変数
      env:
      - name: MYSQL_ROOT_USER
        value: root
      - name: MYSQL_ROOT_PASSWORD
        value: pass
      - name: MYSQL_DATABASE
        value: sampledb
    # 所属するボリューム
    volumes:
      # ボリューム名
    - name: k8s-mysql-storage
      # hostPathの場合、Podをホストするノード(ローカルの場合Kubernetesを動かしているPC)のどこのディレクトリにデータを保存するかの指定
      hostPath:
        path: /Users/myname/Desktop/k8s
```
参考:[kubernetesによるDockerコンテナ管理入門](https://knowledge.sakura.ad.jp/3681/)
volumeについて参考:[Kubernetesで使えるボリューム・タイプのチートシート](https://qiita.com/MahoTakara/items/37b9f9eb0ab7f8ab5b6c)

### ローカルに存在するコンテナイメージを使いたい場合のマニュフェストファイルの記述
Docker Hubといったリポジトリに公開していない、自分のPCの中にあるイメージを使ってPodを作りたいという場合もあるでしょう。
その場合は、マニュフェストファイルを以下のように書きます。

```pod.yml
(略)
      image: my-local-image-name
      # イメージを公開リポジトリから取らないという設定記述
      imagePullPolicy: Never
(略)
```
参考:[kubenetesでローカルコンテナイメージからコンテナを作成する方法](https://www.opensourcetech.tokyo/entry/20190223/1550908537)

### デプロイ
作成したマニュフェストファイルを元にリソースを作る場合は、`kubectl create`コマンドを使用します。

```bash
$ kubectl create -f pod.yml
```

### 後片付け
削除するときは`kubectl delete`を使います。

```bash
$ kubectl delete -f pod.yml
```
なお、Podが削除されても、マウントされたボリューム(今回の場合はローカルPCの`/Users/myname/Desktop/k8s`)の中身はそのまま残ります。

## serviceを作ってみる
先ほど作成したMySQLのPodにエンドポイントを作るために、サービスを作成します。

### マニュフェストファイルの作成
Pod作成のときと同様、まずはマニュフェストファイルを作成します。

```service.yml
apiVersion: v1
kind: Service
metadata:
  name: k8s-mysql-service
  labels:
    app: myapp
spec:
  type: NodePort
  ports:
    - port: 3306
      targetPort: 3306
      protocol: TCP
  selector:
    app: myapp
    tier: db
```
記述の意味は以下の通りです。

```service.yml
apiVersion: v1
kind: Service
metadata:
  # サービス名
  name: k8s-mysql-service
  labels:
    app: myapp
# 作成するサービスの定義
spec:
  # 全てのノードの3306番ポートにアクセスすることでこのサービスにアクセスされるようになる
  type: NodePort
  ports:
      # サービスがlistenするポート
    - port: 3306
      # サービスが転送するpodのlistenポート
      targetPort: 3306
      # 使用プロトコル
      protocol: TCP
  # 以下のlabelがついているpodをサービスの対象に含める(今回の場合、上記で作成したpodにつけた2つのラベルを指定)
  selector:
    app: myapp
    tier: db
```
参考:[Kubernetes道場 9日目 - Serviceについて](https://cstoku.dev/posts/2018/k8sdojo-09/)

### デプロイ
Pod同様、`kubectl create`で作成します。

ただ、今回の場合はサービスと、その対象のPodの2つを作成する必要があります。
`kubectl create`の`-f`コマンドでマニュフェストファイルを複数指定してもいいのですが、面倒な場合は、マニュフェストファイルを一つのディレクトリにまとめて、そのディレクトリ以下にあるyamlファイル全てを作成対象にするというやり方をとります。

```bash
# ./dirディレクトリ以下にあるファイル全てを参照する
$ kubectl create -f ./dir
```
./dir以下のymlファイルを全て見て、リソースを作る。

### サービスにアクセスできるか確認
クラスター内でサービスに正しくアクセスできるかどうか確認してみましょう。

クラスター中にあるどれか1つのpodの中にログインして確かめてみます。
Podへのログインは以下のコマンドで行えます。

```bash
$ kubectl exec -it <podname> -- /bin/bash
```

まずは、サービスに接続するためにはどんなドメインを使えばいいのかを調べてみましょう。

```bash
# podの中で実行
# dig, nslookupといったDNS接続確認を行うコマンドをインストール
$ apt update
$ apt get install dnsutils

# サービス名でnslookup
$ nslookup k8s-mysql-service
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   k8s-mysql-service.default.svc.cluster.local
Address: 10.110.179.176

# サービス名でdig
$ dig k8s-mysql-service

; <<>> DiG 9.11.5-P4-5.1+deb10u1-Debian <<>> k8s-mysql-service
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 34032
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 4529e3e33e3e0a28 (echoed)
;; QUESTION SECTION:
;k8s-mysql-service.             IN      A

;; Query time: 34 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Mon Jul 06 17:16:29 UTC 2020
;; MSG SIZE  rcvd: 58
```
どちらのコマンドでも、マニュフェストファイルで指定したサービス名`k8s-mysql-service`でアクセスできることが確認できました。

また、`nslookup`コマンドで取得できたIPアドレス`10.110.179.176`は、`kubectl describe`で確認できるサービスのIPと一致します。

```bash
# ローカルで実行
$ kubectl describe service k8s-mysql-service
#(略)
IP:                       10.110.179.176
#(略)
```

この名前解決を利用して、クラスター内からMySQLサービスに接続してみましょう。

```bash
# Pod内で実行
# mysqlサービスへのアクセス確認のため、sqlクライアントのインストールを行う
$ apt-get install default-mysql-client
$ mysql -h k8s-mysql-service -u root -p
Enter password:
MySQL [(none)]>
```
このように、サービス名を使うことで接続できました。

参考:[Kubernetesの名前解決を確認する](https://varu3.hatenablog.com/entry/2018/05/24/200311)

### serviceにMacのローカルホストを接続
Kubernetes Dashboardのように、起動しているサービスにクラスタ外のMacから接続したい！という状況があると思います。
例えば`web-service`という名前のサービスを作り、そのサービスにMacのLocalhostを繋ぎブラウザ閲覧したいとします。
この場合、マニュフェストファイルを以下のように作ります。

```web.yml
apiVersion: v1
kind: Service
metadata:
  name: web-service
  labels:
    app: myapp
spec:
  # ここのtypeをLoadBalancerにすることが重要
  type:
    LoadBalancer
  ports:
    - port: 9090
      targetPort: 9090
      protocol: TCP
  selector:
    app: myapp
    tier: web
```
このサービスをデプロイして、`kubectl get`で情報を確認してみます。

```bash
$ kubectl get service
(略)
NAME                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/web-service   NodePort    10.101.53.215   localhost     8080:31392/TCP   4s
```
この場合、`web-service`にはMacの`http://localhost:8080`でアクセスすることができます。

### サービスのTypeについて
今回、NodeTypeやLoadBalancerといった種類のサービスを扱いましたが、それぞれのネットワーク構成については、以下の記事がわかりやすいので紹介しておきます。
参考:[Kubernetes ネットワーク構成](https://medium.com/@aki030402/kubernetes-ネットワーク構成-6859ad9f0254)

## developmentを作ってみる
Pod定義でコンテナを増やしていってもいいのですが、今後の運用面を考えてコンテナはdevelopmentという形でデプロイしましょう。

### developmentとは
developmentは、ReplicaSet(レプリカセット)を管理するための仕組みです。

まず、レプリカセットについて説明します。
例えば、同じPodを複数個作って冗長化したい！という場合は、Pod単独をいくつも繰り返し作るのではなく、レプリカセットという、「Podと作りたい個数を指定することで、指定Podのコピーを指定数だけ作る」機能で作ります。
(ECSでサービスを作成する際に、タスクを同時に何個起動させるかを選択するのと思想は同じです)

また、Podの内容を更新したい！というときは、レプリカセット単独ではなく、development中のレプリカセットという形でデプロイすることで、Podの自動更新・ロールバック等の運用操作が簡単にできるようになります。

それぞれの関係としては、Deployment　→　ReplicaSet　→　Podという包含関係になります。
つまり、developmentの中にレプリカセット(≒複数個のPodのコピー)を入れることで、バージョン管理や、複数個のPodをまとめて運用しやすくしているのです。

参考:[Kubernetes: Deployment の仕組み](https://qiita.com/tkusumi/items/01cd18c59b742eebdc6a)

### マニュフェストファイルの作成
先ほど作ったMySQLのPodをdevelopmentに直してみます。
以下のようなファイルを作ります。

```dev.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-development
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
        tier: db
    spec:
      containers:
      - name: k8s-mysql
        image: mysql:5.7
        volumeMounts:
        - name: k8s-mysql-storage
          mountPath: /var/lib/mysql
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_USER
          value: root
        - name: MYSQL_ROOT_PASSWORD
          value: pass
        - name: MYSQL_DATABASE
          value: sampledb
      volumes:
      - name: k8s-mysql-storage
        hostPath:
          path: /Users/myname/Desktop/k8s
```
記述の意味は以下の通りです。

```dev.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  # developmentの名前
  name: mysql-development
# developmentで作る状態について記述
spec:
  # レプリカセットの数
  replicas: 2
  # developmentが管理するリソースのラベル
  selector:
    matchLabels:
      app: myapp
  # developmentで管理するものの一覧
  template:
    # Pod, volumeにつけるラベル 
    metadata:
      labels:
        app: myapp
        tier: db
    # 以下はPod定義のときと同じ記述
    spec:
      containers:
      - name: k8s-mysql
        image: mysql:5.7
        volumeMounts:
        - name: k8s-mysql-storage
          mountPath: /var/lib/mysql
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_USER
          value: root
        - name: MYSQL_ROOT_PASSWORD
          value: pass
        - name: MYSQL_DATABASE
          value: sampledb
      volumes:
      - name: k8s-mysql-storage
        hostPath:
          path: /Users/myname/Desktop/k8s
```
参考:[Kubernetes公式ドキュメント Deployment](https://kubernetes.io/ja/docs/concepts/workloads/controllers/deployment/)
参考:[DeploymentとServiceをyamlファイルで定義する](https://reiki4040.hatenablog.com/entry/2017/04/16/225428)

### デプロイ・後片付け
Podやサービス同様、`kubectl create/delete`を使って行います。

```bash
$ kubectl create -f dev.yml
$ kubectl delete -f dev.yml
```

# EKSにデプロイ
ローカルで簡単な操作ができてコツをつかんだところで、いよいよ本番環境に乗せていきます。
今回は、AWSのEKSを利用します。

## EKS上にクラスターを作成
### クラスター作成の2つのやり方比較
まずは、EKS上にクラスターを作成します。
やり方は2つあり、1つはAWSのWebコンソール上で作成操作を行うやり方、もう1つはターミナルから`eksctl`コマンドを用いて作成操作を行うやり方です。

今回は`eksctl`コマンドを用いた方法でクラスター作成を行います。なぜかというと設定が圧倒的に楽だからです。
`eksctl`を用いることで、以下の設定が自動的に行われます。

- EKSクラスターに属するノードに与えるIAMロール作成
- VPCネットワーク/サブネット/ルートテーブル/IGW/NATゲートウェイの作成
- セキュリティグループの作成
- EKSクラスターヘの`kubectl`の接続

Webコンソールでクラスター作成を行なった場合、このような煩雑な設定を手動でやる必要があります。複雑な構成にしたいのではない場合は、`eksctl`コマンドを使用するのが効率的でしょう。

参考:[「eksctl」コマンドを使ったAmazon EKS構築入門](https://dev.classmethod.jp/articles/getting-started-amazon-eks-with-eksctl/)

### `eksctl`コマンドのインストール
EKSにクラスターを作るための`eksctl`コマンドをインストールします。
(できたクラスターを操作するのは、ローカルのときと同様に`kubectl`コマンドです。`eksctl`にできるのはあくまでクラスター関連の操作だけです。)

ターミナルで以下のコマンドを実行します。

```bash
$ brew tap weaveworks/tap
$ brew install weaveworks/tap/eksctl

#ダウンロードできたかは以下のコマンドで確認
$ which eksctl
/usr/local/bin/eksctl
```
参考:[AWS公式ドキュメント eksctl コマンドラインユーティリティ](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/eksctl.html#installing-eksctl)

### クラスター作成コマンド実行
早速コマンドを打ってクラスターを作成します。

```bash
$ eksctl create cluster \
      --vpc-cidr 10.0.0.0/16 \
      --name eks-sample \
      --region ap-northeast-1 \
      --version 1.14 \
      --nodegroup-name sample-workers \
      --node-type t2.micro \
      --nodes 1 \
      --nodes-min 1 \
      --nodes-max 3 \
      --managed
```
オプションの意味は以下の通りです。

- vpc-cidr: 新規作成するVPCのCIDR
- name: クラスター名
- region: リージョン。東京リージョンを使いたいのでap-northeast-1を指定
- version: Kubernetesのバージョン
- nodegroup-name: ノードグループ(EKSクラスターに属するEC2インスタンスノード集団のこと)の名前
- node-type: ノードに使うマシンのタイプ
- nodes: 起動時点でのノード数
- nodes-min: 最小ノード数
- nodes-max: 最大ノード数
- managed: ノードグループをWebコンソール上で表示・いじれるようにする

参考:[eksctlを使った簡単Amazon EKS環境構築](https://tech.smartcamp.co.jp/entry/eksctl-handson)
参考:[[アップデート] EKSがマネジメントコンソールおよびCLIでのワーカーノードの作成・管理をサポートしました](https://dev.classmethod.jp/articles/eks-support-provisioning-and-managing-worker-nodes/)

実行には結構時間がかかりますので気長に待ちましょう。

### 結果
クラスターがちゃんとできてます。
<img width="1440" alt="スクリーンショット 2020-07-11 0.24.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/cd4c04fc-ecb7-15ab-f6ef-277982c3d30e.png">
コマンドでもその結果が確認できます。

```bash
# EKS上のクラスター一覧
$ eksctl get cluster
NAME            REGION
eks-sample      ap-northeast-1

# eks-sampleというクラスター上にあるnodegroupの確認
$ eksctl get nodegroup --cluster eks-sample
CLUSTER         NODEGROUP       CREATED                 MIN SIZE        MAX SIZE        DESIRED CAPACITY        INSTANCE TYPE   IMAGE ID
eks-sample      sample-workers  2020-07-11T04:57:37Z    1               3               1                       t2.micro
```

クラスターができるに当たって、以下のものが自動で作成されました。

- VPC: 新しいものが1つ
- サブネット: ap-northeast-1にある3つのAZにそれぞれ2個ずつ
- ルートテーブル: パブリックサブネット用が1つ、プライベートサブネット用が3つのAZにそれぞれ1つずつ、新しいVPCのデフォルトルートテーブル1つの計5つ
- インターネットゲートウェイ: 新しいVPC用に1つ
- Elastic IP: 新しいVPCのNATゲートウェイ用に1つ
- NATゲートウェイ: 1つ
- セキュリティグループ: 新しいVPCのデフォルト1つと、EKSが作ったもの3つ

↓サブネットの様子
<img width="985" alt="スクリーンショット 2020-07-11 0.26.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/64524227-8c34-b195-2f07-21a39239d157.png">
↓ルートテーブルの様子
<img width="1213" alt="スクリーンショット 2020-07-11 0.27.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/d8d34286-0b7b-a6bb-7423-b3c009ad33b2.png">
↓セキュリティグループの様子
<img width="1195" alt="スクリーンショット 2020-07-11 0.29.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/b9274618-180c-40c7-64ef-06a2d60786dd.png">

結果的に、以下のような構成の環境が出来上がっています。
![amazon-eks-on-aws-architecture-diagram.7fdf06380021e6dc7c622d298d99e3c1154163bc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/215e6512-804a-5eac-51b5-3ea06b542318.png)
画像出典:[EKS公式ドキュメント スケーラブルなモジュール式 Amazon EKS アーキテクチャ](https://aws.amazon.com/jp/quickstart/architecture/amazon-eks/)

## `kubectl`の設定
EKS上のクラスターにリソースをデプロイするのは、ローカル同様`kubectl`だという話は先ほどしました。
しかし、そのためには`kubectl`コマンドで、ローカルではなくてEKSクラスターを選択するような設定が必要になります。

### contextの確認
「どのクラスターを`kubectl`でいじるか」という設定は上述したcontextの選択で行います。
EKSクラスター作成後、存在するcontext一覧を確認してみましょう。

```bash
$ kubectl config get-contexts
CURRENT   NAME                                              CLUSTER                               AUTHINFO                                          NAMESPACE
          docker-desktop                                    docker-desktop                        docker-desktop                                    
          docker-for-desktop                                docker-desktop                        docker-desktop                                    
*         myname@eks-sample.ap-northeast-1.eksctl.io   eks-sample.ap-northeast-1.eksctl.io   myname@eks-sample.ap-northeast-1.eksctl.io
```
なんと、EKSクラスターをいじる用のcontextが自動作成・選択されていました。これは`eksctl`でクラスターを作成したからこそ行われたものです。
(WebコンソールでEKSクラスターを作成したら、これも手動で行います。`eksctl`コマンドの便利さがこれでわかりますね。)

### kubeconfigの確認
なぜ`eksctl`コマンドを実行しただけで、自動でEKS用のcontextが追加・選択されていたのでしょうか。
それはコマンド実行時にkubeconfigという設定ファイルが自動で編集されていたからです。

kubeconfigファイルの中身を見てみましょう。以下のようにコマンドを打ってみます。

```bash
$ kubectl config view

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: seeeeeeeeecret
    server: https://kubernetes.docker.internal:6443
  name: docker-desktop
- cluster:
    # EKSコンソールで確認できる認証機関の値
    certificate-authority-data: seeeeeeeeecret
    # EKSコンソールで確認できるAPIサーバーエンドポイントのアドレス
    server: https://********************.***.ap-northeast-1.eks.amazonaws.com
  name: eks-sample.ap-northeast-1.eksctl.io

contexts:
- context:
    cluster: docker-desktop
    user: docker-desktop
  name: docker-desktop
- context:
    cluster: docker-desktop
    user: docker-desktop
  name: docker-for-desktop
- context:
    cluster: eks-sample.ap-northeast-1.eksctl.io
    user: myname@eks-sample.ap-northeast-1.eksctl.io
  name: myname@eks-sample.ap-northeast-1.eksctl.io

current-context: myname@eks-sample.ap-northeast-1.eksctl.io
kind: Config
preferences: {}

users:
- name: docker-desktop
  user:
    client-certificate-data: seeeeeeeeecret
    client-key-data: seeeeeeeeecret
- name: myname@eks-sample.ap-northeast-1.eksctl.io
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - token
      - -i
      - eks-sample
      command: aws-iam-authenticator
      env:
      - name: AWS_STS_REGIONAL_ENDPOINTS
        value: regional
      - name: AWS_DEFAULT_REGION
        value: ap-northeast-1
```
これは`$HOME/.kube/config`にある設定ファイルの中身がそのまま出力されている様子です。何もしていないのに、明らかにAWS用の設定と思われる箇所が存在します。
このように、kubeconfigに、EKSのクラスターに接続できるようなcontext設定が自動で追加されていることがここからもわかります。

### `kubectl`の認証トークン設定
ローカル側で`kubectl`の対象クラスターをEKSに向けることはできました。しかし、EKS側では`kubectl`コマンドでアクセスしてきた人が正規の権限を持った開発者であるとどのように認識しているのでしょうか。

EKSでは、クライアントにIAM認証情報から得たトークンを`kubectl`コマンド実行時に付与してもらい、そのトークンを見ることで、正規の権限を持った人かどうかを判定しています。

![eks-iam.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520877/c56d97ec-4d88-a297-3773-94480bdccb19.png)
画像出典:[EKS公式ドキュメント クラスター認証の管理](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/managing-auth.html)

そのため、EKSクラスターを操作するためのcontextで、`kubectl`コマンド実行時に認証トークンを渡すように設定する必要があります。
やり方は2つあります。`aws-iam-authenticator`コマンドを使う方法と`aws eks get-token`コマンドを使う方法です。

#### `aws-iam-authenticator`コマンドの方法
デフォルトではこちらの方法になっています。`aws-iam-authenticator`コマンドがインストール済みの方はこちらを使えば余計な手間がかからなくてよいでしょう。
kubeconfigの以下の記述の部分が該当箇所です。

```$HOME/.kube/config
      args:
      - token
      - -i
      - eks-sample
      command: aws-iam-authenticator
```

#### `aws eks get-token`コマンドの方法
`aws-iam-authenticator`コマンドはないが`aws`コマンドはある！という方はこちらの方法をとれば何もインストールしなくても大丈夫です。
上記のkubeconfig(`$HOME/.kube/config`に存在)の記述部分を、以下のように書き換えます。

```$HOME/.kube/config
      #args:
      #- token
      #- -i
      #- eks-sample
      #command: aws-iam-authenticator

      args:
      - eks
      - get-token
      - --cluster-name
      - eks-sample
      command: aws
```
参考:[[アップデート]EKSを使う際にaws-iam-authenticatorが不要になりました!](https://dev.classmethod.jp/articles/eks-update-get-token-cmd/)

### `kubectl`がEKSクラスターを向いていることを実際のコマンドで確認
ここまでの準備ができたところで、ノード一覧を取得してみましょう。

```bash
$ kubectl get node
NAME                                             STATUS   ROLES    AGE   VERSION
ip-10-0-13-242.ap-northeast-1.compute.internal   Ready    <none>   85s   v1.15.11-eks-908ff6
```
明らかにAWS上のリソースが取得できました。`eksctl`コマンドで指定した通り、ノードが1つ作成されていることがわかります。

## EKSクラスター上にリソース作成
`kubectl`コマンドでEKSクラスターを扱えるようになったので、いよいよEKS上にリソースを作成してみましょう。

### マニュフェストファイルの修正(適宜)
もしもデプロイするコンテナのイメージとして、ECR上のイメージを使いたい！という場合は、マニュフェストファイルのコンテナイメージを指定する箇所を、ECRのリポジトリURIに書き換えればOKです。

```dev.yml
# 以下は一例です
(略)
image: your-aws-account-id.dkr.ecr.ap-northeast-1.amazonaws.com/myapp/api:v1
(略)
```

### デプロイ/削除
ローカル同様、`kubectl create/delete`コマンドを実行します。

```bash
$ kubectl create -f dev.yml
deployment.apps/myapp-mysql created
$ kubectl delete -f dev.yml
deployment.apps/myapp-mysql deleted
```

また、LoadBalancer型のサービスをデプロイした場合、自動的にELBが作成→当該サービスとの紐付けが行われています。
例えば、LoadBalancer型のサービスがあるとき、`kubectl get`コマンドを実行し情報を確認してみます。

```bash
$ kubectl get service
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP                                                                    PORT(S)          AGE
(略)
myservice    LoadBalancer   172.20.78.107   *******.ap-northeast-1.elb.amazonaws.com   9090:31806/TCP   7m25s
```
EXTERNAK-IPの部分に表示されているドメインは、自動作成されたELBのアドレスです。
そのため、`http://*******.ap-northeast-1.elb.amazonaws.com:9090`にブラウザからアクセスすれば、そのサービスにWebからアクセスすることができます。
参考:[Amazon EKS のチュートリアルで Kubernetes を理解する #02 アプリのデプロイ](https://qiita.com/takanorig/items/6b2eced40b309b557d70)

## 後片付け
使い終わったらEKS環境を片付けましょう。
デプロイしたリソースを`kubectl delete`するのはもちろん、余計な費用がかからないようにEKSクラスターも以下のように削除しましょう。

```bash
$ eksctl delete cluster --name=eks-sample
```
これを実行することで、クラスター作成時に自動で作られたVPCやNATゲートウェイなども全てなくなります。また、kubeconfigに書かれたEKS用の設定記述も自動で消去されます。