EKSでMattermostを構築した話：3-1. EKSクラスターでアプリケーションを稼働させる前にセットアップしておくべきツール編

## 今回、作成するもの
- 今回はEKSクラスターにMattermostをデプロイする前に、設定しておくと便利なものを順次作成していこうと思います。具体的には以下のようなものを作成する予定です。
    - IRSA
    - ALB Ingress Controller
    - external dns
    - Metrics Server
    - Amazon EFS CSI ドライバー
   
## IRSA
- これはIAM Roles for Service Accountsのことで、AWSの世界の権限管理の仕組みである`Role`とKubernetesの世界の権限管理の仕組みである` Service Accounts`をいい感じに仲介することで、AWSとKubernetesの世界の行き来を可能にしようっていうものです。
- で、この`いい感じに仲介する`役目を担うのが、`OIDCプロバイダー`というものになります。なので、まずはこの`OIDCプロバイダー`を作成していきましょう。

### OIDCプロバイダーを作成する
- `eksctl`を利用して作成していくのですが、作成前の状況をIAMの画面で確認してみましょう。
![OIDC001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/415280/b6898ae5-e431-b6ca-fa56-76d34d77ad44.png)
  - 現時点では何もないことが分かりますね。

- では、踏み台サーバから以下のコマンドを実行します

```shell:
$ eksctl utils associate-iam-oidc-provider --region ap-northeast-1 --name ver-Mattermost-eks --approve
Flag --name has been deprecated, use --cluster
[ℹ]  eksctl version 0.29.1
[ℹ]  using region ap-northeast-1
[ℹ]  will create IAM Open ID Connect provider for cluster "ver-Mattermost-eks" in "ap-northeast-1"
[✔]  created IAM Open ID Connect provider for cluster "ver-Mattermost-eks" in "ap-northeast-1"
```
- すると先程のIAMの画面にOIDCプロバイダーが作成されたことが確認できます
![OIDC002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/415280/0abca69e-a2dd-7be7-8861-1c7db1ddd873.png)

- これでAWSの世界とKubernetesの世界のつなぎ目が作成できたので、次からはその両方の世界を利用するようなものを作っていきます。

### 事前準備するリソース郡
- 具体的には、以下のようなリソース郡を作成していきます。
    - Mattermostのコンテナ(`Kubernetesの世界`)をインターネット経由でエンドユーザーからアクセスできるようにするためのロードバランサー(`AWSの世界`)
        - ここに`ALB Ingress Controller`を利用する
    - 上記で作成したロードバランサーのDNS名を、指定したドメイン名に自動で割り振ってくれる機能
        - これに`external DNS`を利用する
    - 負荷が高まった時にコンテナの数をオートスケールしてくれるもの
        - これに`Metrics Server`を利用する
    - Mattermostで利用されるデータを共有ストレージに補完するもの
        - これに`Amazon EFS CSI ドライバー`を利用する
- 上記のリソース郡をMattermostをデプロイする前に作成しておくことで、Mattermostに関しては1回デプロイをするだけで、あとは何も手をかけないでいいという状態にすることを目指しています。
- AWSの世界でこれを準備して、Kubernetesの世界であれを準備しておいて、その2つをこうして結びつけてみたいなことは、とても手間だし大変です。そこをKubernetesの世界の定義ファイルで一括で管理する(今回はこの管理に`helm`を利用します)というのが、Kubernetesの良さなのではないかと個人的には考えています。

## ALB Ingress Controller設定する
- では作成していきましょう
    - [Amazon EKS の ALB Ingress Controller - Amazon EKS](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/alb-ingress.html)の手順に沿って対応していきます。

- 手順
    1. ALB Ingress Controllerがロードバランサーを作成していいサブネットがどこにあるかを知らせるために、サブネットにタグ付けをする
    1. OIDCプロバイダーを設定（上記のIRSAで作成済）
    1. ALB Ingress Controller ポッド用の IAM ポリシー作成
    1. ALB Ingress Controller用のサービスアカウントを作成
    1. ALB Ingress Controller の IAM ロールを作成
    1. ALB Ingress Controller をデプロイ
    1. ALB Ingress Controllerのマニフェストファイルを編集

### 1.サブネットにタグ付け
- PublicSubnetに以下を追加
  
| キー	| 値 |
| --- | --- | 
|kubernetes.io/role/elb | 1 |


### 2. OIDCプロバイダーを設定
- OIDCプロバイダーを設定する → ★ここは上記で対応済なので飛ばします★

### 3. ALB Ingress Controller ポッド用の IAM ポリシー作成
- ALB Ingress Controller ポッド用の IAM ポリシーをダウンロード
  - `curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.8/docs/examples/iam-policy.json`
- IAMポリシーの作成

```
aws iam create-policy \
--policy-name ALBIngressControllerIAMPolicy \
--policy-document file://iam-policy.json
```

- 実行結果

```
{
"Policy": {
    "PolicyName": "ALBIngressControllerIAMPolicy",
    "PolicyId": "ANPAVX42E4WIMVDNCCYS3",
    "Arn": "arn:aws:iam::xxxxxxxxxxxx:policy/ALBIngressControllerIAMPolicy",
    "Path": "/",
    "DefaultVersionId": "v1",
    "AttachmentCount": 0,        
    "PermissionsBoundaryUsageCount": 0,
    "IsAttachable": true,
    "CreateDate": "2020-07-24T02:51:28+00:00",
    "UpdateDate": "2020-07-24T02:51:28+00:00"
   }
}
```

### 4. ALB Ingress Controller用のサービスアカウントを作成
- サービスアカウントを作成します

```shell:
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.8/docs/examples/rbac-role.yaml
clusterrole.rbac.authorization.k8s.io/alb-ingress-controller created
clusterrolebinding.rbac.authorization.k8s.io/alb-ingress-controller created
serviceaccount/alb-ingress-controller created
```

- 結果確認
    - `kube-system`にできているので確認します

```shell:
$ kubectl -n kube-system get sa
NAME                                 SECRETS   AGE
alb-ingress-controller               1         101s
attachdetach-controller              1         6d7h
aws-cloud-provider                   1         6d7h
aws-node                             1         6d7h
certificate-controller               1         6d7h
clusterrole-aggregation-controller   1         6d7h
coredns                              1         6d7h
cronjob-controller                   1         6d7h
daemon-set-controller                1         6d7h
default                              1         6d7h
deployment-controller                1         6d7h
disruption-controller                1         6d7h
endpoint-controller                  1         6d7h
expand-controller                    1         6d7h
generic-garbage-collector            1         6d7h
horizontal-pod-autoscaler            1         6d7h
job-controller                       1         6d7h
kube-proxy                           1         6d7h
namespace-controller                 1         6d7h
node-controller                      1         6d7h
persistent-volume-binder             1         6d7h
pod-garbage-collector                1         6d7h
pv-protection-controller             1         6d7h
pvc-protection-controller            1         6d7h
replicaset-controller                1         6d7h
replication-controller               1         6d7h
resourcequota-controller             1         6d7h
service-account-controller           1         6d7h
service-controller                   1         6d7h
statefulset-controller               1         6d7h
ttl-controller                       1         6d7h
```

### 5. ALB Ingress Controller の IAM ロールを作成
- ALB Ingress Controller の IAM ロールを作成し、このロールを前のステップで作成したサービスアカウントにアタッチします

```
eksctl create iamserviceaccount \
    --region ap-northeast-1 \
    --name alb-ingress-controller \
    --namespace kube-system \
    --cluster ver-Mattermost-eks \
    --attach-policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/ALBIngressControllerIAMPolicy \
    --override-existing-serviceaccounts \
    --approve
```

- 結果確認

```
$ eksctl create iamserviceaccount \
>     --region ap-northeast-1 \
>     --name alb-ingress-controller \
>     --namespace kube-system \
>     --cluster ver-Mattermost-eks \
>     --attach-policy-arn arn:aws:iam::xxxxxxxxxxxx:policy/ALBIngressControllerIAMPolicy \
>     --override-existing-serviceaccounts \
>     --approve
[ℹ]  eksctl version 0.29.1
[ℹ]  using region ap-northeast-1
[ℹ]  2 iamserviceaccounts (kube-system/alb-ingress-controller, kube-system/aws-node) were included (based on the include/exclude rules)
[!]  metadata of serviceaccounts that exist in Kubernetes will be updated, as --override-existing-serviceaccounts was set
[ℹ]  2 parallel tasks: { 2 sequential sub-tasks: { create IAM role for serviceaccount "kube-system/alb-ingress-controller", create serviceaccount "kube-system/alb-ingress-controller" }, 2 sequential sub-tasks: { create IAM role for serviceaccount "kube-system/aws-node", create serviceaccount "kube-system/aws-node" } }
[ℹ]  building iamserviceaccount stack "eksctl-ver-Mattermost-eks-addon-iamserviceaccount-kube-system-alb-ingress-controller"
[ℹ]  building iamserviceaccount stack "eksctl-ver-Mattermost-eks-addon-iamserviceaccount-kube-system-aws-node"
[ℹ]  deploying stack "eksctl-ver-Mattermost-eks-addon-iamserviceaccount-kube-system-aws-node"
[ℹ]  deploying stack "eksctl-ver-Mattermost-eks-addon-iamserviceaccount-kube-system-alb-ingress-controller"
[ℹ]  serviceaccount "kube-system/alb-ingress-controller" already exists
[ℹ]  updated serviceaccount "kube-system/alb-ingress-controller"
[ℹ]  serviceaccount "kube-system/aws-node" already exists
[ℹ]  updated serviceaccount "kube-system/aws-node"
```

- 以下の画像にあるようなロールが作成されます。
    - 信頼されたエンティティにOIDCプロバイダーが登録されている
    - 条件のところにサービスアカウントの`alb-ingress-controller`が登録されている
![alb-ingress-contoroller-role.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/415280/c9a8f53a-e8d2-12ca-580d-d0be5b809516.png)


### 6.ALB Ingress Controller をデプロイ
- ここようやく`ALB Ingress Controller本体`をデプロイしていきます。

```
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.8/docs/examples/alb-ingress-controller.yaml
```

- ここで結果確認はしません。確認してもpodがクラッシュしている様子が見えるだけです。
    - クラッシュの原因は設定が足りていないからです。改善するために以下の対応が必要になります。

### 7.ALB Ingress Controller のデプロイマニフェストを編集
- 以下のコマンドでマニフェストファイルを編集します。

```
kubectl edit deployment.apps/alb-ingress-controller -n kube-system
```

- マニフェストファイルの以下の部分に追記をしていきます

```yaml:
 spec:
      containers:
      - args:
        - --ingress-class=alb
```

- 追記するのは、`クラスタ名`と`VPCid`と`リージョン`です

```yaml:
 spec:
      containers:
      - args:
        - --ingress-class=alb
        - --cluster-name=ver-Mattermost-eks
        - --aws-vpc-id=vpc-xxxxxxxxxxxxxxxx
        - --aws-region=ap-northeast-1
```

- ここで結果確認をします。すると`alb-ingress-controller`の機能を提供するpodが正常に稼働していることが確認できます。


```
$ kubectl get -n kube-system pod
NAME                                     READY   STATUS    RESTARTS   AGE
alb-ingress-controller-869744b58-s6blb   1/1     Running   0          33s
```

## まとめ
- ちょっと長くなったので、残りのリソース郡は次回にします。
- 残りは以下の3つです。
    - external dns
    - Metrics Server
    - Amazon EFS CSI ドライバー

## 関連記事
- [EKSでMattermostを構築した話：0.概要編 - Qiita](https://qiita.com/tnagano1981/items/555301cecd3ed309fa43)
- [EKSでMattermostを構築した話：1. VPC作成編 - Qiita](https://qiita.com/tnagano1981/items/75408d509c0660408c97)
- [EKSでMattermostを構築した話：2. EKSクラスター作成編 - Qiita](https://qiita.com/tnagano1981/items/fc5d96ddf9a3b5c4fb03)