SecurityGroupが有効のNLBをEKSでプロビジョニングする

### 背景
3番煎じくらいのネタですが、最新版のLoadBalancerControllerでSecurityGroupが有効のNLBが作成できるようになったとのことなので実際に作成してみたのでその際の記録です。

### 手順

1. LBCのインストール
1. Podの起動
1. NLB用のマニフェスト作成と適用
1. 動作確認

### 環境

```bash
[root@ip-192-168-0-50 ~]# k version
Client Version: v1.28.3-eks-e71965b
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.28.4-eks-8cb36c9
```

### LBCのインストール

EKSがNLBをプロビジョニングするために、LoadBalancerControllerをインストールします。[公式](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/aws-load-balancer-controller.html)の手順に従って導入しました。既に導入済みの環境では割愛してください。

#### LBCが使用するIAMロールとServiceAccountの作成

```bash
[root@ip-192-168-0-50 lbc]# k apply -f aws-load-balancer-controller-service-account.yaml
serviceaccount/aws-load-balancer-controller created
[root@ip-192-168-0-50 lbc]# k get sa -n kube-system | grep aws-load
aws-load-balancer-controller         0         18s
```

#### LoadBalancerControllerのインストール

```bash
[root@ip-192-168-0-50 linux-amd64]# helm install aws-load-balancer-controller eks/aws-load-balancer-controller   -n kube-system   --set clusterName=eks-test-cluster   --set serviceAccount.create=false   --set serviceAccount.name=aws-load-balancer-controller
NAME: aws-load-balancer-controller
LAST DEPLOYED: Tue Jan  2 01:28:50 2024
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
AWS Load Balancer controller installed!
[root@ip-192-168-0-50 linux-amd64]# k get po -n kube-system
NAME                                            READY   STATUS    RESTARTS   AGE
aws-load-balancer-controller-55dcfccf84-9bvh6   1/1     Running   0          16s
aws-load-balancer-controller-55dcfccf84-r9d9g   1/1     Running   0          16s
```

この時、インストールされたAPPのバージョンがv2.6.Xであることを確認してください。（v2.6系からNLBのSecurityGroupをサポートしたため）

```bash
[root@ip-192-168-0-50 linux-amd64]# helm list -n kube-system
NAME                            NAMESPACE       REVISION        UPDATED                STATUS          CHART                                   APP VERSION
aws-load-balancer-controller    kube-system     1               2024-01-02 01:28:50.353761198 +0000 UTC      deployed        aws-load-balancer-controller-1.6.2      v2.6.2
```

### Podの起動

テスト用のNamespaceにnginxを起動します。

```bash
[root@ip-192-168-0-50 lbc]# k run nginx --image nginx:latest -n test
pod/nginx created
[root@ip-192-168-0-50 lbc]# k get po -n test
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          9s
```

### NLB用のマニフェスト作成と適用

今回は動作確認のため、必要最低限の設定で作成します。自宅のブラウザからnginxへアクセスしたいので、スキームには __insternet-facing__ を設定しました。

```bash:Service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: test
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: instance
    service.beta.kubernetes.io/aws-load-balancer-subnets: subnet-XXXXXXXXXXXXXXXXX, subnet-YYYYYYYYYYYYYYYYY, subnet-ZZZZZZZZZZZZZZZZZ
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
spec:
  selector:
    run: nginx
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  type: LoadBalancer
  loadBalancerClass: service.k8s.aws/nlb
```

作成したマニフェストを適用します。

```bash
[root@ip-192-168-0-50 lbc]# k apply -f service.yaml
service/nginx-service configured
[root@ip-192-168-0-50 lbc]# k get svc -n test
NAME            TYPE           CLUSTER-IP       EXTERNAL-IP                                    PORT(S)        AGE
nginx-service   LoadBalancer   10.100.176.138   k8s-test-nginxser-XXXXXXXXXX-XXXXXXXXXXXXXXXX.elb.ap-northeast-1.amazonaws.com   80:30324/TCP   14m
```

### 動作確認

NLBのDNS名を使ってブラウザからアクセス。

接続できました。
![スクリーンショット 2024-01-02 111147.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389171/dd0c6700-6559-84ae-e325-952ad23f02b9.png)

SecurityGroupはデフォルトで有効（自動作成）のようで、特に何も指定しなかった場合は以下のような設定になりました。

#### NLB

以下の2つが自動的に作成され、NLBにアタッチされた。

```bash
[root@ip-192-168-0-50 lbc]# aws elbv2 describe-load-balancers --names k8s-test-nginxser-2d6f594bd5 --query 'LoadBalancers[0].SecurityGroups'
[
    "sg-081014ae8ef46db98",
    "sg-04a1f7d70c70fd904"
]
```

SecurityGroupIDだけだと中身がわからないので以下補足。

|名前|説明|備考|
|---|---|---|
|k8s-traffic-eksworkcluster~|[k8s] Shared Backend SecurityGroup for LoadBalancer|バックエンドリソース用のSecurityGroup。今回はターゲットタイプにインスタンスを設定しているため使用しません。|
|k8s-test-nginx~|[k8s] Managed SecurityGroup for LoadBalancer|NLB自体のトラフィックを制御するSecurityGroup。今回の設定ではIPアドレスの範囲0.0.0.0/0をソースとした80ポート宛の通信を許可するルールが設定されました。|

#### ワーカーノード(EC2)

SecurityGroup：k8s-traffic-eksworkcluster~をソースとしたNodePort宛のTCPトラフィックの許可ルールがLoadBalancerControllerによって追加されました。

### つまづきポイント

#### NLBが起動してこない

NLB用Serviceリソースのマニフェストをapplyした時、LoadBalancerControllerがNLBを作成してくれませんでした。LoadBalancerControllerのPodのログを出力すると以下の内容が表示されました。

```bash
{"level":"error","ts":"2024-01-02T01:45:18Z","msg":"Reconciler error","controller":"service","object":{"name":"nginx-service","namespace":"test"},"namespace":"test","name":"nginx-service","reconcileID":"1fe71c3b-cb88-4cfd-916f-18d77e3ed20c","error":"unable to resolve at least one subnet (0 match VPC and tags)"}
```

サブネットが解決できないとのエラー。解決方法はいくつかある模様だが、今回は最もシンプルそうだったアノテーションにプロビジョニングする先のサブネットを指定する方法で回避。

```yaml:service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: test
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: instance
    service.beta.kubernetes.io/aws-load-balancer-subnets: subnet-XXXXXXXXXXXXXXXXX, subnet-YYYYYYYYYYYYYYYYY, subnet-ZZZZZZZZZZZZZZZZZ
```

### さいごに
SecurityGroupが設定されたNLBを作成することが出来ましたが、次回はもっと具体的な挙動について確認しようと思います。

### 参考
- [AWS Load Balancer Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.6/)