Blog AWS Indonesia
Mengekspos Aplikasi Kubernetes, Bagian 1: Resource Service dan Ingress
Perkenalan
Seri Mengekspos Aplikasi Kubernetes berfokus pada cara untuk mengekspos aplikasi yang berjalan di cluster Kubernetes untuk akses eksternal.
Dalam Bagian 1 dari seri ini, kita akan membahas Service dan tipe resource Ingress yang menentukan dua cara untuk mengontrol traffic masuk dalam Kubernetes cluster. Kami membahas penanganan tipe resource ini melalui Service dan Ingress controller, diikuti dengan gambaran umum kelebihan dan kekurangan beberapa varian implementasi controller.
Di Bagian 2, kami memberikan gambaran umum tentang implementasi open-source AWS dari Service dan Ingress controller, AWS Load Balancer Controller. Kami mendemonstrasikan pengaturan, konfigurasi, kemungkinan use case, dan limitasi controller.
Bagian 3 memberikan panduan serupa tentang implementasi open-source tambahan dari Ingress controller, NGINX Ingress Controller, dan beberapa cara yang berbeda dari AWS lainnya.
Motivasi
Kubernetes adalah container orchestration engine yang memungkinkan Anda untuk men-deploy, scaling, dan mengelola aplikasi dalam container.
Cluster administrator dan developer aplikasi menentukan resource logical yang menggambarkan keadaan cluster dan aplikasi yang diinginkan di dalamnya. Berbagai mekanisme Kubernetes kemudian bekerja untuk mencapai dan mempertahankan keadaan tersebut.
Untuk beberapa aplikasi, biasanya yang menangani operasi batch atau asynchronous, mengaktifkan akses jaringan mungkin bukan persyaratan. Untuk yang lain, seperti backend RESTful service atau aplikasi web sifatnya wajib.
Memahami berbagai use case dan cara yang tepat untuk mengekspos aplikasi ini adalah kunci untuk menyiapkan infrastruktur cluster yang dapat discaling dan mudah secara operasional.
Service Kubernetes
Aplikasi Kubernetes terdiri dari satu atau beberapa Pod yang menjalankan satu atau beberapa container. Setiap Pod mendapatkan alamat IP-nya sendiri. Alamat IP Pod dapat diakses di luar cluster tergantung pada implementasi cluster Container Network Interface (CNI) plugin. Beberapa implementasi CNI plugin membuat jaringan overlay di seluruh node Kubernetes, menjaga IP Pod tetap internal ke cluster Amazon Virtual Private Cloud (VPC) CNI plugin menggunakan VPC IP addressing, sehingga setiap Pod mendapatkan alamat IP yang valid dari VPC CIDR range, yang membuat IP yang sama dapat diakses baik secara internal maupun eksternal ke cluster.
Meskipun memungkinkan, mengakses aplikasi dengan IP Pod mereka biasanya merupakan anti-pattern. Pod adalah objek tidak permanen yang dapat dibuat dan dihancurkan, “berpindah” di antara node pada cluster, karena adanya scaling, penggantian node, atau perubahan konfigurasi. Selain itu, metode direct access tidak menjawab kebutuhan load balancing atau routing aplikasi.
Untuk mengatasi masalah ini dan mengekspos aplikasi dengan lebih baik, tipe resource Service diperkenalkan. Service adalah abstraksi atas sekumpulan Pod yang dibangun secara dinamis (dynamically constructed) yang ditentukan oleh sekumpulan label selector.
Selama seri artikel ini, kita akan mengikuti terminologi Kubernetes, di mana tipe resource (misalnya, Service) adalah definisi logis yang, ketika dibuat melalui panggilan Kubernetes Application Programming Interface (API), menjadi resource (misalnya, Service), kadang-kadang juga disebut sebagai objek.
Berikut adalah contoh definisi Service yang mencocokkan sekumpulan Pod dalam sebuah deployment menggunakan label selector:
apiVersion: v1
kind: Service
metadata:
name: some-service
namespace: some-namespace
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: some-app
ports:
- name: svc-port
port: 80
targetPort: app-port
protocol: TCP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: some-deployment
namespace: some-namespace
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: some-app
template:
metadata:
labels:
app.kubernetes.io/name: some-app
spec:
containers:
- name: nginx
image: public.ecr.aws/nginx/nginx
ports:
- name: app-port
containerPort: 80
...
Mengekspos sebuah Service
Cara di mana Service resource diekspos dikontrol melalui pengaturan spec.type-nya, dengan hal-hal berikut relevan dengan diskusi kita:
- ClusterIP (seperti pada contoh di atas), yang memberikan service cluster-private virtual IP dan merupakan default
- NodePort, yang mengekspos ClusterIP di atas melalui static port pada setiap cluster node
- Load balancer, yang secara otomatis membuat ClusterIP, mengatur NodePort, dan menunjukkan bahwa infrastruktur environment yang dibuat pada cluster (misalnya, cloud provider) diharapkan untuk membuat komponen load balancer untuk mengekspos Pod di belakang Service
Setelah Pod yang ditargetkan oleh Service dibuat dan siap, IP-nya dipetakan ke ClusterIP untuk memberikan load balancing antara Pod. Sebuah kube-proxy daemon, pada setiap node cluster, mendefinisikan pemetaan itu dalam aturan iptables (secara default) untuk digunakan kernel Linux saat routing paket jaringan, tetapi itu sendiri sebenarnya tidak ada di data path.
Kubernetes juga menyediakan built-in internal service discovery dan mekanisme komunikasi. Setiap ClusterIP Service dilengkapi dengan nama DNS cluster-private <service-name>.<namespace-name>.
svc.cluster.local
form, dapat diakses dari Pod di cluster.
Untuk memungkinkan akses eksternal, tipe LoadBalancer biasanya merupakan solusi yang dipilih, karena menggabungkan opsi lain dengan kemampuan load balancing dan fitur tambahan yang mungkin ada. Di AWS, fitur-fitur ini, tergantung pada jenis load balancer, termasuk perlindungan Distributed Denial of Service (DDoS) dengan AWS WAF service, certificate management dengan AWS Certificate Manager, dan banyak lagi.
Dalam Kubernetes, controller adalah implementasi dari control loop pattern, dan tanggung jawabnya adalah untuk menjaga state yang diinginkan, yang didefinisikan oleh berbagai Kubernetes resource, dengan state aktual dari sistem. Service controller mengawasi Service resource baru yang akan dibuat dan, bagi mereka yang memiliki spec.type LoadBalancer, controller menyediakan load balancer menggunakan API cloud provider. Kemudian mengonfigurasi listener dan target groups dari load balancer dan mendaftarkan Pod di belakang Service sebagai target.
Cara load balancer melakukan routing ke Pod adalah tergantung dari tipe load balancer dan Service controller. Misalnya, dengan AWS Network Load Balancer dan Application Load Balancer Anda dapat meng-konfigurasi target groups yang menggunakan tipe target instance dan routing ke NodeIP:NodePort pada node yang relevan dalam cluster atau target tipe ip dan dirouting langsung ke IP Pod.
Secara skematis, dengan asumsi tipe target ip, dapat ditunjukkan dalam diagram berikut:
In-tree Service Controller
Saat ini, di samping setiap versi Kubernetes, terdapat versi rilis kode yang sesuai dengan cloud provider tertentu yang bertanggung jawab untuk mengintegrasikan cluster dengan API cloud provider. Kode ini, sampai saat ini, berada di dalam repositori Kubernetes dan dengan demikian disebut sebagai in-tree cloud provider, diinstall secara default pada Kubernetes cluster cloud provider yang sesuai. Amazon EKS cluster, melalui AWS cloud provider, sudah terinstall dengan AWS Cloud Controller Manager, yang berisi Service controller, yang disebut sebagai in-tree Service controller.
Pada cluster Amazon EKS kosong (dari segi controller), in-tree controller yang menangani objek Service, sehingga definisi Service berikut membuat Classic Load Balancer dan menghubungkannya ke node (karena classic load balancer hanya mendukung yang setara dengan tipe instance target):
apiVersion: v1
kind: Service
metadata:
name: some-service
namespace: apps
labels:
app.kubernetes.io/name: some-service
spec:
type: LoadBalancer
selector:
app.kubernetes.io/name: some-service
ports:
- name: svc-port
port: 80
targetPort: app-port
protocol: TCP
Anda dapat mengontrol konfigurasi in-tree controller melalui annotations. Misalnya, berikut ini akan menyediakan AWS Network Load Balancer, bukan Classic (sekali lagi, hanya target tipe instance yang didukung):
apiVersion: v1
kind: Service
metadata:
name: some-service
namespace: apps
labels:
app.kubernetes.io/name: some-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
...
In-tree controller relatif terbatas dalam fungsionalitas, seperti yang terbukti dengan kurangnya dukungan untuk target tipe IP, yang lebih cocok untuk aplikasi container. Kami akan membahas alternatif yang jauh lebih kaya fitur, AWS Load Balancer Controller, di Bagian 2 dari seri ini.
Menangani Banyak Service
Aplikasi nontrivial (kompleks) dapat berisi lusinan API endpoint yang perlu diekspos secara eksternal. Aplikasi semacam itu akan membutuhkan lusinan load balancer, dengan satu untuk setiap Service yang mengekspos API endpoint ini. Ini memperkenalkan kompleksitas operasional tambahan dan biaya infrastruktur.
Solusi yang mungkin adalah membuat sebuah load balancer dan kemudian menghubungkan Service dan Pod mereka ke target group load balancer. Ini adalah implementasi yang relatif kompleks, mengingat Service yang berbeda mungkin dimiliki oleh tim lain dengan siklus development dan deployment yang independen. Ini membutuhkan penetapan prioritas dan proses penggabungan dan menyediakan tim-tim ini beberapa bentuk akses ke konfigurasi load balancer, yang seringkali tidak diinginkan.
Untungnya, Kubernetes memberikan abstraksi atas proses itu, yang merupakan tipe resource Ingress.
Apa itu Ingress?
Ingress adalah built-in Kubernetes tipe resource yang bekerja dalam kombinasi dengan Service untuk menyediakan akses ke Pod di belakang Service ini. Ingress mendefinisikan seperangkat rule untuk routing traffic HTTP/HTTPS yang masuk (tidak mendukung TCP/UDP) ke backend Service dan default backend jika tidak ada rule yang cocok. Setiap rule dapat menentukan host, path, dan backend yang diinginkan untuk menerima traffic jika ada kecocokan.
Contoh definisi Ingress mungkin terlihat seperti berikut:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: some-ingress
annotations:
alb.ingress.kubernetes.io/load-balancer-name: ingress
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/scheme: internet-facing
spec:
ingressClassName: alb
rules:
- host: my.example.com
http:
paths:
- path: /some-path
pathType: Prefix
backend:
service:
name: service-a
port:
number: 80
- path: /some-other-path
pathType: Exact
backend:
service:
name: service-b
port:
number: 81
- host: '*.example.com'
http:
paths:
- path: /some-path
pathType: Prefix
backend:
service:
name: service-c
port:
number: 82
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service-d
port:
number: 80
Kode di atas mendefinisikan bahwa setiap traffic:
- untuk example.com dengan path yang:
- dimulai dengan some-path harus dirouting ke service-a pada port 80
- sama dengan some-other-path harus dirouting ke service-b pada port 81
- selain itu, untuk setiap subdomain dari example.com dengan jalur yang
- dimulai dengan some-path harus dirouting ke service-c pada port 82
- yang tidak memiliki hostname yang ditentukan dalam permintaan harus dirouting ke service-d pada port 80
Jika tidak ada skenario ini yang cocok, maka permintaan dirouting ke default backend yang telah ditentukan sebelumnya.
Lihat spesifikasi lengkap dan gambaran umum dalam dokumentasi resmi Kubernetes.
Selain itu, ada beberapa annotations: yang pertama, kubernetes.io/ingress.class, yang mendefinisikan hubungan antara resource Ingress dan implementasinya. Yang lain mendefinisikan target type, ip, dari load balancer yang akan disediakan. Anotasi lain dapat digunakan untuk memberikan implementasi khusus parameter konfigurasi.
Penerapan Ingress
Jika Anda membuat resource Ingress pada Kubernetes cluster, itu sebenarnya tidak melakukan banyak hal, selain membuat representasi objeknya di Kubernetes key-value data store: etcd.
Untuk objek Ingress, Ingress controller bertanggung jawab untuk membuat jalur yang diperlukan, menyediakan komponen load balancer, dan merekonsiliasi status cluster. Tidak ada Ingress controller default yang termasuk dalam controller manager yang didistribusikan dengan Kubernetes, sehingga harus diinstall secara terpisah.
Dalam posting ini, kita akan membahas dua pendekatan yang mungkin untuk implementasi Ingress controller: External Load Balancer dan Internal Reverse Proxy, perbedaan di antara keduanya, dan pro dan kontra dari setiap implementasi.
External Load Balancer
Pendekatannya mirip dengan pendekatan berbasis Service yang telah kami jelaskan sebelumnya:
Implementasi AWS untuk Ingress controller, AWS Load Balancer Controller, menerjemahkan rule, parameter, dan annotation Ingress ke dalam konfigurasi Application Load Balancer, membuat listeners dan target group, serta menghubungkan target mereka ke backend Service.
Pengaturan ini meringankan kompleksitas monitoring, pengelolaan, dan mekanisme routing untuk scaling ke cloud provider dengan menggunakan load balancer service yang dikelola, highly available, dan dapat diskalakan. Fitur tambahan Distributed Denial of Service attack (DDOS attack) juga dapat ditangani oleh load balancer service.
Internal Reverse Proxy
Dalam hal ini, implementasi didelegasikan ke Internal, in-cluster Layer 7 Reverse Proxy (misalnya, NGINX), yang menerima traffic dari luar cluster dan me-routing ke backend Service berdasarkan konfigurasi Ingress.
Penginstalan, konfigurasi, dan maintenance dari reverse proxy ditangani oleh operator cluster, berbeda dengan penggunaan AWS Elastic Load Balancing service yang dimanage oleh AWS yang merupakan pendekatan sebelumnya. Akibatnya, meskipun dapat memberikan tingkat penyesuaian yang lebih tinggi agar sesuai dengan kebutuhan aplikasi yang berjalan di cluster, fleksibilitas ini ada konsekuensinya.
Implementasi reverse proxy menempatkan elemen tambahan pada data path, yang berdampak pada latensi, tetapi yang lebih penting, ini secara signifikan meningkatkan beban operasional. Tidak seperti layanan AWS Elastic Load Balancing yang dimanage sepenuhnya oleh AWS yang digunakan oleh implementasi sebelumnya, operator cluster bertanggung jawab untuk me-monitor, memelihara, men-scaling, dan mem-patch perangkat lunak proxy dan instance yang dijalankannya.
Perlu disebutkan bahwa dalam beberapa kasus, dua implementasi controller dapat digunakan secara paralel, menangani segmen terpisah dari cluster atau dalam kombinasi untuk membentuk solusi lengkap. Kita akan melihat contoh ini di Bagian 3 dari seri ini.
Kubernetes Gateway API
Meskipun kami tidak akan membahas detail implementasinya, Kubernetes gateway API (saat ini dalam versi beta) dalam spesifikasi lain adalah yang menyediakan cara untuk mengekspos aplikasi di Kubernetes cluster, selain tipe resource Service dan Ingress.
Gateway API saat ini belum didukung oleh Amazon EKS, dikarenakan baru saja diluncurkan ke versi beta.
Gateway API mendekonstruksi abstraksi lebih lanjut menjadi:
- GatewayClass yang, mirip dengan IngressClass, menunjukkan controller untuk menangani API objek
- Gateway yang, mirip dengan Ingress, mendefinisikan titik masuk dan memicu pembuatan komponen load balancer, berdasarkan handling controller dan definisi gateway
- HTTPRoute (dengan TLSRoute, TCPRoute, dan UDPRoute yang akan datang), yang mendefinisikan rule routing yang menghubungkan gateway ke Service di belakangnya, memungkinkan pencocokan traffic berdasarkan host, header, dan path dan membaginya berdasarkan weight
- ReferencePolicy, yang memungkinkan untuk mengontrol rute mana yang dapat diekspos melalui gateway mana dan Service mana yang dapat diekspos (termasuk cross-namespace)
Ini hanyalah gambaran sekilas, tetapi seharusnya terlihat sangat mirip dengan apa yang telah kita lihat pada tulisan ini:
Penyediaan aktual komponen load balancer oleh controller, yang hilang dari diagram di atas, dapat mengambil salah satu rute (external load balancer atau in-cluster reverse proxy) atau terhubung ke paradigma yang berbeda, seperti service mesh.
Kesimpulan
Di Bagian 1 dari seri ini, kami membahas beberapa cara untuk mengekspos aplikasi yang berjalan di Kubernetes cluster: Berbasis Service dengan external load balancer dan berbasis Ingress dengan external load balancer atau in-cluster reverse proxy Layer 7. Kami secara singkat menyentuh Kubernetes Gateway API yang sedang berkembang yang bertujuan untuk memberikan kontrol lebih lanjut atas bagaimana aplikasi diekspos.
Selama sisa seri, kami fokus pada implementasi berbasis Ingress dengan AWS Load Balancer Controller dan NGINX Ingress Controller, mendiskusikan pengaturan dan konfigurasinya, dan berjalan melalui serangkaian contoh.
Artikel ini diterjemahkan dari artikel asli berjudul “Exposing Kubernetes Applications, Part 1: Service and Ingress Resources” yang ditulis oleh Dmitry Notels dan Tsahi Duek.