😎

AWS Load Balancer Controllerを試してみる(EKS on Fargate with NLB)

2020/10/25に公開

AWS Load Balancer Controllerとは

https://aws.amazon.com/jp/blogs/containers/introducing-aws-load-balancer-controller/
で発表された、ALB Ingress Controllerに変わる新しいAWS EKS用のLB管理Controllerです。

できるようになったこと

EKS on FargateでNLBが利用できる

今までEKS on FargateではALBしか利用できなかったですが、NLBが利用可能になったことでHTTP/HTTPS以外のPortの利用や、PrivateLinkを利用したFargateでのPodの利用が可能になりました。

複数Ingressに対してグルーピングが可能に

今まではIngressリソースごとにALBが作成されましたが、グルーピングすることで一つのALBで複数のIngressリソースを管理可能になりました。

今回はEKS on Fargate with NLBを試してみました。

ドキュメント

現状ドキュメントの方ではなく、docsに手順が乗っています。

前提

  • EKSのバージョンが1.18以上であること
  • CertManagerをインストールしていること(ドキュメントにインストール方法があります)

上記のドキュメントの通りに作成(厳密にはTerraform管理しているため、実施内容は別ですが、やっていることは同じです)しました。また、自分の環境ではdefault/kube-systemもfargate profileに追加しております。

動作確認

実行に失敗する

ALB Ingress Controllerと同様に、region/vpc-idが必要となります。

kubectl logs aws-load-balancer-controller-8964bc966-55cpb
> {"level":"info","ts":1603606317.8964105,"msg":"version","GitVersion":"v2.0.0-dirty","GitCommit":"1028fa4f363a9a8e37b07ff6a093b7b422923512","BuildDate":"2020-10-23T01:34:38+0000"}
{"level":"error","ts":1603606324.157537,"logger":"setup","msg":"unable to initialize AWS cloud","error":"failed to introspect region from EC2Metadata, specify --aws-region instead if EC2Metadata is unavailable: EC2MetadataRequestError: failed to get EC2 instance identity document\ncaused by: RequestError: send request failed\ncaused by: Get \"http://169.254.169.254/latest/dynamic/instance-identity/document\": dial tcp 169.254.169.254:80: i/o timeout (Client.Timeout exceeded while awaiting headers)"}

そのため、以下のようにdeploymentにparameterを追加する必要があります。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: aws-load-balancer-controller
spec:
  ...snip...
      containers:
        - name: controller
          args:
            - --cluster-name=<my cluster name>
            - --ingress-class=alb
            - --aws-region=ap-northeast-1
            - --aws-vpc-id=<my vpc id>

こちらをみたところ、EC2のPodであれば起きないかもしれないです。

Roleの権限がない

AWS Load Balancer Controllerの作成後、Podでエラーが発生しました。

kubectl logs aws-load-balancer-controller-79d6b9dc85-89stk     
> E1025 07:26:49.919688       1 leaderelection.go:324] error initially creating leader election record: configmaps is forbidden: User "system:serviceaccount:kube-system:aws-load-balancer-controller" cannot create resource "configmaps" in API group "" in the namespace "kube-system"

そのため、install.yamlのRoleを以下に変更しました。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    app.kubernetes.io/name: aws-load-balancer-controller
  name: aws-load-balancer-controller-leader-election-role
  namespace: kube-system
rules:
  - apiGroups:
      - ""
    # resourceNames:
    #   - aws-load-balancer-controller-leader
    resources:
      - configmaps
    verbs:
      - create
      - get
      - update
      - patch

上記を適用した後、正常に起動しました。

{"level":"info","ts":1603611222.7421174,"msg":"version","GitVersion":"v2.0.0-dirty","GitCommit":"1028fa4f363a9a8e37b07ff6a093b7b422923512","BuildDate":"2020-10-23T01:34:38+0000"}
...snip...
{"level":"info","ts":1603611242.1381829,"logger":"controller","msg":"Starting workers","controller":"service","worker count":3}
{"level":"info","ts":1603611242.2380457,"logger":"controller","msg":"Starting workers","controller":"ingress","worker count":3}
{"level":"info","ts":1603611242.239579,"logger":"controller","msg":"Starting Controller","reconcilerGroup":"elbv2.k8s.aws","reconcilerKind":"TargetGroupBinding","controller":"targetGroupBinding"}
{"level":"info","ts":1603611242.239718,"logger":"controller","msg":"Starting workers","reconcilerGroup":"elbv2.k8s.aws","reconcilerKind":"TargetGroupBinding","controller":"targetGroupBinding","worker count":3}

EKS on FargateでNLB

サンプルとして、NginXをたてます。Manifestは以下の通りです。
ポイントは、service.beta.kubernetes.io/aws-load-balancer-type: "nlb-ip"をannotationで追加する点です。

nginx.yaml

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: default
spec:
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb-ip"
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer
kubectl apply -f nginx.yaml

動作確認

上記作成時に、AWS Load Balancer Controllerがfetchし、設定をしてくれます。

  1. Serviceの作成をControllerが検知
  2. TargetGroupを作成
  3. LoadBalancerを作成
  4. Listenerを作成
  5. targetGroupBindingを作成(ServiceとAWSのTargetGroupを紐づけるCRDです)
  6. securityGroupを作成
  7. TargetGroupにPodのIPを登録

その後、AWS側で確認すると、NLBでType: IPで作成できているのが確認できました。

疎通もOKです。

curl k8s-default-nginx-<domain>
>
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

annotation typeはこちらにあります。NLBの場合基本Internalに立てると思いますので、その場合にはservice.beta.kubernetes.io/aws-load-balancer-internal: trueを設定する必要があります。

削除

kubectl delete -f nginx.yaml 

作成時と同様に、AWS Load Balancer Controllerがfetchし、AWSリソースを削除してくれます。

おわりに

これでNLBでもFargateが利用できるようになったので、EKS Fargateの幅も大きく広がったのかなと思います。EKS Master UpgradeでもFargateはPodを再作成するだけでバージョンがあげられるので、運用コストの削減ができれば良いかなと考えています。

また、複数Ingressに対してグルーピングが可能となる機能も次に試してみようと思います。

Discussion