DoiTのChris McGrathが、Kubernetes AWS Load Balancer Controllerの仕組みと裏側の動作を解説します。

BLUF(要点)
Kubernetesコミュニティには、Kubernetes本体に組み込まれている機能は名前にkubernetes.ioを含み、アドオンには含めないという慣例があります。アドオンはebs.csi.aws.comのように、名前を見ただけでアドオンだと判別できる自己説明的な命名規則に従うのが一般的です。ところが、aws-load-balancer-controllerアドオンはこの慣例から外れています。
想定読者
本記事の想定読者と目的は次の3つです。
1. AWS上でEKSや汎用Kubernetesディストリビューションを運用しているKubernetes管理者。今すぐ読む必要はありませんが、ブックマークしておくことをおすすめします。service.beta.kubernetes.io/aws-load-balancer-*のようなアノテーションを使ったKubernetes ServiceでAWS Load Balancerをプロビジョニングする際、デバッグが必要になったときの参考資料として活用してください。
2. Kubernetesの理解を深めたい、深掘り記事が好きなKubernetesマニア。
3. EKS、aws-cloud-controller-manager、aws-load-balancer-controller、AWS Docsのメンテナーの皆さま。本記事の狙いは、AWS上のKubernetes Load Balancerプロビジョニングに固有の、わかりにくい不整合に光を当てることです。Kubernetesコミュニティ全体との整合性に向けた変更が促されることを願っています(この問題は複数のgitリポジトリやドキュメントサイトにまたがっており、いくつかのMerge Requestで解決できるものではありません)。
はじめに
最近、EKS(Elastic Kubernetes Service)クラスターにAWS Load BalancerをプロビジョニングするPoC(概念実証)に取り組み始めました。service.beta.kubernetes.io/aws-load-balancer-*形式のアノテーションを付けたtype LoadBalancerのKubernetes Serviceを使う方式で、アノテーションの一覧はこのページに掲載されています。
当初、いくつかのアノテーションが期待どおりに動作しませんでした。トラブルシュート自体はできたのですが、注目すべきは、デバッグするためには「なぜ動かないのか」を理解する必要があったという点です。リンク先のドキュメントは仕組みの説明としては悪くないものの、初心者向けとは言いがたい内容です。
そこで本記事では、以下のトピックを深掘りして解説します。
- aws-load-balancer-controllerがわかりにくい理由
- 初心者がキャッチアップするための背景情報
- なぜ現在の動作になっているのかの詳細
- 基本的ながら役立つトラブルシューティングのコツ
- 各メンテナーグループが今後この混乱を減らすためにできること
課題:取り違えやすい正体
先に述べたとおり、リンク先のページは初心者にあまり優しくありません。具体的には、私自身、このプロジェクトを理解するのに丸一日かかるほど混乱しました。2018年7月からKubernetesのSME(専門家)として活動してきた私がそうだったというのは、由々しきサインです。理解できた直後の感想は「ああ、そういうことか。今日学んだ(TIL):type Load BalancerのKubernetes Serviceに付けたアノテーションを使ってAWS LBをプロビジョニング・管理するAWS固有のKubernetesコントローラーが、実は2種類存在する」というものでした。次に思ったのは「専門家がいない状況で、ほかの人はどうやってこれを理解するんだ……? 記事を書こう」でした。
AWS Load Balancer Controllerプロジェクトをわかりにくくしている要因をまとめると:
1.) 公式の組み込み機能のように見えるが、実はそうではない
「aws service of type lb」でGoogle検索をすると:
1番目の結果:docs.aws.amazon.com/eks/latest/userguide/network-load-balancing.html
2番目の結果:kubernetes-sigs.github.io/aws-load-balancer-controller/v2.4/guide/service/annotations/
そして「kubernetes service of type loadbalancer」で検索した際の1番目の結果である、Kubernetes公式ドキュメントの該当セクション:
https://kubernetes.io/docs/concepts/services-networking/service/
これら3ページはどれも公式ドキュメントのように見え、しかも同じアノテーションが3ページすべてに登場するため、同じトピックを扱っているように見えます。
3ページすべてで以下の文字列をCtrl+F検索してみてください:
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags
同じリソースが3ページすべてに登場します。これだけ見ると、3つのサイトが同じものを説明していると思ってしまいます。
実際には、aws-load-balancer-controllerは組み込み機能を拡張するKubernetesアドオンです。つまり、上記3つのリンクのうち2つは組み込み機能を扱っており、3つ目は機能を拡張するアドオンを扱っているのです。
2.) プロジェクトのウェブサイトとアノテーションの命名規則が直感に反しており、組み込み機能を参照しているかのように錯覚させる
2A.) プロジェクトのドキュメントがホストされているDNS名はkubernetes-sigs.github.ioで、これだけ見るとKubernetesの組み込み機能のように見えます。
2B.) アドオンのアノテーションはservice.beta.kubernetes.ioを参照していますが、これは通常、組み込み機能のために予約されているものです。
3.) プロジェクトのドキュメントサイトのトップページでは、これがKubernetesの組み込み機能を拡張するアドオンであることが一目では分からない
ドキュメントの2ページ目の下部までスクロールして
helm install aws-load-balancer-controllerを見つけて初めて、「ああ! アドオンだったのか、なるほど」と腑に落ちます。
4.) APIが採用しているパターンが、Kubernetesコミュニティ全体の標準パターンと一致していない
標準的なパターンの例として、Cert ManagerとEBS Volume CSI(Container Storage Interface)ドライバーを取り上げます。
- cert-managerのドキュメントでは、アノテーションの95%が
cert-manager.ioを使っています。これにより、アノテーションがサードパーティのアドオンを参照していることが一目で直感的にわかります。 - ドキュメントのトップページの最初の文は「cert-manager adds certificates and certificate issuers as resource types in Kubernetes clusters…」となっており、このプロジェクトが機能を追加する拡張であることを冒頭で明確にしています。
- EBS Volume CSI Driverの場合、組み込み機能とは別物であることが一目で直感的にわかる命名規則が用いられています。
組み込みのAWS Storage Classはprovisioner: kubernetes.io/aws-ebsを使用
EBSアドオンのStorage Classはprovisioner: ebs.csi.aws.comを使用
- EBS CSI関連の複数のドキュメントサイトでは、トップページの冒頭で「これはデフォルトではインストールされないアドオンである」ことを繰り返し明示しているのが一般的です。このプロジェクトのドキュメントでは、より直感的にするため、あえて「driver」というキーワードを含めています:「The Amazon EBS CSI driver isn't installed when you first create a cluster. To use the driver, you must add it as an Amazon EKS add-on or as a self-managed add-on.」 また、ドキュメントではなくGitHubページに辿り着いた場合に備えて、プロジェクトのGitHubトップページにも「Driver Installation」へのリンクが用意されています。
5.) AWSのUIとドキュメントもaws-load-balancer-controllerに関しては一貫していない
AWS Load Balancer Controllerにはdocs.aws.amazon.comに「Installing the AWS Load Balancer Controller add-on」というユーザーガイドがあります。
しかしGUIで見ると、公式アドオンとしては表示されません。「Get more add-ons」をクリックしてAmazon EBS CSI DriverやAWS Distro for OpenTelemetryが表示される画面でも出てきません。

6.) プロジェクトに背景情報が欠けている
ドキュメントのservice annotationページでは、2つのトピックに簡単に触れています。これらは理解しておくと役立つ(理解はトラブルシュートの助けになる)一方で、追加の説明なしでは初心者が把握するのはほぼ不可能なものです。Googleで調べても、得られる情報は非常に曖昧で断片的、しかも多くのニュアンスを汲み取れない限り矛盾して見えるものばかりです。
ドキュメントで説明なしに簡単に触れられている2つのトピックとは:
1. 「in-tree」:「the k8s in-tree kube-controller-manager」
2. 「Legacy AWS Cloud Provider」:「The AWS Load Balancer Controller manages Kubernetes Services in a compatible way with the legacy aws cloud provider.」
本来であれば、これらの言葉の意味の要約と、興味のある人向けに参考リンクを添えるのが理想です。私なりに要約すると、技術的には2つは別物ですが、実質的には同じものとして扱って問題ありません。Legacy AWS Cloud Providerは、AWS上で動作するKubernetesクラスターに対してtype Load Balancerのサービスをプロビジョニングする、デフォルトの組み込み機能を提供するものです。
背景情報
何かをトラブルシュートするとき、私が最初にするのは対象を理解することです。AWS LBのプロビジョニングというトピックを完全に理解するには、多くの背景情報が必要です。残念ながら、これまでこの情報は散在しており、深く掘り下げて説明されることもなく、把握しにくいニュアンスにあふれていました。本記事は、いくつかの重要な背景情報をまとめ、理解しやすくしようとする試みです。
主要トピックの背景情報
1.) kube-controller-manager vs cloud-controller-manager vs aws-cloud-controller-manager
「in-tree」と「Legacy AWS Cloud Provider」が指すものには微妙なニュアンスがあり、関連トピックの背景を押さえないと把握しづらいので、ここから始めます。
かつてKubernetesのコントロールプレーンは、controller-manager、scheduler、api-server、etcdの4つのコンポーネントで構成されていました。kube-controller-managerかcloud-controller-managerのどちらか一方を実行する形で、両方を同時に動かすことはありませんでした。
95%のケースで使われていたのはcloud-controller-managerです。kube-controller-managerと同じ機能に加えて、複数のCSP(クラウドサービスプロバイダー)APIとやり取りする機能が組み込まれていました。CSP APIと通信できるため、AWS EBSボリュームやAWS Load Balancerのプロビジョニングなどが可能でした。
kube-controller-managerはクラウド非依存の実装であり、CSPストレージやCSP Load Balancerの自動プロビジョニングといった組み込み機能はありません。
現在のKubernetesでは、コントロールプレーンは通常5つのコンポーネントで構成されます。
etcd、kube-api-server、kube-scheduler、kube-controller-manager、そしてaws-cloud-controller-managerのようなCSP固有のcontroller managerです。Kubernetes公式ドキュメントの図もこの新しいアーキテクチャを反映するように更新されています。kopsやkubeadmなど、コントロールプレーンが見えるデプロイ方法を使えば、これを確認できます。主な変更点は、特定のクラウドサービスプロバイダー専用のcloud controller managerが存在し、それらをkube-controller-managerと並行して実行する設計になったことです。元のcloud-controller-managerは、より汎用的なオールインワンソリューションでした。
2.) 「In-tree」とは、複数のCSP APIとやり取りできるGo言語ライブラリがKubernetesリポジトリ内に存在し、汎用Kubernetes Cloud Controller Managerコンテナイメージをビルドしていた時期を指す
In-tree:Kubernetesのコアリポジトリk8s.io/kubernetes内に存在するコード。
Out-of-Tree:k8s.io/kubernetesのgitリポジトリ外の外部リポジトリに存在するコード。
Kubernetes 1.14のコードベースには、8種類のCSP用APIが組み込まれていました。さらに追加したいCSPもありましたが、すべてが一緒にバンドルされているということは、リリースのために全部が同時に安定状態に到達しなければならないことを意味します。これは保守性の観点で持続不可能なパターンでした。この問題に対処するため、KEP(Kubernetes Enhancement Proposal)が承認され、CSP機能をKubernetesから切り離してアドオンとしてリファクタリングすることが提案されました。
この機能の分離により、Kubernetesのリリースプロセスが簡素化され、クラウドプロバイダーはKubernetesのリリースサイクルやプロセスに縛られずに機能やバグ修正をリリースできるようになります。プロジェクトの長期的な健全性を確保するため、技術的負債を返済する判断でした。
3.) このトピックを自分で調べると、複数のニュアンスを汲み取れない限り矛盾して見える情報がいくつも見つかります。順不同でいくつかのニュアンスを挙げます:
- in-treeからout-of-treeへの移行は何年もかかっているように見えます。一方で、ずっと昔に始まりずっと昔に完了したかのような情報も多くあります。異なる時期に始まり完了したという情報も、いまだに進行中だという情報もあります。
- 先ほどKubernetes 1.14のコードベースには8種類のCSP用APIがあったと述べました。
Kubernetes 1.26のコードベースを見ると、依然として4種類のCSPがin-treeに存在します。AWSもまだin-tree CSPのリストに含まれています。一方でaws-cloud-providerを参照するout-of-treeのgitリポジトリを見ると、AWSは1.20の時点で移行を完了しているように読めます。
さらにKEPでは移行はバージョン1.27あたりで完了する見込みと示されています。
こうした事情があるため、私はドキュメントの問題修正にコントリビュートするのではなく、この記事を書くことを選びました。AWSや他のCSPはin-tree、つまり汎用CSP版のcloud controller managerに依然として存在するものの、実際にはそのバージョンは使われていません。AWSや他のCSPは、古いin-tree汎用オールインワンcloud-controller-managerではなく、aws-cloud-controller-managerのようなCSP固有の実装を使っています。
各CSPは、汎用in-treeからCSP固有のout-of-treeへの移行を、それぞれ異なるペースで進めてきました。さらに少しややこしいのは、この複雑な作業が2つに分割されたことです。元のin-tree組み込み機能には、CSPストレージとCSP LBをプロビジョニングするロジックが含まれていました。それがout-of-treeに移されただけでなく、さらに分離されて、CSPストレージ用のCSIドライバーが、独自の移行スケジュールを持つ独立したコンポーネントになったのです。
- このリファクタリングの複雑さの規模を理解すると、いくつかのことが腑に落ちます。第一に、リファクタリングに4年以上かかっているのも当然です。Out-of-tree cloud providerの実装機能はバージョン1.11でベータステータスに到達しました。2019年5月のことです。第二に、移行プロセスを支えるために複数の機能凍結(feature freeze)が実施されたことを知ると、AWS LB上で
ExternalTrafficPolicy: Localを実装する際のバグなどが、修正されるまでに何年もかかった理由が見えてきます。組み込みのAWS LBプロビジョニングロジックに対する機能拡張が長年ほとんどなかった理由も、これで説明がつきます。
4.) 「Legacy AWS Cloud Provider」は基本的に、EKSまたはAWS上のKubernetesのデフォルトインストールで利用できる、デフォルトのload balancerプロビジョニング機能を指す
厳密には100%正確とは言えないニュアンスがいくつかありますが、実用上は十分に近い表現です。
そのニュアンスは次のとおりです。
- Legacy AWS Cloud Providerは、(汎用CSP版の)cloud-controller-manager内にin-treeで存在していた、AWS EBSボリュームやAWS LBをプロビジョニングできるAWS固有のロジックを指すことがあります。
- Legacy AWS Cloud Providerは、aws-cloud-controller-managerに存在するデフォルトのload balancerプロビジョニングロジックを指すこともあります。
- aws-cloud-controller-managerはユーザーから見えないことが多いです。
– EKSを使っている場合、aws-cloud-controller-managerはマネージドのマスターノードで動作するため、見えません。
– kopsやkubeadmのようにセルフホスト型のマスターノードを使っている場合は見えます。
– RKE2を使っている場合、特定のコントロールプレーンコンポーネントをKubernetesから隔離されたプロセスとして動かす多層防御セキュリティの実装上の都合で、見えません。
- Legacy AWS Cloud Providerは2つの異なるものを指す可能性がありますが、AWS LBの文脈では同じアノテーションをサポートしているため、実質的に同じものです。元の22個のアノテーションは、このページで
const ServiceAnnotationLoadBalancerという文字列を検索すると見つけられます。本稿執筆時点では、ドキュメントページでservice.beta.kubernetes.io/aws-load-balancerを検索すると21個のアノテーションしか見つからない点に注意してください。これはドキュメントの問題であり、コードの変更ではありません。
デフォルトで利用できる22個のアノテーションは以下のとおりです。
service.beta.kubernetes.io/aws-load-balancer-typeservice.beta.kubernetes.io/aws-load-balancer-internalservice.beta.kubernetes.io/aws-load-balancer-proxy-protocolservice.beta.kubernetes.io/aws-load-balancer-access-log-emit-intervalservice.beta.kubernetes.io/aws-load-balancer-access-log-enabledservice.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-nameservice.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefixservice.beta.kubernetes.io/aws-load-balancer-connection-draining-enabledservice.beta.kubernetes.io/aws-load-balancer-connection-draining-timeoutservice.beta.kubernetes.io/aws-load-balancer-connection-idle-timeoutservice.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabledservice.beta.kubernetes.io/aws-load-balancer-extra-security-groupsservice.beta.kubernetes.io/aws-load-balancer-security-groupsservice.beta.kubernetes.io/aws-load-balancer-ssl-certservice.beta.kubernetes.io/aws-load-balancer-ssl-portsservice.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policyservice.beta.kubernetes.io/aws-load-balancer-backend-protocolservice.beta.kubernetes.io/aws-load-balancer-additional-resource-tagsservice.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-thresholdservice.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-thresholdservice.beta.kubernetes.io/aws-load-balancer-healthcheck-timeoutservice.beta.kubernetes.io/aws-load-balancer-healthcheck-interval5.) AWS Load Balancer ControllerプロジェクトはAWS EBS CSI Driverプロジェクトと概念的に類似している
どちらも、汎用オールインワンcloud-controller-managerにin-treeで存在していたKubernetes Controllerロジックの分離を体現しています。両者とも下位互換性の確保という共通の目的を持っていました。これがプロジェクトが一部のアノテーションを再利用するという判断につながったのではないか、と私は推測しています。
6.) EBS CSI DriverアドオンとAWS LB Controllerアドオンの両プロジェクトは、別々のグループによって開始された
EBS CSI DriverアドオンプロジェクトはAWSが開始しました。AWS LB ControllerアドオンプロジェクトはもともとTicketmasterとCoreOSが開始したもので、以前は「AWS ALB Ingress Controller」として知られていました。2018年にKubernetes SIG-AWSへ寄贈されたものです。ALB Ingress Controllerは当初「Application Load Balancer Controller」と表現するのが最もふさわしいものでした。やがてプロジェクトのスコープがNLBの制御も含むように広がったため、2021年7月に「AWS Load Balancer Controller」へとリブランドされました。
なぜ今の形になっているのか
もしオールインワン汎用cloud-controller-managerのロジックがout-of-treeの分離されたアドオンに移されていなかったら、技術的負債が今後の機能開発とバグ修正をすべて恒久的に遅らせていたでしょう。externalTrafficPolicy: local関連のバグが何度も再発し、適切に修正されるまで何年もかかった時期を覚えています。今やロジックは公式Kubernetesプロジェクトのコード、リリースプロセス、テストから切り離されています。バグは数年ではなく数か月で修正されるようになり、機能要望も再び検討されるようになりました。
開発の高速化は、AWS CognitoとALBプロビジョニングロジックの新たな統合により、Authn/zプロキシ経由のSoftware Defined Perimeter(SDP)の概念を実装しやすくするなど、大きな改善をもたらしました。AWS LB Controllerプロジェクトでは、アノテーション経由でNLBをプロビジョニングする際のオプションも増えています。私が特に気に入っている新機能の1つは、service.beta.kubernetes.io/aws-load-balancer-nlb-target-type:アノテーションです。これにより、バックエンドのPodへのトラフィックの経路を選べます。デフォルト値の"instance"では、トラフィックはnELB -> NodePort -> Kube service -> Podと流れます。新たに追加された値"ip"では、aELBの動作と同様に、nELB -> Podと直接流れるようになります。
略語リファレンス:
nELB = network Elastic Load Balancer(L4 LB as a service)
aELB/ALB = application Elastic Load Balancer(L7 LB as a service)
cELB = classic Elastic Load Balancer(L4/L7 LB as a service)
ALB Ingress Controllerとして知られていたプロジェクトにNLB管理が組み込まれるというスコープ拡大が起きた理由の一部は、aws-cloud-controller-managerがin-tree移行のために機能凍結中だった時期に、ALB Ingress Controllerプロジェクトのほうが変更や新機能を受け入れやすかったからではないか、と私は推測しています。
では、なぜAWS Load Balancer ControllerはAWS EBS CSI Driverアドオンのような形になっていないのでしょうか。これは、AWSがEBS CSIプロジェクトを最初から最後まで主導していたのに対し、LB Controllerプロジェクトは引き継いだものであり、大組織はブルックスの法則のために変更の実装が遅くなりがちだ、ということと関係していると思います(大組織ではコミュニケーションのオーバーヘッドが変更を大きく遅らせます)。
AWS LB Controllerトラブルシューティングのコツ
これらのトラブルシューティングのコツは、網羅的・徹底的なものを目指したものではありません。あくまで詰まった状況を打開し、フォローアップ調査に役立つトピックの方向性を示せる程度に有用であることを意図しています。
1.) AWS LB Controllerがインストールされているかを確認する
kubectl get deployments --namespace=kube-system
これが重要なのは、挙動に大きな違いを生み得るからです。たとえば2つのクラスターでデプロイされているYAML workloadsと設定の99%が同じで、1%の違いがAWS LB Controllerのインストール有無だけだとしても、99%同じYAMLが異なる結果を生むことがあります。
2.) 最新バージョンへのアップデートを強く検討する
以下のコマンドで実行中のバージョンを確認できます。
kubectl get deploy aws-load-balancer-controller -n=kube-system -o yaml | grep image:
image: public.ecr.aws/eks/aws-load-balancer-controller:v2.4.6
最新を保つというプラクティスが役立った最近の実例を紹介します。
EKS 1.21は2023年2月15日にEnd of Lifeを迎えました。AWS LB Controllerの一部ユーザーは2.3.x → 2.4.xにアップデートするまで障害を経験しました。原因は、Kubernetes 1.21から1.22へのアップグレードで多くの非推奨APIが削除されたことです。AWS LB Controller 2.4.xは新しいnetworking.k8s.io/v1 Ingress APIをサポートしています。2.3.xは古いAPIであるnetworking.k8s.io/v1beta1のみをサポートしており、これはKubernetes 1.22で削除されました。aws-lb-controllerプロジェクトのissueチケットでこれが問題になることが認識され、2.4.x系がKubernetes 1.19以降で動作するよう対応されたため、各組織は移行の時間を確保できました。アドオンを最新に保つベストプラクティスに従っていた組織は障害を回避できました。最低限のメンテナンスしか行わない組織は、サポート対象リリースに留まるためにKubernetesを更新した際、この問題に直面したと考えられます。
3.) インストールドキュメントをエンドツーエンドで通読する。要件は見落としやすい
aws-load-balancer-controllerをkube-system名前空間にインストールし、IAMロールを正しく設定するだけでなく、VPCのサブネットにも正しくタグを付ける必要があります。
# Terraform VPC設定(Config as Code)の抜粋module vpc { ... public_subnet_tags = { "kubernetes.io/role/elb" = "1" } private_subnet_tags = { "kubernetes.io/role/internal-elb" = "1" }}
/*追加の背景情報:EKSドキュメントhttps://aws.amazon.com/premiumsupport/knowledge-center/eks-load-balancer-controller-subnets/を見ると以下の記述があります:"kubernetes.io/cluster/${local.cluster_name}" = "shared"このタグは、古いバージョンのaws-load-balancer-controllerでは必須でした*/4.) Ingressオブジェクトをデバッグする必要がある場合は、インストール済みのIngressClassを確認する
kubectl get ingressclass
複数表示される場合は、kubectl describe ingressclassを実行し、いずれかのingress classにデフォルトとしてマークするアノテーションが付いているかを確認してください。
albのingress classがデフォルトとしてマークされていない場合は、デバッグ対象のIngressオブジェクトに使いたいingress classを明示的に指定する必要があります。
5. Serviceオブジェクトに固有のLBプロビジョニングアノテーションをデバッグする必要がある場合、事情はもう少し複雑です…… どう複雑か:
事実上、同じクラスター内で同時に2つの異なるコントローラーが動作することになります。
EKSの場合、マネージドサービス/マネージドKubernetesマスターノードであるため、視覚的に確認できるのは2つのうち1つだけです(aws-cloud-controller-managerはマネージドマスターノード上で動作しているため見えません)。
2つのコントローラーは機能や担当オブジェクトの面で多くの重複があります。
– aws-cloud-controller-manager:cELBとnELBをプロビジョニング
– aws-load-balancer-controller:aELBとnELBをプロビジョニング
5A.) どちらのコントローラーが対象のKubernetes Serviceオブジェクトをアクティブに管理しているかを判別する
このドキュメントによれば、Kubernetes Serviceに以下のいずれかのアノテーションを付けると:
service.beta.kubernetes.io/aws-load-balancer-type: nlb-ip
service.beta.kubernetes.io/aws-load-balancer-type: external
aws-cloud-controller-managerコントローラーはそのオブジェクトを無視するため、aws-load-balancer-controllerが管理できるようになります。
5B.) aws-load-balancer-controllerがServiceを管理している場合、kubectl describe serviceが役立つ!
高度なLBオプションを試したことがある方なら、LBがpending状態のままプロビジョニングされない場面に遭遇した経験があるかもしれません。kubectl describe service $NAMEでデバッグするとしましょう。Legacy AWS Controller ManagerがServiceを管理している場合、得られるエラーメッセージはほぼ役に立ちません。aws-load-balancer-controllerが管理している場合は、デバッグに役立つエラーメッセージが実際に得られます(IAM権限の不足やサブネットへのタグ付け漏れといったインストール手順のミスを指摘するのに非常に有用です)。
5C.) 考慮すべき変更点を確認するため、リリースノートに目を通す:
- aws-cloud-controller-managerはデフォルトでパブリックIPでLBをプロビジョニングします。プライベートIPでプロビジョニングするには設定の追加が必要です。aws-load-balancer-controllerはその逆です(v2.2.0以降)。
- aws-cloud-controller-managerはデフォルトでcELBをプロビジョニングします。aws-load-balancer-controllerはデフォルトでnELBをプロビジョニングします(
service.beta.kubernetes.io/aws-load-balancer-type: externalでアノテートされたものが対象。これがどのコントローラーが担当するかを決めるためです)。 - aws-cloud-controller-managerのコンテナイメージはかつてDocker Hubで提供されていましたが、v2.4.6以降は今後public.ecr.awsコンテナレジストリのみでホストされます。
5D.) ほとんどのKubernetesオブジェクトは、現在の状態を望ましい状態に遷移させる調整ループ(reconciliation loop)をサポートしています。Load Balancerコントローラーには、反復的な変更を反映させるために削除して再作成する必要があるエッジケースがいくつかあります。
通常は不要ですが、試す価値がある場合もあります。5Aのアノテーションは、ドキュメントが変更ではなく再作成を推奨している例です。また、nlb-ipとexternalはAWS LB Controller固有の値であり、Legacy Controllerはnlbと(空白でcELBがプロビジョニングされる)を使う点も指摘しておきます。この落とし穴は、ArgoCDやFluxのようなGitOpsコントローラーで反復的な変更を行っている方には重要かもしれません。これらは通常、リソースを削除・再作成するのではなく、マニフェストを更新するためです。ArgoCDやFluxのユーザーが開発環境で反復的な変更をテストしている場合、このエッジケースでは変更を反映させるために手動介入が必要になる可能性があります。
本記事を書いた主な理由は2つあります。1つ目は知識を共有することで、こちらは達成できました。2つ目は、混乱を減らすための変更を促すことです。プロジェクトとドキュメントのメンテナーが行えば混乱の解消に大きく寄与するであろう変更が3つあります。いずれもaws-load-balancer-controllerをEBS-CSIプロジェクトに近づけるものです。
- AWS Console GUIからインストール可能な、EKSの公式アドオン一覧にこのプロジェクトを追加する。
- 複数のドキュメント箇所を更新し、aws-load-balancer-controllerがアドオンであることが一目で分かるようにする。
- アノテーションを
kubernetes.io参照からebs.csi.aws.comのような形に更新する。これにより一目でアドオンであることが明白になり、関連ドキュメントを検索する際のユーザー体験を改善するSEO(検索エンジン最適化)効果も期待できる。