Hari ini kami menerbitkan terjemahan bagian ketiga dari Panduan Jaringan Kubernetes. Bagian
pertama adalah tentang pod, yang
kedua tentang layanan, dan hari ini kita akan berbicara tentang penyeimbangan beban dan sumber daya Kubernet dari tipe Ingress.
Routing bukan load balancing
Pada artikel
sebelumnya dalam seri ini, kami mempertimbangkan konfigurasi yang terdiri dari sepasang perapian dan layanan yang diberi alamat IP yang disebut "cluster IP". Pertanyaan yang ditujukan untuk perapian dikirim ke alamat ini. Di sini kami akan terus bekerja pada sistem pelatihan kami, mulai dari tempat kami lulus terakhir kali. Ingatlah bahwa alamat IP cluster dari layanan,
10.3.241.152
, milik serangkaian alamat IP yang berbeda dari yang digunakan dalam jaringan perapian dan dari yang digunakan dalam jaringan di mana node berada. Saya menyebut jaringan yang didefinisikan oleh ruang alamat ini sebagai "jaringan layanan", meskipun hampir tidak layak untuk nama khusus, karena tidak ada perangkat yang terhubung ke jaringan ini, dan ruang alamatnya, pada kenyataannya, seluruhnya terdiri dari aturan routing. Sebelumnya diperlihatkan bagaimana jaringan ini diimplementasikan berdasarkan komponen Kubernetes, yang disebut
kube-proxy, dan berinteraksi dengan modul kernel Linux
netfilter untuk mencegat dan mengarahkan lalu lintas yang dikirim ke cluster IP untuk bekerja di bawah.
Diagram jaringanSejauh ini, kami berbicara tentang "koneksi" dan "permintaan" dan bahkan menggunakan konsep "lalu lintas" yang sulit diinterpretasikan, tetapi untuk memahami fitur mekanisme Ingress Kubernetes, kita perlu menggunakan istilah yang lebih tepat. Jadi, koneksi dan permintaan berfungsi pada level 4 dari
model OSI (tcp) atau pada level 7 (http, rpc, dan sebagainya). Aturan Netfilter adalah aturan routing, mereka bekerja dengan paket IP di level ketiga. Semua router, termasuk netfilter, membuat keputusan lebih atau kurang hanya berdasarkan informasi yang terkandung dalam paket. Secara umum, mereka tertarik dari mana paket itu berasal dan ke mana ia pergi. Oleh karena itu, untuk menggambarkan perilaku ini dalam hal tingkat ketiga model OSI, harus dikatakan bahwa setiap paket yang ditujukan untuk layanan yang terletak di
10.3.241.152:80
, yang tiba di antarmuka node
eth0
, diproses oleh netfilter, dan, sesuai dengan aturan yang ditetapkan untuk layanan kami dialihkan ke alamat IP dari perapian yang bisa diterapkan.
Tampaknya cukup jelas bahwa mekanisme apa pun yang kami gunakan untuk memungkinkan klien eksternal mengakses pod harus menggunakan infrastruktur perutean yang sama. Akibatnya, klien eksternal ini akan mengakses alamat IP dan port cluster, karena mereka adalah "titik akses" untuk semua mekanisme yang telah kita bicarakan sejauh ini. Mereka memungkinkan kita untuk tidak khawatir tentang di mana tepatnya itu dieksekusi pada titik waktu tertentu. Namun, sama sekali tidak jelas bagaimana membuat semuanya berfungsi.
Layanan IP Cluster hanya dapat dijangkau dengan antarmuka node Ethernet. Tidak ada di luar gugus yang tahu apa yang harus dilakukan dengan alamat dari rentang tempat alamat ini berada. Bagaimana saya bisa mengarahkan lalu lintas dari alamat IP publik ke alamat yang hanya dapat dijangkau jika paket telah tiba di host?
Jika kami mencoba menemukan solusi untuk masalah ini, maka salah satu hal yang dapat dilakukan dalam proses menemukan solusi adalah mempelajari aturan netfilter menggunakan utilitas
iptables . Jika Anda melakukan ini, Anda dapat menemukan sesuatu yang, pada pandangan pertama, mungkin tampak tidak biasa: aturan untuk layanan tidak terbatas pada jaringan sumber tertentu. Ini berarti bahwa setiap paket yang dihasilkan di mana saja yang tiba pada antarmuka Ethernet dari simpul dan memiliki alamat tujuan
10.3.241.152:80
akan diakui sebagai sesuai dengan aturan dan akan dialihkan ke sub. Bisakah kita memberi klien IP cluster, mungkin dengan mengikatnya ke nama domain yang sesuai, dan kemudian mengatur rute yang memungkinkan kita untuk mengatur pengiriman paket-paket ini ke salah satu node?
Klien dan kluster eksternalJika semuanya diatur dengan cara ini, maka desain seperti itu akan terbukti berfungsi. Klien mengakses IP cluster, paket mengikuti rute yang mengarah ke host, dan kemudian mereka diarahkan ke bawah. Pada saat ini, tampaknya bagi Anda solusi semacam itu dapat dibatasi, tetapi ia mengalami beberapa masalah serius. Yang pertama adalah bahwa node, pada kenyataannya, konsep sesaat, mereka tidak terlalu berbeda dalam hal ini dari perapian. Mereka, tentu saja, sedikit lebih dekat ke dunia material daripada polong, tetapi mereka dapat bermigrasi ke mesin virtual baru, cluster dapat naik atau turun, dan sebagainya. Router bekerja pada level ketiga model OSI dan paket tidak dapat membedakan antara layanan yang berfungsi normal dan yang tidak bekerja dengan benar. Mereka berharap bahwa transisi berikutnya dalam rute akan dapat diakses dan stabil. Jika node tidak dapat dijangkau, rute akan menjadi tidak beroperasi dan akan tetap demikian, dalam banyak kasus, banyak waktu. Bahkan jika rute tersebut tahan terhadap kegagalan, skema semacam itu akan mengarah pada kenyataan bahwa semua lalu lintas eksternal melewati satu node, yang mungkin tidak optimal.
Tidak peduli bagaimana kita membawa lalu lintas klien ke sistem, kita perlu melakukan ini sehingga tidak tergantung pada keadaan node cluster tunggal. Dan, pada kenyataannya, tidak ada cara yang dapat diandalkan untuk melakukan ini hanya dengan menggunakan routing, tanpa beberapa cara mengelola router secara aktif. Sebagai soal fakta, justru peran ini, peran sistem kontrol, yang dimainkan oleh kube-proxy dalam kaitannya dengan netfilter. Memperluas tanggung jawab Kubernetes untuk mengelola router eksternal mungkin tidak masuk akal bagi arsitek sistem, terutama karena kami telah memiliki alat yang terbukti untuk mendistribusikan lalu lintas klien di beberapa server. Mereka disebut load balancers, dan tidak mengherankan bahwa mereka adalah solusi yang benar-benar andal untuk Kubernetes Ingress. Untuk memahami dengan tepat bagaimana ini terjadi, kita perlu bangkit dari OSI tingkat ketiga dan berbicara tentang koneksi lagi.
Untuk menggunakan load balancer untuk mendistribusikan lalu lintas klien di antara node cluster, kami membutuhkan alamat IP publik yang dapat disambungkan klien, dan kami juga membutuhkan alamat node itu sendiri yang dapat digunakan oleh penyeimbang beban untuk mengalihkan permintaan. Untuk alasan di atas, kita tidak bisa begitu saja membuat rute statis yang stabil antara router gateway dan node menggunakan jaringan berbasis layanan (IP cluster).
Di antara alamat lain yang dapat digunakan untuk bekerja, hanya alamat jaringan yang terhubung dengan antarmuka Ethernet dari node, yaitu, dalam contoh ini,
10.100.0.0/24
, yang dapat dicatat. Router sudah tahu cara meneruskan paket ke antarmuka ini, dan koneksi yang dikirim dari load balancer ke router akan menuju ke mana mereka harus pergi. Tetapi jika klien ingin terhubung ke layanan kami di port 80, maka kami tidak bisa hanya mengirim paket ke port ini di antarmuka jaringan node.
Load balancer, upaya yang gagal untuk mengakses port 80 dari antarmuka jaringan hostAlasan mengapa hal ini tidak dapat dilakukan benar-benar jelas. Yaitu, kita berbicara tentang fakta bahwa tidak ada proses menunggu koneksi di
10.100.0.3:80
(dan jika ada, maka ini jelas bukan proses yang sama), dan aturan netfilter, yang, seperti yang kami harapkan, akan mencegat permintaan dan mereka akan mengirimkannya kepadanya, mereka tidak akan bekerja di alamat tujuan itu. Mereka hanya menanggapi jaringan IP cluster berdasarkan layanan, yaitu ke alamat
10.3.241.152:80
. Akibatnya, paket-paket ini, pada saat kedatangan, tidak dapat dikirimkan ke alamat tujuan, dan kernel akan mengeluarkan respons
ECONNREFUSED
. Ini menempatkan kita dalam posisi yang membingungkan: tidak mudah untuk bekerja dengan jaringan untuk pengalihan paket yang netfilter dikonfigurasi ketika mengarahkan data dari gateway ke node, dan jaringan yang routingnya mudah dikonfigurasikan bukan jaringan yang netfilter mengarahkan paket. Untuk mengatasi masalah ini, Anda dapat membuat jembatan antara jaringan-jaringan ini. Inilah yang dilakukan Kubernetes menggunakan layanan seperti NodePort.
Layanan seperti NodePort
Layanan yang kami, misalnya, buat di artikel sebelumnya, tidak diberi tipe, jadi ia mengadopsi tipe default -
ClusterIP
. Ada dua jenis layanan yang berbeda dalam fitur tambahan, dan salah satu yang kami minati saat ini adalah
NodePort
. Berikut adalah contoh deskripsi layanan jenis ini:
kind: Service apiVersion: v1 metadata: name: service-test spec: type: NodePort selector: app: service_test_pod ports: - port: 80 targetPort: http
Layanan tipe
NodePort
adalah layanan tipe
ClusterIP
yang memiliki peluang tambahan: akses ke mereka dapat diperoleh baik dengan alamat IP yang ditugaskan ke host dan oleh alamat yang diberikan ke cluster di jaringan layanan. Ini dicapai dengan cara yang agak sederhana: ketika Kubernetes membuat layanan NodePort, kube-proxy mengalokasikan port dalam kisaran 30000-32767 dan membuka port ini pada antarmuka
eth0
dari setiap node (maka nama jenis layanan -
NodePort
). Koneksi yang dilakukan ke port ini (kami akan memanggil port
NodePort
) dialihkan ke IP cluster dari layanan. Jika kita membuat layanan yang dijelaskan di atas dan menjalankan perintah
kubectl get svc service-test
, kita dapat melihat port yang ditugaskan untuk itu.
$ kubectl get svc service-test NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE service-test 10.3.241.152 <none> 80:32213/TCP 1m
Dalam hal ini, layanan ini diberikan NodePort
32213
. Ini berarti bahwa kita sekarang dapat terhubung ke layanan melalui sembarang simpul di gugus eksperimental kami di
10.100.0.2:32213
atau di
10.100.0.3:32213
. Dalam hal ini, lalu lintas akan dialihkan ke layanan.
Setelah bagian dari sistem ini mengambil tempat, kami memiliki semua fragmen pipa untuk menyeimbangkan beban yang dibuat oleh permintaan klien ke semua node cluster.
Layanan NodePortDalam gambar sebelumnya, klien terhubung ke penyeimbang beban melalui alamat IP publik, penyeimbang beban memilih node dan menghubungkannya di
10.100.0.3:32213
, kube-proxy menerima koneksi ini dan mengarahkannya ke layanan yang dapat diakses melalui cluster IP
10.3.241.152:80
. Di sini, permintaan berhasil diproses sesuai dengan aturan yang ditetapkan oleh netfilter, dan dialihkan ke pod server di alamat
10.0.2.2:8080
. Mungkin semua ini mungkin terlihat sedikit rumit, dan sedikit banyak, tetapi tidak mudah untuk menghasilkan solusi yang lebih sederhana yang mendukung semua fitur hebat yang memberi kita pod dan jaringan berbasis layanan.
Namun mekanisme ini bukan tanpa masalah sendiri. Menggunakan layanan seperti
NodePort
memberi pelanggan akses ke layanan menggunakan port non-standar. Seringkali ini bukan masalah, karena load balancer dapat memberi mereka port reguler dan menyembunyikan
NodePort
dari pengguna akhir. Tetapi dalam beberapa skenario, misalnya, ketika menggunakan penyeimbang beban platform Google Cloud eksternal, mungkin perlu untuk menyebarkan
NodePort
klien. Perlu dicatat bahwa pelabuhan seperti itu, di samping itu, mewakili sumber daya yang terbatas, meskipun 2.768 pelabuhan mungkin cukup bahkan untuk kelompok terbesar. Dalam kebanyakan kasus, Anda dapat membiarkan Kubernetes memilih nomor port secara acak, tetapi Anda dapat mengaturnya sendiri jika perlu. Masalah lain adalah beberapa batasan mengenai penyimpanan alamat IP sumber dalam permintaan. Untuk mengetahui cara mengatasi masalah ini, Anda dapat merujuk materi
ini dari dokumentasi Kubernetes.
Ports
NodePorts
adalah mekanisme fundamental di mana semua lalu lintas eksternal memasuki kluster Kubernetes. Namun, mereka sendiri tidak memberi kami solusi yang sudah jadi. Untuk alasan di atas, sebelum cluster, apakah klien adalah entitas internal atau eksternal yang terletak di jaringan publik, selalu diharuskan untuk memiliki semacam penyeimbang beban.
Arsitek platform, menyadari hal ini, menyediakan dua cara untuk mengonfigurasikan penyeimbang beban dari platform Kubernetes itu sendiri. Mari kita bahas ini.
Layanan seperti LoadBalancer dan sumber daya dari tipe Ingress
Layanan seperti
LoadBalancer
dan sumber daya dari tipe
Ingress
adalah beberapa mekanisme Kubernet yang paling kompleks. Namun, kami tidak akan menghabiskan terlalu banyak waktu pada mereka, karena penggunaannya tidak menyebabkan perubahan mendasar dalam segala hal yang telah kita bicarakan sejauh ini. Semua lalu lintas eksternal, seperti sebelumnya, memasuki cluster melalui
NodePort
.
Arsitek bisa berhenti di sini, memungkinkan mereka yang membuat cluster hanya peduli tentang alamat IP publik dan memuat penyeimbang. Bahkan, dalam situasi tertentu, seperti memulai cluster di server biasa atau di rumah, inilah yang sebenarnya mereka lakukan. Tetapi di lingkungan yang mendukung konfigurasi sumber daya jaringan yang dikontrol API, Kubernetes memungkinkan Anda untuk mengkonfigurasi semua yang Anda butuhkan di satu tempat.
Pendekatan pertama untuk memecahkan masalah ini, yang paling sederhana, adalah dengan menggunakan layanan Kubernetes seperti
LoadBalancer
. Layanan tersebut memiliki semua kemampuan layanan seperti
NodePort
, dan, di samping itu, memiliki kemampuan untuk membuat jalur penuh untuk lalu lintas masuk, berdasarkan asumsi bahwa cluster berjalan di lingkungan seperti GCP atau AWS yang mendukung konfigurasi sumber daya jaringan melalui API.
kind: Service apiVersion: v1 metadata: name: service-test spec: type: LoadBalancer selector: app: service_test_pod ports: - port: 80 targetPort: http
Jika kami menghapus dan membuat kembali layanan dari contoh kami di Google Kubernetes Engine, maka segera setelah itu, menggunakan
kubectl get svc service-test
command, kami dapat memverifikasi bahwa IP eksternal ditugaskan.
$ kubectl get svc service-test NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE openvpn 10.3.241.52 35.184.97.156 80:32213/TCP 5m
Dikatakan di atas bahwa kita akan dapat memverifikasi fakta penugasan alamat IP eksternal "segera", meskipun fakta bahwa penugasan IP eksternal dapat memakan waktu beberapa menit, yang tidak mengejutkan, mengingat jumlah sumber daya yang perlu dibawa ke keadaan sehat. Pada platform GCP, misalnya, ini membutuhkan sistem untuk membuat alamat IP eksternal, aturan pengalihan lalu lintas, server proxy target, layanan backend, dan, mungkin, sebuah instance dari grup. Setelah mengalokasikan alamat IP eksternal, Anda dapat terhubung ke layanan melalui alamat ini, menetapkannya nama domain dan menginformasikan klien. Sampai layanan dihancurkan dan diciptakan kembali (untuk melakukan ini, jarang ketika ada alasan yang bagus), alamat IP tidak akan berubah.
Layanan seperti
LoadBalancer
memiliki beberapa batasan. Layanan semacam itu tidak dapat dikonfigurasikan untuk mendekripsi lalu lintas HTTPS. Anda tidak dapat membuat host virtual atau mengonfigurasi rute berbasis jalur, jadi Anda tidak bisa, menggunakan konfigurasi praktis, menggunakan penyeimbang beban tunggal dengan banyak layanan. Keterbatasan ini menyebabkan pengenalan Kubernetes 1.1. Sumber daya khusus untuk mengonfigurasi penyeimbang beban. Ini adalah sumber dari tipe
Ingress . Layanan seperti
LoadBalancer
ditujukan untuk memperluas kemampuan layanan tunggal untuk mendukung klien eksternal. Sebaliknya, sumber daya
Ingress
adalah sumber daya khusus yang memungkinkan Anda mengkonfigurasi penyeimbang beban secara fleksibel. API Ingress mendukung dekripsi lalu lintas TLS, host virtual, dan perutean berbasis jalur. Menggunakan API ini, penyeimbang beban dapat dengan mudah dikonfigurasikan untuk bekerja dengan beberapa layanan backend.
API sumber daya dari tipe
Ingress
terlalu besar untuk membahas fitur-fiturnya di sini, apalagi, tidak terlalu memengaruhi cara kerja sumber daya Ingress di tingkat jaringan. Implementasi sumber daya ini mengikuti pola Kubernetes yang biasa: ada tipe sumber daya dan pengontrol untuk mengontrol tipe ini. Sumber daya dalam hal ini adalah sumber daya
Ingress
, yang menggambarkan permintaan ke sumber daya jaringan. Berikut ini uraian sumber daya
Ingress
.
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress annotations: kubernetes.io/ingress.class: "gce" spec: tls: - secretName: my-ssl-secret rules: - host: testhost.com http: paths: - path: /* backend: serviceName: service-test servicePort: 80
Pengontrol Ingress bertanggung jawab untuk mengeksekusi permintaan ini dengan membawa sumber daya lain ke kondisi yang diinginkan. Saat menggunakan Ingress, layanan seperti
NodePort
dibuat, setelah itu pengontrol Ingress diizinkan untuk membuat keputusan tentang cara mengarahkan lalu lintas ke node. Ada implementasi pengontrol Ingress untuk penyeimbang beban GCE, untuk penyeimbang AWS, untuk server proxy populer seperti nginx dan haproxy. Perhatikan bahwa pencampuran sumber daya dan layanan Ingress seperti
LoadBalancer
dapat menyebabkan masalah kecil di beberapa lingkungan. Mereka mudah ditangani, tetapi, secara umum, yang terbaik adalah menggunakan Ingress bahkan untuk layanan sederhana.
HostPort dan HostNetwork
Apa yang akan kita bicarakan sekarang, yaitu,
HostPort
dan
HostNetwork
, dapat dikaitkan dengan kategori kelangkaan yang menarik, dan bukan karena alat yang bermanfaat. Bahkan, saya berjanji untuk menyatakan bahwa dalam 99,99% kasus penggunaannya dapat dianggap sebagai anti-pola, dan sistem apa pun di mana mereka digunakan harus menjalani pemeriksaan wajib terhadap arsitekturnya.
Saya pikir itu tidak layak untuk dibicarakan sama sekali, tetapi itu adalah sesuatu seperti alat yang digunakan oleh sumber daya Ingress untuk memproses lalu lintas masuk, jadi saya memutuskan bahwa layak untuk menyebutkannya, setidaknya secara singkat.
Pertama,
HostPort
bicara tentang
HostPort
. Ini adalah properti kontainer (dideklarasikan dalam struktur
ContainerPort
). Ketika nomor port tertentu tertulis di dalamnya, ini mengarah ke pembukaan port ini pada node dan pengalihan langsung ke wadah. Tidak ada mekanisme proxy, dan port hanya terbuka pada node di mana wadah berjalan. Pada hari-hari awal platform, sebelum mekanisme
DaemonSet dan
StatefulSet muncul di dalamnya,
HostPort
adalah trik yang memungkinkan hanya satu kontainer dari jenis tertentu untuk diluncurkan pada node apa pun. Sebagai contoh, saya pernah menggunakan ini untuk membuat cluster Elasticsearch dengan mengatur
HostPort
ke
9200
dan menentukan replika sebanyak ada node. , Kubernetes, -
HostPort
.
NostNetwork
, , Kubernetes ,
HostPort
.
true
, -
network=host
docker run
. , .
eth0
. , . , , , Kubernetes, - .
Ringkasan
Kubernetes, , Ingress. , , , Kubernetes.
Pembaca yang budiman! Ingress?
