Service headless adalah Service yang tidak memiliki IP virtual dan tidak melakukan pembagian koneksi secara otomatis. Nilai clusterIP: None pada manifest mematikan alamat virtual, sehingga DNS kluster menjawab nama Service dengan daftar alamat Pod secara langsung. Topik ini membahas cara kerja Service headless, bentuk manifest dan record DNS per Pod, serta alasan objek ini menjadi pasangan alami StatefulSet. Simulasi di bagian akhir menyusun record DNS tersebut langsung dari berkas manifest nyata.
Service tanpa IP virtual#
Service tipe ClusterIP biasa menyediakan satu alamat virtual yang stabil, dan kube-proxy meneruskan setiap koneksi ke salah satu Pod di belakangnya. Pemilihan Pod tersebut tidak berada dalam kendali klien karena semua Pod dianggap setara. Apabila nilai clusterIP: None dituliskan, Service tidak memperoleh alamat virtual, kube-proxy tidak membuat aturan penerusan apa pun, dan objek Endpoints tetap diisi dengan alamat Pod yang cocok dengan selector. Daftar tersebut diperbarui controller seiring Pod dibuat dan dihapus, sehingga daftarnya tetap mutakhir seperti pada Service biasa.
Tanpa alamat virtual, klien yang menyelesaikan nama DNS menerima seluruh alamat Pod sekaligus dan memilih sendiri tujuan koneksinya. Pola ini berguna bagi aplikasi yang membutuhkan keputusan koneksi tersendiri, misalnya gRPC yang menjaga banyak koneksi sekaligus atau klien yang membaca daftar anggota kluster secara berkala. Karena itulah Service headless tidak melakukan load balancing, yaitu pembagian koneksi merata ke beberapa Pod, dan hanya berperan sebagai daftar alamat yang selalu terbarui. Tanpa aturan penerusan pada Node, permintaan klien menuju alamat Pod secara langsung tanpa melewati lapisan antara mana pun.
Manifest Service headless#
Manifest Service headless hanya memerlukan clusterIP: None pada bagian spec, sedangkan selector dan ports tetap dituliskan seperti Service biasa. Selector tetap menentukan Pod mana yang masuk daftar, dan objek Endpoints tetap berisi pasangan alamat dan port dari Pod yang siap. Karena daftar itu tetap mengikuti selector, perubahan label Pod langsung mengubah isi daftar Service headless. Bidang type: ClusterIP boleh dituliskan agar maksud manifest terbaca, karena nilai None pada clusterIP sudah cukup menandai perilaku headless-nya. Pada keluaran kubectl get service, kolom CLUSTER-IP yang berisi None menjadi tanda visual bahwa Service berjalan tanpa IP virtual.
Berkas service-headless.yaml berikut mendefinisikan Service bernama web yang memilih Pod berlabel app: aplikasi-catatan pada port 80:
apiVersion: v1
kind: Service
metadata:
name: web
labels:
app: aplikasi-catatan
spec:
type: ClusterIP
clusterIP: None
selector:
app: aplikasi-catatan
ports:
- name: http
port: 80
targetPort: 80Perintah berikut menerapkan manifest tersebut lalu menampilkan objek Endpoints yang terbentuk. Kolom ENDPOINTS berisi alamat Pod secara langsung, dan tidak ada alamat virtual yang muncul di mana pun. Apabila daftar ENDPOINTS kosong, kesesuaian label Pod dengan selector menjadi pemeriksaan pertama yang paling murah dilakukan:
# tidak-dijalankan
# terapkan manifest Service headless ke kluster
kubectl apply -f service-headless.yaml
# tampilkan endpoint yang menempel pada Service web
kubectl get endpoints webNAME ENDPOINTS AGE
web 10.244.1.10:80,10.244.2.21:80,10.244.3.12:80 12sDNS per Pod#
DNS kluster menyimpan nama Service biasa sebagai satu record A, yaitu entri jawaban DNS yang memuat satu alamat IP virtual. Untuk Service headless, record A pada nama Service berisi seluruh alamat Pod yang cocok dengan selector, dan jawaban DNS dapat terdiri atas lebih dari satu baris. Resolver, yaitu perangkat lunak penyelesai nama pada klien, menerima semuanya dan memilih sendiri alamat yang dituju.
Pod StatefulSet memperoleh lapisan tambahan, yaitu record A khusus untuk setiap Pod. Bentuknya <nama-pod>.<nama-service>.<namespace>.svc.cluster.local, misalnya web-0.web.default.svc.cluster.local. Nama tersebut terbentuk karena StatefulSet mengisi hostname setiap Pod dengan nama Pod dan subdomain-nya dengan nama Service headless yang dirujuk serviceName. Record per Pod menunjuk langsung ke alamat Pod pemiliknya, sehingga klien dapat mengirim permintaan ke anggota tertentu, misalnya anggota yang terpilih sebagai pemimpin.
Pasangan alami StatefulSet#
StatefulSet menyandingkan Service headless melalui bidang serviceName, dan identitas DNS per Pod berasal dari pasangan nama Pod dan nama Service itu. Tanpa Service headless yang cocok, StatefulSet tetap berjalan, tetapi nama DNS per Pod tidak terbentuk, sehingga jaminan identitas jaringannya turun satu lapis. Service ini kerap disebut governing service, yaitu Service yang mengatur identitas jaringan seluruh anggota StatefulSet.
Kombinasi tersebut menjelaskan mengapa keduanya hampir selalu muncul bersama. Basis data yang berjalan di atas StatefulSet memerlukan klien yang mengarahkan penulisan ke satu Pod tertentu dan pembacaan ke Pod lain. Antrean pesan dan sistem pembagian peran memerlukan daftar anggota yang dapat dibaca ulang kapan saja. Record per Pod memberikan alamat tetap untuk semua kebutuhan tersebut, sedangkan nama Service tetap tersedia bagi klien yang hanya menginginkan satu alamat mana pun.
Simulasi record DNS#
Skrip berikut membaca service-headless.yaml menggunakan PyYAML, lalu menyusun record DNS yang dikembalikan DNS kluster untuk nama Service dan untuk setiap Pod anggota. Daftar alamat Pod bersifat ilustratif dan mewakili isi objek Endpoints yang dilaporkan controller. Setiap baris record meniru bentuk jawaban DNS kluster, sehingga pola yang sama dapat diuji langsung dengan nslookup setelah manifest diterapkan.
"""Record DNS A untuk Service headless dan tiap pod anggota StatefulSet."""
import yaml
NAMESPACE = "default" # manifest tanpa metadata.namespace berjalan di namespace default
with open("service-headless.yaml", encoding="utf-8") as berkas:
service = yaml.safe_load(berkas)
spec = service["spec"]
nama = service["metadata"]["name"]
fqdn_service = f"{nama}.{NAMESPACE}.svc.cluster.local"
# alamat pod yang dilaporkan objek Endpoints untuk selector di atas
pod_alamat = {
"web-0": "10.244.1.10",
"web-1": "10.244.2.21",
"web-2": "10.244.3.12",
}
print(f"Service : {nama}")
print(f"clusterIP : {spec['clusterIP']} (tanpa IP virtual)")
print(f"selector : {spec['selector']}")
print()
print(f"Record A untuk nama Service {fqdn_service}:")
for alamat in pod_alamat.values():
print(f" A {alamat}")
print()
print("Record A per pod (identitas stabil anggota StatefulSet):")
for pod, alamat in pod_alamat.items():
fqdn_pod = f"{pod}.{nama}.{NAMESPACE}.svc.cluster.local"
print(f" {fqdn_pod}")
print(f" A {alamat}")
print()
print(f"Jumlah record untuk Service: {len(pod_alamat)} alamat, bukan satu IP virtual")Service : web
clusterIP : None (tanpa IP virtual)
selector : {'app': 'aplikasi-catatan'}
Record A untuk nama Service web.default.svc.cluster.local:
A 10.244.1.10
A 10.244.2.21
A 10.244.3.12
Record A per pod (identitas stabil anggota StatefulSet):
web-0.web.default.svc.cluster.local
A 10.244.1.10
web-1.web.default.svc.cluster.local
A 10.244.2.21
web-2.web.default.svc.cluster.local
A 10.244.3.12
Jumlah record untuk Service: 3 alamat, bukan satu IP virtualKeluaran memperlihatkan dua tingkat record. Tingkat pertama adalah nama Service yang menjawab tiga alamat sekaligus, sedangkan tingkat kedua adalah tiga nama per Pod yang masing-masing menjawab satu alamat. Kontras dengan Service ClusterIP biasa tampak jelas, yaitu perubahan dari satu nama dengan satu IP virtual menjadi satu nama dengan daftar alamat, ditambah nama khusus untuk setiap anggota. Dua tingkat tersebut dibangun dari objek Endpoints yang sama, sehingga Pod yang baru dibuat ikut masuk jawaban DNS dan Pod yang hilang otomatis keluar dari daftar. Pola inilah yang membuat klien dapat menunjuk anggota tertentu atau seluruh grup secara bergantian tanpa mengubah konfigurasi.
Kesalahan umum#
Tiga kesalahan berikut paling sering muncul saat Service headless mulai digunakan. Penyebabnya berada di luar manifest Service itu sendiri, sehingga pemeriksaannya melibatkan objek lain. Objek yang tepat untuk diperiksa adalah Endpoints sebagai daftar alamat dan DNS sebagai sumber nama.
- Berharap pembagian koneksi merata dari Service headless. Tanpa IP virtual, tidak ada kube-proxy yang memilih endpoint, sehingga klien yang selalu mengambil alamat pertama membebani satu Pod. Perbaikannya adalah menggunakan Service ClusterIP biasa apabila kebutuhannya hanyalah pembagian trafik.
- Lupa membuat Service yang dirujuk oleh
serviceName. StatefulSet tetap membuat Pod dengan nama ordinal, tetapi record DNS per Pod tidak pernah terbentuk dan pemanggilan antara anggota gagal. Perbaikannya adalah membuat Service headless yang namanya persis sama dengan nilaiserviceName. - Memanggil anggota dengan nama Pod saja. Pencarian atas
web-0tidak menemukan apa pun, karena bentuk yang benar menyertakan nama Service, misalnyaweb-0.web.default.svc.cluster.local. Bentuk lengkap tersebut berhasil dari namespace mana pun, sehingga cocok ditulis di konfigurasi.
Ringkasan#
- Service headless tidak memiliki IP virtual dan tidak melakukan load balancing, sehingga klien memilih alamat Pod sendiri dari jawaban DNS.
- Record A pada nama Service berisi seluruh alamat Pod, sedangkan setiap Pod StatefulSet memperoleh record khusus berbentuk
<nama-pod>.<nama-service>.<namespace>.svc.cluster.local. - Bidang
serviceNamepada StatefulSet menjadikan Service headless penyedia identitas jaringan untuk setiap anggota. - Bidang
publishNotReadyAddresses: truemenampilkan record Pod yang belum siap, yang diperlukan saat anggota saling mencari pada bootstrap pertama.
Referensi#
- Service — Kubernetes
— Bagian headless services pada dokumentasi Service, termasuk
clusterIP: Nonedan perilaku DNS-nya. - StatefulSets — Kubernetes — Dokumentasi StatefulSet yang menjelaskan peran Service headless sebagai penyedia identitas DNS Pod.