こんにちは。みらい翻訳 SRE チームの jeff です。
現在 SRE で EKS 導入を進めています。
EKS を導入するにあたり、EKS でロードバランサー気軽に扱えるように aws-loadbalancer-controller を有効化しようとしましたが、色々とハマりポイントがあったので備忘として記事にしました。
aws-loadbalancer-controller とは
EKS で使用するロードバランサーを管理してくれるアドオンです。
Ingress リソースを apply すると自動で ALB, NLB を作ってくれます。
aws-loadbalancer-controller 導入経緯
EKS で LoadBalancer サービスを作成した場合、デフォルトでは自動で ELB の一つである CLB(Classic Load Balancer)が作られます。 現在構築している EKS は Fargate 環境を使用しています。しかし、 Fargate は CLB に対応していません。 そのため EKS が Fargate に対応したロードバランサー (具体的には ALB(Application Load Balancer) ) を作れるように aws-loadbalancer-controller を導入しようというのが今回の経緯になります。
導入の前に
確認環境
以下の環境で導入及び動作確認をしています。
- EKS on Fargate
- Kubernetes 1.22
- aws-loadbalancer-controller 2.4.2
前提条件の確認
AWS のマニュアルから EKS で ALB を使えるようにするための前提条件を確認します。
導入手順
基本的には以下のマニュアルに沿っていけば導入を進めます。
aws-loadbalancer-controller を導入する
IAM ロールを作る
aws-loadbalancer-controller のサービスアカウントが ELB を管理するために使用する IAM ロールを作成します。 また、ロールに必要な IAM OIDC プロバイダーとポリシーを作成します。
EKS クラスタ用の IAM OIDC プロバイダーを作成する
$ aws iam create-open-id-connect-provider \ --url [クラスターのOIDCプロバイダURL] \ --client-id-list "sts.amazonaws.com" \ --thumbprint-list [サムプリント]
クラスターのOIDCプロバイダURL 確認
以下のコマンドで確認します。
$ aws eks describe-cluster \ --name [EKS クラスター名] --query "cluster.identity.oidc.issuer" \ --output text
サムプリント確認
こちらの手順でサムプリントを確認します
画面から登録
サムプリントの確認が手間な場合はマネジメントコンソールからも登録できます。
- AWS マネジメントコンソールの IAM 管理画面で [ID プロバイダ] を開きます
- [プロバイダを追加] を押します
- プロバイダのタイプを
OpenID Connect
を選択します - プロバイダURLに上記
クラスターのOIDCプロバイダURL 確認
で取得した URL を入力します。 - [サムプリント取得] を押します
- 対象者に
sts.amazonaws.com
を入力します - [プロバイダを追加] を押します
ポリシーの作成
aws-loadbalancer-controller に必要なポリシーを作成します。 以下の json を使用してポリシーを作成します。
$ aws iam create-policy \ --policy-name [ポリシー名] \ --policy-document file://iam_policy.json
ロールの作成
AssumeRole Policy の用意
AWS のドキュメントに沿って AssumeRole Policy の JSON を用意します。
cat >load-balancer-role-trust-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com", "oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller" } } } ] } EOF
ロールの作成&ポリシーアタッチ
こちらも AWS のドキュメントに沿ってロールの作成とポリシーアタッチを行います。
上記で作成した assume role policy の json を使用して IAM ロールを作成します。
$ aws iam create-role \ --role-name [IAM ロール名] \ --assume-role-policy-document file://"load-balancer-role-trust-policy.json"
「ポリシーの作成」で作ったポリシーを先ほど作成したロールにアタッチします。
$ aws iam attach-role-policy \ --policy-arn [IAM ポリシー ARN] \ --role-name [IAM ロール名]
EKS クラスターにサービスアカウント作成
aws-loadbalancer-controller のサービスアカウントを作成します。アノテーションに上記で作成したロールを設定してサービスアカウントが IAM ロールを使用できるようにします。
apply する yaml を用意します。
cat >aws-load-balancer-controller-service-account.yaml <<EOF apiVersion: v1 kind: ServiceAccount metadata: labels: app.kubernetes.io/component: controller app.kubernetes.io/name: aws-load-balancer-controller name: aws-load-balancer-controller namespace: kube-system annotations: eks.amazonaws.com/role-arn: [IAM ロール ARN] EOF
上記で作成した yaml を apply します。
kubectl apply -f aws-load-balancer-controller-service-account.yaml
これで認証周りの準備は OK です。
eksctl を使う
ここまで IAM ロールとサービスアカウントの準備について書きましたが、eksctl を使えばワンコマンドでサクッと作ることができます(ポリシーだけは事前に作成しておきます)。
$ eksctl create iamserviceaccount \ --cluster=[EKS クラスター名] \ --namespace=kube-system \ --name=aws-load-balancer-controller \ --role-name [IAM ロール名] \ --attach-policy-arn=[IAM ポリシー ARN] \ --approve
aws-loadbalancer-controller インストール
認証周りの準備ができたら aws-loadbalancer-controller をインストールします。 Fargate だと cert-manager に対応していないため helm でインストールします。
$ helm repo add eks https://aws.github.io/eks-charts $ helm repo update
AWS のドキュメント通りでインストールは問題ないですが、Fargate だとリージョンコードと vpcId が必須になります。
$ helm install aws-load-balancer-controller eks/aws-load-balancer-controller \ -n kube-system \ --set clusterName=[EKS クラスター名] \ --set serviceAccount.create=false \ --set serviceAccount.name=aws-load-balancer-controller \ --set region=[リージョン名] \ --set vpcId=[EKS クラスターが属している VPC の Id]
これで aws-loadbalancer-controller のインストールは完了です!
動作確認
aws-loadbalancer-controller のインストールが完了しました。EKS クラスタで Ingress リソースを特定のアノテーションを付けて作成すると ALB を自動で作ってくれるので試してみます。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/target-type: ip alb.ingress.kubernetes.io/backend-protocol-version: HTTP1 alb.ingress.kubernetes.io/healthcheck-path: /health alb.ingress.kubernetes.io/success-codes: '200' name: test namespace: test spec: rules: - host: hogehoge.com http: paths: - path: pathType: ImplementationSpecific backend: service: name: test port: number: 80
ALB の作成に失敗する
この yaml を apply してみましたがエラーが出てしまいました(エラーメッセージは失念してしまいました)。 pods の状況を確認したところ、pods の起動に失敗していました。
$ kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE aws-load-balancer-controller-xxxxxxxxxx-xxxxx 0/1 ImagePullBackOff 0 10m aws-load-balancer-controller-xxxxxxxxxx-xxxxx 0/1 ImagePullBackOff 0 10m coredns-xxxxxxxxxx-xxxxx 0/1 ImagePullBackOff 0 10m coredns-xxxxxxxxxx-xxxxx 0/1 ImagePullBackOff 0 10m
STATUS をみてみるとイメージの Pull に失敗しているようなことがわかります。 さらに describe で pods の情報を見てみます。
$ kubectl describe pod aws-load-balancer-controller-xxxxxxxxxx-xxxxx -n kube-system (中略) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning LoggingDisabled 6m48s fargate-scheduler Disabled logging because aws-logging configmap was not found. configmap "aws-logging" not found Normal Scheduled 5m57s fargate-scheduler Successfully assigned kube-system/aws-load-balancer-controller-xxxxxxxxxx-xxxxx to fargate-ip-xxx-xxx-xxx-xxx.us-west-2.compute.internal Warning Failed 3m26s kubelet Failed to pull image "602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.3": rpc error: code = Unknown desc = failed to pull and unpack image "602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.3": failed to resolve reference "602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.3": failed to do request: Head "https://602401143452.dkr.ecr.us-west-2.amazonaws.com/v2/amazon/aws-load-balancer-controller/manifests/v2.4.3": dial tcp xxx.xxx.xxx.xxx:443: i/o timeout Warning Failed 40s (x2 over 3m26s) kubelet Error: ErrImagePull Warning Failed 40s kubelet Failed to pull image "602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.3": rpc error: code = Unknown desc = failed to pull and unpack image "602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.3": failed to resolve reference "602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.3": failed to do request: Head "https://602401143452.dkr.ecr.us-west-2.amazonaws.com/v2/amazon/aws-load-balancer-controller/manifests/v2.4.3": dial tcp xxx.xxx.xxx.xxx:443: i/o timeout Normal BackOff 25s (x2 over 3m25s) kubelet Back-off pulling image "602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.3" Warning Failed 25s (x2 over 3m25s) kubelet Error: ImagePullBackOff Normal Pulling 12s (x3 over 5m57s) kubelet Pulling image "602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon/aws-load-balancer-controller:v2.4.3"
ネットワーク設定不備
aws-load-balancer-controller のイメージ Pull に失敗する原因としては EKS を構築した VPC では ECR の VPC エンドポイントを使用していたためでした。 ECR への接続はプライベートなネットワークで行われていて、 ECR の VPC エンドポイントが EKS からの接続を許可していませんでした。そのため、ECR の VPC エンドポイントに設定しているセキュリティグループの ingress に EKS クラスタに設定しているセキュリティグループを追加したところ、イメージが Pull されるようになりました。
ただ、これだけでは解決しませんでした・・・
ALB の作成に失敗する2
ingress の apply でエラーは出なくなりましたが、なぜか ALB が作られません。再度 pods の状況を見たところ、 coredns が起動していないことに気づきました。
$ kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE aws-load-balancer-controller-xxxxxxxxxx-xxxxx 1/1 Running 0 15m aws-load-balancer-controller-xxxxxxxxxx-xxxxx 1/1 Running 0 15m coredns-xxxxxxxxxx-xxxxx 0/1 ImagePullBackOff 0 15m coredns-xxxxxxxxxx-xxxxx 0/1 ImagePullBackOff 0 15m
aws-load-balancer-controller のログをみてみると、名前解決できていないようなエラーが出ていたので coredns が起動していないことが原因のように思われました。
$ kubectl logs aws-load-balancer-controller-xxxxxxxxxx-xxxxx -n kube-system {"level":"error","ts":1661560470.824888,"logger":"controller-runtime.manager.controller.ingress","msg":"Reconciler error","name":"test","namespace":"test-namespace","error":"ingress: test-namespace/test: WebIdentityErr: failed to retrieve credentials\ncaused by: RequestError: send request failed\ncaused by: Post \"https://sts.us-west-2.amazonaws.com/\": dial tcp: lookup sts.us-west-2.amazonaws.com on xxx.xxx.xxx.xxx:xxx: read udp xxx.xxx.xxx.xxx:xxxxx->xxx.xxx.xxx.xxx:xxx: read: connection refused"} {"level":"error","ts":1661560654.9364552,"logger":"controller-runtime.manager.controller.ingress","msg":"Reconciler error","name":"test","namespace":"test-namespace","error":"ingress: test-namespace/test: WebIdentityErr: failed to retrieve credentials\ncaused by: RequestError: send request failed\ncaused by: Post \"https://sts.us-west-2.amazonaws.com/\": dial tcp: lookup sts.us-west-2.amazonaws.com on xxx.xxx.xxx.xxx:xxx: read udp xxx.xxx.xxx.xxx:xxxxx->xxx.xxx.xxx.xxx:xxx: read: connection refused"}
coredns が原因を調べていたところ、coredns は Fargate だとデフォルトから設定変更が必要とのことを公式ドキュメントで確認しました。
coredns を Fargate 用に設定変更
ドキュメント通りに設定すればOKです
profile の作成
$ aws eks create-fargate-profile \ --fargate-profile-name coredns \ --cluster-name [EKS クラスタ名] \ --pod-execution-role-arn [pod 実行 IAM ロール ARN] \ --selectors namespace=kube-system,labels={k8s-app=kube-dns} \ --subnets [サブネットID1] [サブネットID1] [サブネットID1]
アノテーションの削除
$ kubectl patch deployment coredns \ -n kube-system \ --type json \ -p='[{"op": "remove", "path": "/spec/template/metadata/annotations/eks.amazonaws.com~1compute-type"}]'
設定を完了したら pod を再起動すれば OK です
$ kubectl rollout restart -n kube-system deployment coredns
動作確認2
再度 ingress を apply すると aws-loadbalancer-controller から作成した ALB が作られているのを確認できます。
$ aws elbv2 \ describe-load-balancers \ --query "LoadBalancers[].LoadBalancerName" \ --region us-west-2 \ --output text k8s-eksmanag-test-xxxxxxxx
終わりに
今回は EKS on Fargate で aws-loadbalancer-cotroller を導入して動作確認するところまではまった点を書きました。この後 EKS の構築を terraform 化したのでそのことについて書こうと思います。
みらい翻訳ではSREを募集しています
EKS の構築・運用に興味がある方、その他運用改善など SRE に興味がある方を募集しております。 ご興味がおありの方は下記のリンクからご応募・お問い合わせをお待ちしております。