Konrad Kowalski (rootsher)Principal Platform & Reliability Architect000100000101111001001100010000101000100110000110

Migracja z ingress-nginx do Gateway API

data
kategoria
Networking
także w
Containers
czytanie
2 min / 354 słów

Najgorszy plan migracji brzmi:

text
weź każdy Ingress
zamień go na Gateway i HTTPRoute
usuń ingress-nginx

To wygląda szybko tylko na diagramie.

W prawdziwym klastrze Ingress często niesie dwa różne typy informacji:

text
kontrakt aplikacji
zachowanie ingress-nginx

Te dwie rzeczy trzeba rozdzielić przed migracją.

Punkt startowy

Prosty Ingress:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "20m"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - example.com
      secretName: example-com-tls
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80

Tu są rzeczy standardowe:

text
host
path
backend Service
TLS secret

I rzeczy specyficzne dla ingress-nginx:

text
ssl-redirect
proxy-body-size

Jeżeli przepiszemy tylko strukturę, możemy stracić zachowanie.

Jeżeli będziemy przepisywać wszystko jeden do jednego, możemy przenieść zachowania, których już nie chcemy.

Nowy model

W Gateway API wejście ruchu i trasa HTTP są osobnymi zasobami.

Gateway:

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: public
  namespace: platform
spec:
  gatewayClassName: public
  listeners:
    - name: https
      hostname: example.com
      port: 443
      protocol: HTTPS
      tls:
        certificateRefs:
          - name: example-com-tls

HTTPRoute:

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: web
spec:
  parentRefs:
    - name: public
      namespace: platform
  hostnames:
    - example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: web
          port: 80

To nie jest idealny odpowiednik każdego Ingress.

To jest nowy podział odpowiedzialności.

Platforma może trzymać Gateway w namespace platform.

Aplikacja może trzymać HTTPRoute obok swojego Service.

Co sprawdzić przed migracją

Najpierw robimy inwentaryzację adnotacji.

Nie liczbę Ingressów.

Adnotacji.

Lista, która zwykle decyduje o trudności:

text
rewrite-target
use-regex
configuration-snippet
server-snippet
auth-url
auth-signin
proxy-read-timeout
proxy-send-timeout
proxy-body-size
ssl-redirect
backend-protocol
canary

Każdą pozycję warto oznaczyć jako jedną z trzech kategorii:

text
standard Gateway API
rozszerzenie implementacji
do usunięcia albo przebudowy

Ta trzecia kategoria jest najważniejsza.

Migracja jest dobrą okazją, żeby odkryć konfigurację, która powstała przez przypadek i nikt już nie wie, po co istnieje.

ingress2gateway jako punkt startowy

ingress2gateway może wygenerować Gateway i HTTPRoute na podstawie istniejących Ingressów.

To jest przydatne.

Ale wynik trzeba czytać jak raport z audytu, nie jak gotowy manifest do produkcji.

Szczególnie ważne są ostrzeżenia dla rzeczy, które nie mapują się czysto:

text
configuration-snippet
proxy-body-size
timeouts
regex path matching
URL normalization

Jeżeli narzędzie czegoś nie przeniesie, to nie musi być błąd narzędzia.

Czasem to informacja, że stare zachowanie było zależne od konkretnego kontrolera.

Migracja obok starego kontrolera

Gateway API można uruchomić obok ingress-nginx.

To powinien być domyślny plan.

text
ingress-nginx działa dalej
nowy gateway controller działa obok
nowy Gateway dostaje własny adres
testujemy route bez zmiany produkcyjnego DNS

Najpierw sprawdzamy:

text
TLS
redirect HTTP -> HTTPS
Host header
path matching
rewrite
timeouts
large request body
headers
metrics
logs
traces

Potem dopiero przenosimy ruch.

Najprostszy rollback to taki, który nie wymaga odtwarzania starego kontrolera.

Stary kontroler powinien jeszcze żyć, kiedy zmieniamy DNS albo load balancer.

Czego nie robić po cichu

Nie zmieniać semantyki path matchingu bez testu.

Nie zakładać, że regex działa tak samo.

Nie zakładać, że timeouty znaczą to samo.

Nie przenosić configuration-snippet jako losowego rozszerzenia tylko dlatego, że da się je gdzieś wkleić.

Nie usuwać limitu body size bez sprawdzenia, czy aplikacja i proxy mają zgodne domyślne wartości.

To są małe różnice dopóki nie trafią w produkcyjny request.

Definicja końca migracji

Migracja nie kończy się wtedy, gdy kubectl apply przyjmie nowe manifesty.

Kończy się wtedy, gdy można powiedzieć:

text
wiemy, która GatewayClass obsługuje ruch
wiemy, które HTTPRoute zastąpiły stare Ingressy
wiemy, które adnotacje stały się standardowym API
wiemy, które zachowania są rozszerzeniem implementacji
wiemy, czego świadomie nie przenieśliśmy
wiemy, jak wrócić

Dopiero wtedy usunięcie ingress-nginx jest porządkiem, a nie aktem wiary.