Ingress

Aturan routing HTTP dengan Ingress dan peran ingress controller di dalam kluster.

Daftar isi

Ingress adalah kumpulan aturan routing HTTP yang mengarahkan permintaan eksternal ke Service di dalam kluster berdasarkan host dan path permintaannya. Aturan itu sendiri tidak melakukan apa pun sampai sebuah ingress controller membacanya dan mengonfigurasi proxy di dalam kluster. Topik ini membahas peran controller tersebut, struktur aturan host dan path, serta simulasi pencocokan URL terhadap manifest Ingress yang dapat dijalankan di sandbox. Setelah membacanya, satu alamat publik dapat diatur untuk melayani banyak layanan melalui aturan yang terdokumentasi rapi.

Peran ingress controller#

Objek Ingress hanya menyimpan aturan, sedangkan penerapannya ditangani ingress controller, yaitu komponen yang memantau seluruh objek Ingress di kluster dan menerjemahkannya menjadi konfigurasi proxy aktual. Kluster bawaan tidak menyertakan controller apa pun, sehingga controller harus dipasang terlebih dahulu sebelum objek Ingress pertama dibuat. Proyek ingress-nginx merupakan controller yang paling lazim, dan kelas controller yang menangani satu Ingress ditentukan pada bidang spec.ingressClassName.

Apabila belum ada controller yang berjalan, objek Ingress tetap diterima API server, tetapi kolom ADDRESS tidak pernah terisi dan aturan tidak pernah dijalankan. Controller yang berjalan memperoleh alamat itu dari Service miliknya, misalnya melalui LoadBalancer, lalu menjadi satu-satunya pintu trafik HTTP yang masuk ke kluster. Alasan inilah yang membuat pemeriksaan ADDRESS menjadi langkah pertama setelah Ingress diterapkan. Alternatif yang lebih baru bernama Gateway API menata ulang peran ini dalam objek-objek terpisah, tetapi hal itu berada di luar lingkup topik ini.

Perintah berikut memastikan controller berjalan, menerapkan manifest Ingress, lalu memeriksa alamat yang diperolehnya.

bash
# tidak-dijalankan
# pastikan ingress controller sudah berjalan di dalam kluster
kubectl get pods -n ingress-nginx
# terapkan manifest Ingress, lalu periksa kolom ADDRESS
kubectl apply -f ingress.yaml
kubectl get ingress
text Contoh keluaran
NAME                                        READY   STATUS    RESTARTS   AGE
ingress-nginx-controller-7d4b8f6c9c-qtzwx   1/1     Running   0          10m
NAME               CLASS   HOSTS                 ADDRESS      PORTS   AGE
ingress-aplikasi   nginx   catatan.example.com   192.0.2.10   80      5s

Aturan host dan path#

Setiap entri pada spec.rules berisi satu aturan. Bidang host menyaring permintaan berdasarkan nilai header Host, sehingga satu alamat controller dapat melayani banyak situs sekaligus. Bidang http.paths memuat daftar path dengan pathType, dan setiap path menunjuk ke backend berupa Service beserta portnya.

pathType: Prefix berarti path cocok apabila permintaan diawali nilai tersebut, sedangkan pathType: Exact menuntut kesamaan penuh. Apabila beberapa path berpotensi cocok dengan satu permintaan, path yang paling spesifik atau terpanjang yang menang, sehingga /api lebih diutamakan daripada / untuk permintaan /api/nilai.

Pada pathType: Prefix, pencocokan dilakukan per segmen path, sehingga /api cocok dengan /api/nilai tetapi tidak cocok dengan /aplikasi. Perilaku ini mencegah kecocokan palsu yang lazim terjadi pada pencocokan string biasa. Apabila satu path perlu dipetakan persis tanpa turunannya, pathType: Exact menyediakan kecocokan satu banding satu.

Berkas berikut mengarahkan permintaan untuk host catatan.example.com, dengan path /api menuju Service service-api dan sisanya menuju service-web. Bidang spec.ingressClassName menunjuk kelas controller yang menangani aturan ini, sedangkan bidang spec.tls yang opsional untuk pengakhiran TLS tidak dimuat pada contoh. Satu objek Ingress dapat memuat beberapa aturan host sekaligus, sehingga situs tambahan cukup ditambahkan sebagai entri baru pada daftar spec.rules.

yaml ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-aplikasi
spec:
  ingressClassName: nginx
  rules:
    - host: catatan.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: service-api
                port:
                  number: 80
          - path: /
            pathType: Prefix
            backend:
              service:
                name: service-web
                port:
                  number: 80

Simulasi pencocokan rute#

Aturan host dan path pada Ingress pada akhirnya menjadi tabel pencocokan URL. Skrip berikut membaca ingress.yaml menggunakan PyYAML, memeriksa host terlebih dahulu, lalu menelusuri daftar path dengan memprioritaskan prefix terpanjang. Lima URL sampel diuji, termasuk satu host yang tidak dicakup aturan mana pun. Fungsi pencocokannya sengaja ditulis sederhana agar hasilnya mudah dihitung ulang, tanpa pengaturan tambahan apa pun.

python simulasi-ingress.py
"""Simulasi pencocokan host dan path terhadap aturan Ingress."""
import yaml

with open("ingress.yaml", encoding="utf-8") as berkas:
    ingress = yaml.safe_load(berkas)

# URL sampel yang diuji terhadap aturan pada manifest
sampel = [
    ("catatan.example.com", "/"),
    ("catatan.example.com", "/api"),
    ("catatan.example.com", "/api/nilai"),
    ("catatan.example.com", "/statistik"),
    ("kalender.example.com", "/"),
]

def cari_backend(host, path):
    for aturan in ingress["spec"]["rules"]:
        if aturan.get("host") != host:
            continue
        # path terpanjang diperiksa lebih dahulu, sesuai perilaku prefix paling spesifik
        urutan = sorted(aturan["http"]["paths"], key=lambda p: len(p["path"]), reverse=True)
        for jalur in urutan:
            akar = jalur["path"].rstrip("/")
            if path == akar or path.startswith(akar + "/"):
                return jalur["backend"]["service"]["name"]
    return None

print("Host yang dicakup:")
for aturan in ingress["spec"]["rules"]:
    print(f"  {aturan['host']}")

print()
print("Hasil pencocokan URL sampel:")
for host, path in sampel:
    backend = cari_backend(host, path)
    if backend:
        print(f"  http://{host}{path:<12s} -> Service {backend}")
    else:
        print(f"  http://{host}{path:<12s} -> tidak ada rute (404)")
text Keluaran
Host yang dicakup:
  catatan.example.com

Hasil pencocokan URL sampel:
  http://catatan.example.com/            -> Service service-web
  http://catatan.example.com/api         -> Service service-api
  http://catatan.example.com/api/nilai   -> Service service-api
  http://catatan.example.com/statistik   -> Service service-web
  http://kalender.example.com/            -> tidak ada rute (404)

Permintaan ke /api/nilai diarahkan ke service-api karena prefix /api lebih spesifik daripada /. Permintaan ke /statistik diarahkan ke service-web karena hanya path / yang cocok. Host kalender.example.com gagal seluruhnya karena tidak ada aturan host yang mencakupnya, dan proxy mengembalikan 404 untuk permintaan semacam itu. Kelima hasil tersebut konsisten dengan perilaku controller yang menerapkan aturan pada manifest yang sama.

Perhatikan pula bahwa urutan penulisan path pada manifest tidak menentukan hasil, karena skrip mengurutkan kandidat berdasarkan panjangnya sebelum mencocokkan. Controller asli menerapkan prinsip yang sama, sehingga aturan / yang ditulis lebih dahulu tidak mengambil alih /api. Kedua perilaku tersebut menjadikan manifest yang sama dapat dihitung ulang tanpa menjalankan controller mana pun.

Kesalahan umum#

Tiga kesalahan berikut paling sering muncul ketika Ingress mulai digunakan. Masing-masing memiliki gejala yang berbeda dan dapat diperiksa dengan cepat.

  • Ingress dibuat tanpa controller yang berjalan. Objek diterima, tetapi kolom ADDRESS kosong dan permintaan tidak pernah diteruskan. Perbaikannya adalah memasang controller terlebih dahulu, kemudian memastikan nilai ingressClassName cocok dengan kelas yang dipasang.
  • Service backend belum ada atau salah nama. Controller berjalan dan ADDRESS terisi, tetapi proxy mengembalikan 503 karena tujuan upstream tidak dapat ditemukan. Perbaikannya adalah mencocokkan nama Service dan port pada backend dengan objek yang benar-benar ada.
  • pathType tidak ditulis. Pada apiVersion: networking.k8s.io/v1, bidang tersebut wajib, sehingga manifest ditolak dengan pesan error validasi. Perbaikannya adalah menulis Prefix atau Exact sesuai maksud setiap path.

Ketiga gejala ini dapat dibedakan dari kolom ADDRESS dan kode status yang dikembalikan. ADDRESS yang kosong menunjuk pada controller yang belum ada, sedangkan 404 menandakan host yang tidak terdaftar dan 503 menandakan backend yang tidak dapat dijangkau. Pengamatan cepat ini biasanya sudah cukup untuk menentukan perbaikan mana yang perlu dijalankan.

Ringkasan#

  • Ingress menyimpan aturan routing HTTP per host dan per path, sedangkan ingress controller menerjemahkannya menjadi konfigurasi proxy yang aktif.
  • pathType: Prefix mencocokkan awalan path dan mengutamakan kecocokan terpanjang, sehingga aturan spesifik seperti /api dapat berdampingan dengan aturan umum /.
  • Kolom ADDRESS pada kubectl get ingress menjadi indikator cepat apakah controller sudah mengambil aturan, dan 404 untuk host yang tidak terdaftar adalah perilaku proxy yang normal.

Referensi#