Chuyển đến nội dung chính

BÀI 7: SERVICES VÀ ENDPOINTSLICES

Service discovery và load balancing với Kubernetes Services. ClusterIP, NodePort, LoadBalancer, ExternalName. EndpointSlices là chuẩn mới thay thế Endpoints API (deprecated K8s 1.33). Headless Services và DNS trong Kubernetes.

🎯 Mục tiêu bài học

Hiểu tại sao cần Service trong Kubernetes, các loại Service và khi nào dùng mỗi loại, EndpointSlices là chuẩn mới thay thế Endpoints API, DNS-based service discovery với CoreDNS.

1. Tại sao cần Services?

Pods có IP động — mỗi lần Pod được tạo lại (sau crash, update, scaling), nó nhận IP mới. Nếu Service A muốn gọi Service B, Service A không thể hardcode IP của B.

Service cung cấp một endpoint ổn định (IP và DNS name) cho một tập hợp Pods. Traffic đến Service sẽ được load balance tới các Pods khỏe mạnh.

2. Service Types

Kubernetes Service Types - ClusterIP, NodePort, LoadBalancer, ExternalName

2.1 ClusterIP (mặc định)

Expose service với IP nội bộ trong cluster. Chỉ accessible từ trong cluster.

apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  type: ClusterIP   # mặc định, có thể bỏ qua
  selector:
    app: backend
  ports:
  - port: 80        # port của Service (clients dùng port này)
    targetPort: 8080 # port của Pods

2.2 NodePort

Expose service ra ngoài cluster qua IP của Node và một port tĩnh (30000-32767).

apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  type: NodePort
  selector:
    app: frontend
  ports:
  - port: 80
    targetPort: 3000
    nodePort: 31000   # cố định port, hoặc để K8s tự chọn

Truy cập: http://<any-node-ip>:31000

2.3 LoadBalancer

Tạo external load balancer (trên cloud providers: AWS ELB, GCP CLB, Azure LB). Dùng trong production trên cloud.

apiVersion: v1
kind: Service
metadata:
  name: api-service
spec:
  type: LoadBalancer
  selector:
    app: api
  ports:
  - port: 80
    targetPort: 8080

Thay thế hiện đại: dùng Gateway API (xem Module 4) — expressive hơn, không vendor lock-in.

2.4 ExternalName

Map service đến DNS name bên ngoài cluster. Không tạo load balancing, chỉ là CNAME.

apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  type: ExternalName
  externalName: mydb.example.com

3. Service Discovery với DNS

CoreDNS tạo DNS records cho mỗi Service. Format:

# Service trong cùng namespace
http://backend-service

Service trong namespace khác

http://backend-service.production.svc.cluster.local

Format đầy đủ

{service-name}.{namespace}.svc.{cluster-domain}

# Kiểm tra DNS từ trong pod
kubectl exec -it debug-pod -- nslookup backend-service
kubectl exec -it debug-pod -- curl http://backend-service/api

4. EndpointSlices — Chuẩn mới K8s 1.33+

Trước đây, Kubernetes dùng Endpoints resource để lưu danh sách IP của Pods. Vấn đề: khi số lượng Pods lớn (hàng nghìn), Endpoints object rất lớn, gây network overhead khi update.

EndpointSlices chia nhỏ thành các slices (mặc định tối đa 100 endpoints/slice), cải thiện scalability đáng kể.

  • Endpoints API: deprecated K8s 1.33
  • EndpointSlices: chuẩn hiện tại, đã GA từ K8s 1.21
# Xem EndpointSlices
kubectl get endpointslices
kubectl get endpointslices -l kubernetes.io/service-name=backend-service -o yaml

Xem Endpoints (deprecated, vẫn hoạt động nhưng tránh dùng)

kubectl get endpoints

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: backend-service-xyz
  labels:
    kubernetes.io/service-name: backend-service
addressType: IPv4
ports:
- name: http
  protocol: TCP
  port: 8080
endpoints:
- addresses:
  - 10.244.1.5
  conditions:
    ready: true
    serving: true
  targetRef:
    kind: Pod
    name: backend-pod-abc

5. Headless Services

Headless Service (clusterIP: None) không có ClusterIP. DNS query trả về trực tiếp IPs của các Pods, không qua load balancing. Dùng cho StatefulSets để có stable DNS names cho từng Pod.

apiVersion: v1
kind: Service
metadata:
  name: postgres-headless
spec:
  clusterIP: None     # Headless
  selector:
    app: postgres
  ports:
  - port: 5432
# DNS resolution cho headless service
# Trả về danh sách Pod IPs
nslookup postgres-headless.production.svc.cluster.local

DNS resolution cho từng Pod trong StatefulSet

nslookup postgres-0.postgres-headless.production.svc.cluster.local nslookup postgres-1.postgres-headless.production.svc.cluster.local

6. Session Affinity

Mặc định, mỗi request được round-robin đến một Pod ngẫu nhiên. Nếu cần sticky sessions:

spec:
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 3600  # 1 giờ

7. kube-proxy và Service Implementation

kube-proxy chạy trên mỗi Node, implement Service load balancing bằng cách tạo iptables/nftables rules.

  • iptables mode: legacy, phổ biến nhất
  • nftables mode: khuyến nghị 2026 (IPVS deprecated K8s 1.35)

Khi packet đến ClusterIP, iptables/nftables rules chuyển hướng đến một Pod IP ngẫu nhiên (DNAT).

8. Service Best Practices

  • Luôn dùng ClusterIP cho internal services
  • Dùng Gateway API thay vì LoadBalancer type cho external exposure
  • Đặt tên service rõ ràng, dùng labels nhất quán
  • Dùng targetPort là tên port thay vì số (flexibility khi thay đổi port trong Pod)
  • Theo dõi EndpointSlices để debug connectivity issues

Tóm tắt

  • Service = stable endpoint cho dynamic Pods
  • ClusterIP: internal; NodePort: dev/testing; LoadBalancer: cloud production (nhưng ưu tiên Gateway API)
  • EndpointSlices thay thế Endpoints API (deprecated K8s 1.33)
  • Headless Service: DNS trả về Pod IPs trực tiếp, dùng cho StatefulSets
  • CoreDNS: svc-name.namespace.svc.cluster.local