Ingress #

Ketika kita merancang eksposur aplikasi web atau API ke luar kluster, kita diperkenalkan pada Service bertipe LoadBalancer. Tipe tersebut sangat andal untuk mengekspos satu layanan eksternal. Namun, seiring dengan pertumbuhan sistem kita menjadi arsitektur layanan mikro (microservices), kita akan mendapati diri kita memiliki puluhan layanan backend yang berbeda (misalnya layanan user, payment, dashboard, katalog, dst).

Jika kita membuat satu Service bertipe LoadBalancer untuk setiap layanan tersebut, kita akan dipaksa membayar biaya bulanan yang sangat mahal untuk puluhan Load Balancer fisik yang disediakan oleh cloud provider. Selain itu, mengelola puluhan alamat IP publik atau nama DNS publik eksternal yang berbeda-beda akan menjadi mimpi buruk operasional bagi tim SysOps.

Untuk menyelesaikan masalah efisiensi biaya dan fleksibilitas routing layer 7 ini, Kubernetes menyediakan objek khusus yang bernama Ingress. Ingress bertindak sebagai satu pintu gerbang masuk terpadu (single entry point) yang menerima seluruh lalu lintas data HTTP/HTTPS dari luar kluster, kemudian menyebarkannya ke layanan-layanan internal yang tepat berdasarkan aturan kueri nama domain host (host-based routing) atau jalur URL path (path-based routing).

Artikel ini akan mengulas secara mendalam komponen Ingress, cara kerja Ingress Controller, penulisan aturan manifes, instalasi TLS, optimasi anotasi produksi, serta evolusi menuju Gateway API.


Komponen Ingress: Resource vs Controller #

Salah satu konsep penting yang wajib kita pahami saat pertama kali menggunakan Ingress adalah pemisahan antara konfigurasi dan implementasi. Ingress di Kubernetes terbagi menjadi dua komponen yang terpisah:

flowchart TD
    System["KUBERNETES INGRESS SYSTEM"]
    System --> Resource["Ingress Resource (Berkas manifes YAML yang mendefinisikan aturan routing)"]
    System --> Controller["Ingress Controller (Aplikasi reverse proxy aktif yang memproses lalu lintas data)"]

1. Ingress Resource #

Ini adalah manifes YAML standar Kubernetes yang kita buat untuk mendefinisikan rute lalu lintas. Di dalam manifes ini, kita menuliskan aturan seperti: “Jika ada lalu lintas masuk dengan domain api.example.com menuju URL path /payments, belokkan lalu lintas tersebut ke Service payment-service di Port 80”. Objek ini hanyalah data konfigurasi statis di dalam database etcd; objek ini tidak melakukan pemrosesan data apa pun sendiri.

2. Ingress Controller #

Ingress Controller adalah aplikasi reverse proxy dan load balancer aktif yang berjalan sebagai Pod di dalam kluster kita. Kubernetes tidak menyertakan Ingress Controller secara default saat kluster diinisialisasi. Kita wajib menginstalnya sendiri secara manual (misalnya menginstal NGINX Ingress Controller, Traefik, Kong, atau HAProxy).

Ingress Controller bertugas memantau (watch) Kubernetes API Server untuk setiap objek Ingress Resource yang kita buat. Begitu mendeteksi adanya konfigurasi baru atau perubahan rute, Ingress Controller akan memperbarui file konfigurasi reverse proxy internalnya secara dinamis dan melakukan reload (misalnya menulis ulang blok nginx.conf secara runtime) tanpa memutus koneksi aktif pengguna.


Alur Penanganan Ingress Request #

Mari kita perhatikan bagaimana paket data dari luar kluster mengalir melintasi komponen Ingress melalui diagram berikut:

flowchart TD
    Client["Client luar (api.company.com/payments)"] --> LB["Cloud Load Balancer (NLB/ALB)"]
    LB --> IngressCtrl["Ingress Controller Pod (NGINX/Envoy)"]
    IngressCtrl -. Evaluasi rules .-> Svc["payment-service (ClusterIP)"]
    Svc --> Pod1["Pod payment-0"]
    Svc --> Pod2["Pod payment-1"]

Ketika client luar mengirimkan kueri HTTPS ke api.company.com/payments:

  1. Koneksi mendarat di satu-satunya Cloud Load Balancer fisik eksternal kita.
  2. Load Balancer meneruskan koneksi ke Pod Ingress Controller yang aktif di kluster.
  3. Ingress Controller menganalisis header HTTP kueri tersebut (menemukan host api.company.com dan path /payments).
  4. Ingress Controller mengevaluasi kecocokan aturan, lalu melompati ClusterIP Service internal dan mengirimkan lalu lintas tersebut langsung (direct bypass) ke salah satu alamat IP Pod backend payment yang sehat yang terdaftar di tabel Endpoints.

Struktur Manifes Ingress Produksi #

Mari kita pelajari contoh manifes Ingress standar produksi yang menggabungkan host-based routing, path-based routing, dan TLS termination:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: enterprise-ingress
  namespace: production
  annotations:
    kubernetes.io/ingress.class: "nginx" # Menentukan tipe controller (legacy method)
    nginx.ingress.kubernetes.io/ssl-redirect: "true" # Mengarahkan HTTP ke HTTPS otomatis
spec:
  ingressClassName: nginx # Pilihan standar modern untuk menunjuk Ingress Controller
  tls:
    - hosts:
        - api.mycompany.com
        - app.mycompany.com
      secretName: wildcard-tls-secret # Secret berisi sertifikat SSL/TLS
  rules:
    # 1. Host-based routing (api.mycompany.com)
    - host: api.mycompany.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: gateway-api-service
                port:
                  number: 8080
    # 2. Path-based routing (app.mycompany.com)
    - host: app.mycompany.com
      http:
        paths:
          - path: /api/users
            pathType: Prefix
            backend:
              service:
                name: user-service
                port:
                  number: 80
          - path: /api/billing
            pathType: Exact
            backend:
              service:
                name: billing-service
                port:
                  number: 80

Penyelaman Parameter pathType #

Kubernetes menyediakan tiga opsi pencocokan jalur URL path yang wajib kita tentukan secara tepat:

  • Exact: Kueri URL dari client harus cocok persis dengan karakter path yang ditulis. Sebagai contoh, /api/billing hanya akan cocok dengan /api/billing. Kueri seperti /api/billing/details atau /api/billing/ akan menghasilkan error 404 (Not Found).
  • Prefix: Kueri URL dinilai cocok jika memiliki awalan path yang sesuai. Sebagai contoh, /api/users akan mencocokkan /api/users, /api/users/, /api/users/123, dan /api/users/profile. Opsi ini adalah yang paling umum kita gunakan untuk API routing.
  • ImplementationSpecific: Algoritma pencocokan diserahkan sepenuhnya kepada implementasi internal Ingress Controller yang kita gunakan. Perilakunya dapat berbeda-beda antar penyedia controller.

TLS Termination dan Pengamanan HTTPS #

Salah satu fitur terbaik dari Ingress adalah kemampuannya melakukan TLS Termination (Pengakhiran TLS). Dengan TLS termination, proses jabat tangan kriptografi SSL/TLS yang berat didelegasikan sepenuhnya di tingkat Ingress Controller.

Lalu lintas data dari internet luar ke Ingress Controller berjalan di port aman 443 HTTPS terenkripsi. Setelah didekripsi di Ingress Controller, lalu lintas data diteruskan ke Pod internal kluster menggunakan port HTTP biasa (port 80). Hal ini sangat menghemat penggunaan daya CPU pada Pod aplikasi kita karena mereka tidak perlu melakukan proses enkripsi/dekripsi secara berulang-ulang.

1. Membuat Secret TLS Secara Manual #

Kita harus menyimpan berkas sertifikat SSL (.crt atau .pem) dan kunci privat (.key) kita ke dalam bentuk objek Secret Kubernetes bertipe kubernetes.io/tls:

kubectl create secret tls wildcard-tls-secret \
  --cert=path/to/fullchain.pem \
  --key=path/to/privkey.pem \
  -n production

2. Integrasi Otomatis dengan cert-manager (Let’s Encrypt) #

Daripada memperbarui sertifikat SSL secara manual setiap tiga bulan sekali, kita sangat disarankan menginstal addon cert-manager. cert-manager akan berkolaborasi dengan Let’s Encrypt menggunakan protokol ACME untuk mengotomatiskan pembuatan, penerbitan, dan perpanjangan sertifikat SSL kita.

Kita cukup menambahkan anotasi khusus pada Ingress Resource kita:

apiVersion: v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: [email protected]
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
      - http01:
          ingress:
            class: nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: auto-ssl-ingress
  namespace: production
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod" # Memicu cert-manager membuat SSL otomatis
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - app.mycompany.com
      secretName: app-tls-auto-secret # cert-manager akan menulis sertifikat Let's Encrypt ke Secret ini
  rules:
    - host: app.mycompany.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-service
                port:
                  number: 80

Optimasi Anotasi Ingress NGINX untuk Produksi #

Karena spesifikasi dasar Ingress Kubernetes sangat sederhana, seluruh konfigurasi canggih tingkat lanjut reverse proxy (seperti rate limiting, CORS, rewrite, dst) diselesaikan menggunakan annotations yang spesifik sesuai dengan Ingress Controller yang kita pilih.

Berikut adalah anotasi penting untuk NGINX Ingress Controller yang sering kita butuhkan di produksi:

1. Rate Limiting (Pencegahan DDOS & Brute Force) #

Membatasi jumlah permintaan koneksi dari satu alamat IP client per detik demi mengamankan ketersediaan backend:

nginx.ingress.kubernetes.io/limit-rps: "15" # Maksimal 15 request per detik dari satu IP client
nginx.ingress.kubernetes.io/limit-burst-multiplier: "3"

2. Mengizinkan Unggahan File Besar #

Secara default, NGINX membatasi ukuran body request maksimal 1MB. Jika aplikasi kita memiliki fitur unggah file gambar atau dokumen, kita harus menaikkan batas ini agar tidak mengalami error 413 Request Entity Too Large:

nginx.ingress.kubernetes.io/proxy-body-size: "50m" # Menaikkan batas unggahan file hingga 50 MegaBytes

3. Konfigurasi CORS (Cross-Origin Resource Sharing) #

Mengizinkan aplikasi frontend di domain lain (misalnya mobile app atau partner API) untuk melakukan kueri ke API kluster secara aman:

nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://my-partner-domain.com"

4. Konfigurasi Timeout Koneksi #

Mencegah koneksi tertahan terlalu lama saat memproses kueri database yang berat:

nginx.ingress.kubernetes.io/proxy-read-timeout: "120" # Batas waktu baca timeout disetel ke 120 detik
nginx.ingress.kubernetes.io/proxy-send-timeout: "120"

Ingress vs Gateway API: Masa Depan Routing Jaringan #

Meskipun Ingress sangat sukses, spesifikasi Ingress memiliki keterbatasan struktural yang mendasar. Karena spesifikasi Ingress dibuat sangat sederhana, konfigurasi kompleks akhirnya ditumpuk pada annotations. Hal ini membuat manifes Ingress antar kluster tidak portable (misalnya anotasi NGINX tidak bisa dipahami oleh Traefik). Selain itu, Ingress memaksakan satu file manifes dikelola bersama oleh SysOps (mengurus domain/SSL) dan Developer (mengurus path routing).

Untuk mengatasi keterbatasan ini, CNCF mengembangkan Gateway API sebagai standar routing modern generasi berikutnya.

flowchart TD
    Ops["1. Cluster Operator / SysOps (Mengurus GatewayClass)<br>'Gunakan Controller Envoy untuk Load Balancer'"]
    Ops --> Plat["2. Platform Engineer (Mengurus Gateway)<br>'Buka Port 443 HTTPS dengan SSL Wildcard Domain'"]
    Plat --> Dev["3. Application Developer (Mengurus HTTPRoute)<br>'Petakan path /payments ke Service payment-service'"]

Kelebihan Utama Gateway API #

  • Separation of Concerns: Memisahkan tanggung jawab pengelolaan jaringan secara deklaratif melalui objek-objek terpisah (GatewayClass, Gateway, dan HTTPRoute).
  • Kecanggihan Bawaan: Mendukung fitur canggih seperti weighted traffic splitting (canary deployment), header-based routing, dan URL redirection secara standar langsung dari spec API tanpa bantuan annotations.
  • Keamanan Multi-Tenant: Platform Engineer dapat menentukan kebijakan keamanan ketat di objek Gateway untuk membatasi namespace mana saja yang boleh membuat objek HTTPRoute di domain tertentu.

Anti-Pattern vs Solusi dalam Desain Ingress #

Mari kita pelajari beberapa kesalahan konfigurasi fatal yang sering kita temukan saat mengimplementasikan Ingress di kluster produksi.

Anti-Pattern 1: Mengabaikan Penentuan ingressClassName Modern #

Kita mendeploy objek Ingress Resource tanpa menyertakan properti ingressClassName, melainkan mengandalkan anotasi legacy kubernetes.io/ingress.class: "nginx".

Kode Manifest Salah (Gaya Lama Tanpa Kelas Eksplisit) #

# JANGAN GUNAKAN STYLE INI LAGI
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress-legacy
  namespace: production
  annotations:
    kubernetes.io/ingress.class: "nginx" # ANOTASI LEGACY: Rentan diabaikan oleh kluster modern
spec:
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-service
                port:
                  number: 80

Konsekuensi Buruk #

Mulai Kubernetes versi 1.22+, anotasi kubernetes.io/ingress.class telah dinyatakan deprecated (usang). Jika kluster kita menjalankan lebih dari satu Ingress Controller (misalnya menjalankan NGINX untuk akses publik dan Kong untuk API Gateway internal), mengosongkan properti ingressClassName dapat memicu kegagalan routing karena tidak ada controller yang merasa bertanggung jawab memproses manifest tersebut.

Kode Solusi (Gaya Modern Deklaratif) #

# SOLUSI: Selalu gunakan properti ingressClassName yang eksplisit
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress-modern
  namespace: production
spec:
  ingressClassName: nginx # Eksplisit memilih NGINX Ingress Controller
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-service
                port:
                  number: 80

Anti-Pattern 2: Salah Konfigurasi Regex pada Anotasi URL Rewrite #

Kita ingin agar seluruh request dengan URL prefix /api diteruskan ke backend aplikasi web kita, tetapi kita ingin agar Ingress memotong kata /api tersebut saat paket tiba di backend (misalnya kueri /api/v1/users di-rewrite menjadi /v1/users).

Kode Manifest Salah (Rewrite Tanpa Capturing Group) #

# JANGAN LAKUKAN INI: Memotong path secara mentah
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress-rewrite-failure
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: / # Menimpa seluruh path menjadi root!
spec:
  ingressClassName: nginx
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /api # Tanpa regex capturing group
            pathType: Prefix
            backend:
              service:
                name: backend-service
                port:
                  number: 80

Konsekuensi Buruk #

Dengan konfigurasi di atas, jika client mengakses http://app.example.com/api/v1/users, NGINX akan menimpa seluruh URL path tersebut menjadi root /. Aplikasi backend kita akan menerima request di path / dan mengembalikan respon error 404 karena path /v1/users hilang seluruhnya akibat proses rewrite yang salah sasaran.

Kode Solusi (Menggunakan Capturing Group Regex secara Tepat) #

# SOLUSI: Gunakan capturing group regex untuk melestarikan sub-path
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress-rewrite-success
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2 # Mengambil sisa path dari group kedua ($2)
spec:
  ingressClassName: nginx
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /api(/|$)(.*) # Group 1: (/|$), Group 2: sisa path (.*)
            pathType: Prefix
            backend:
              service:
                name: backend-service
                port:
                  number: 80

Panduan Praktis Debugging Konektivitas Ingress #

Jika domain publik kita mengembalikan pesan error 502 Bad Gateway atau 503 Service Temporarily Unavailable, berikut adalah langkah-langkah audit sistematis:

1. Memeriksa Alamat IP Ingress #

Pastikan API Server berhasil memberikan alokasi IP eksternal publik pada objek Ingress kita:

kubectl get ingress -n production

Jika kolom ADDRESS kosong setelah beberapa menit, periksa apakah Ingress Controller telah dikonfigurasi dengan LoadBalancer Service yang sehat.

2. Memeriksa Log Ingress Controller Pod #

Kunci utama pemecahan masalah Ingress berada di dalam berkas log pod controller-nya. Cari pod NGINX Ingress Controller di namespace kube-system atau namespace kustomnya:

# Mengambil log dari NGINX Ingress Controller
kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=100

Tinjau apakah ada baris log berisi error reload:

  • "Configuration is invalid ...": Terjadi kesalahan sintaksis pada regex path atau parameter SSL secret yang kita definisikan.
  • "502 Bad Gateway": Ingress Controller berhasil mengidentifikasi rute, tetapi Pod backend aplikasi kita tidak merespon (misalnya Pod crash atau port kontainer tidak cocok dengan targetPort Service).

Ringkasan #

  • Ingress meminimalkan cloud cost: Menggunakan satu unit Load Balancer cloud untuk melayani puluhan Service internal kluster melalui mekanisme routing HTTP layer 7.
  • Pahami peran Controller vs Resource: Ingress Resource adalah berkas konfigurasi statis, sedangkan Ingress Controller (seperti NGINX) adalah engine proxy aktif yang menjalankan aturan tersebut.
  • Implementasikan TLS Termination: Bebaskan beban CPU Pod aplikasi kita dari proses dekripsi SSL/TLS dengan mengakhiri koneksi HTTPS secara aman di tingkat Ingress Controller.
  • Gunakan cert-manager untuk manajemen SSL: Otomatiskan proses pembuatan dan perpanjangan sertifikat SSL Let’s Encrypt dengan mengintegrasikan cert-manager langsung ke Ingress Resource.
  • Manfaatkan annotations untuk fitur produksi: Konfigurasi rate limiting, proxy body size, CORS, dan timeout koneksi menggunakan annotations spesifik controller.
  • Gunakan regex capturing group untuk rewrite: Pastikan penulisan target rewrite URL menyertakan capturing group agar tidak merusak segmentasi sub-path yang dikirim ke aplikasi backend.

← Sebelumnya: DNS & Service Discovery   Berikutnya: Network Policy →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact