AWS Load Balancer Controller@Ingress Controller¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. AWS Load Balancer Controllerの仕組み¶
アーキテクチャ¶
AWS Load Balancer Controller は、aws-load-balancer-controller、TargetGroupBinding、といったコンポーネントから構成されている。
aws-load-balancer-controller は、etcd 上の Ingress のマニフェストを検知し、設定値に応じた AWS ALB や AWS NLB をプロビジョニングし、これらのリスナールールごとにターゲットグループもプロビジョングする。
その後、TargetGroupBinding の設定値を経由して、ALB のターゲットグループと Ingress を紐付ける。
これらにより、Cluster 外からのリクエストを Pod へルーティングできるようにする。

- https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.4/how-it-works/
- https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.2/guide/service/nlb/
- https://blog.recruit.co.jp/rmp/infrastructure/post-21469/
- https://aws.amazon.com/cn/blogs/china/use-aws-load-balancer-controller-s-targetgroupbinding-function-to-realize-flexible-load-balancer-management/
Nodeをターゲットグループに登録/ドレイン¶
▼ 登録の流れ¶
AWS Load Balancer Controller は、以下の仕組みでターゲットグループに新しい Node を登録する。
- 対象の Cluster のサブネット内に EC2 Node が起動状態に移行すると、AWS Load Balancer Controller はそれを検知する。
- 検知した EC2 Node をターゲットグループに追加する。
- EC2 Node が正常になれば、Node へルーティングできるようになる。
▼ ドレイン処理の流れ¶
AWS Load Balancer Controller は、以下の仕組みでターゲットグループから EC2 Node をドレインする。
- EC2 Node が停止状態に移行すると、AWS Load Balancer Controller はそれを検知する。
- 検知した EC2 Node をターゲットグループからドレインする。
- 停止状態移行中の EC2 Node 以外の Node にリクエストをロードバランシングする。
Serviceタイプ¶
NodePort Service を使用しなければならない。
AWS Load Balancer Controller を使用しない場合は、NodePort Service のポート番号に合わせて AWS ターゲットグループを作成する必要がある。
AWS Load Balancer Controller を使用する場合は、NodePort Service のポート番号をランダムにしても、そのポート番号を指定する AWS ターゲットグループを AWS Load Balancer Controller がプロビジョニングしてくれる。
パブリックネットワーク
⬇⬆️︎
Amazon Route 53
⬇⬆️︎
# L7ロードバランサー (単一のL7ロードバランサーを作成し、異なるポートを開放する複数のL4ロードバランサーの振り分ける)
AWS Load Balancer ControllerによるAWS ALB
⬇⬆️︎
# L4ロードバランサー
NodePort Service (ポート番号はランダムでよい)
⬇⬆️︎
Pod
- https://developer.mamezou-tech.com/containers/k8s/tutorial/ingress/ingress-aws/#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4
- https://qiita.com/mksamba/items/c0e41a2a63e62a50aea3#21-%E5%85%AC%E9%96%8B%E5%AF%BE%E8%B1%A1%E3%81%AEdeploymentservice%E3%81%AE%E4%BD%9C%E6%88%90
01-02. 設計パターン¶
AWS Load Balancer Controllerを使用しない場合¶
もし AWS CLB を作成したい場合は、AWS Load Balancer Controller を使用しない。
LoadBalancer Service を作成すると、Amazon EKS 内の cloud-controller-manager が AWS CLB を自動的にプロビジョニングする。
TargetGroupBindingパターン¶
02. セットアップ¶
AWS側¶
▼ 共通¶
AWS Load Balancer Controller は、サブネットを自動的に検出し、これに AWS ALB をプロビジョニングする。
Ingress で作成する AWS ALB をパブリックサブネットで作成する場合、kubernetes.io/role/elb というタグ (値は 1 または空文字) をすべてのパブリックサブネットに設定する。
一方で、プライベートサブネットで作成する場合、kubernetes.io/role/internal-elb というタグ (値は 1 または空文字) をプライベートサブネットに設定する。
またパブリックサブネットまたはプライベートサブネットのいずれであっても kubernetes.io/cluster/<Amazon EKS Clusterの名前> (値は、複数の Amazon EKS Cluster で共有するサブネットの場合は shared、単一の Amazon EKS Cluster の場合は owned とする) を設定する。
▼ Terraformの公式モジュールの場合¶
AWS Load Balancer Controller のセットアップのうち、AWS 側で必要なものをまとめる。
ここでは、Terraform の公式モジュールを使用する。
コマンド (例:eksctl コマンド) を使用してもよい。
module "iam_assumable_role_with_oidc_aws_load_balancer_controller" {
source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role-with-oidc"
version = "<バージョン>"
# AWS Load Balancer ControllerのPodに紐付けるIAMロール
create_role = true
role_name = "foo-aws-load-balancer-controller"
# Amazon EKS ClusterのOIDCプロバイダーURLからhttpsプロトコルを除いたもの
provider_url = replace(module.eks.cluster_oidc_issuer_url, "https://", "")
# AWS IAMロールに紐付けるIAMポリシー
role_policy_arns = [
aws_iam_policy.aws_load_balancer_controller.arn
]
# AWS Load Balancer ControllerのPodのServiceAccount名
# ServiceAccountは、Terraformではなく、マニフェストで定義したほうが良い
oidc_fully_qualified_subjects = [
"system:serviceaccount:kube-system:foo-aws-load-balancer-controller"
]
}
# GitHubにリクエストを送信し、IAMポリシーのファイルを取得する
data "http" "aws_load_balancer_controller_policy" {
# チャートバージョンが提供するIAMポリシーのURLを指定する
# (例) チャートのバージョンが 1.5.3 の場合
# https://github.com/kubernetes-sigs/aws-load-balancer-controller/blob/v2.5.2/helm/aws-load-balancer-controller/Chart.yaml#L4
url = "https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.5.2/docs/install/iam_policy.json"
}
# レスポンスからJSONファイルの内容を取得する
resource "aws_iam_policy" "aws_load_balancer_controller" {
name = "foo-aws-load-balancer-controller"
# GitHubリポジトリが返信したIAMポリシーのjsonを設定する
policy = data.http.aws_load_balancer_controller_policy.response_body
}
別途、AWS Load Balancer Controller の Pod に紐付ける ServiceAccount を作成し、IAM ロールの ARN を設定する。
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-aws-load-balancer-controller
namespace: kube-system
annotations:
eks.amazonaws.com/role-arn: <IAMロールのARN>
IRSA により、ServiceAccount に AWS の IAM ロールが紐づく。

▼ awscli コマンド、eksctl コマンドの場合¶
AWS Load Balancer Controller のセットアップのうち、AWS 側で必要なものをまとめる。
ここではコマンドを使用しているが、IaC (例:Terraform) を使用してもよい。
(1)-
ローカルマシンに IAM ポリシーの
jsonファイルをダウンロードする。
$ curl -L https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.0/docs/install/iam_policy.json -o iam_policy.json
(2)-
jsonファイルを使用して、ServiceAccount の IAM ロールに紐付けるための IAM ポリシーを作成する。
$ aws iam create-policy \
--policy-name AWSLoad BalancerControllerIAMPolicy \
--policy-document file://iam_policy.json
(3)-
Amazon EKS Cluster を OIDC プロバイダーとして使用する。
これにより、Amazon EKS Cluster内で認証済みのServiceAccountにIAMロールを紐付けることができるようになる。
$ eksctl utils associate-iam-oidc-provider \
--region=ap-northeast-1 \
--cluster=foo-eks-cluster \
--approve
2022-05-30 23:39:04 [ℹ] eksctl version 0.96.0
2022-05-30 23:39:04 [ℹ] using region ap-northeast-1
2022-05-30 23:39:05 [ℹ] IAM Open ID Connect provider is already associated with cluster "foo-eks-cluster" in "ap-northeast-1"
(4)-
AWS Load Balancer Controller の Pod の ServiceAccount と、これに紐づく IAM ロールを作成する。
$ eksctl create iamserviceaccount \
--cluster=foo-eks-cluster \
-n kube-system \
--name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::<AWSアカウントID>:policy/AWSLoad BalancerControllerIAMPolicy \
--override-existing-serviceaccounts \
--approve
(5)-
ServiceAccount を作成できたことを確認する。IAM ロールはコンソール画面から確認する。
$ eksctl get iamserviceaccount \
--cluster foo-eks-cluster \
--name foo-aws-load-balancer-controller \
--namespace kube-system
2022-06-06 13:47:33 [ℹ] eksctl version 0.96.0
2022-06-06 13:47:33 [ℹ] using region ap-northeast-1
NAMESPACE NAME ROLE ARN
kube-system foo-aws-load-balancer-controller arn:aws:iam::<AWSアカウントID>:role/eksctl-foo-eks-cluster-addon-i-Role1-****
$ kubectl get serviceaccount -n kube-system foo-aws-load-balancer-controller -o yaml
---
# 作成されたServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<AWSアカウントID>:role/eksctl-foo-eks-cluster-addon-i-Role1-****
creationTimestamp: "2022-05-29T12:59:15Z"
labels:
app.kubernetes.io/managed-by: eksctl
name: foo-aws-load-balancer-controller
namespace: kube-system
resourceVersion: "2103515"
uid: *****
secrets:
- name: foo-aws-load-balancer-controller-token-****
Kubernetes側¶
▼ Helmの場合¶
AWS Load Balancer Controller のセットアップのうち、Kubernetes 側で必要なものをまとめる。
(1)-
指定したリージョンに AWS Load Balancer Controller をデプロイする。
この時、事前にマニフェストや
eksclt create iamserviceaccountコマンドで作成したServiceAcountをALBに紐付ける。IRSAの仕組みにより、ServiceAccountを経由してPodとAWS IAMロールが紐づく。
$ helm repo add <チャートリポジトリ名> https://aws.github.io/eks-charts
# FargateにAWS Load Balancer Controllerをデプロイする場合
$ helm install <Helmリリース名> <チャートリポジトリ名>/aws-load-balancer-controller \
-n kube-system \
--set clusterName=foo-eks-cluster \
--set serviceAccount.create=false \
--set serviceAccount.name=foo-aws-load-balancer-controller \
--set image.repository=602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon/aws-load-balancer-controller \
--set region=ap-northeast-1 \
--set vpcId=vpc-*****
AWS Load Balancer controller installed!
$ helm repo add <チャートリポジトリ名> https://aws.github.io/eks-charts
# EC2にAWS Load Balancer Controllerをデプロイする場合
$ helm install <Helmリリース名> <チャートリポジトリ名>/aws-load-balancer-controller \
-n kube-system \
--set clusterName=foo-eks-cluster \
--set serviceAccount.create=false \
--set serviceAccount.name=foo-aws-load-balancer-controller \
--set image.repository=602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon/aws-load-balancer-controller
AWS Load Balancer controller installed!
(2)-
AWS Load Balancer Controller がデプロイされ、READY 状態になっていることを確認する。
$ helm list -n kube-system
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
aws-load-balancer-controller kube-system 2 2022-01-01 00:00:00.309065 +0900 JST deployed aws-load-balancer-controller-1.4.2 v2.4.2
$ kubectl get deployment -n kube-system aws-load-balancer-controller
NAME READY UP-TO-DATE AVAILABLE AGE
aws-load-balancer-controller 2/2 2 0 22m
(3)-
もし、以下のように、
53番ポートへの接続でエラーになってしまう場合は、CoreDNS による名前解決が正しくできていない。そのため、CoreDNSが正常に稼働しているか否かを確認する。
{
"level": "error",
"ts": "*****.*****",
"logger": "controller-runtime.manager.controller.ingress",
"msg": "Reconciler error",
"name": "foo-ingress",
"namespace": "foo",
"error": "ingress: foo/foo-ingress: WebIdentityErr: failed to retrieve credentials\ncaused by: RequestError: send request failed\ncaused by: Post \"https://sts.ap-northeast-1.amazonaws.com/\": dial tcp: lookup sts.ap-northeast-1.amazonaws.com on *.*.*.*:53: read udp *.*.*.*:43958->*.*.*.*:53: read: connection refused",
}
(4)-
Ingress をデプロイし、Ingress から AWS ALB を自動的に作成させる。
以下の条件を満たす必要がある。
02-02. マニフェスト¶
マニフェストの種類¶
AWS Load Balancer Controller は、Deployment (aws-load-balancer-controller) 、Service (aws-load-balancer-controller-webhook-service) 、TargetGroupBinding、MutatingWebhookConfiguration などのマニフェストから構成されている。
Deployment配下のPod¶
▼ aws-load-balancer-controller¶
Deployment は、Ingress で alb の IngressClass を指定していること検知して、AWS ALB をプロビジョニングする。
apiVersion: v1
kind: Pod
metadata:
name: aws-load-balancer-controller
namespace: kube-system
spec:
containers:
- args:
# AWS ALBでL7ロードバランシングするCluster名を設定する
- "--cluster-name=foo-cluster"
# Ingressに紐づけるIngressClassを設定する
- "--ingress-class=alb"
# AWS ALBのあるリージョンを設定する
- "--aws-region=ap-northeast-1"
# AWS ALBのあるVPCのIDを設定する
- "--aws-vpc-id=vpc-*****"
name: aws-load-balancer-controller
image: public.ecr.aws/eks/aws-load-balancer-controller:v2.4.0
ports:
# 内蔵されているwebhookサーバー
- containerPort: 9443
name: webhook-server
protocol: TCP
# 内蔵されているmetricsサーバー
- containerPort: 8080
name: metrics-server
protocol: TCP
MutatingWebhookConfiguration¶
Webhook の宛先の Service を決定する。
Service を経由して、aws-load-balancer-controller に内蔵されている webhook サーバーに Webhook リクエストを送信する。
この webhook サーバーが AdmissionResponse を作成し、これを kube-apiserver に返信する。
AdmissionResponse に応じて、kube-apiserver はマニフェストを変更する。
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: aws-load-balancer-webhook
webhooks:
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: ...
service:
name: aws-load-balancer-webhook-service
namespace: kube-system
path: /mutate-v1-pod
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: mpod.elbv2.k8s.aws
namespaceSelector:
matchExpressions:
- key: elbv2.k8s.aws/pod-readiness-gate-inject
operator: In
values:
- enabled
objectSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: NotIn
values:
- aws-load-balancer-controller
reinvocationPolicy: Never
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- pods
scope: "*"
sideEffects: None
timeoutSeconds: 30
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: ...
service:
name: aws-load-balancer-webhook-service
namespace: kube-system
path: /mutate-elbv2-k8s-aws-v1beta1-targetgroupbinding
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: mtargetgroupbinding.elbv2.k8s.aws
namespaceSelector: {}
objectSelector: {}
reinvocationPolicy: Never
rules:
- apiGroups:
- elbv2.k8s.aws
apiVersions:
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- targetgroupbindings
scope: "*"
sideEffects: None
timeoutSeconds: 30
Service¶
AWS Load Balancer Controller が作成された場合に、webhook サーバーに Webhook リクエストを送信する。
ここでは、ClusterIP Service を使用する。
apiVersion: v1
kind: Service
metadata:
name: aws-load-balancer-webhook-service
namespace: kube-system
spec:
ports:
- name: webhook-server
port: 443
protocol: TCP
targetPort: webhook-server
selector:
app.kubernetes.io/instance: aws-load-balancer-controller
app.kubernetes.io/name: aws-load-balancer-controller
type: ClusterIP
ServiceAccount¶
IRSA の仕組みで、Pod と IAM ロールを紐付ける。
apiVersion: v1
kind: ServiceAccount
metadata:
name: foo-aws-load-balancer-controller
namespace: kube-system
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<アカウントID>:role/foo-aws-load-balancer-controller-role
secrets:
- name: foo-aws-load-balancer-controller-token
TargetGroupBinding¶
記入中...
kind: TargetGroupBinding
metadata:
name: foo-target-group-binding
namespace: foo
spec:
serviceRef:
name: foo-service
port: 80
targetGroupARN: <ターゲットグループのARN>
