Skip to main content
BlogDevOps

Ingress2Gateway 1.0: Migrasi ingress-nginx ke Gateway API

Pembacaan teliti Ingress2Gateway 1.0 untuk migrasi ingress-nginx: perintahnya, warning yang muncul, yang tidak bisa diterjemahkan, dan cutover yang bisa dibatalkan.

Matthews Wong

Software Engineer

Oktober 202612 menit baca
Ingress2Gateway 1.0: Migrasi ingress-nginx ke Gateway API

Ringkasan Utama

Ingress2Gateway 1.0, asisten migrasi resmi dari SIG Network, mengonversi lebih dari 30 annotation ingress-nginx ke Gateway API dan menguji tiap annotation pada controller sungguhan. Tool ini tetap tidak bisa menerjemahkan configuration snippet, batas body size atau URL normalization, jadi setiap hasil perlu direview, diuji di dev cluster, dan trafik dialihkan bertahap sebelum Ingress dihapus.

Migrasi yang paling ditakuti bukan HTTPRoute pertama. Yang menakutkan adalah annotation yang tiga tahun lalu ditambahkan entah oleh siapa dan diam-diam mengubah perilaku satu path. ingress-nginx mengumpulkan hal seperti itu lewat annotation, ConfigMap dan snippet, sementara Gateway API tidak punya tempat untuk menyalinnya. Ingress2Gateway 1.0 adalah tool dari proyek Kubernetes untuk menemukannya.

Tulisan ini adalah pembacaan teliti atas pengumuman 1.0, README repository, dokumentasi provider ingress-nginx, dan artikel Kubernetes tentang perilaku ingress-nginx yang merusak migrasi. Saya tidak menjalankannya pada cluster sungguhan untuk artikel ini, jadi semua input, output dan warning di bawah dikutip dari sumber tersebut, dan setiap angka bisa ditelusuri ke sana. Urutannya mengikuti cara kerja nyata: install, jalankan, baca warning, perbaiki manual, lalu cutover.

Yang berubah di 1.0, dan yang masih bukan

Perubahan utamanya adalah cakupan. Sebelum 1.0, Ingress2Gateway hanya mendukung tiga annotation ingress-nginx. Rilis 1.0 mendukung lebih dari 30 annotation umum, termasuk CORS, backend TLS, regex matching dan path rewrite. Perubahan kedua lebih penting untuk kepercayaan: setiap annotation yang didukung, beserta kombinasi representatif annotation umum, diuji dengan integration test yang menjalankan controller ingress-nginx sungguhan dan beberapa controller Gateway API, menerapkan Ingress, menerjemahkannya dengan tool ini, menerapkan hasilnya, lalu membandingkan perilaku runtime seperti routing, redirect dan rewrite. Artikel rilisnya menegaskan bahwa yang dibandingkan adalah perilaku, bukan bentuk YAML.

Arsitekturnya punya dua sisi. Provider membaca resource Ingress dan CRD provider menjadi intermediate representation. Emitter mengubahnya menjadi output: emitter standard bawaan menulis resource Gateway dan HTTPRoute inti, sedangkan emitter lain menambah resource untuk satu implementasi. Artikel rilis menyebut agentgateway, envoy-gateway dan kgateway. README di branch main, yang saya baca pada 2026-10-17 dan bisa lebih baru dari tag 1.0, juga mencantumkan airlock-microgateway dan gce, serta sembilan provider seperti istio, kong, traefik dan nginx. v1.0 menargetkan Gateway API v1.5.0, dan README menyebut outputnya umumnya forward-compatible dengan v1.4.

Yang bukan dilakukannya: konversi sekali jalan. Artikel rilis mendefinisikan tiga tugas, yaitu memigrasi konfigurasi dan perilaku yang didukung, mengidentifikasi konfigurasi yang tidak didukung beserta alternatifnya, dan memberi kesempatan menilai ulang serta membuang konfigurasi yang tidak lagi diinginkan. README menambahkan bahwa tool ini tidak dimaksudkan untuk menyalin annotation dari Ingress ke Gateway API. Anggap outputnya sebagai draf pertama yang disertai daftar tugas. Panduan migrasi dari proyek Gateway API sendiri sejalan soal cakupan: menjelaskan konsep, menunjukkan konversi manual dan menunjuk tool ini untuk konversi otomatis, tetapi menyatakan tidak akan menyiapkan Anda untuk live migration.

Install dan jalankan dengan tiga cara

Install dengan go install pada tag 1.0.0 atau dengan Homebrew; README juga menunjuk halaman releases berisi binary. Perintah print menerima input dengan tiga cara: file manifest, satu namespace yang dibaca langsung dari cluster, atau semua namespace. Flag yang wajib adalah --providers. Semua di bawah ini diambil dari artikel rilis dan tabel flag di README.

# Install: pin the tag, or use Homebrew
go install github.com/kubernetes-sigs/ingress2gateway@v1.0.0
brew install ingress2gateway

# 1. From manifest files (comma-separated)
ingress2gateway print --input-file my-manifest.yaml,my-other-manifest.yaml \
  --providers=ingress-nginx > gwapi.yaml

# 2. One namespace, read live from your current kubeconfig context
ingress2gateway print --namespace my-api --providers=ingress-nginx > gwapi.yaml

# 3. The whole cluster
ingress2gateway print --providers=ingress-nginx --all-namespaces > gwapi.yaml

# Optional: implementation-specific extras (agentgateway | envoy-gateway | kgateway)
ingress2gateway print --providers=ingress-nginx -A --emitter envoy-gateway > gwapi.yaml

# If your controller uses a different IngressClass, the default (nginx) selects nothing
ingress2gateway print --providers=ingress-nginx \
  --ingress-nginx-ingress-class=ingress-nginx -A > gwapi.yaml

Ada empat flag yang perlu diketahui sebelum run pertama. --output menerima yaml, json atau kyaml. --ingress-nginx-ingress-class bawaannya nginx, jadi cluster yang memakai nama class lain tidak memilih apa pun sampai flag ini diatur. --allow-experimental-gw-api menyertakan field Gateway API experimental seperti URLRewrite di output. Urutannya deterministik: Ingress tertua berdasarkan creation timestamp menang saat konflik, seri diputuskan oleh namespace dan nama, dan rule konflik yang datang belakangan dilaporkan sebagai error, bukan digabung.

Contoh konversi: input, output dan warning

Artikel rilis memproses satu Ingress dengan tool ini. Ingress itu membawa enam annotation: proxy-body-size 1G, use-regex, proxy-send-timeout dan proxy-read-timeout bernilai 1, enable-cors, serta configuration-snippet yang mengatur header Request-Id. Path-nya regex, /users/(\d+), dengan path type ImplementationSpecific, dan TLS dikonfigurasi.

# Input: the Ingress used in the Kubernetes release post
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  namespace: my-ns
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "1G"
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "1"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "1"
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers "Request-Id: $req_id";
spec:
  ingressClassName: nginx
  rules:
    - host: my-host.example.com
      http:
        paths:
          - path: /users/(\d+)
            pathType: ImplementationSpecific
            backend:
              service:
                name: website-service
                port:
                  number: 80
  tls:
    - hosts: [my-host.example.com]
      secretName: my-secret

Manifest hasilnya berisi Gateway dengan listener HTTP dan HTTPS, sebuah HTTPRoute dengan CORS filter, path match RegularExpression dan request timeout, ditambah HTTPRoute kedua yang mengalihkan port 80 ke HTTPS dengan status 308. Route kedua itu meniru redirect bawaan ingress-nginx untuk host ber-TLS. Baca baris timeout dua kali: kedua annotation sumber bernilai 1, tetapi tool menghasilkan request timeout 10 detik, yang disebut artikel sebagai terjemahan best-effort dari timeout level TCP. Informasi sebenarnya ada di warning.

# Output (excerpt): the HTTPRoute as first generated
rules:
- backendRefs:
  - name: website-service
    port: 80
  filters:
  - type: CORS
    cors:
      allowOrigins: ['*']
      maxAge: 1728000
  matches:
  - path:
      type: RegularExpression
      value: (?i)/users/(\d+).*      # prefix + case-insensitive, like ingress-nginx
  timeouts:
    request: 10s                      # input said 1 and 1: this is the tool's best effort
# plus a second HTTPRoute on port 80: RequestRedirect, scheme https, statusCode 308
Pesan dari toolArtinyaKeputusan yang dipaksakan
WARN: annotation configuration-snippet tidak didukungDirective NGINX mentah tidak punya field di Gateway API.Cari padanan spesifik implementasi, atau buang perilakunya.
INFO: regex path match case-insensitivePola output memakai (?i) di depan dan .* di belakang.Pertahankan jika klien memakai huruf campuran; jika tidak, hapus keduanya untuk exact match.
WARN: timeouts.request best-effortTimeout ingress-nginx berlevel TCP; tool memperkirakannya menjadi 10s.Pilih request timeout yang benar-benar diinginkan, misalnya 3s.
WARN: gagal menerapkan proxy-body-sizeTidak ada field standar Gateway API; kebanyakan implementasi punya default.Periksa batas di implementasi Anda, atau coba ekstensi emitter.
WARN: URL normalization tidak bisa dikonfigurasiGateway API tidak bisa mengatur normalisasi RFC 3986; tiap implementasi berbeda.Uji dot segment dan double slash pada controller tujuan.

Rekomendasi tool untuk listener HTTP juga merupakan keputusan: port 80 dan redirect ditambahkan hanya untuk menyamai ingress-nginx, dan artikel menyarankan Anda boleh menghapus keduanya jika tidak ingin melayani HTTP sama sekali.

Yang tidak bisa diterjemahkan dan yang hanya setengah

README provider ingress-nginx memisahkan annotation menjadi yang dikonversi dan yang dikenali tetapi tidak dikonversi. Kelompok kedua hanya memberi warning tanpa output, itu mode gagal yang aman: Anda tahu saat review. Tabel di bawah dirangkum dari README tersebut sebagaimana dibaca pada 2026-10-17; isinya keluarga annotation yang menentukan apakah cluster nyata bisa bermigrasi mulus.

Keluarga annotationDikonversi menjadiCatatan di README
canary, canary-weight, canary-by-headerWeight backend dan HTTPHeaderMatchcanary-by-header-pattern dan canary-by-cookie dikenali tetapi tidak dikonversi
rewrite-target, app-rootURLRewrite dengan ReplaceFullPath; redirect 302 untuk app-rootReferensi capture group seperti $1 tidak didukung dan ditandai
permanent-redirect, temporal-redirect, ssl-redirectFilter HTTPRequestRedirect dengan status code yang bisa dipilihproxy-redirect-from dan proxy-redirect-to dikenali tetapi tidak dikonversi
upstream-vhost, connection-proxy-header, x-forwarded-prefixFilter HTTPRequestHeaderModifiercustom-headers dikenali tetapi tidak dikonversi
proxy-connect, send dan read timeoutKonfigurasi timeout Gateway API, nilai dalam detikArtikel rilis menyebutnya best-effort dan menunjukkan input 1s menghasilkan request timeout 10s
backend-protocol, proxy-ssl-*GRPCRoute untuk GRPC dan GRPCS; BackendTLSPolicy untuk HTTPS dan GRPCSproxy-ssl-verify-depth dan proxy-ssl-protocols tidak dikonversi; FCGI memberi warning
whitelist-source-range, denylist-source-rangeTercantum sebagai kontrol CIDR yang didukungREADME tidak menyebut objek Gateway API yang membawanya; baca outputnya
ssl-passthroughTLSRoute plus listener Passthrough di port 443HTTPRoute untuk Ingress itu digantikan, bukan ditambah

Dua hal yang tidak diterjemahkan perlu disebut. configuration-snippet, annotation yang dalam pengumuman retirement Kubernetes disebut sebagai celah keamanan serius, memang tidak punya terjemahan. Lalu proxy-body-size dikonversi oleh README provider menjadi Kubernetes quantity, tetapi run di artikel rilis sendiri melaporkan bahwa emitter standard tidak bisa menerapkannya karena Gateway API tidak punya field standar untuk itu. Keduanya bersumber; hanya beda lapisan, dan aturan praktisnya: percayai warning di output Anda sendiri di atas tabel mana pun.

# Which ingress-nginx annotations does this cluster actually use, most common first?
# Compare the result with the provider README before you trust a clean run.
kubectl get ingress -A -o json \
  | jq -r '.items[].metadata.annotations // {} | keys[]' \
  | grep '^nginx.ingress.kubernetes.io/' \
  | sort | uniq -c | sort -rn

Buat inventaris sebelum menjalankan. Hitung annotation ingress-nginx mana yang benar-benar dipakai cluster Anda, lalu bandingkan dengan README provider. Annotation yang muncul di banyak Ingress dan tidak didukung adalah biaya migrasi yang sesungguhnya.

Kegagalan yang harus diantisipasi: terjemahan benar yang menghasilkan 404

Artikel Kubernetes tentang perilaku mengejutkan ingress-nginx menyatakan pola risikonya dalam satu kalimat: terjemahan yang tampak benar tetap bisa menyebabkan outage jika mengabaikan keanehan ingress-nginx. Ada lima. Path regex bersifat prefix match dan case-insensitive. use-regex berlaku untuk setiap path pada host itu di semua Ingress. rewrite-target diam-diam berarti regex. Request tanpa trailing slash dialihkan dengan 301 ke path ber-slash. Dan URL dinormalisasi sebelum dicocokkan, misalnya menggabungkan double slash dan dot segment.

Contoh paling tajam adalah soal regex. Pola yang dimaksudkan mencocokkan tiga huruf kapital ternyata mencocokkan /uuid di ingress-nginx, karena aturan prefix dan case. Implementasi berbasis Envoy seperti Istio, Envoy Gateway dan Kgateway melakukan full match yang case-sensitive, sehingga route yang tampak setia itu mengembalikan 404 untuk trafik yang tadinya berjalan. Perbaikan di artikel adalah pola prefix yang case-insensitive, atau flag (?i). Logika yang sama menjebak rewrite-target: ada typo di path yang tidak disadari karena matching-nya longgar, lalu beralih ke Exact mengubah setiap request yang dimaafkan menjadi 404.

# Wrong: a "faithful" copy of use-regex with path /[A-Z]{3}.
# ingress-nginx matched /uuid (prefix + case-insensitive).
# A full, case-sensitive matcher returns 404 for it.
- matches:
  - path:
      type: RegularExpression
      value: "/[A-Z]{3}"

# Right: preserve the old semantics explicitly...
- matches:
  - path:
      type: RegularExpression
      value: "/[a-zA-Z]{3}.*"

# ...or use the (?i) flag, which Istio, Envoy Gateway and Kgateway support
- matches:
  - path:
      type: RegularExpression
      value: "(?i)/[a-z]{3}.*"

Jangan merapikan output regex dari tool sebelum tahu apa yang dikirim klien. Menghapus (?i) dan .* di belakang hanya benar jika tidak ada klien yang memanggil path dengan huruf berbeda atau dengan suffix. 404 di gateway bersifat senyap, karena tidak ada yang gagal selama migrasi sampai trafik tiba.

Kasus trailing slash adalah bayangan cerminnya. ingress-nginx mengalihkan untuk Anda; implementasi Gateway API yang conformant tidak mengatur redirect secara diam-diam, jadi apa pun yang bergantung pada 301 itu butuh filter request redirect eksplisit. Uji kelimanya dengan perintah curl yang sama ke kedua data plane sebelum mempercayai hasilnya.

Edit manual output menjadi sesuatu yang bisa Anda pertanggungjawabkan

Proses edit di artikel rilis adalah template yang bagus. Edit itu menghapus (?i) di depan dan .* di belakang untuk mendapat pola exact yang case-sensitive, menurunkan request timeout dari 10s ke 3s karena service seharusnya menjawab cepat, membuang listener port 80 beserta route redirect-nya karena HTTP tidak diinginkan, dan menyerahkan body size ke default implementasi setelah dicek. Tiap edit menjawab satu warning, kebiasaan yang layak ditiru. Jika sebuah route tidak boleh punya timeout sama sekali, panduan timeout Gateway API menyebut agar request diatur ke 0s; HTTPRouteRequestTimeout adalah fitur extended support, jadi pastikan implementasi Anda mendukungnya.

# The release post's hand-edited result (excerpt)
spec:
  gatewayClassName: nginx
  listeners:                          # port 80 listener removed: no HTTP wanted
  - hostname: my-host.example.com
    name: my-host-example-com-https
    port: 443
    protocol: HTTPS
    tls:
      certificateRefs:
      - group: ""
        kind: Secret
        name: my-secret
---
# HTTPRoute rule, after editing
    matches:
    - path:
        type: RegularExpression
        value: /users/(\d+)           # (?i) and trailing .* removed on purpose
    timeouts:
      request: 3s                     # was 10s as generated
# The ssl-redirect HTTPRoute (port 80, 308) was deleted with the listener.

Lalu verifikasi sebelum trafik apa pun dipindah. Dry-run sisi server menangkap error skema, status route memberi tahu apakah controller menerimanya, dan curl dengan header Host menguji aturan path tanpa menyentuh DNS. Periksa minimal bahwa default body size cocok dan timeout tiga detik cukup, dua pengecekan yang sama dengan yang disebut artikel rilis.

# Schema and admission errors, without creating anything
kubectl apply --dry-run=server -f gwapi.yaml

# Apply to the DEV cluster, then read the status the controller wrote back
kubectl apply -f gwapi.yaml
kubectl get gateway,httproute -n my-ns
kubectl describe httproute my-ingress-my-host-example-com -n my-ns

# Exercise the rules without touching DNS: pin the host to the new gateway address
curl -isS --resolve my-host.example.com:443:<gateway-ip> https://my-host.example.com/users/42

Cutover tanpa big bang

Saran cutover di artikel rilis singkat dan layak diikuti apa adanya. Uji di development cluster, deploy konfigurasi Gateway API berdampingan dengan Ingress yang ada, alihkan trafik bertahap dengan weighted DNS, cloud load balancer atau fitur traffic splitting platform Anda, dan hanya setelah semuanya pindah, hapus resource Ingress dan uninstall Ingress controller. Alasannya adalah kemampuan pulih: kesalahan konfigurasi yang lolos dari tes hanya memakan perubahan weight, bukan insiden.

#!/usr/bin/env bash
# My scaffolding, not part of ingress2gateway: same paths against both data planes,
# print any status code that differs. Fill in both addresses and your real paths.
HOST=my-host.example.com
OLD=<ingress-nginx-ip>
NEW=<gateway-ip>
for path in /users/42 /USERS/42 /users/42/orders /users/42/ //users/42; do
  a=$(curl -sk -o /dev/null -w '%{http_code}' --resolve "$HOST:443:$OLD" "https://$HOST$path")
  b=$(curl -sk -o /dev/null -w '%{http_code}' --resolve "$HOST:443:$NEW" "https://$HOST$path")
  [ "$a" = "$b" ] || echo "DIFF $path  ingress-nginx=$a  gateway=$b"
done

Trade-off-nya adalah biaya dan waktu. Menjalankan dua data plane paralel berarti dua set load balancer dan dua tempat bug bisa bersembunyi, dan retirement ingress-nginx, yang dalam pengumuman dijadwalkan Maret 2026 tanpa rilis maupun perbaikan keamanan sesudahnya, adalah alasan Anda tidak bisa paralel selamanya. Deployment yang ada tetap berjalan menurut pengumuman, jadi tekanannya ada pada postur keamanan, bukan outage seketika.

Yang dikerjakan hari Senin

Mulai dengan pass read-only. Tidak ada langkah di bawah yang mengubah cluster sampai langkah kelima.

  1. Hitung annotation ingress-nginx yang dipakai cluster Anda dan bandingkan dengan README provider.
  2. Jalankan ingress2gateway print untuk semua namespace, tulis manifest dan warning ke file terpisah.
  3. Ubah setiap WARN menjadi tiket dengan pemilik dan keputusan: terjemahkan, ganti atau buang.
  4. Daftar klien yang mengirim path huruf campuran atau ber-suffix dan yang bergantung pada redirect trailing slash.
  5. Terapkan ke development cluster, bandingkan status code dengan jalur lama, lalu alihkan trafik bertahap.
# Steps 1 and 2, read-only. The manifest goes to stdout and the warnings to the
# terminal in the release post's examples, so split them to keep both.
ingress2gateway print --providers=ingress-nginx --all-namespaces \
  > gwapi.yaml 2> warnings.log

grep -c 'WARN' warnings.log
grep -B1 -A3 'Unsupported annotation' warnings.log

Loop perbandingan di blok terakhir adalah scaffolding buatan saya, bukan bagian dari tool: ia mengambil path yang sama dari kedua controller dan mencetak status code yang berbeda. Isi alamat dan path dari daftar langkah empat Anda.

Ingress2Gateway 1.0 layak dipakai karena jujur soal batasnya: ia menerjemahkan apa yang bisa dibuktikan, memperingatkan sisanya, dan proyeknya menguji terjemahan terhadap controller sungguhan. Aturan yang saya bawa dari sini: perlakukan setiap warning sebagai keputusan, bukan noise, dan anggap 404 dari route yang tampak setia sebagai kegagalan yang paling mungkin. Migrasi dengan kedua plane berjalan dan hapus Ingress paling akhir.

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Apa itu Ingress2Gateway 1.0?

Ingress2Gateway 1.0 adalah asisten migrasi dari SIG Network yang menerjemahkan resource Ingress dan annotation ingress-nginx menjadi resource Gateway API. Tool ini mendukung lebih dari 30 annotation ingress-nginx, naik dari tiga sebelum 1.0. Ia memperingatkan konfigurasi yang tidak bisa diterjemahkan, bukan membuangnya diam-diam.

Bagaimana cara mengonversi ingress-nginx ke Gateway API dengan Ingress2Gateway?

Install dengan brew install ingress2gateway atau go install, lalu jalankan ingress2gateway print --providers=ingress-nginx dengan file input, satu namespace atau semua namespace. Arahkan output ke file dan baca warning-nya. Setelah itu edit manifest, uji di development cluster dan alihkan trafik bertahap.

Annotation ingress-nginx apa yang tidak bisa diterjemahkan Ingress2Gateway?

Artikel rilis menyebut configuration-snippet dan, sebagai field standar, proxy-body-size. README provider juga mencantumkan annotation yang dikenali tetapi tidak dikonversi seperti canary-by-cookie, canary-by-header-pattern, custom-headers dan proxy-redirect-from. Selalu percayai warning pada run Anda sendiri.

Mengapa route hasil konversi saya mengembalikan 404 padahal ingress-nginx berjalan?

Path regex ingress-nginx adalah prefix match dan case-insensitive, dan rewrite-target diam-diam berarti regex. Implementasi Gateway API berbasis Envoy melakukan full match yang case-sensitive, sehingga pola yang sama bisa berhenti cocok. Gunakan pola prefix case-insensitive atau flag (?i) jika klien memakai huruf berbeda.

Bisakah Ingress2Gateway memigrasi cluster saya sekali jalan?

Tidak. Proyeknya menyebutnya asisten, bukan pengganti sekali jalan. Jalankan Gateway API berdampingan dengan Ingress, alihkan trafik dengan weighted DNS atau load balancer, dan hapus Ingress beserta controller hanya setelah semua trafik pindah.