はじめに
EKS Auto ModeでLoadBalancer型のServiceをデプロイしたところ、NLBが作成されず FailedBuildModel というエラーが出ました。
原因はサブネットのタグ不足で、annotationでサブネットを直接指定することで解決できました。
発生したエラー
LoadBalancer型のServiceを作成した後、kubectl describe svc でイベントを確認すると以下のエラーが出ていました。
kubectl describe svc web-service-lb
NLBを配置するサブネットが見つからない、というエラーです。
原因
EKS Auto Modeのロードバランサーコントローラーは、NLBを配置するサブネットをタグで自動検出します。internet-facingのNLBであれば kubernetes.io/role/elb=1 というタグが付いたサブネットを探しに行きます。
今回のクラスターでは、サブネットにこのタグが設定されていなかったため、候補が0件となりエラーになっていました。
eksctl create cluster でクラスターを作成した場合は自動でタグが付与されますが、既存のサブネットを使う場合は手動で設定が必要です。
解決方法
サブネットにタグを後付けする方法もありますが、コントローラーのキャッシュの関係で反映に時間がかかることがあります。確実なのは、annotationでサブネットを直接指定する方法です。
まず、ノードが稼働しているサブネットIDを確認します。
aws ec2 describe-instances \
--filters "Name=tag:eks:cluster-name,Values=<クラスター名>" \
--query "Reservations[*].Instances[*].{SubnetId:SubnetId,AZ:Placement.AvailabilityZone}" \
--output table
確認できたサブネットIDをServiceのannotationに設定します。
kubectl annotate svc <Service名> \
"service.beta.kubernetes.io/aws-load-balancer-subnets=subnet-xxxx,subnet-yyyy" \
--overwrite
これでNLBが作成されます。kubectl get svc でEXTERNAL-IPにホスト名が表示されれば成功です。
本来の対策
そもそもこのエラーを避けるには、クラスター作成時にサブネットへ適切なタグを付けておくのが正解です。
| サブネット種別 | 必要なタグ |
|---|---|
| パブリック(internet-facing用) | kubernetes.io/role/elb=1 |
| プライベート(internal用) | kubernetes.io/role/internal-elb=1 |
eksctl create cluster でVPCごと新規作成する場合はこれらのタグが自動で付与されるため、この問題は起きません。一方、aws eks create-cluster(AWS CLI)やマネジメントコンソールで既存VPCのサブネットを指定する場合は自動付与されないため、手動でタグを設定する必要があります。特にこだわりがなければ、eksctl でクラスターを作成するのが手軽です。
まとめ
-
FailedBuildModelはサブネットのタグ不足で発生する - annotation
aws-load-balancer-subnetsでサブネットを直接指定すれば即座に解決できる - 根本対策として、サブネットに
kubernetes.io/role/elb=1等のタグを付けておく
