Triển khai và sử dụng Headless Service trong Kubernetes

Trong Kubernetes, Headless Service là một loại Service đặc biệt cho phép các ứng dụng tự quản lý việc cân bằng tải thay vì dựa vào Service để thực hiện điều này. Khác với các Service thông thường có ClusterIP được Kubernetes tự động gán, Headless Service được cấu hình với clusterIP: None. Điều này dẫn đến việc DNS của Kubernetes không trả về một địa chỉ IP duy nhất cho Service, mà thay vào đó, nó sẽ trả về danh sách các địa chỉ IP của tất cả các Pod đang chạy thuộc Service đó.

Việc không có ClusterIP đồng nghĩa với việc kube-proxy không can thiệp vào việc định tuyến hoặc cân bằng tải cho Headless Service. Các yêu cầu đến Service sẽ được phân giải trực tiếp thành địa chỉ IP của các Pod backend. Điều này mang lại lợi ích về hiệu suất do bỏ qua một lớp trung gian, đồng thời cho phép các nhà phát triển xây dựng các giải pháp cân bằng tải tùy chỉnh dựa trên danh sách IP Pod trả về.

Lưu ý quan trọng:

  • Cả Headless Service và ClusterIP Service đều có thể được phân giải tên từ bên trong các container cùng namespace.
  • Headless Service phân giải trực tiếp ra địa chỉ IP của Pod. Bạn có thể ping tên Service và nhận được phản hồi từ các IP Pod.
  • ClusterIP Service phân giải ra địa chỉ ClusterIP được gán. Việc ping trực tiếp tên Service sẽ không thành công.
  • Khi truy cập một Headless Service, bạn sẽ kết nối trực tiếp đến cổng của Pod. Các thuộc tính porttargetPort trong định nghĩa Service ít quan trọng hơn trong trường hợp này.
  • Khi truy cập ClusterIP Service, bạn cần chỉ định targetPort (cổng trên Pod) và port (cổng của Service để truy cập).

Tạo Headless Service

Để tạo một Headless Service, bạn chỉ cần đặt giá trị của trường clusterIP trong phần spec của tài nguyên Service thành None.

Ví dụ 1: Deployment và Headless Service `app-one`

File cấu hình app-one-headless.yaml:


apiVersion: v1
kind: Namespace
metadata:
  name: dev
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-one-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: app-one
  template:
    metadata:
      labels:
        app: app-one
    spec:
      containers:
      - name: app-one-container
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: app-one-svc
  namespace: dev
spec:
  selector:
    app: app-one
  clusterIP: None # Đây là điểm mấu chốt để tạo Headless Service
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

Ví dụ 2: Deployment và Headless Service `app-two`

File cấu hình app-two-headless.yaml:


apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-two-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: app-two
  template:
    metadata:
      labels:
        app: app-two
    spec:
      containers:
      - name: app-two-container
        image: httpd:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: app-two-svc
  namespace: dev
spec:
  selector:
    app: app-two
  clusterIP: None
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

Kiểm tra tài nguyên Kubernetes

Sau khi áp dụng các tệp cấu hình trên, bạn có thể kiểm tra các Pod, Service và Deployment:


kubectl get pods,svc,deploy -o wide -n dev

Kết quả sẽ hiển thị các Pod đang chạy, Service với CLUSTER-IPNone và các Deployment tương ứng.

Truy cập Headless Service

Vì Headless Service không có ClusterIP, bạn không thể truy cập nó bằng địa chỉ IP. Thay vào đó, bạn phải sử dụng tên DNS của Service. Việc phân giải tên Service này chỉ hoạt động hiệu quả khi được thực hiện từ bên trong một container trong cluster.

Định dạng tên DNS chuẩn là:


[tên-service].[namespace].svc.cluster.local

Thực hiện truy vấn DNS từ bên trong container

Để kiểm tra, bạn có thể truy cập vào một Pod và thực hiện các lệnh dig hoặc nslookup.


# Truy cập vào một Pod của app-one
kubectl exec -it app-one-deployment- -- bash -n dev

# Kiểm tra tệp resolv.conf để xem cấu hình DNS
cat /etc/resolv.conf

# Sử dụng dig để phân giải tên Service
dig app-one-svc.dev.svc.cluster.local

Lệnh dig sẽ trả về danh sách các địa chỉ IP của tất cả các Pod thuộc app-one-svc.


# Ví dụ kết quả dig:
;; ANSWER SECTION:
app-one-svc.dev.svc.cluster.local.	30	IN	A	10.244.1.9
app-one-svc.dev.svc.cluster.local.	30	IN	A	10.244.2.8
app-one-svc.dev.svc.cluster.local.	30	IN	A	10.244.0.8

Bạn cũng có thể sử dụng nslookup:


nslookup app-one-svc 10.96.0.10 # Giả sử 10.96.0.10 là IP của CoreDNS

Kết quả sẽ tương tự, liệt kê các IP của Pod backend.

Truy cập dịch vụ khác bằng tên

Từ bên trong một Pod, bạn có thể thử truy cập các dịch vụ khác bằng tên DNS của chúng:


# Thử kết nối tới app-two-svc bằng telnet (hoặc ping)
telnet app-two-svc 80
ping app-two-svc -c 3

Các lệnh này sẽ tương tác với một trong các Pod thuộc app-two-svc dựa trên kết quả phân giải DNS.

Cấu hình chi tiết

Dưới đây là một ví dụ chi tiết về cách định nghĩa một Headless Service cùng với Deployment của nó, bao gồm cả các cấu hình tài nguyên và probe:


apiVersion: v1
kind: Service
metadata:
  name: web-app-headless
  namespace: dev
spec:
  clusterIP: None
  ports:
  - name: web-app-port
    port: 8080 # Cổng mà Service sẽ lắng nghe
    protocol: TCP
    targetPort: 80 # Cổng trên container của Pod
  selector:
    app: web-app
  type: ClusterIP # Mặc định là ClusterIP, nhưng clusterIP: None sẽ ghi đè
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app-deployment
  namespace: dev
  labels:
    app: web-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: web-app-container
        image: my-custom-webapp:v1.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: http
          protocol: TCP
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
          requests:
            cpu: 100m
            memory: 128Mi
        livenessProbe:
          tcpSocket:
            port: 80
          initialDelaySeconds: 10
          timeoutSeconds: 3
          periodSeconds: 10
          failureThreshold: 3
        readinessProbe:
          httpGet:
            path: /healthz
            port: 80
          initialDelaySeconds: 5
          timeoutSeconds: 2
          periodSeconds: 5
          successThreshold: 1
          failureThreshold: 3

Thẻ: Kubernetes Service Headless Service dns Networking

Đăng vào ngày 24 tháng 6 lúc 20:29