Terraformを使ってArgo CDによるGitOpsなリリースができるEKS環境を構築してみる（中編～AWS Load Balancer Controller使ってみた～） 

# 今回やること

前回はterraformを使って、EKSとその他AWSリソースを作成するところまで実施しました。
今回はEKSのリソースを作成しつつ、AWS Load Balancer Controllerを使ってALBを作成し、外部から通信を受け付け可能な状態にするところまで試してみます。

このシリーズの記事
[Terraformを使ってArgo CDによるGitOpsなリリースができるEKS環境を構築してみる（前編～TerraformでAWSリソースを構築してみた～）](https://qiita.com/kawashimat/items/779c981922d32429e268)
Terraformを使ってArgo CDによるGitOpsなリリースができるEKS環境を構築してみる（中編～AWS Load Balancer Controller使ってみた～） ←今回はこちら
[Terraformを使ってArgo CDによるGitOpsなリリースができるEKS環境を構築してみる（後編～Argo CDでGitOpsなデプロイやってみた～））](https://qiita.com/kawashimat/items/520d00475b48de97b69c)

# Kubernetesにおけるインターネットアクセス

Kubernetesでは、インターネットから通信を受け付ける方法として、大きく以下の2つの方法があります。

- Serviceのサービスタイプの1つであるLoad Balancerを使う
- Ingressを使う

2つとも外部のロードバランサーと連携してKubernetesクラスタへの外部アクセスを可能にするリソースです。大きな違いはロードバランシングがL4かL7のどちらで提供されるかという点。

今回は、Ingressを使った方式を試してみます。

# AWS Load Balancer Controllerとは

Ingressを使用する場合、Ingressリソースと、Ingress Controllerと呼ばれるリソースの一式を用意する必要があります。ざっくり言うと、

- Ingress：ロードバランサーの設定を定義する
- Ingress Controller：Ingressリソースの内容に基づいて、ロードバランサーを作成する

という役割がそれぞれにあります。AWS Load Balancer Controllerは、AWSにおける「Ingress Controllerと呼ばれるリソースの一式」に相当します。

今回は以下の通り、Private Subnet内のKubernetesの各リソースと、ALBを作成し、アプリに疎通するところまで確認したいと思います。上記の通り、Ingress Controller(AWS Load Balancer Controller)がIngressを検知してALBを作ってくれます。

![nw3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2881538/ae87c516-ff97-d870-2c16-eb037123f0fe.png)


# 作ってみる

というわけで、AWS Load Balancer ControllerとIngressを作成して、ALBが作られていく様子を確認してみたいと思います。AWS Load Balancer Controllerの作成手順は以下のAWSの公式ガイドに書かれています。

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/aws-load-balancer-controller.html

## IAMロールとServiceAccountの作成

まず初めにIAMロールとServiceAccountを作成します。いずれもAWSからテンプレートが提供されています。

該当のIAMロールにアタッチするポリシー「AWSLoadBalancerControllerIAMPolicy」を見る限り、これはKubernetesリソースであるAWS Load Balancer ControllerがAWSリソースであるALBを作成したりその他もろもろの権限を許可するためのロールとみなしてよさそうです。

なお、ロールの信頼関係は、リージョン、AWSアカウントIDおよび、EKSのOIDC部分（以下XXX…）を使用しているものに書き換えておく必要があります。

```json:AmazonEKSLoadBalancerControllerRole
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.region-code.amazonaws.com/id/XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "oidc.eks.region-code.amazonaws.com/id/XXXXXXXXXXXXXXXXXXXXXXXXXXXXX:aud": "sts.amazonaws.com",
                    "oidc.eks.region-code.amazonaws.com/id/XXXXXXXXXXXXXXXXXXXXXXXXXXXXX:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller"
                }
            }
        }
    ]
}

```

## AWS Load Balancer Controllerのインストール
AWS Load Balancer Controllerをインストールします。こちらも、必要なマニフェストファイルがAWSより提供されていますので、順番にapplyしていけばOKです。


``` :cert-manager をインストール
$ kubectl apply -f cert-manager.yaml
namespace/cert-manager created
customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created
…(以下省略)
```

``` :AWS Load Balancer Controller をインストール
$ kubectl apply -f v2_4_4_full.yaml
customresourcedefinition.apiextensions.k8s.io/ingressclassparams.elbv2.k8s.aws created
customresourcedefinition.apiextensions.k8s.io/targetgroupbindings.elbv2.k8s.aws created
role.rbac.authorization.k8s.io/aws-load-balancer-controller-leader-election-role created
clusterrole.rbac.authorization.k8s.io/aws-load-balancer-controller-role created
rolebinding.rbac.authorization.k8s.io/aws-load-balancer-controller-leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/aws-load-balancer-controller-rolebinding created
service/aws-load-balancer-webhook-service created
deployment.apps/aws-load-balancer-controller created
certificate.cert-manager.io/aws-load-balancer-serving-cert created
issuer.cert-manager.io/aws-load-balancer-selfsigned-issuer created
mutatingwebhookconfiguration.admissionregistration.k8s.io/aws-load-balancer-webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/aws-load-balancer-webhook created
ingressclass.networking.k8s.io/alb created
```

加えて、IngressClassおよびIngressClassParams作成のマニフェストを実行します。
これが、IngressとAWS Load Balancer Controllerを関連付けます。

```:IngressClassおよびIngressClassParamsをクラスターに適用
$ kubectl apply -f v2_4_4_ingclass.yaml
ingressclassparams.elbv2.k8s.aws/alb created
ingressclass.networking.k8s.io/alb configured
```

最後にAWS Load Balancer Controllerが稼働していることを確認します。
```
$ kubectl get deployment -n kube-system aws-load-balancer-controller
NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
aws-load-balancer-controller   1/1     1            1           5m43s
```

## Ingressの作成

AWS Load Balancer Controllerが用意できたので、後はIngressを作成すれば、ALBが作られます。
その前に、ALBから通信を受け付けるアプリ群を作っておかないといけないので、以下のマニフェストを実行しておきます。

```yaml:dev-ap.yaml
# NameSpace
apiVersion: v1
kind: Namespace
metadata:
  name: dev-ap
---

# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: dev-ap
  name: dev-ap-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: dev-ap-deployment
  template:
    metadata:
      labels:
        app: dev-ap-deployment
    spec:
      #今回は予めECRリポジトリに格納しておいたNginxコンテナのイメージを使用
      containers:
      - image: 111122223333.dkr.ecr.ap-northeast-1.amazonaws.com/otameshi-ecr:latest 
        name: dev-ap-pod
---

# NodePort
apiVersion: v1
kind: Service
metadata:
  namespace: dev-ap
  name: dev-ap-nodeport
  labels:
    app: dev-ap-nodeport
spec:
  type: NodePort
  selector:
    app: dev-ap-deployment
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
```


```:コマンドと実行結果
$ kubectl apply -f dev-ap.yaml 
namespace/dev-ap created
deployment.apps/dev-ap-deployment created
service/dev-ap-nodeport created
```

いよいよIngressを作成します。アノテーション部分でALBの設定ができるのがポイントです。
今回はinternet-facingにしつつ、あらかじめ作ったSecurityGroupをアタッチしています。

```yaml:ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: dev-ap
  name: alb-ingress
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/security-groups: dev-sg
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: dev-ap-nodeport
              port:
                number: 8080
```


```:コマンドと実行結果
$ kubectl apply -f ingress.yaml 
ingress.networking.k8s.io/alb-ingress created
```

# 動作確認

AWSコンソールにて、LoadBalancerのリソースを覗いてみると、、、
![スクリーンショット 2022-12-01 082659.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2881538/4d4e7f68-7ea7-a028-4de1-d6c85b60a52f.png)

ALBが作成されています！

アノテーションで設定したSecurityGroupも反映されています。
![スクリーンショット 2022-12-01 082859.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2881538/44cdea45-4dd2-19ba-d2a9-12dc2428df67.png)

ALBのDNSにアクセスすると、アプリ(シンプルなNginxの画面ですが)が表示されました。

![スクリーンショット 2022-12-01 083702.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2881538/6ed31450-52cf-b2ae-2243-ea356a352b3c.png)

Ingress Controller(AWS Load Balancer Controller)によってALBが作成され、ALB⇒NodePort⇒Podsの経路で問題なく通信することが確認できました。

# ここまでのまとめ
前回からかなり間が空いてしまいましたが、ようやくKubernetesがアプリケーションサービスを提供する状態となりました。

外部通信の方法は冒頭に示した通りいくつかの方式があるようですが、各クラウドサービスが提供するIngress Controllerを使用するのが比較的シンプルな構成になるのではという個人的な所感です。(AWSで言えば今回試したAWS Load Balancer Controller、GCPの場合、GKE Ingress controllerというものがある模様)

次回、ようやく本題のArgo CD君が登場します。