背景
ingress-nginxが3人くらいだとメンテナンスできねえしGatewayAPIが主流になるし廃止ですとアナウンスが。
https://www.kubernetes.dev/blog/2025/11/12/ingress-nginx-retirement/
https://www.codecentric.de/en/knowledge-hub/blog/nginx-ingress-retirement-dont-panic-weve-got-you-covered
わりといろんな意味で負荷が高いとみんな思っているのでは。がんばりますけど。→3末オンスケで完了済みです(ingressコントローラ入れ替えるとこは)。
できないといけないこと
これは私が受け持たせていただいてる環境の要件
・メンテで事故を起こさない平行運用切り替え切り戻しできること(ingressClass変えるといける感じ)
・ログフォーマット、IPホワイトリスト制限(traficmanager経由)、内外複数コントローラ配置、Basic認証、サーバ証明書認証、正規表現リダイレクト、カスタムエラーページ、などの機能を完全再現移行が必要(アプリの修正なし)
・helmチャートをpullして変数とテンプレを上書きしgit管理できるようにする
・モノnamespaceとchartだけどchartsディレクトリに入れる。環境ごとの変数はpipelineで上書きさす。
大まかな経路
まんまこうではないですが雑にいうとこうという経路です
1 pubuser-443-frontDoor-80-aksIngressExternal-80-service-pod
2 menteuser-443-traficManager-443-aksIngressExternal2-80-service-pod
3 admin-exroute-privDns-443-aksIngressInternal-80-service-pod
この辺の構成を変えるとドキュメント修正が山盛りになり工数がかさみそうでgatewayApiにするまでに何しないといけないのか戦々恐々です。
候補
ingressコントローラの単純な代替えで延命の場合
- Traefik:クライアントIPのヘッダをTraficManager等のL4のLB経由でとってこれずそれ経由のIP制限に難があり→位置が違っててspecを挟む必要性を確認できておらず実際のserviceの-o yaml結果みたらClusterになってたというオチでした。
service:
spec:
externalTrafficPolicy: Local
あとLogformatもあんまり柔軟にできずでログ監視のクエリを数十件変更が必要になるのが確定してますね。結構移行元と別物だったので検証に時間を要しました。Basic認証はできてた。DefaultBackendがないので、TrraficmanagerのHostヘッダ無しアクセスを404にしないようなルーティングが必要だったりもしました(ingress-nginxだとvaluesに追記で勝手にdefaultbackend作られてた)。正規表現リダイレクトもカスタムエラーページも機能してたのでもうこれでいいです。レビューと作業MTGでダメ出ししてもらったらどうにかなった。
- HAproxyIngress:候補として検討したが、Traefikで要件を満たせたため採用しなかった。Logformatがsyslog様にできるのは良いですがGatewayAPIにするにはなんかOLDっぽいところにListされていた。
- Application Gateway for Containers (AGIC):オープンソースから月300ドルに移行するのはオーナーを説得できない。無理です。
GatewayAPIに変える場合
短期でGatewayAPIに移行はちょっと無理です。履修とかドキュメント整備のコストが。
- https://gateway-api.sigs.k8s.io/implementations/#gateway-controller-implementation-status
- Gateway APIベースのApplication routing(Istio Gatewayのみ):長期的にはメッシュ使わなくてリソースコスト抑えられてMSサポート対象っぽいので候補。https://learn.microsoft.com/ja-jp/azure/aks/istio-gateway-api
- Istioのサービスメッシュのやつ:リソースコストが高すぎてギリギリで運用してるのに全Podにサイドカー入れるとか気が狂ったような感じになるので提案できない。
traefikで機能してた定義
helmチャートをGitリポジトリで管理してパイプラインで流す派ですのでhelm upgradeでどうにかするタイプのやり方ではなくpullしたtraefikのチャートディレクトリをchartsに突っ込んで親チャートのvalues.yamlから上書きしています。
traefik:
enabled: true
nameOverride: traefik
ingressClass:
enabled: true
name: traefik
isDefaultClass: false
additionalArguments:
- --providers.kubernetesingress=true
- --providers.kubernetesingress.ingressClass=traefik
#- --providers.kubernetesingressnginx=true
#- --providers.kubernetesingressnginx.ingressClass=nginx
#- --providers.kubernetesingressnginx.controllerClass=k8s.io/ingress-nginx
#- --providers.kubernetesingressnginx.watchnamespace=default
- --providers.kubernetescrd=true
- --log.level=DEBUG #あとでINFOに戻す
- --ping=true
- --ping.entryPoint=traefik
- --entrypoints.web.forwardedHeaders.trustedIPs=100.98.0.0/24,このほか前段とメンテ元の信頼さすIPを定義
- --entrypoints.websecure.forwardedHeaders.trustedIPs=100.98.0.0/24,このほか前段とメンテ元の信頼さすIPを定義
- --entrypoints.web.address=:8000
- --entrypoints.websecure.address=:8443
- --api.dashboard=true
- --entrypoints.traefik.address=:9000/tcp
- --entrypoints.metrics.address=:9100/tcp
service:
enabled: true
type: LoadBalancer
annotations: {}
spec:
externalTrafficPolicy: Local
ports:
web:
port: 80
expose:
default: true
exposedPort: 80
targetPort: 8000
websecure:
port: 443
expose:
default: true
exposedPort: 443
targetPort: 8443
traefik: # /ping用
port: 9000
expose:
default: true
exposedPort: 9000 # Service の port
targetPort: 9000
metrics: #とりあえずトラフィックレート等を将来的に何かで見れるように開けとく
port: 9100
targetPort: 9100
deployment:
kind: DaemonSet #externalTrafficPolicy: Localの場合に必要だったので
#replicas: 1
readinessProbe:
httpGet:
path: /ping
port: traefik
livenessProbe:
httpGet:
path: /ping
port: traefik
logs:
general:
format: json
access:
enabled: true
format: json
fields:
defaultMode: keep
names:
ClientUsername: drop
headers:
defaultMode: keep
names:
X-Forwarded-For: keep
X-Forwarded-Proto: keep
X-Azure-ClientIP: keep
X-Azure-FDID: keep
Referer: keep
User-Agent: keep
Authorization: drop
Cookie: drop
podSecurityContext:
runAsNonRoot: true
runAsGroup: 65532
runAsUser: 65532
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
多少こうなった理由を書いときます
- 今後のセキュリティ的に推奨とかでsecurityContextのあたり等を入れたせいでLowPort(1024以下)がtargetPortで使えない→8443とか使う→exporseとtargetのポート番号がずれてるとhealthProbeに失敗する→kubeletからのPingに失敗してPodが延々Crashloop→キャパびりてぃのNetBindなんとかを入れるも特に改善せず→PingPortをtraefikの9000にする→Ping成功
- アクセスログが何も設定しないと出ない→logs.access.enabled:trueを設定
- ダッシュボードはそれ用のingressリソース定義するかPortforwardしないと有効にする設定しただけだとみられない(まあいいか)
- isDefaultClassは平行運用中falseにしないと事故る
- entrypoints.websecure.forwardedHeaders.trustedIPsはservice.spec.externalTrafficPolicy: Localと一緒にいれとかないとIP制限するためのリモートのIPを信頼しないせいで認識できないらしいのでいれた
あと環境ごとのやつ(pipelineのhelm upgradeコマンドの-fで渡すやつ)
traefik:
service:
annotations:
service.beta.kubernetes.io/azure-load-balancer-resource-group: "MC_myrg"
service.beta.kubernetes.io/azure-pip-name: "my-cluster2-ing2-pip"
spec:
loadBalancerIP: "135.xxx.xx.xx"
参考まで。middleware名のプレフィックスついてるのはnamespace名です。
---
# ==========================================
# 内部向け Ingress(Traefik-Internal / 80-443)
# ==========================================
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-tf-int
namespace: default
annotations:
# Middlewares 適用(Basic認証 / エラーページ / リダイレクト)
traefik.ingress.kubernetes.io/router.middlewares: "default-basic-auth-mw@kubernetescrd,default-errors-mw@kubernetescrd,default-pointfile-redirect@kubernetescrd"
traefik.ingress.kubernetes.io/router.tls: "true"
traefik.ingress.kubernetes.io/router.entrypoints: "websecure" #serviceのentrypointに合わせる
#traefik.ingress.kubernetes.io/router.tls.options: "internal-mtls@kubernetescrd" # ←クライアント証明不要
spec:
ingressClassName: traefik-internal
rules:
- host: my-int.default.svc.cluster.local # ← 内部向けホスト名に置き換え
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-int # ← 内部用 Service 名
port:
number: 80
tls:
- hosts: ["my-int.default.svc.cluster.local"]
secretName: private-cert # ← 内部サーバ証明書 Secret 名
# =========================
# Basic 認証(Secret + Middleware)
# =========================
apiVersion: v1
kind: Secret
metadata:
name: basic-auth
namespace: default
type: kubernetes.io/basic-auth
data:
username: <base64-username>
password: <base64-password>
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: basic-auth-mw
namespace: default
spec:
basicAuth:
secret: basic-auth
removeHeader: true
realm: "Authentication Required"
そのた
- networkpolicyがingress-nginxのラベルついてるやつfromで許可してた→traefikのラベルも追加した
→kubeletからping通らないのでClusterのCIDERのfromから9000許可した
→LBからping通らないので8443,8000も許可した(8000はsslリダイレクトのために必要) - あと正規表現リダイレクトはpathだけでのリダイレクトができなかったのでhttpsから全部書く必要があった
- SSLリダイレクトのためにhttpの経路の定義もそれぞれ必要だったので設定追加した
- logにClientIP等出すのに必要なヘッダの定義を追加した( X-Forwarded-Proto: keep、X-Azure-ClientIP: keep、X-Azure-FDID: keep)
以上です。