Március 25-én ébredtem egy Slack üzenetre a security csapattól: “Az ingress-nginx tegnaptól EOL. Mi a terv a migrációra?”
Hónapok óta halogattam. A nyugdíjazást még 2025 novemberében bejelentették, de messzinek tűnt. Most viszont valóság lett. Nincs több CVE patch. Nincs több hibajavítás. Az óra ketyeg.
Mi történt pontosan
- március 24-én a Kubernetes SIG Network és a Security Response Committee hivatalosan nyugdíjazta az ingress-nginx-et. A projekt lezárult. A container image-ek és Helm chartok elérhetők maradnak (nem törölnek semmit), de új release nem lesz. Ha holnap jön egy kritikus sebezhetőség, magadra vagy utalva.
Ez nem egy deprecation warning, amit három release-en át ignorálhatsz. Ez azt jelenti, hogy a karbantartók elmentek.
Felmérés
Először megnéztem, mi fut egyáltalán. Három klaszteren:
kubectl get ingress -A -o json | jq -r '.items[] | [.metadata.namespace, .metadata.name, (.spec.rules[]?.host // "no-host")] | @tsv' | sort
Eredmény: 6 Ingress resource 4 namespace-ben. Kettőnek az annotációihoz egy éve nem nyúltam. Az egyiken egy configuration-snippet volt, amitől összeszorult a gyomrom.
kubectl get ingress -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' | wc -l
# 6
Nem tragikus. De néhánynak komplex konfigja volt: rate limiting, egyedi headerek, CORS, SSL redirect logika annotációkba rejtve.
A csere kiválasztása
Két klaszteren már futott Gateway API (erről korábban írtam). A harmadik klaszter régebbi volt, bare metal-en futott. Három opció:
- Gateway API Envoy Gateway-jel - ez volt a preferenciám
- Traefik - stabil, jól karbantartott
- HAProxy Ingress - ha közel akarnék maradni az Ingress resource modellhez
Az Envoy Gateway mellett döntöttem a konzisztencia kedvéért. Ha már Traefik-en vagy Contour-on vagy, maradj ott. A cél az ingress-nginx elhagyása, nem proxy-háború.
Envoy Gateway telepítése
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.3.0 \
--namespace envoy-gateway-system \
--create-namespace
Ellenőrzés:
kubectl -n envoy-gateway-system get pods
# NAME READY STATUS RESTARTS AGE
# envoy-gateway-5d89f7c5b6-x2k4m 1/1 Running 0 45s
Aztán a GatewayClass és Gateway:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: main-gateway
namespace: envoy-gateway-system
spec:
gatewayClassName: eg
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: wildcard-tls
allowedRoutes:
namespaces:
from: All
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
A tényleges migráció, service-ről service-re
Egyszerű service-ek (4 a 6-ból)
Négy Ingress resource egyértelmű volt: host alapú routing, TLS termination, semmi extra. Ezek tisztán leképezhetők HTTPRoute-ra:
Előtte (Ingress):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 8080
Utána (HTTPRoute):
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
spec:
parentRefs:
- name: main-gateway
namespace: envoy-gateway-system
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: api-svc
port: 8080
Az SSL redirect a Gateway szinten van kezelve, nem kell hozzá annotáció. Egy dologgal kevesebb, amit el lehet felejteni.
Mind a négyet párhuzamosan alkalmaztam, teszteltem, aztán töröltem a régi Ingress resource-okat:
for route in api-route dashboard-route docs-route webhook-route; do
kubectl apply -f "${route}.yaml"
done
# tesztelés
for host in api.example.com dash.example.com docs.example.com hooks.example.com; do
curl -s -o /dev/null -w "%{http_code} ${host}\n" "https://${host}/healthz"
done
Mind 200-at adott vissza. Régi Ingress objektumok törölve.
A trükkös: Rate Limiting
Egyik service-en rate limiting volt nginx annotációkkal:
annotations:
nginx.ingress.kubernetes.io/limit-rps: "10"
nginx.ingress.kubernetes.io/limit-burst-multiplier: "5"
Envoy Gateway-nél ehhez BackendTrafficPolicy kell:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: api-ratelimit
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: public-api-route
rateLimit:
type: Global
global:
rules:
- clientSelectors:
- headers:
- name: x-forwarded-for
type: Distinct
limit:
requests: 10
unit: Second
Bőbeszédűbb, de sokkal erősebb is. Tudsz header, IP vagy path alapján limitálni. Az nginx annotációs megoldás mindig olyan volt, mint a szigetelőszalag.
A ronda: Configuration Snippets
Az utolsó service-en configuration-snippet annotáció volt nyers nginx konfiggal:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Frame-Options: DENY";
more_set_headers "X-Content-Type-Options: nosniff";
if ($request_uri ~* "^/old-path") {
return 301 https://$host/new-path;
}
Ettől féltem a legjobban. Az egyedi headerek egyszerűek voltak SecurityPolicy-val. A redirect-hez HTTPRoute filter kellett:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: legacy-redirect
spec:
parentRefs:
- name: main-gateway
namespace: envoy-gateway-system
hostnames:
- app.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /old-path
filters:
- type: RequestRedirect
requestRedirect:
path:
type: ReplaceFullPath
replaceFullPath: /new-path
statusCode: 301
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app-svc
port: 8080
Egyedi headerek SecurityPolicy-val:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
name: security-headers
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: main-gateway
headers:
setHeaders:
X-Frame-Options: "DENY"
X-Content-Type-Options: "nosniff"
A csapda, ami két órámba került
Migráció után az egyik service időnként 503-at dobott. A logok szerint a backend egészséges volt. Kiderült, hogy a régi nginx LoadBalancer Service externalTrafficPolicy: Local beállítása és az Envoy Gateway saját Service-e között volt konfliktus.
A javítás: az új Envoy Gateway Service-nek a helyes externalTrafficPolicy-t kellett beállítani, és a node-okon ellenőrizni a health check konfigot. Ha bare metal-en vagy MetalLB-vel, nézd át az L2 advertisement konfigot a controller csere után.
kubectl -n envoy-gateway-system get svc
# Ellenőrizd az EXTERNAL-IP-t és TYPE-ot
kubectl describe svc -n envoy-gateway-system envoy-main-gateway
Takarítás
Miután 48 órán át minden rendben működött, eltávolítottam az ingress-nginx-et:
helm uninstall ingress-nginx -n ingress-nginx
kubectl delete namespace ingress-nginx
Aztán a régi IngressClass:
kubectl delete ingressclass nginx
DNS átállás
Amit az emberek elfelejtenek: ha a régi nginx LoadBalancer-nek más külső IP-je volt, mint az új Envoy Gateway-nek, frissítened kell a DNS-t. External-dns-t használok annotáció alapú szűréssel, szóval csak azt kellett biztosítani, hogy az új Gateway Service-en rajta legyenek a megfelelő annotációk:
metadata:
annotations:
external-dns.alpha.kubernetes.io/hostname: "*.example.com"
Ha manuálisan kezeled a DNS-t, frissítsd az A rekordokat az új LoadBalancer IP-re.
Mit csinálnék másként
- Korábban kezdeném. A novemberi bejelentés négy hónapot adott. Ebből körülbelül két napot használtam ki. Ne legyél olyan, mint én.
- A rate limitinget tesztelném először. Az egyszerű service-ek könnyűek. A komplex, annotáció-terhelt service-ek viszik az idő 80%-át.
- Mindkét controllert párhuzamosan futtatnám. Ezt csináltam, és megmentett. Hagyd futni az ingress-nginx-et, amíg validálod az új route-okat. A régi Ingress resource-okat csak akkor töröld, ha az újak bizonyítottan működnek.
- Ellenőrizd a monitoringot. Ha nginx-specifikus Prometheus metrikáid voltak (mint az
nginx_ingress_controller_requests), azok eltűnnek. Az Envoy Gateway más metrikákat ad. Frissítsd a dashboardjaidat, mielőtt elveszíted a rálátást.
Végszó
Az ingress-nginx évekig jól szolgálta a közösséget. De most vége, és minél tovább vársz, annál kockázatosabbak a klasztereid. A migráció egy hétvégémbe került hat service-re. Ha neked tucatnyi van, kezdj el tervezni most.
A Gateway API tényleg jobb. Kifejezőbb, kompozálhatóbb, kevesebb annotáció-spagetti. Ha ez a nyugdíjazás az, ami végre ráveszi a csapatodat az átállásra, az összességében pozitív.
Ne várd meg az első foltozatlan CVE-t ahhoz, hogy ez sürgőssé váljon.