Amazon EKS 上に Istio / Prometheus / Grafana をデプロイ

# 前置き
この構成を今後使うかもしれないのでチュートリアルをやった
Kubernetes を触ったことが無かったため
まとめる意味も含め調べたことを一通り記す

# Kubernetes
複数のコンテナを効率的に運用管理するためのオープンソースプラットフォーム

[Production-Grade Container Orchestration - Kubernetes](https://kubernetes.io/)

## Kubernetes を使う利点

### コンテナ技術の利用
- 開発環境の統一
- 本番環境への適応
- 単純構成
  - 高速
  - 軽量
  - コスト削減

### コンテナの統合管理
- 自動化
  - デプロイ
  - スケーリング
  - ヘルスチェック
  - 自己修復
  - 効率的なリソース使用
- 稼働を維持しての変更
  - アップデート
  - 機能追加

## Kubernetes の構成
![Kubernetes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/e2587875-8ce3-a588-5042-2cabab4cb102.png)

## Kubernertes の基本用語
用語自体は他にもあるが今回利用する範囲に留める

### Cluster
- Kubernetes のリソースをひとくくりにまとめたもの

### Node
- 物理マシン
  - AWS であれば EC2 インスタンス
- Master Node と Node で区別がある
  - Master Node は Kubernetes を管理する
  - Node ではアプリケーションを動かす

### Plane
- Control Plane は Master Node が配置される
- Data Plane には Node が配置される

### Pod
- コンテナの集合
- デプロイする際の最小単位

### ReplicaSet
- 常に稼働している同一仕様の Pod の数
  - 冗長化

### Deployment
- デプロイ管理ができる
  - アップデート
  - ロールバック

# Amazon EKS
AWS が提供している Kubernetes のマネージドサービス
主に Kubernetes における Master Node の部分を担ってくれる

[Amazon EKS とは - AWS](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/what-is-eks.html)

# EKS クラスターの作成
AWS の公式ドキュメントでも紹介されている [eksctl](https://eksctl.io/) というワンライナーで全て作成できるコマンドもあるらしいが
内部で何が起きているのかわからないため今回は通常の方法で作成する

## 環境
Windows 10

AWS CLI 1.16.191
[AWS CLI のインストール - AWS](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html)

kubectl 1.14.8
[kubectl のインストール - AWS](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/install-kubectl.html)

Helm 2.15.1
[Installing Helm - Helm](https://helm.sh/docs/intro/install/)

Istio 1.3.4
[Download the release - Istio](https://github.com/istio/istio/releases/)

## 流れ
以下の手順で作成していく
1. [ロール](#ロール)
2. [VPC](#vpc)
3. [EKS クラスター](#eks-クラスター)
4. [ノード](#ノード)
5. [EKS クラスターへのデプロイ](#eks-クラスターへのデプロイ)

[AWS マネジメントコンソール の開始方法 - AWS](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/getting-started-console.html)

### 構成図
![AWS-EKS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/2a66f70c-0fdb-849b-2d7b-1b79179c7c37.png)



### ロール
サービスから EKS を入力しアクセスを許可するポリシーをあてたロールを作成
![role.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/65411567-2c92-5f78-d155-4854a4c434ce.png)

### VPC
公式のサンプルを利用し CloudFormation で作成
https://amazon-eks.s3-us-west-2.amazonaws.com/cloudformation/2019-10-08/amazon-eks-vpc-sample.yaml
![vpc-stack-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/0ea348b9-7175-a9ba-c031-3aa4c495ef29.png)

### EKS クラスター
コンソールパネルからだとこの後の確認がうまくいかなかったためコマンドを使った

- [cluster-name] は任意
- [eks-role] は先ほど作成したロール
- [subnet-ids] と [security-group-ids] は VPC の CloudFormation の出力を参照
![vpc-stack-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/edc91790-dea7-2eab-fd04-84abf512db2d.png)

```
  $ aws eks create-cluster --name [cluster-name] --role-arn [eks-role] --resources-vpc-config subnetIds=[subnet-ids],securityGroupIds=[security-group-ids]

  $ aws eks update-kubeconfig --name [cluster-name]
```

サービスに Kubernetes が出力されれば完了

```
  $ kubectl get svc
```

<img width="477" alt="eks-cluster-svc.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/b67fbff4-499a-d84e-a1d8-dcd6949eb315.png">


### ノード 
CloudFormation で EKS 最適化ノードを作成
以下を参考に NodeImageId と BootstrapArguments 以外のパラメータを埋める

[Amazon EKS ワーカーノードを起動して設定する - AWS](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/getting-started-console.html#eks-launch-workers)
![node-stack-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/2ef473bd-0c1a-56e2-ae34-082dee71150a.png)

公式の認証用設定マップを編集する
https://amazon-eks.s3-us-west-2.amazonaws.com/cloudformation/2019-10-08/aws-auth-cm.yaml
rolearn: の value をノード作成時に出力される [NodeInstanceRole] に変更して適用
![node-stac-2k.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/819d2304-1e7e-4287-5c5d-23d8189dc250.png)

```
  $ kubectl apply -f aws-auth-cm.yaml
```
Node が Ready になれば完了

```
  $ kubectl get nodes
```
![get-nodes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/8a67dcef-ce26-d136-4b7f-5303625c422d.png)

# Helm / Istio / Prometheus / Grafana
今回利用するソフトウェア及びツール

- [Helm](https://helm.sh/)
Kubernetes のパッケージマネージャ
クラスター内に tiller コンポーネントをデプロイすることで APIserver を介してコマンドでリソースの操作ができる

- [Istio](https://istio.io/)
マイクロサービスを構成するためのオープンソースソフトウェア
条件や割合でのトラフィック制御やログ収集ができる

- [Prometheus](https://prometheus.io/)
メトリクスベースのモニタリングシステム

- [Grafana](https://grafana.com/)
データ可視化ツール

# EKS クラスターへのデプロイ

### Helm tiller のデプロイ

```
  $ kubectl -n kube-system create serviceaccount tiller

  $ kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller

  $ helm init --service-account=tiller
```
Client / Server が出力されれば完了

```
  $ helm version
```
<img width="834" alt="helm-tiller.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/7d544ad8-2451-9929-d760-75308ad53c6c.png">

### Istio のデプロイ
Prometheus と Granfana を含めた Istio をデプロイする
Istio を展開したディレクトリに移動し

```
  $ helm install --name istio-init install/kubernetes/helm/istio-init --namespace istio-system

  $ helm install --name istio install/kubernetes/helm/istio --namespace istio-system --set grafana.enabled=true --set grafana.persistentVolume.storageClass="gp2",server.persistentVolume.storageClass="gp2"
```
Istio の Pod が出力されれば完了

```
  $ kubectl get pods -n istio-system
```
<img width="555" alt="istio.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/a68881c5-e25c-1423-a4c3-4a9374463627.png">

### BookInfo (サンプル用アプリ) のデプロイ
<img width="509" alt="istio-bookinfo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/48cf1b4d-f13e-ee1f-6cc6-8bd99c16b57c.png">

> [引用 Bookinfo Application](https://istio.io/docs/examples/bookinfo/)

```
  $ kubectl create namespace bookinfo

  $ kubectl label namespace bookinfo istio-injection=enabled

  $ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -n bookinfo

  $ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml -n bookinfo
```
BookInfo の Pod が出力されれば完了

```
  $ kubectl get pods -n bookinfo
```
<img width="465" alt="bookinfo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/e9951e57-e3f2-1a93-763e-aef5e05b24d5.png">

### デプロイ確認

```
  $ kubectl get svc -n istio-system
```
EXTERNAL-IP/productpage/ にアクセス

<img width="959" alt="page-1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/63b7423f-2c5e-a15c-a649-b4ceec4265e9.png">
<img width="959" alt="page-2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/29b82373-1643-f680-eb8c-a02690f2df8f.png">
<img width="960" alt="page-3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/64e9dae5-3d07-ef25-08d1-cbe9f8f587eb.png">

### Prometheus / Grafana での確認

#### Prometheus

```
  $ kubectl port-forward deploy/prometheus -n istio-system 9090:9090
```
http://localhost:9090
<img width="959" alt="prometheus.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/55d48b75-c7bd-9cbd-88d3-17cb2ee56706.png">

#### Grafana

```
  $ kubectl port-forward deploy/grafana -n istio-system 3000:3000
```
http://localhost:3000
<img width="959" alt="grafana.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/4163e75f-6b1e-5eb1-cb43-dd979a0943f8.png">
<img width="959" alt="grafana-dashboard.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/ad497379-9cc8-c90f-a243-fb421c814588.png">

# 削除
EKS ではコマンドで AWS リソースが作成される
今回 Istio のデプロイ時にロードバランサが作成されているためクラスターを削除する前に消しておく

```
  $ kubectl get svc --all-namespaces
```
EXTERNAL-IP の値があるサービスを削除する

```
  $ kubectl delete svc istio-ingressgateway -n istio-system
```
コンソールパネルから順次削除
1. ノードスタック
2. クラスター
3. VPC スタック

# まとめ
CloudoFormation 以外初めて触ったものだったので勝手がわからず失敗した時のリカバリが大変だった
特に Istio や Prometheus は資料が少なく時間がかかってしまった

Kubernetes 自体はコマンドで手軽かつ即座にリソース操作ができるため強力な技術だと再認識したが
実運用するにあたって Helm などの関連ツールも含め学習コストは高いように思う

設定ファイルの編集などはしておらず手順をまとめただけの記事となってしまったので
さらっと解説ができるくらいには理解を深めていきたい