AWS EKSのAWS ALB Ingress Controllerを破壊的変更を加えずにAWS Load Balancer ControllerにアップデートかつELBをまとめる方法
AWS ALB Ingress Controller to AWS Load Balancer Controller自体は割りと簡単
前提
現在面倒をみているプロダクトがEKSv1.19→v1.21にアップデートをした。事業部専属というわけではなくてSREとして別プロダクトばっかりみてたらサポート残り1ヶ月の状態で「あ、やべ。残り一ヶ月でEKS強制アプデ入るわ」となり、やらなくては~となったがプロダクトのフロントエンドの子が「やってみたいです!」というので他のレイヤーに対する熱意◎でまかせたら、会社都合でその子が部署異動で「開発環境はアプデ終わりましたが本番はできませんでした…後はよろしくお願いいたします…」とバトンを渡され虚構に陥りながら開発のリハ無しに本番のアップデートをした。まぁよくある話っすね
基本的には弊社のSREの方針としては運用は各事業部に任せることが前提とはいいつつほぼほぼノールックだったのは反省点。
で、昔に1.19に上げた時に各APIリソースのアップデートもそこまでしておらず、残り時間と加味してリソースのアップデートの検証もできなかったので最新の1.22ではなく現行のリソースで最大ギリアップデート可能な1.21にした。
1.22のアップデートに向けて早めに手を打とうとAPIリソースのアップデートを隙あらばやっていたが、ALB Ingress ControllerがAWS Load Balancer Controllerというものに変わるらしく、今まで地味に不便だった1service⇔1ELBをNservice⇔1ELBにできるのでついでにやってしまおう。そう、ダウンタイムゼロで。
という前提の元、話を進めていきます。
まずはともあれIngressのアップデート
extensions/v1beta1
から networking.k8s.io/v1
にアップデートしないと1.22にアップデートできないうえ、AWS Load Balancer Controllerが使えない。
と言うこと自体簡単だが地味にハマるポイントがあり、k8s公式ドキュメントのパスタイプを見ると /
ですべてのリクエストを受け入れる設定になる。
https://kubernetes.io/ja/docs/concepts/services-networking/ingress/#%E3%83%91%E3%82%B9%E3%81%AE%E3%82%BF%E3%82%A4%E3%83%97
だがAWS ALB Ingress Controllerは /*
じゃないとすべてのリクエストを受け入れてくれないわけですよ。
なので公式ドキュメントどおりに /
にすると /
しか受け付けないELBが爆誕します。 (e.g. example.com は受け付けるが exmaple.com/hoge は受け付けなくなる
ぐっとこらえて /*
のままアップデートしましょう
サンプルコードはこんな感じです
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example.ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:123456789:certificate/hogehogehoge-fugafugafuga-piyopiyopiyopiyo-poyopoyopoyopoyo-pukapukapuka
spec:
rules:
- host: "example.com"
http:
paths:
- path: /*
pathType: Prefix
backend:
service:
name: ssl-redirect
port:
name: use-annotation
- path: /*
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
rules
配下の host
は必須かと言われると必須ではないんですが、AWS Load Balancer ControllerでELBまとめるときに必要なので今のうちに書いておくと忘れなくて良いです。
AWS Load Balancer Controller インストール
基本的に公式ドキュメント通りにやれば問題ないです。(それはそう
ただPolicy作成時に既存リソースを破壊させないようにちょこっと弄る必要があります
流れは
- EKSのOIDC発行(すでに発行済みならスルー
- AWS Load Balancer Controller用のIAM policyを公式ドキュメントどおりにDL
- 既存リソースを破壊しないように弄る *1
- Policy作成
- AWS Load Balancer Controller用のIAM作成
- AWS ALB Ingress Controllerの削除
- AWS Load Balancer Controllerをインストール(fargate化を少しでも考えてるなら大人しくhelmにしましょう
こんな感じ。
んで、普通に公式ドキュメントどおりにやるとAWS ALB Ingress Controllerで作成されたリソースを書き換えようとするんですが、今回は既存リソースをそのままにしたかったのでちょこっとPolicyをいじります。
公式の
curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.2/docs/install/iam_policy.json
となっているPolicyに次のような感じで追加します
``` [ .json .code] "Condition": { "Null": { "aws:ResourceTag/kubernetes.io/cluster/CLUSTER-NAME": "false" } }
これで既存リソースはいじられないようになります(たぶん
意味は「aws policy Condition」あたりでぐぐってください
### まとめたELBを作成
簡単! `annotations` に `alb.ingress.kubernetes.io/group.name` 追加するだけ!!!!!!!!!!
```{ .yaml .code }
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mamadays.server.loadbalancer
annotations:
alb.ingress.kubernetes.io/load-balancer-attributes: access_logs.s3.enabled=true,access_logs.s3.bucket=elb-log-s3-bucket,access_logs.s3.prefix=log-s3-prefix
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:123456789:certificate/hogehogehoge-fugafugafuga-piyopiyopiyopiyo-poyopoyopoyopoyo-pukapukapuka
alb.ingress.kubernetes.io/group.name: matometa-elb
正直開発環境のELBが無駄に立ち上がってるのは地味に費用面でイラッとしてたので助かる。
一応デメリットがあって、今のところlogのs3のprefixがserviceで分けられないので面倒ではある。
弊社だとelbのlogはs3に置いて、athenaで分析してるんですがscan量増えて料金増えるな~と思いつつ減らしたELB分考えれば+かなと判断してやってます。
ちなみにさっきの rules
配下の host
にhostname書いておかないと大惨事になりますのでちゃんとつけましょう
route53で切り替え
これで AWS ALB Ingress Controllerで作成されたELBsとAWS Load Balancer Controllerで作成されたまとめられたELBが立っているのでroute53の加重ルーティングあたりで切り替えていきましょう。
FAQ
自分で疑問に思ったり同僚に質問されたこと
Q. AWS ALB Ingress Controller消したら既存のELBとか削除されないの?
A. あいつらの仕事はkind Ingressを監視してリソースの追加と削除するだけで、作ったリソース自体を常時監視している(紐づいている)わけではないので問題なし
Q. kustomizeで管理してるからmanifestで管理したいんだけど。
A. https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml と https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.4.2/v2_4_2_full.yaml を見て「管理できる!」って自信持ったらやってください。僕は諦めました。あとfargate対応考えるとねぇ。
Q. なんかAWS ALB Ingress Controllerで作成されたingressが消せないんだけど。消せないっていうかレスポンス帰ってこないんだけど。
A. わかる。僕も半日ぐらい潰れました
結論から言うと finalizers
をemptyにするとOK
簡単にいうと旧ingressが無のfinalizersを掴んでて、旧ingressを消そうとすると、旧ingressが「無を消してからワイ消えますわ!」って状態になり無は無なので無を消せずにレスポンス帰ってこないってわけです。
https://github.com/kubernetes/kubernetes/issues/95983
なんで、finalizersを空で上書きすることで「ワイ何も持ってないのでそのまま消えますね~」って感じで消えてくれる
$kubectl get ingress [ingress-loadbalancername] -o yaml -n development
(略)
finalizers:
- ingress.k8s.aws/resources
(略)
みたいな感じで残ってるので $kubectl patch ingress [ingress-loadbalancername] -n development -p '{"metadata":{"finalizers":[]}}' --type=merge
おりゃ!ってすればemptyで上書きします。
一応 -wait false
つければレスポンス待たずに消えるらしいのでお好みで。
ちなみにsystem:admin権限でも消せなかったので特級呪物って呼んでました