1067 lines
51 KiB
Markdown
1067 lines
51 KiB
Markdown
---
|
|
title: Service
|
|
feature:
|
|
title: Service discovery dan load balancing
|
|
description: >
|
|
Kamu tidak perlu memodifikasi aplikasi kamu untuk menggunakan mekanisme _service discovery_ tambahan. Kubernetes menyediakan IP untuk setiap kontainer serta sebuah DNS bagi sebuah sekumpulan kontainer, serta akan melakukan mekanisme _load balance_ bagi sekumpulan kontainer tersebut.
|
|
|
|
content_type: concept
|
|
weight: 10
|
|
---
|
|
|
|
|
|
<!-- overview -->
|
|
|
|
[`Pod`](/id/docs/concepts/workloads/pods/pod/) pada Kubernetes bersifat *mortal*.
|
|
Artinya apabila _pod-pod_ tersebut dibuat dan kemudian mati, _pod-pod_ tersebut
|
|
tidak akan dihidupkan kembali. [`ReplicaSets`](/id/docs/concepts/workloads/controllers/replicaset/) secara
|
|
khusus bertugas membuat dan menghapus `Pod` secara dinamis (misalnya, pada proses *scaling out* atau *scaling in*).
|
|
Meskipun setiap `Pod` memiliki alamat IP-nya masing-masing, kamu tidak dapat mengandalkan alamat IP
|
|
yang diberikan pada _pod-pod_ tersebut, karena alamat IP yang diberikan tidak stabil.
|
|
Hal ini kemudian menimbulkan pertanyaan baru: apabila sebuah sekumpulan `Pod` (yang selanjutnya kita sebut _backend_)
|
|
menyediakan _service_ bagi sebuah sekumpulan `Pod` lain (yang selanjutnya kita sebut _frontend_) di dalam
|
|
klaster Kubernetes, bagaimana cara _frontend_ menemukan _backend_ mana yang digunakan?
|
|
|
|
Inilah alasan kenapa `Service` ada.
|
|
|
|
Sebuah `Service` pada Kubernetes adalah sebuah abstraksi yang memberikan definisi
|
|
set logis yang terdiri beberapa `Pod` serta _policy_ bagaimana cara kamu mengakses sekumpulan `Pod` tadi - seringkali disebut sebagai _microservices_.
|
|
Set `Pod` yang dirujuk oleh suatu `Service` (biasanya) ditentukan oleh sebuah [`Label Selector`](/id/docs/concepts/overview/working-with-objects/labels/#label-selectors)
|
|
(lihat penjelasan di bawah untuk mengetahui alasan kenapa kamu mungkin saja membutuhkan `Service` tanpa
|
|
sebuah _selector_).
|
|
|
|
Sebagai contoh, misalnya terdapat sebuah _backend_ yang menyediakan fungsionalitas _image-processing_
|
|
yang memiliki 3 buah _replica_. _Replica-replica_ tadi sifatnya sepadan - dengan kata lain _frontend_
|
|
tidak peduli _backend_ manakah yang digunakan. Meskipun `Pod` penyusun sekumpulan _backend_ bisa berubah,
|
|
_frontend_ tidak perlu peduli bagaimana proses ini dijalankan atau menyimpan _list_ dari _backend-backend_
|
|
yang ada saat itu. `Service` memiliki tujuan untuk _decouple_ mekanisme ini.
|
|
|
|
Untuk aplikasi yang dijalankan di atas Kubernetes, Kubernetes menyediakan API _endpoint_ sederhana
|
|
yang terus diubah apabila _state_ sebuah sekumpulan `Pod` di dalam suatu `Service` berubah. Untuk
|
|
aplikasi _non-native_, Kubernetes menyediakan _bridge_ yang berbasis _virtual-IP_ bagi `Service`
|
|
yang diarahkan pada `Pod` _backend_.
|
|
|
|
|
|
|
|
<!-- body -->
|
|
|
|
## Mendefinisikan sebuah `Service`
|
|
|
|
Sebuah `Service` di Kubernetes adalah sebuah objek REST, layaknya sebuah `Pod`. Seperti semua
|
|
objek _REST_, definisi `Service` dapat dikirim dengan _method POST_ pada _apiserver_ untuk membuat
|
|
sebuah instans baru. Sebagai contoh, misalnya saja kamu memiliki satu sekumpulan `Pod` yang mengekspos _port_
|
|
9376 dan memiliki _label_ `"app=MyApp"`.
|
|
|
|
```yaml
|
|
kind: Service
|
|
apiVersion: v1
|
|
metadata:
|
|
name: my-service
|
|
spec:
|
|
selector:
|
|
app: MyApp
|
|
ports:
|
|
- protocol: TCP
|
|
port: 80
|
|
targetPort: 9376
|
|
```
|
|
|
|
Spesifikasi ini akan ditranslasikan sebagai sebuah objek `Service` baru dengan nama `"my-service"`
|
|
dengan _target port_ 9376 pada setiap `Pod` yang memiliki _label_ `"app=MyApp"`. `Service` ini
|
|
juga akan memiliki alamat IP tersendiri (yang terkadang disebut sebagai _"cluster IP"_), yang nantinya
|
|
akan digunakan oleh _service proxy_ (lihat di bagian bawah). _Selector_ pada `Service` akan selalu dievaluasi
|
|
dan hasilnya akan kembali dikirim dengan menggunakan _method POST_ ke objek `Endpoints`
|
|
yang juga disebut `"my-service"`.
|
|
|
|
Perhatikan bahwa sebuah `Service` dapat melakukan pemetaan setiap _incoming port_ pada `targetPort`
|
|
mana pun. Secara _default_, _field_ `targetPort` akan memiliki _value_ yang sama dengan _value_ dari _field_ `port`.
|
|
Hal menarik lainnya adalah _value_ dari `targetPort` bisa saja berupa string yang merujuk pada nama
|
|
dari _port_ yang didefinisikan pada `Pod` _backend_. Nomor _port_ yang diberikan pada _port_ dengan nama
|
|
tadi bisa saja memiliki nilai yang berbeda di setiap `Pod` _backend_. Hal ini memberikan fleksibilitas
|
|
pada saat kamu melakukan _deploy_ atau melakukan perubahan terhadap `Service`. Misalnya saja suatu saat
|
|
kamu ingin mengubah nomor _port_ yang ada pada `Pod` _backend_ pada rilis selanjutnya tanpa menyebabkan
|
|
permasalahan pada sisi klien.
|
|
|
|
Secara _default_, protokol yang digunakan pada _service_ adalah `TCP`, tapi kamu bisa saja menggunakan
|
|
[protokol yang tersedia](#protokol-yang-tersedia). Karena banyak `Service` memiliki kebutuhan untuk
|
|
mengekspos lebih dari sebuah _port_, Kubernetes menawarkan definisi _multiple_ _port_ pada sebuah objek
|
|
_Service_. Setiap definisi _port_ dapat memiliki protokol yang berbeda.
|
|
|
|
### `Service` tanpa _selector_
|
|
|
|
Secara umum, `Service` memberikan abstraksi mekanisme yang dilakukan untuk mengakses `Pod`, tapi
|
|
mereka juga melakukan abstraksi bagi _backend_ lainnya. Misalnya saja:
|
|
|
|
* Kamu ingin memiliki sebuah basis data eksternal di _environment_ _production_ tapi pada tahap _test_,
|
|
kamu ingin menggunakan basis datamu sendiri.
|
|
* Kamu ingin merujuk _service_ kamu pada _service_ lainnya yang berada pada
|
|
[_Namespace_](/id/docs/concepts/overview/working-with-objects/namespaces/) yang berbeda atau bahkan klaster yang berbeda.
|
|
* Kamu melakukan migrasi _workloads_ ke Kubernetes dan beberapa _backend_ yang kamu miliki masih
|
|
berada di luar klaster Kubernetes.
|
|
|
|
Berdasarkan skenario-skenario di atas, kamu dapat membuat sebuah `Service` tanpa _selector_:
|
|
|
|
```yaml
|
|
kind: Service
|
|
apiVersion: v1
|
|
metadata:
|
|
name: my-service
|
|
spec:
|
|
ports:
|
|
- protocol: TCP
|
|
port: 80
|
|
targetPort: 9376
|
|
```
|
|
|
|
Karena `Service` ini tidak memiliki _selector_, objek `Endpoints` bagi `Service` ini tidak akan dibuat.
|
|
Dengan demikian, kamu bisa membuat `Endpoints` yang kamu inginkan:
|
|
|
|
```yaml
|
|
kind: Endpoints
|
|
apiVersion: v1
|
|
metadata:
|
|
name: my-service
|
|
subsets:
|
|
- addresses:
|
|
- ip: 1.2.3.4
|
|
ports:
|
|
- port: 9376
|
|
```
|
|
|
|
{{< note >}}
|
|
Perhatikan bahwa alamat IP yang kamu buat untuk `Endpoints` tidak boleh berupa
|
|
_loopback_ (127.0.0.0/8), _link-local_ (169.254.0.0/16), atau _link-local multicast_ (224.0.0.0/24).
|
|
Alamat IP tersebut juga tidak boleh berupa _cluster IP_ dari `Service` Kubernetes lainnya,
|
|
karena `kube-proxy` belum menyediakan dukungan IP virtual sebagai _destination_.
|
|
{{< /note >}}
|
|
|
|
Cara mengakses suatu `Service` tanpa _selector_ sama saja dengan mengakses suatu `Service`
|
|
dengan _selector_. Trafik yang ada akan di-*route* ke `Endpoints` yang dispesifikasikan oleh
|
|
pengguna (dalam contoh kali ini adalah `1.2.3.4:9376`).
|
|
|
|
Sebuah `ExternalName` `Service` merupakan kasus spesial dari `Service`
|
|
dimana `Service` tidak memiliki _selector_ dan menggunakan penamaan _DNS_. Untuk
|
|
informasi lebih lanjut silahkan baca bagian [ExternalName](#externalname).
|
|
|
|
## IP Virtual dan _proxy_ `Service`
|
|
|
|
Setiap *node* di klaster Kubernetes menjalankan `kube-proxy`. `kube-proxy`
|
|
bertanggung jawab terhadap implementasi IP virtual bagi _Services_ dengan tipe
|
|
selain [`ExternalName`](#externalname).
|
|
|
|
Pada Kubernetes versi v1.0, _Services_ adalah "layer 4" (TCP/UDP pada IP), _proxy_
|
|
yang digunakan murni berada pada _userspace_. Pada Kubernetes v1.1, API `Ingress`
|
|
ditambahkan untuk merepresentasikan "layer 7"(HTTP), _proxy_ `iptables` juga ditambahkan
|
|
dan menjadi mode operasi _default_ sejak Kubernetes v1.2. Pada Kubernetes v1.8.0-beta.0,
|
|
_proxy_ _ipvs_ juga ditambahkan.
|
|
|
|
### Mode _Proxy_: _userspace_
|
|
|
|
Pada mode ini, `kube-proxy` mengamati master Kubernetes apabila terjadi penambahan
|
|
atau penghapusan objek `Service` dan `Endpoints`. Untuk setiap `Service`, `kube-proxy`
|
|
akan membuka sebuah _port_ (yang dipilih secara acak) pada *node* lokal. Koneksi
|
|
pada _"proxy port"_ ini akan dihubungkan pada salah satu `Pod` _backend_ dari `Service`
|
|
(yang tercatat pada `Endpoints`). `Pod` _backend_ yang akan digunakan akan diputuskan berdasarkan
|
|
`SessionAffinity` pada `Service`. Langkah terakhir yang dilakukan oleh `kube-proxy`
|
|
adalah melakukan instalasi _rules_ `iptables` yang akan mengarahkan trafik yang ada pada
|
|
`clusterIP` (IP virtual) dan _port_ dari `Service` serta melakukan _redirect_ trafik ke _proxy_
|
|
yang memproksikan `Pod` _backend_. Secara _default_, mekanisme _routing_ yang dipakai adalah
|
|
_round robin_.
|
|
|
|

|
|
|
|
### Mode _Proxy_: iptables
|
|
|
|
Pada mode ini, `kube-proxy` mengamati master Kubernetes apabila terjadi penambahan
|
|
atau penghapusan objek `Service` dan `Endpoints`. Untuk setiap `Service`,
|
|
`kube-proxy` akan melakukan instalasi _rules_ `iptables` yang akan mengarahkan
|
|
trafik ke `clusterIP` (IP virtual) dan _port_ dari `Service`. Untuk setiap objek `Endpoints`,
|
|
`kube-proxy` akan melakukan instalasi _rules_ `iptables` yang akan memilih satu buah `Pod`
|
|
_backend_. Secara _default_, pemilihan _backend_ ini dilakukan secara acak.
|
|
|
|
Tentu saja, `iptables` yang digunakan tidak boleh melakukan _switching_
|
|
antara _userspace_ dan _kernelspace_, mekanisme ini harus lebih kokoh dan lebih cepat
|
|
dibandingkan dengan _userspace_ _proxy_. Meskipun begitu, berbeda dengan mekanisme
|
|
_proxy_ _userspace_, _proxy_ `iptables` tidak bisa secara langsung menjalankan mekanisme
|
|
_retry_ ke `Pod` lain apabila `Pod` yang sudah dipilih sebelumnya tidak memberikan respons,
|
|
dengan kata lain hal ini akan sangat bergantung pada
|
|
[readiness probes](/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#defining-readiness-probes).
|
|
|
|

|
|
|
|
### Mode _Proxy_: ipvs
|
|
|
|
{{< feature-state for_k8s_version="v1.9" state="beta" >}}
|
|
|
|
Pada mode ini, `kube-proxy` mengamati _Services_ dan `Endpoints`, kemudian memanggil
|
|
_interface_ _netlink_ untuk membuat _rules_ _ipvs_ yang sesuai serta melakukan sinkronisasi
|
|
_rules_ _ipvs_ dengan _Services_ dan `Endpoints` Kubernetes secara periodik, untuk memastikan
|
|
status _ipvs_ konsisten dengan apa yang diharapkan. Ketika sebuah _Services_ diakses,
|
|
trafik yang ada akan diarahkan ke salah satu `Pod` _backend_.
|
|
|
|
Sama halnya dengan `iptables`, _ipvs_ juga berdasarkan pada fungsi _hook_ _netfilter_,
|
|
bedanya adalah _ipvs_ menggunakan struktur data _hash table_ dan bekerja di _kernelspace_.
|
|
Dengan kata lain _ipvs_ melakukan _redirect_ trafik dengan lebih cepat dan dengan performa yang lebih
|
|
baik ketika melakukan sinkronisasi _rules_ _proxy_. Selain itu, _ipvs_ juga menyediakan
|
|
lebih banyak opsi algoritma _load balancing_:
|
|
|
|
- `rr`: round-robin
|
|
- `lc`: least connection
|
|
- `dh`: destination hashing
|
|
- `sh`: source hashing
|
|
- `sed`: shortest expected delay
|
|
- `nq`: never queue
|
|
|
|
{{< note >}}
|
|
Mode _ipvs_ menggunakan _module_ _IPVS_ _kernel_ yang diinstal pada *node*
|
|
sebelum `kube-proxy` dijalankan. Ketika `kube-proxy` dijalankan dengan mode _proxy_ _ipvs_,
|
|
`kube-proxy` akan melakukan proses validasi, apakah _module_ _IPVS_ sudah diinstal di *node*,
|
|
jika _module_ tersebut belum diinstal, maka `kube-proxy` akan menggunakan mode `iptables`.
|
|
{{< /note >}}
|
|
|
|

|
|
|
|
Dari sekian model _proxy_ yang ada, trafik _inbound_ apa pun yang ada diterima oleh _IP:Port_ pada `Service`
|
|
akan dilanjutkan melalui _proxy_ pada _backend_ yang sesuai, dan klien tidak perlu mengetahui
|
|
apa informasi mendetail soal Kubernetes, `Service`, atau `Pod`. afinitas _session_ (_session affinity_) berbasis
|
|
_Client-IP_ dapat dipilih dengan cara menerapkan nilai _"ClientIP"_ pada `service.spec.sessionAffinity`
|
|
(nilai _default_ untuk hal ini adalah _"None"_), kamu juga dapat mengatur nilai maximum _session_
|
|
_timeout_ yang ada dengan mengatur opsi `service.spec.sessionAffinityConfig.clientIP.timeoutSeconds` jika
|
|
sebelumnya kamu sudah menerapkan nilai _"ClusterIP"_ pada `service.spec.sessionAffinity`
|
|
(nilai _default_ untuk opsi ini adalah _"10800"_).
|
|
|
|
## _Multi-Port Services_
|
|
|
|
Banyak _Services_ dengan kebutuhan untuk mengekspos lebih dari satu _port_.
|
|
Untuk kebutuhan inilah, Kubernetes mendukung _multiple_ _port_ _definitions_ pada objek `Service`.
|
|
Ketika menggunakan _multiple_ _port_, kamu harus memberikan nama pada setiap _port_ yang didefinisikan,
|
|
sehingga _Endpoint_ yang dibentuk tidak ambigu. Contoh:
|
|
|
|
```yaml
|
|
kind: Service
|
|
apiVersion: v1
|
|
metadata:
|
|
name: my-service
|
|
spec:
|
|
selector:
|
|
app: MyApp
|
|
ports:
|
|
- name: http
|
|
protocol: TCP
|
|
port: 80
|
|
targetPort: 9376
|
|
- name: https
|
|
protocol: TCP
|
|
port: 443
|
|
targetPort: 9377
|
|
```
|
|
|
|
Perhatikan bahwa penamaan _port_ hanya boleh terdiri dari karakter _alphanumeric_ _lowercase_
|
|
dan _-_, serta harus dimulai dan diakhiri dengan karakter _alphanumeric_, misalnya saja `123-abc` dan `web`
|
|
merupakan penamaan yang valid, tapi `123_abc` dan `-web` bukan merupakan penamaan yang valid.
|
|
|
|
## Memilih sendiri alamat IP yang kamu inginkan
|
|
|
|
Kamu dapat memberikan spesifikasi alamat _cluster IP_ yang kamu inginkan
|
|
sebagai bagian dari _request_ pembuatan objek `Service`. Untuk melakukan hal ini,
|
|
kamu harus mengisi _fields_ `.spec.clusterIP` field. Contoh penggunaannya adalah sebagai berikut,
|
|
misalnya saja kamu sudah memiliki _entry_ DNS yang ingin kamu gunakan kembali,
|
|
atau sebuah sistem _legacy_ yang sudah diatur pada alamat IP spesifik
|
|
dan sulit untuk diubah. Alamat IP yang ingin digunakan pengguna haruslah merupakan alamat IP
|
|
yang valid dan berada di dalam _range_ _CIDR_ `service-cluster-ip-range` yang dispesifikasikan di dalam
|
|
penanda yang diberikan _apiserver_. Jika _value_ yang diberikan tidak valid, _apiserver_ akan
|
|
mengembalikan _response_ _code_ HTTP _422_ yang mengindikasikan _value_ yang diberikan tidak valid.
|
|
|
|
### Mengapa tidak menggunakan DNS _round-robin_?
|
|
|
|
Pertanyaan yang selalu muncul adalah kenapa kita menggunakan IP virtual dan bukan
|
|
DNS _round-robin_ standar? Terdapat beberapa alasan dibalik semua itu:
|
|
|
|
* Terdapat sejarah panjang dimana _library_ DNS tidak mengikuti _TTL_ DNS dan
|
|
melakukan _caching_ hasil dari _lookup_ yang dilakukan.
|
|
* Banyak aplikasi yang melakukan _lookup_ DNS hanya sekali dan kemudian melakukan _cache_ hasil yang diperoleh.
|
|
* Bahkan apabila aplikasi dan _library_ melakukan resolusi ulang yang _proper_, _load_ dari setiap
|
|
klien yang melakukan resolusi ulang DNS akan sulit untuk di _manage_.
|
|
|
|
Kami berusaha untuk mengurangi ketertarikan pengguna untuk melakukan yang mungkin akan menyusahkan pengguna.
|
|
Dengan demikian, apabila terdapat justifikasi yang cukup kuat, kami mungkin saja memberikan implementasi
|
|
alternatif yang ada.
|
|
|
|
## _Discovering services_
|
|
|
|
Kubernetes mendukung 2 buah mode primer untuk melakukan `Service` - variabel _environment_ dan DNS.
|
|
|
|
### Variabel _Environment_
|
|
|
|
Ketika sebuah `Pod` dijalankan pada *node*, _kubelet_ menambahkan seperangkat variabel _environment_
|
|
untuk setiap `Service` yang aktif. _Environment_ yang didukung adalah [Docker links compatible](https://docs.docker.com/userguide/dockerlinks/) variabel (perhatikan
|
|
[makeLinkVariables](http://releases.k8s.io/{{< param "githubbranch" >}}/pkg/kubelet/envvars/envvars.go#L49))
|
|
dan variabel `{SVCNAME}_SERVICE_HOST` dan `{SVCNAME}_SERVICE_PORT`, dinama nama `Service` akan diubah
|
|
menjadi huruf kapital dan tanda _minus_ akan diubah menjadi _underscore_.
|
|
|
|
Sebagai contoh, `Service` `"redis-master"` yang mengekspos _port_ TCP 6379 serta _alamat_
|
|
_cluster IP_ _10.0.0.11_ akan memiliki _environment_ sebagai berikut:
|
|
|
|
```shell
|
|
REDIS_MASTER_SERVICE_HOST=10.0.0.11
|
|
REDIS_MASTER_SERVICE_PORT=6379
|
|
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
|
|
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
|
|
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
|
|
REDIS_MASTER_PORT_6379_TCP_PORT=6379
|
|
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
|
|
```
|
|
|
|
Hal ini merupakan kebutuhan yang urutannya harus diperhatikan - `Service` apa pun yang
|
|
akan diakses oleh sebuah `Pod` harus dibuat sebelum `Pod` tersebut dibuat,
|
|
jika tidak variabel _environment_ tidak akan diinisiasi.
|
|
Meskipun begitu, DNS tidak memiliki keterbatasan ini.
|
|
|
|
### DNS
|
|
|
|
Salah satu [_add-on_](/id/docs/concepts/cluster-administration/addons/) opsional
|
|
(meskipun sangat dianjurkan) adalah server DNS. Server DNS bertugas untuk mengamati apakah
|
|
terdapat objek `Service` baru yang dibuat dan kemudian bertugas menyediakan DNS baru untuk
|
|
_Service_ tersebut. Jika DNS ini diaktifkan untuk seluruh klaster, maka semua `Pod` akan secara otomatis
|
|
dapat melakukan resolusi DNS.
|
|
|
|
Sebagai contoh, apabila kamu memiliki sebuah `Service` dengan nama `"my-service"` pada _Namespace_
|
|
_"my-ns"_, maka _record_ DNS `"my-service.my-ns"` akan dibuat. `Pod` yang berada di dalam
|
|
_Namespace_ _"my-ns"_ dapat langsung melakukan _lookup_ dengan hanya menggunakan `"my-service"`.
|
|
Sedangkan `Pod` yang berada di luar _Namespace_ _my-ns"_ harus menggunakan `"my-service.my-ns"`.
|
|
Hasil dari resolusi ini menrupakan _cluster IP_.
|
|
|
|
Kubernetes juga menyediakan _record_ DNS SRV (service) untuk _named ports_. Jika
|
|
_Service_ `"my-service.my-ns"` memiliki _port_ dengan nama `"http"` dengan protokol `TCP`,
|
|
kamu dapat melakukan _query_ DNS SRV untuk `"_http._tcp.my-service.my-ns"` untuk mengetahui
|
|
nomor _port_ yang digunakan oleh _http_.
|
|
|
|
Server DNS Kubernetes adalah satu-satunya cara untuk mengakses
|
|
_Service_ dengan tipe `ExternalName`. Informasi lebih lanjut tersedia di
|
|
[DNS _Pods_ dan _Services_](/id/docs/concepts/services-networking/dns-pod-service/).
|
|
|
|
## `Service` _headless_
|
|
|
|
Terkadang kamu tidak membutuhkan mekanisme _load-balancing_ dan sebuah _single_ IP _Sevice_.
|
|
Dalam kasus ini, kamu dapat membuat _"headless"_ `Service` dengan cara memberikan spesifikasi
|
|
_None_ pada _cluster IP_ (`.spec.clusterIP`).
|
|
|
|
Opsi ini memungkinkan pengguna mengurangi ketergantungan terhadap sistem Kubernetes
|
|
dengan cara memberikan kebebasan untuk mekanisme _service discovery_. Aplikasi akan
|
|
tetap membutuhkan mekanisme _self-registration_ dan _adapter service discovery_
|
|
lain yang dapat digunakan berdasarkan API ini.
|
|
|
|
Untuk `Service` _"headless"_ alokasi _cluster IP_ tidak dilakukan dan `kube-proxy`
|
|
tidak me-_manage_ _Service-Service_, serta tidak terdapat mekanisme _load balancing_
|
|
yang dilakukan. Bagaimana konfigurasi otomatis bagi DNS dilakukan bergantung pada
|
|
apakah `Service` tersebut memiliki _selector_ yang dispesifikasikan.
|
|
|
|
### Dengan _selector_
|
|
|
|
Untuk `Service` _"headless"_ dengan _selector_, kontroler `Endpoints` akan membuat suatu
|
|
_record_ `Endpoints` di API, serta melakukan modifikasi konfigurasi DNS untuk mengembalikan
|
|
_A records (alamat)_ yang merujuk secara langsung pada `Pod` _backend_.
|
|
|
|
### Tanpa _selector_
|
|
|
|
Untuk `Service` _"headless"_ tanpa _selector_, kontroler `Endpoints`
|
|
tidak akan membuat _record_ _Enpoints_. Meskipun demikian,
|
|
sistem DNS tetap melakukan konfigurasi salah satu dari:
|
|
|
|
* _record_ CNAME untuk [`ExternalName`](#externalname)-tipe services.
|
|
* _record_ untuk semua `Endpoints` yang memiliki nama `Service` yang sama, untuk
|
|
tipe lainnya.
|
|
|
|
## Mekanisme _publish_ `Service` - jenis-jenis `Service`
|
|
|
|
Untuk beberapa bagian dari aplikasi yang kamu miliki (misalnya saja, _frontend_),
|
|
bisa saja kamu memiliki kebutuhan untuk mengekspos `Service` yang kamu miliki
|
|
ke alamat IP eksternal (di luar klaster Kubernetes).
|
|
|
|
`ServiceTypes` yang ada pada Kubernetes memungkinkan kamu untuk menentukan
|
|
jenis `Service` apakah yang kamu butuhkan. Secara _default_, jenis `Service`
|
|
yang diberikan adalah `ClusterIP`.
|
|
|
|
_Value_ dan perilaku dari tipe `Service` dijelaskan sebagai berikut:
|
|
|
|
* `ClusterIP`: Mengekspos `Service` ke _range_ alamat IP di dalam klaster. Apabila kamu memilih _value_ ini
|
|
`Service` yang kamu miliki hanya dapat diakses secara internal. tipe ini adalah
|
|
_default_ _value_ dari _ServiceType_.
|
|
* [`NodePort`](#nodeport): Mengekspos `Service` pada setiap IP *node* pada _port_ statis
|
|
atau _port_ yang sama. Sebuah `Service` `ClusterIP`, yang mana `Service` `NodePort` akan di-_route_
|
|
, dibuat secara otomatis. Kamu dapat mengakses `Service` dengan tipe ini,
|
|
dari luar klaster melalui `<NodeIP>:<NodePort>`.
|
|
* [`LoadBalancer`](#loadbalancer): Mengekspos `Service` secara eksternal dengan menggunakan `LoadBalancer`
|
|
yang disediakan oleh penyedia layanan _cloud_. `Service` dengan tipe `NodePort` dan `ClusterIP`,
|
|
dimana trafik akan di-_route_, akan dibuat secara otomatis.
|
|
* [`ExternalName`](#externalname): Melakukan pemetaan `Service` ke konten
|
|
dari _field_ `externalName` (misalnya: `foo.bar.example.com`), dengan cara mengembalikan
|
|
catatan `CNAME` beserta _value_-nya. Tidak ada metode _proxy_ apa pun yang diaktifkan. Mekanisme ini
|
|
setidaknya membutuhkan `kube-dns` versi 1.7.
|
|
|
|
### Type NodePort {#nodeport}
|
|
|
|
Jika kamu menerapkan _value_ `NodePort` pada _field_ _type_, master Kubernetes akan mengalokasikan
|
|
_port_ dari _range_ yang dispesifikasikan oleh penanda `--service-node-port-range` (secara _default_, 30000-32767)
|
|
dan setiap _Node_ akan memproksikan _port_ tersebut (setiap _Node_ akan memiliki nomor _port_ yang sama) ke `Service`
|
|
yang kamu miliki. `Port` tersebut akan dilaporkan pada _field_ `.spec.ports[*].nodePort` di `Service` kamu.
|
|
|
|
Jika kamu ingin memberikan spesifikasi IP tertentu untuk melakukan _poxy_ pada _port_.
|
|
kamu dapat mengatur penanda `--nodeport-addresses` pada `kube-proxy` untuk _range_ alamat IP
|
|
tertentu (mekanisme ini didukung sejak v1.10). Sebuah daftar yang dipisahkan koma (misalnya, _10.0.0.0/8_, _1.2.3.4/32_)
|
|
digunakan untuk mem-_filter_ alamat IP lokal ke _node_ ini. Misalnya saja kamu memulai `kube-proxy` dengan penanda
|
|
`--nodeport-addresses=127.0.0.0/8`, maka `kube-proxy` hanya akan memilih _interface_ _loopback_ untuk `Service` dengan tipe
|
|
`NodePort`. Penanda `--nodeport-addresses` memiliki nilai _default_ kosong (`[]`), yang artinya akan memilih semua _interface_ yang ada
|
|
dan sesuai dengan perilaku `NodePort` _default_.
|
|
|
|
Jika kamu menginginkan nomor _port_ yang berbeda, kamu dapat memberikan spesifikasi
|
|
_value_ dari _field_ _nodePort_, dan sistem yang ada akan mengalokasikan _port_ tersebut untuk kamu,
|
|
jika _port_ tersebut belum digunakan (perhatikan bahwa jika kamu menggunakan teknik ini, kamu perlu
|
|
mempertimbangkan _collision_ yang mungkin terjadi dan bagaimana cara mengatasi hal tersebut)
|
|
atau transaksi API yang dilakukan akan gagal.
|
|
|
|
Hal ini memberikan kebebasan bagi pengembang untuk memilih _load balancer_ yang akan digunakan, terutama apabila
|
|
_load balancer_ yang ingin digunakan belum didukung sepenuhnya oleh Kubernetes.
|
|
|
|
Perhatikan bahwa `Service` dapat diakses baik dengan menggunakan `<NodeIP>:spec.ports[*].nodePort`
|
|
atau `.spec.clusterIP:spec.ports[*].port`. (Jika penanda `--nodeport-addresses` diterapkan, <NodeIP> dapat di-_filter_ dengan salah satu atau lebih _NodeIP_.)
|
|
|
|
### Type LoadBalancer {#loadbalancer}
|
|
|
|
Pada penyedia layanan _cloud_ yang menyediakan pilihan _load balancer_ eksternal, pengaturan _field_ _type_
|
|
ke `LoadBalancer` akan secara otomatis melakukan proses _provision_ _load balancer_ untuk `Service` yang kamu buat.
|
|
Informasi mengenai _load balancer_ yang dibuat akan ditampilkan pada _field_ `.status.loadBalancer`
|
|
pada `Service` kamu. Contohnya:
|
|
|
|
```yaml
|
|
kind: Service
|
|
apiVersion: v1
|
|
metadata:
|
|
name: my-service
|
|
spec:
|
|
selector:
|
|
app: MyApp
|
|
ports:
|
|
- protocol: TCP
|
|
port: 80
|
|
targetPort: 9376
|
|
clusterIP: 10.0.171.239
|
|
loadBalancerIP: 78.11.24.19
|
|
type: LoadBalancer
|
|
status:
|
|
loadBalancer:
|
|
ingress:
|
|
- ip: 146.148.47.155
|
|
```
|
|
|
|
Trafik dari _load balancer_ eksternal akan diarahkan pada `Pod` _backend_, meskipun mekanisme
|
|
bagaimana hal ini dilakukan bergantung pada penyedia layanan _cloud_. Beberapa penyedia layanan
|
|
_cloud_ mengizinkan konfigurasi untuk _value_ `loadBalancerIP`. Dalam kasus tersebut, _load balancer_ akan dibuat
|
|
dengan _loadbalancerIP_ yang dispesifikasikan. Jika _value_ dari `loadBalancerIP` tidak dispesifikasikan.
|
|
sebuah IP sementara akan diberikan pada _loadBalancer_. Jika `loadBalancerIP` dispesifikasikan,
|
|
tetapi penyedia layanan _cloud_ tidak mendukung hal ini, maka _field_ yang ada akan diabaikan.
|
|
|
|
**Catatan Khusus untuk Azure**: Untuk spesifikasi `loadBalancerIP` publik yang didefinisikan oleh pengguna,
|
|
sebuah alamat IP statis publik akan disediakan terlebih dahulu, dan alamat IP tersebut harus berada di
|
|
_resource group_ dari _resource_ yang secara otomatis dibuat oleh klaster. Misalnya saja, `MC_myResourceGroup_myAKSCluster_eastus`.
|
|
Berikan spesifikasi alamat IP sebagai `loadBalancerIP`. Pastikan kamu sudah melakukan _update_ pada
|
|
_securityGroupName_ pada _file_ konfigurasi penyedia layanan _cloud_.
|
|
Untuk informasi lebih lanjut mengenai _permission_ untuk `CreatingLoadBalancerFailed` kamu dapat membaca _troubleshooting_ untuk
|
|
[Penggunaan alamat IP statis pada _load balancer_ Azure Kubernetes Service (AKS)](https://docs.microsoft.com/en-us/azure/aks/static-ip) atau
|
|
[_CreatingLoadBalancerFailed_ pada klaster AKS dengan _advanced networking_](https://github.com/Azure/AKS/issues/357).
|
|
|
|
{{< note >}}
|
|
Dukungan untuk SCTP _load balancer_ dari penyedia layanan _cloud_ bergantung pada
|
|
implementasi _load balancer_ yang disediakan oleh penyedia layanan _cloud_ tersebut.
|
|
Jika SCTP tidak didukung oleh _load balancer_ penyedia layanan publik maka _request_ pembuatan `Service`
|
|
akan tetap diterima, meskipun proses pembuatan _load balancer_ itu sendiri gagal.
|
|
{{< /note >}}
|
|
|
|
#### _Load balancer_ internal
|
|
Di dalam _environment_, terkadang terdapat kebutuhan untuk melakukan _route_ trafik antar
|
|
_Service_ yang berada di dalam satu VPC.
|
|
|
|
Di dalam _environment_ _split-horizon DNS_ kamu akan membutuhkan dua _service_ yang mampu
|
|
melakukan mekanisme _route_ trafik eskternal maupun internal ke _endpoints_ yang kamu miliki.
|
|
|
|
Hal ini dapat diraih dengan cara menambahkan anotasi berikut untuk _service_ yang disediakan oleh
|
|
penyedia layanan _cloud_.
|
|
|
|
{{< tabs name="service_tabs" >}}
|
|
{{% tab name="Default" %}}
|
|
Pilih salah satu _tab_.
|
|
{{% /tab %}}
|
|
{{% tab name="GCP" %}}
|
|
```yaml
|
|
[...]
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
cloud.google.com/load-balancer-type: "Internal"
|
|
[...]
|
|
```
|
|
Gunakan _cloud.google.com/load-balancer-type: "internal"_ untuk master dengan versi 1.7.0 to 1.7.3.
|
|
Untuk informasi lebih lanjut, dilahkan baca [dokumentasi](https://cloud.google.com/kubernetes-engine/docs/internal-load-balancing).
|
|
{{% /tab %}}
|
|
{{% tab name="AWS" %}}
|
|
```yaml
|
|
[...]
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
|
|
[...]
|
|
```
|
|
{{% /tab %}}
|
|
{{% tab name="Azure" %}}
|
|
```yaml
|
|
[...]
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
|
|
[...]
|
|
```
|
|
{{% /tab %}}
|
|
{{% tab name="OpenStack" %}}
|
|
```yaml
|
|
[...]
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/openstack-internal-load-balancer: "true"
|
|
[...]
|
|
```
|
|
{{% /tab %}}
|
|
{{% tab name="Baidu Cloud" %}}
|
|
```yaml
|
|
[...]
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/cce-load-balancer-internal-vpc: "true"
|
|
[...]
|
|
```
|
|
{{% /tab %}}
|
|
{{< /tabs >}}
|
|
|
|
|
|
#### Dukungan untuk SSL di AWS
|
|
Dukungan parsial untuk SSL bagi klaster yang dijalankan di AWS mulai diterapkan,
|
|
mulai versi 1.3 terdapat 3 anotasi yang dapat ditambahkan pada `Service` dengan tipe
|
|
`LoadBalancer`:
|
|
|
|
```yaml
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012
|
|
```
|
|
|
|
Anotasi pertama memberikan spesifikasi ARN dari sertifikat yang akan digunakan.
|
|
Sertifikat yang digunakan bisa saja berasal dari _third party_ yang diunggah ke IAM atau
|
|
sertifikat yang dibuat secara langsung dengan menggunakan sertifikat manajer AWS.
|
|
|
|
```yaml
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: (https|http|ssl|tcp)
|
|
```
|
|
|
|
Anotasi kedua memberikan spesifikasi bagi protokol yang digunakan oleh `Pod` untuk saling berkomunikasi.
|
|
Untuk HTTPS dan SSL, ELB membutuhkan `Pod` untuk melakukan autentikasi terhadap dirinya sendiri melalui
|
|
koneksi yang dienkripsi.
|
|
|
|
Protokol HTTP dan HTTPS akan memilih mekanisme _proxy_ di tingkatan ke-7:
|
|
ELB akan melakukan terminasi koneksi dengan pengguna, melakukan proses _parsing_ _headers_, serta
|
|
memasukkan _value_ bagi _header_ `X-Forwarded-For` dengan alamat IP pengguna (_Pod_ hanya dapat melihat
|
|
alamat IP dari ELB pada akhir koneksi yang diberikan) ketika melakukan _forwarding_ suatu _request_.
|
|
|
|
Protokol TCP dan SSL akan memilih mekanisme _proxy_ pada tingkatan 4: ELB akan melakukan _forwarding_ trafik
|
|
tanpa melakukan modifikasi _headers_.
|
|
|
|
Pada _environment_ campuran dimana beberapa _port_ diamankan sementara _port_ lainnya dalam kondisi tidak dienkripsi,
|
|
anotasi-anotasi berikut dapat digunakan:
|
|
|
|
```yaml
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
|
|
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443,8443"
|
|
```
|
|
|
|
Pada contoh di atas, jika `Service` memiliki 3 buah _port_, yaitu: `80`, `443`, dan
|
|
`8443`, maka `443` adan `8443` akan menggunakan sertifikat SSL, tetapi `80` hanya akan
|
|
di-_proxy_ menggunakan protokol HTTP.
|
|
|
|
Mulai versi 1.9, `Service` juga dapat menggunakan [_predefined_ _policy_](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html)
|
|
untuk HTTPS atau _listener_ SSL. Untuk melihat _policy_ apa saja yang dapat digunakan, kamu dapat menjalankan perintah _awscli_:
|
|
|
|
```bash
|
|
aws elb describe-load-balancer-policies --query 'PolicyDescriptions[].PolicyName'
|
|
```
|
|
|
|
_Policy_ ini kemudian dapat dispesifikasikan menggunakan anotasi
|
|
"_service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy_", contohnya:
|
|
|
|
```yaml
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: "ELBSecurityPolicy-TLS-1-2-2017-01"
|
|
```
|
|
|
|
#### Protokol PROXY pada AWS
|
|
|
|
Untuk mengaktifkan dukungan [protokol PROXY](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
|
|
untuk klaster yang dijalankan di AWS, kamu dapat menggunakan anotasi di bawah ini:
|
|
|
|
```yaml
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
|
|
```
|
|
|
|
Sejak versi 1.3.0, penggunaan anotasi berlaku untuk semua _port_ yang diproksi oleh ELB
|
|
dan tidak dapat diatur sebaliknya.
|
|
|
|
#### Akses _Log_ ELB pada AWS
|
|
|
|
Terdapat beberapa anotasi yang digunakan untuk melakukan manajemen
|
|
akses _log_ untuk ELB pada AWS.
|
|
|
|
Anotasi `service.beta.kubernetes.io/aws-load-balancer-access-log-enabled`
|
|
mengatur akses _log_ mana sajakah yang diaktifkan.
|
|
|
|
Anotasi `service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval`
|
|
mengatur interval (dalam menit) publikasi akses _log_. Kamu dapat memberikan spesifikasi interval
|
|
diantara _range_ 5-60 menit.
|
|
|
|
Anotasi `service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name`
|
|
mengatur nama _bucket_ Amazon S3 dimana akses _log_ _load balancer_ disimpan.
|
|
|
|
Anotasi `service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix`
|
|
memberikan spesifikasi hierarki logis yang kamu buat untuk _bucket_ Amazon S3 yang kamu buat.
|
|
|
|
```yaml
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/aws-load-balancer-access-log-enabled: "true"
|
|
# Specifies whether access logs are enabled for the load balancer
|
|
service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval: "60"
|
|
# The interval for publishing the access logs. You can specify an interval of either 5 or 60 (minutes).
|
|
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name: "my-bucket"
|
|
# The name of the Amazon S3 bucket where the access logs are stored
|
|
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix: "my-bucket-prefix/prod"
|
|
# The logical hierarchy you created for your Amazon S3 bucket, for example _my-bucket-prefix/prod_
|
|
```
|
|
|
|
#### Mekanisme _Draining_ Koneksi pada AWS
|
|
|
|
Mekanisme _draining_ untuk ELB klasik dapat dilakukan dengan menggunakan anotasi
|
|
`service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled` serta mengatur
|
|
_value_-nya menjadi `"true"`. Anotasi
|
|
`service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout` juga
|
|
dapat digunakan untuk mengatur _maximum time_ (dalam detik), untuk menjaga koneksi yang ada
|
|
agar selalu terbuka sebelum melakukan _deregistering_ _instance_.
|
|
|
|
```yaml
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true"
|
|
service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout: "60"
|
|
```
|
|
|
|
#### Anotasi ELB lainnya
|
|
|
|
Terdapat beberapa anotasi lain yang dapat digunakan untuk mengatur ELB klasik
|
|
sebagaimana dijelaskan seperti di bawah ini:
|
|
|
|
```yaml
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "60"
|
|
# The time, in seconds, that the connection is allowed to be idle (no data has been sent over the connection) before it is closed by the load balancer
|
|
|
|
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
|
|
# Specifies whether cross-zone load balancing is enabled for the load balancer
|
|
|
|
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "environment=prod,owner=devops"
|
|
# A comma-separated list of key-value pairs which will be recorded as
|
|
# additional tags in the ELB.
|
|
|
|
service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: ""
|
|
# The number of successive successful health checks required for a backend to
|
|
# be considered healthy for traffic. Defaults to 2, must be between 2 and 10
|
|
|
|
service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: "3"
|
|
# The number of unsuccessful health checks required for a backend to be
|
|
# considered unhealthy for traffic. Defaults to 6, must be between 2 and 10
|
|
|
|
service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "20"
|
|
# The approximate interval, in seconds, between health checks of an
|
|
# individual instance. Defaults to 10, must be between 5 and 300
|
|
service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: "5"
|
|
# The amount of time, in seconds, during which no response means a failed
|
|
# health check. This value must be less than the service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval
|
|
# value. Defaults to 5, must be between 2 and 60
|
|
|
|
service.beta.kubernetes.io/aws-load-balancer-extra-security-groups: "sg-53fae93f,sg-42efd82e"
|
|
# A list of additional security groups to be added to ELB
|
|
```
|
|
|
|
#### Dukungan _Network Load Balancer_ (NLB) pada AWS [alpha]
|
|
|
|
{{< warning >}}
|
|
Ini merupakan tingkatan _alpha_ dan tidak direkomendasikan untuk digunakan pada _environment_ _production_.
|
|
{{< /warning >}}
|
|
|
|
Sejak versi 1.9.0, Kubernetes mendukung _Network Load Balancer_ (NLB). Untuk
|
|
menggunakan NLB pada AWS, gunakan anotasi `service.beta.kubernetes.io/aws-load-balancer-type`
|
|
dan atur _value_-nya dengan `nlb`.
|
|
|
|
```yaml
|
|
metadata:
|
|
name: my-service
|
|
annotations:
|
|
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
|
|
```
|
|
|
|
Tidak seperti ELB klasik, NLB, melakukan _forwarding_ IP klien melalui _node_.
|
|
Jika _field_ `.spec.externalTrafficPolicy` diatur _value_-nya menjadi `Cluster`, maka
|
|
alamat IP klien tidak akan diteruskan pada `Pod`.
|
|
|
|
Dengan mengatur _value_ dari _field_ `.spec.externalTrafficPolicy` ke `Local`,
|
|
alamat IP klien akan diteruskan ke `Pod`, tapi hal ini bisa menyebabkan distribusi trafik
|
|
yang tidak merata. _Node_ yang tidak memiliki `Pod` untuk `Service` dengan tipe `LoadBalancer`
|
|
akan menyebabkan kegagalan _health check_ _NLB Target_ pada tahapan _auto-assigned_ `.spec.healthCheckNodePort`
|
|
dan tidak akan menerima trafik apa pun.
|
|
|
|
Untuk menghasilkan distribusi trafik yang merata, kamu dapat menggunakan
|
|
_DaemonSet_ atau melakukan spesifikasi
|
|
[pod anti-affinity](/id/docs/concepts/configuration/assign-pod-node/#inter-pod-affinity-and-anti-affinity-beta-feature)
|
|
agar `Pod` tidak di-_assign_ ke _node_ yang sama.
|
|
|
|
NLB juga dapat digunakan dengan anotasi [internal load balancer](/id/docs/concepts/services-networking/service/#internal-load-balancer).
|
|
|
|
Agar trafik klien berhasil mencapai _instances_ dibelakang ELB,
|
|
_security group_ dari _node_ akan diberikan _rules_ IP sebagai berikut:
|
|
|
|
| _Rule_ | Protokol | `Port` | _IpRange(s)_ | Deskripsi _IpRange_ |
|
|
|--------|----------|--------|--------------|---------------------|
|
|
| _Health Check_ | TCP | NodePort(s) (`.spec.healthCheckNodePort` for _.spec.externalTrafficPolicy = Local_) | VPC CIDR | kubernetes.io/rule/nlb/health=\<loadBalancerName\> |
|
|
| _Client Traffic_ | TCP | NodePort(s) | `.spec.loadBalancerSourceRanges` (defaults to `0.0.0.0/0`) | kubernetes.io/rule/nlb/client=\<loadBalancerName\> |
|
|
| _MTU Discovery_ | ICMP | 3,4 | `.spec.loadBalancerSourceRanges` (defaults to `0.0.0.0/0`) | kubernetes.io/rule/nlb/mtu=\<loadBalancerName\> |
|
|
|
|
Perhatikan bahwa jika `.spec.loadBalancerSourceRanges` tidak dispesifikasikan,
|
|
Kubernetes akan mengizinkan trafik dari `0.0.0.0/0` ke _Node Security Group_.
|
|
Jika _node_ memiliki akses publik, maka kamu harus memperhatikan tersebut karena trafik yang tidak berasal
|
|
dari NLB juga dapat mengakses semua _instance_ di _security group_ tersebut.
|
|
|
|
Untuk membatasi klien IP mana yang dapat mengakses NLB,
|
|
kamu harus memberikan spesifikasi _loadBalancerSourceRanges_.
|
|
|
|
```yaml
|
|
spec:
|
|
loadBalancerSourceRanges:
|
|
- "143.231.0.0/16"
|
|
```
|
|
|
|
{{< note >}}
|
|
NLB hanya dapat digunakan dengan beberapa kelas _instance_ tertentu baca [dokumentasi AWS](http://docs.aws.amazon.com/elasticloadbalancing/latest/network/target-group-register-targets.html#register-deregister-targets)
|
|
untuk mengetahui lebih lanjut _intance_ apa saja yang didukung.
|
|
{{< /note >}}
|
|
|
|
### Tipe ExternalName {#externalname}
|
|
|
|
Service dengan tipe `ExternalName` melakukan pemetaan antara `Service` dan DNS, dan bukan
|
|
ke _selector_ seperti `my-service` atau `cassandra`. Kamu memberikan spesifikasi `spec.externalName`
|
|
pada `Service` tersebut.
|
|
|
|
Definisi `Service` ini, sebagai contoh, melaukan pemetaan
|
|
`Service` `my-service` pada _namespace_ `prod` ke DNS `my.database.example.com`:
|
|
|
|
```yaml
|
|
kind: Service
|
|
apiVersion: v1
|
|
metadata:
|
|
name: my-service
|
|
namespace: prod
|
|
spec:
|
|
type: ExternalName
|
|
externalName: my.database.example.com
|
|
```
|
|
{{< note >}}
|
|
`ExternalName` menerima alamat IPv4 dalam bentuk string,
|
|
tapi karena DNS tersusun atas angka dan bukan sebagai alamat IP.
|
|
`ExternalName` yang menyerupai alamat IPv4 tidak bisa di-_resolve_ oleh _CoreDNS_
|
|
atau _ingress-nginx_ karena `ExternalName` memang ditujukan bagi penamaan _canonical_ DNS.
|
|
Untuk melakukan _hardcode_ alamat IP, kamu dapat menggunakan _headless_ `Service` sebagai alternatif.
|
|
{{< /note >}}
|
|
|
|
Ketika melakukan pencarian _host_ `my-service.prod.svc.cluster.local`,
|
|
servis DNS klaster akan mengembalikan _record_ `CNAME` dengan _value_ `my.database.example.com`.
|
|
Mekanisme akses pada `my-service` bekerja dengan cara yang sama dengan
|
|
`Service` pada umumnya, perbedaan yang krusial untuk hal ini adalah mekanisme _redirection_
|
|
terjadi pada tingkatan DNS dan bukan melalui _proxy forward_. Apabila kamu berniat memindahkan basis data
|
|
yang kamu pakai ke dalam klaster, kamu hanya perlu mengganti instans basis data kamu dan menjalankannya
|
|
di dalam `Pod`, menambahkan _selector_ atau _endpoint_ yang sesuai, serta mengupah _type_ dari
|
|
_Service_ yang kamu gunakan.
|
|
|
|
{{< note >}}
|
|
Bagian ini berasal dari tulisan [Tips Kubernetes - Bagian
|
|
1](https://akomljen.com/kubernetes-tips-part-1/) oleh [Alen Komljen](https://akomljen.com/).
|
|
{{< /note >}}
|
|
|
|
### IP Eksternal
|
|
|
|
Jika terdapat sebuah alamat IP eksternal yang melakukan mekanisme _route_ ke satu atau lebih _node_ yang ada di klaster, `Service` Kubernetes dapat diekspos
|
|
dengan menggunakan `externalIP`. Trafik yang diarahkan ke klaster dengan IP eksternal
|
|
(sebagai destinasi IP), pada _port_ `Service` akan di-_route_ ke salah satu _endpoint_ `Service`.
|
|
_Value_ dari `externalIP` tidak diatur oleh Kubernetes dan merupakan tanggung jawab
|
|
dari administrator klaster.
|
|
|
|
Pada _ServiceSpec_, kamu dapat memberikan spesifikasi `externalIP` dan `ServiceTypes`.
|
|
Pada contoh di bawah ini. `"my-service"` dapat diakses oleh klien pada "`80.11.12.10:80`" (`externalIP:port`).
|
|
|
|
```yaml
|
|
kind: Service
|
|
apiVersion: v1
|
|
metadata:
|
|
name: my-service
|
|
spec:
|
|
selector:
|
|
app: MyApp
|
|
ports:
|
|
- name: http
|
|
protocol: TCP
|
|
port: 80
|
|
targetPort: 9376
|
|
externalIPs:
|
|
- 80.11.12.10
|
|
```
|
|
|
|
## Kekurangan
|
|
|
|
Penggunaan _proxy_ _userspace_ untuk VIP dapat digunakan untuk skala kecil hingga menengah,
|
|
meski begitu hal ini tidak _scalable_ untuk klaster yang sangat besar dan memiliki ribuan `Service`.
|
|
Perhatikan [Desain proposal orisinil untuk _portal_](http://issue.k8s.io/1107) untuk informasi
|
|
lebih lanjut.
|
|
|
|
Penggunaan _proxy_ _userspace_ menghilangkan _source-IP_ dari _packet_ yang mengakses
|
|
sebuah `Service`. Hal ini membuat mekanisme _firewall_ menjadi sulit untuk diterapkan.
|
|
_Proxy_ `iptables` tidak menghilangkan _source IP_ yang berasal dari dalam klaster,
|
|
meski begitu, hal ini masih berimbas pada klien yang berasal dari `Service` dengan tipe
|
|
_load-balancer_ atau _node-port_.
|
|
|
|
_Field_ tipe didesain sebagai fungsionalitas yang berantai - setiap tingkatan
|
|
menambahkan tambahan pada tingkatansebelumnya. Hal ini tidak selalu berlaku bagi
|
|
semua penyedia layanan _cloud_ (misalnya saja Google Compute Engine tidak perlu
|
|
melakukan alokasi `NodePort` untuk membuat `LoadBalancer` bekerja sebagaimana mestinya,
|
|
hal ini berbeda dengan AWS yang memerlukan hal ini, setidaknya untuk API yang mereka miliki
|
|
saat ini).
|
|
|
|
## Pengerjaan lebih lanjut
|
|
|
|
Di masa mendatang, kami berencana untuk membuat _policy_ _proxy_ menjadi lebih
|
|
bervariasi dan bukan hanya _round robin_, misalnya saja _master-elected_ atau _sharded_.
|
|
Kami juga berharap bahwa beberapa `Service` bisa saja memiliki _load balancer_ yang sebenarnya,
|
|
suatu kasus dimana VIP akan secara langsung mengantarkan paket.
|
|
|
|
Kami ingin meningkatkan dukungan lebih lanjut untuk `Service` dengan tingkatan `Service` L7(HTTP).
|
|
|
|
Kami ingin memiliki mode _ingress_ yang lebih fleksibel untuk `Service` yang
|
|
mencakup mode `ClusterIP`, `NodePort`, dan `LoadBalancer` dan banyak lagi.
|
|
|
|
## Detail mendalam mengenai IP virtual
|
|
|
|
Informasi sebelumnya sudah cukup bagi sebagian orang yang hanya ingin menggunakan
|
|
_Service_. Meskipun begitu, terdapat banyak hal yang sebenarnya terjadi dan akan
|
|
sangat bermanfaat untuk dipelajari lebih lanjut.
|
|
|
|
### Menghindari _collison_
|
|
|
|
Salah satu filosofi Kubernetes adalah pengguna tidak mungkin menghadapi situasi
|
|
dimana apa yang mereka mengalami kegagalan tanpa adanya alasan yang jelas. Dalam kasus ini,
|
|
kita akan coba memahami lebih lanjut mengenai _network port_ - pengguna tidak seharusnya memilih
|
|
nomor _port_ jika hal itu memungkinkan terjadinya _collision_ dengan pengguna lainnya. Hal ini
|
|
merupakan mekanisme isolasi kegagalan.
|
|
|
|
Agar pengguna dapat menentukan nomor _port_ bagi `Service` mereka, kita harus
|
|
memastikan bahwa tidak ada dua `Service` yang mengalami _collision_. Kita melakukan
|
|
hal tersebut dengan cara melakukan alokasi alamat IP pada setiap `Service`.
|
|
|
|
Untuk memastikan setiap `Service` memiliki alamat IP yang unik, sebuah _allocator_
|
|
internal akan secara atomik melakukan pemetaan alokasi global di dalam _etcd_ ketika
|
|
membuat sebuah `Service` baru. Pemetaan objek harus tersedia pada _registry_ `Service`
|
|
dimana `Service` akan diberikan sebuah IP, jika tidak, proses pembuatan `Service` akan gagal
|
|
dan sebuah pesan akan memberikan informasi bahwa alamat IP tidak dapat dialokasikan.
|
|
Sebuah _backgroud_ _controller_ bertanggung jawab terhadap mekanisme pemetaan tersebut (migrasi
|
|
dari versi Kubernetes yang digunakan dalam _memory locking_) sekaligus melakukan pengecekan
|
|
terhadap _assignment_ yang tidak valid yang terjadi akibat intervensi administrator dan melakukan
|
|
penghapusan daftar IP yang dialokasikan tapi tidak digunakan oleh `Service` mana pun.
|
|
|
|
### IP dan VIP
|
|
|
|
Tidak seperti alamat IP `Pod`, yang akan di _route_ ke destinasi yang "pasti",
|
|
IP `Service` tidak mengarahkan _request_ hanya pada satu _host_. Sebagai gantinya,
|
|
kita mneggunakan `iptables` (logika pemrosesan paket pada Linux) untuk melakukan definisi
|
|
alamat IP virtual yang secara transparan akan diarahkan sesuai kebutuhan. Ketika klien
|
|
dihubungkan pada VIP, trafik yang ada akan secara otomatis dialihkan pada _endpoint_ yang sesuai.
|
|
Variabel _environment_ dan DNS untuk `Service` terdiri dalam bentuk VIP dan _port_.
|
|
|
|
Kami mendukung tiga jenis mode _proxy_ - _userspace_, `iptables`, dan _ipvs_ yang memiliki
|
|
perbedaan cara kerja satu sama lainnya.
|
|
|
|
#### _Userspace_
|
|
|
|
Sebagai contoh, anggaplah kita memiliki aplikasi _image processing_ seperti yang sudah
|
|
disebutkan di atas. Ketika `Service` _backend_ dibuat, _master_ Kubernetes akan mengalokasikan
|
|
sebuah alamat IP virtual, misalnya 10.0.0.1. Dengan asumsi _port_ dari `Service` tersebut adalah _1234_,
|
|
maka `Service` tersebut akan diamati oleh semua _instance_ `kube-proxy` yang ada di klaster.
|
|
Ketika sebuah _proxy_ mendapati sebuah `Service` baru, _proxy_ tersebut akan membuka sebuah _port_
|
|
_acak_, menyediakan `iptables` yang mengarahkan VIP pada _port_ yang baru saja dibuat, dan mulai
|
|
koneksi pada _port_ tersebut.
|
|
|
|
Ketika sebuah klien terhubung ke VIP dan terdapat _rules_ `iptables`
|
|
yang diterapkan, paket akan diarahkan ke _port_ dari _proxy_ `Service` itu sendiri.
|
|
_Proxy_ `Service` akan memilih sebuah _backend_, dan mulai melakukan mekanisme _proxy_
|
|
trafik dari klien ke _backend_.
|
|
|
|
Dengan demikian, pemilik `Service` dapat memilih _port_ mana pun yang dia inginkan
|
|
tanpa adanya kemungkinan terjadinya _collision_. Klien dapat dengan mudah mengakses IP dan _port_,
|
|
tanpa harus mengetahui `Pod` mana yang sebenarnya diakses.
|
|
|
|
#### _Iptables_
|
|
|
|
Kembali, bayangkan apabila kita memiliki aplikasi _image processing_ seperti yang sudah
|
|
disebutkan di atas. Ketika `Service` _backend_ dibuat, _master_ Kubernetes akan mengalokasikan
|
|
sebuah alamat IP virtual, misalnya 10.0.0.1. Dengan asumsi _port_ dari `Service` tersebut adalah _1234_,
|
|
maka `Service` tersebut akan diamati oleh semua _instance_ `kube-proxy` yang ada di klaster.
|
|
Ketika sebuah _proxy_ mendapati sebuah `Service` baru, _proxy_ tersebut akan melakukan instalasi
|
|
serangkaian _rules_ `iptables` yang akan melakukan _redirect_ VIP ke _rules_ tiap `Service`. _Rules_
|
|
untuk tiap `Service` ini terkait dengan _rules_ tiap `Endpoints` yang mengarahkan (destinasi NAT)
|
|
ke _backend_.
|
|
|
|
Ketika sebuah klien terhubung ke VIP dan terdapat _rules _iptables
|
|
yang diterapkan. Sebuah _backend_ akan dipilih (hal ini dapat dilakukan berdasarkan _session affinity_
|
|
maupun secara _acak_) dan paket-paket yang ada akan diarahkan ke _backend_. Tidak seperti mekanisme
|
|
yang terjadi di _userspace_, paket-paket yang ada tidak pernah disalin ke _userspace_, `kube-proxy`
|
|
tidak harus aktif untuk menjamin kerja VIP, serta IP klien juga tidak perlu diubah.
|
|
|
|
Tahapan yang dijalankan sama dengan tahapan yang dijalankan ketika trafik masuk melalui sebuah _node-port_
|
|
atau _load-balancer_, meskipun pada dua kasus di atas klien IP tidak akan mengalami perubahan.
|
|
|
|
#### _Ipvs_
|
|
|
|
Operasi `iptables` berlangsung secara lambat pada klaster dengan skala besar (lebih dari 10.000 `Service`).
|
|
_IPVS_ didesain untuk mekanisme _load balance_ dan berbasis pada _hash tables_ yang berada di dalam _kernel_.
|
|
Dengan demikian kita dapat mendapatkan performa yang konsisten pada jumlah `Service` yang cukup besar dengan
|
|
menggunakan `kube-proxy` berbasis _ipvs_. Sementara itu, `kube-proxy` berbasis _ipvs_ memiliki algoritma
|
|
_load balance_ yang lebih bervariasi (misalnya saja _least conns_, _locality_, _weighted_, _persistence_).
|
|
|
|
## Objek API
|
|
|
|
_Service_ merupakan _resource_ _top-level_ pada API Kubernetes.
|
|
Penjelasan lebih lanjut mengenai objek API dapat ditemukan pada:
|
|
[objek API `Service`](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#service-v1-core).
|
|
|
|
## Protokol yang didukung {#protokol-yang-tersedia}
|
|
|
|
### TCP
|
|
|
|
{{< feature-state for_k8s_version="v1.0" state="stable" >}}
|
|
|
|
Kamu dapat menggunakan TCP untuk `Service` dengan _type_ apa pun, dan protokol ini merupakan
|
|
protokol _default_ yang digunakan.
|
|
|
|
### UDP
|
|
|
|
{{< feature-state for_k8s_version="v1.0" state="stable" >}}
|
|
|
|
Kamu dapat menggunakan UDP untuk sebagian besar `Service`.
|
|
Untuk `Service` dengan _type=LoadBalancer_, dukungan terhadap UDP
|
|
bergantung pada penyedia layanan _cloud_ yang kamu gunakan.
|
|
|
|
### HTTP
|
|
|
|
{{< feature-state for_k8s_version="v1.1" state="stable" >}}
|
|
|
|
Apabila penyedia layanan _cloud_ yang kamu gunakan mendukung, kamu dapat menggunakan
|
|
_Service_ dengan _type_ `LoadBalancer` untuk melakukan mekanisme _reverse_ _proxy_
|
|
bagi HTTP/HTTPS, dan melakukan _forwarding_ ke `Endpoints` dari _Service.
|
|
|
|
{{< note >}}
|
|
Kamu juga dapat menggunakan {{< glossary_tooltip term_id="ingress" >}} sebagai salah satu
|
|
alternatif penggunaan `Service` untuk HTTP/HTTPS.
|
|
{{< /note >}}
|
|
|
|
### Protokol PROXY
|
|
|
|
{{< feature-state for_k8s_version="v1.1" state="stable" >}}
|
|
|
|
Apabila penyedia layanan _cloud_ yang kamu gunakan mendukung, (misalnya saja, [AWS](/id/docs/concepts/cluster-administration/cloud-providers/#aws)),
|
|
_Service_ dengan _type_ `LoadBalancer` untuk melakukan konfigurasi _load balancer_
|
|
di luar Kubernetes sendiri, serta akan melakukan _forwarding_ koneksi yang memiliki prefiks
|
|
[protokol PROXY](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt).
|
|
|
|
_Load balancer_ akan melakukan serangkaian inisiasi _octet_ yang memberikan
|
|
deskripsi koneksi yang datang, dengan bentuk yang menyerupai:
|
|
|
|
```
|
|
PROXY TCP4 192.0.2.202 10.0.42.7 12345 7\r\n
|
|
```
|
|
yang kemudian diikuti data dari klien.
|
|
|
|
### SCTP
|
|
|
|
{{< feature-state for_k8s_version="v1.12" state="alpha" >}}
|
|
|
|
Kubernetes memberikan dukungan bagi SCTP sebagai _value_ dari _definition_ yang ada pada
|
|
_Service_, `Endpoints`, `NetworkPolicy` dan `Pod` sebagai fitur _alpha_. Untuk mengaktifkan fitur ini,
|
|
administrator klaster harus mengaktifkan _feature gate_ _SCTPSupport_ pada _apiserver_, contohnya
|
|
`“--feature-gates=SCTPSupport=true,...”`. Ketika _fature gate_ ini diaktifkan, pengguna dapat
|
|
memberikan _value_ SCTP pada _field_ _protocol_ `Service`, `Endpoints`, `NetworkPolicy` dan `Pod`.
|
|
Kubernetes kemudian akan melakukan pengaturan agar jaringan yang digunakan agar jaringan tersebut menggunakan SCTP,
|
|
seperti halnya Kubernetes mengatur jaringan agar menggunakan TCP.
|
|
|
|
#### Perhatian {#kelemahan-penggunaan-sctp}
|
|
|
|
##### Dukungan untuk asoasiasi _multihomed_ SCTP {#kelemahan-sctp-multihomed}
|
|
|
|
Dukungan untuk asosiasi _multihomed_ SCTP membutuhkan _plugin_ CNI yang dapat memberikan
|
|
pengalokasian _multiple interface_ serta alamat IP pada sebuah `Pod`.
|
|
|
|
NAT untuk asosiasi _multihomed_ SCTP membutuhkan logika khusus pada modul kernel terkait.
|
|
|
|
##### `Service` dengan _type=LoadBalancer_ {#kelemahan-sctp-loadbalancer-service-type}
|
|
|
|
Sebuah `Service` dengan _type_ `LoadBalancer` dan protokol SCTP dapat dibuat
|
|
hanya jika implementasi _load balancer_ penyedia layanan _cloud_ menyediakan dukungan
|
|
bagi protokol SCTP. Apabila hal ini tidak terpenuhi, maka _request_ pembuatan _Servixe_ ini akan ditolak.
|
|
_Load balancer_ yang disediakan oleh penyedia layanan _cloud_ yang ada saat ini (_Azure_, _AWS_, _CloudStack_, _GCE_, _OpenStack_) tidak mendukung SCTP.
|
|
|
|
##### Windows {#kelemahan-sctp-windows-os}
|
|
|
|
SCTP tidak didukung pada _node_ berbasis Windows.
|
|
|
|
##### _Kube-proxy_ _userspace_ {#kelemahan-sctp-kube-proxy-userspace}
|
|
|
|
_Kube-proxy_ tidak mendukung manajemen asosiasi SCTP ketika hal ini dilakukan pada mode
|
|
_userspace_
|
|
|
|
|
|
|
|
## {{% heading "whatsnext" %}}
|
|
|
|
|
|
Baca [Bagaimana cara menghubungkan _Front End_ ke _Back End_ menggunakan sebuah `Service`](/docs/tasks/access-application-cluster/connecting-frontend-backend/).
|
|
|
|
|