Chuyển tới nội dung chính

Services & NodePort

1. Vấn đề​

  • Pod chết thì IP đổi → ai đang gọi theo IP sẽ hỏng.
  • Có nhiều Pod giống nhau → gọi Pod nào?
  • Laptop của bạn (192.168.81.1) không gọi thẳng được IP Pod 10.244.x.x – đó là mạng ảo bên trong cluster.
💡 Định nghĩa

Service là một object cho một nhóm Pod một địa chỉ cố định (tên + IP), và tự động chuyển request tới một Pod còn sống trong nhóm. Service cân bằng tải ở Layer 4 (TCP/UDP).

Service giúp các thành phần liên kết lỏng (loose coupling): frontend không cần biết backend có mấy Pod, ở đâu.

2. Các loại Service lồng nhau​

LoạiGọi được từThêm gì so với loại bên trong
ClusterIP (mặc định)Chỉ trong clusterIP ảo + tên DNS
NodePortNgoài cluster qua <IP-node>:30000-32767Mở 1 port trên mọi node
LoadBalancerInternet / VPCCloud tạo LB trỏ vào các node
ExternalNameTrong clusterChỉ là bản ghi CNAME, không có Pod

3. Các thành phần của Service​

Tên & DNS​

CoreDNS tự tạo bản ghi "tên → IP":

Gọi từ đâuTên dùng được
Pod cùng namespacemyapp-service
Pod khác namespacemyapp-service.default
Tên đầy đủ (FQDN)myapp-service.default.svc.cluster.local

ClusterIP​

apiserver cấp một IP trong dải Service (ví dụ 10.96.0.50). IP này không đổi cho tới khi xóa Service.

Ba loại port​

FieldNghĩaVí dụBắt buộc?
portCửa của Service80✅ Có
targetPortCửa của container, nơi app thật sự nghe80Không, mặc định = port
nodePortCửa trên node (NodePort/LoadBalancer)30008Không, tự cấp trong 30000–32767
protocolTCP / UDP / SCTPTCPKhông, mặc định TCP
nameTên cặp porthttpKhi có ≥ 2 port
💡 Hình dung

nodePort = cổng tòa nhà, port = số máy lẻ của hotline, targetPort = cửa căn hộ.

Selector​

Service không ghi tên Pod, chỉ ghi điều kiện nhãn:

selector:          # ✅ map phẳng
app: myapp
selector:
matchLabels: # ❌ của Deployment/ReplicaSet, KHÔNG dùng cho Service
app: myapp

Những gì Kubernetes tự dựng​

Thành phầnLàm gìXem bằng
EndpointSliceDanh sách IP:port các Pod khớp selector và Readykubectl get endpoints myapp-service
kube-proxyTrên mọi node, viết luật iptables: tới ClusterIP → đổi đích thành một Pod ngẫu nhiêniptables-save -t nat
CoreDNSTrả lời "tên → ClusterIP"nslookup myapp-service
Lỗi Service gặp nhiều nhất

kubectl get endpoints ra <none> → Service không có Pod nào để chuyển tới. Kiểm tra lại selector có khớp label Pod không, Pod có Ready không.

Khi có nhiều Pod, iptables chọn bằng xác suất ngẫu nhiên (ví dụ 3 Pod: 1/3, rồi 1/2, rồi 1) – mỗi kết nối mới có thể vào Pod khác.

4. NodePort​

apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
type: NodePort
ports:
- targetPort: 80 # cửa container
port: 80 # cửa Service (bắt buộc)
nodePort: 30008 # cửa trên node, 30000–32767
selector: # chép y nguyên labels của Pod
app: myapp
type: front-end
  • Port 30008 được mở trên tất cả node – kể cả master và node không chạy Pod nào. Gọi node nào cũng tới được Pod.
  • externalTrafficPolicy: Local → chỉ node có Pod mới nhận traffic (giữ IP client gốc, tránh nhảy thêm một hop).
kubectl create -f svc.yaml
kubectl get svc
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# myapp-service NodePort 10.96.0.50 <none> 80:30008/TCP 5s

curl http://192.168.81.102:30008 # từ laptop

Tạo nhanh bằng lệnh​

LệnhĐặc điểm
kubectl expose deployment myapp --type=NodePort --port=80 --name=myapp-svcTự lấy selector từ Deployment; không chọn được nodePort
kubectl create service nodeport myapp --tcp=80:80 --node-port=30008Chọn được nodePort, nhưng selector mặc định là app=myapp

5. Headless Service và Service không selector​

LoạiCách khai báoDùng khi
HeadlessclusterIP: NoneDNS trả về IP từng Pod thay vì một ClusterIP – dùng cho StatefulSet (pod-0.svc…)
Không selectorBỏ selector, tự tạo EndpointSliceTrỏ tới IP ngoài cluster (DB on-prem)