Service trong Kubernetes

1. Tìm hiểu về Service

1.1. Tại sao cần Service?

  • Mỗi Pod đều có địa chỉ IP riêng biệt, tuy nhiên khi Pod bị xóa và tạo lại, địa chỉ IP của Pod mới sẽ thay đổi, điều này gây khó khăn trong việc truy cập
  • Giải pháp đặt ra là tạo một proxy phía trước các Pod, khi client truy cập sẽ thông qua Service rồi mới chuyển tiếp đến Pod được quản lý
  • Service lựa chọn Pod thông qua label selector
  • Service là tập hợp logic của các Pod (có thể thay đổi được), chỉ phụ thuộc vào label
  • Service có địa chỉ IP và cổng riêng, các cổng này đều là ảo. Khi map Service port ra node thì gọi là NodePort
  • Thông tin được lưu trữ trong ipvsadm -Ln
  • kube-proxy theo dõi việc tạo Service và liên kết IP của Pod với IP của Service
  • coredns thực hiện phân giải domain, chuyển đổi tên domain của Service thành địa chỉ IP

1.2. Quy trình Service proxy Pod

  • Khi tạo Service, label selector sẽ tìm các Pod liên quan, endpoint sẽ lưu trữ IP của các Pod đó
  • Khi Pod thay đổi, endpoint cũng cập nhật tương ứng
  • Khi có request, endpoint chuyển tiếp đến Pod phù hợp, còn kube-proxy quyết định node nào sẽ xử lý

1.3. Bốn loại Service

ExternalName
  • Cho phép container trong cluster K8s truy cập resource bên ngoài, không có selector và endpoint
  • Ánh xạ Service với một domain, khi truy cập Service sẽ trả về domain tương ứng
  • Tên domain đầy đủ: <service_name>.<namespace>.svc.cluster.local
ClusterIP
  • Chỉ expose IP nội bộ trong cluster, dịch vụ chỉ có thể truy cập từ bên trong cluster
  • Đây là loại Service mặc định
NodePort
  • Expose dịch vụ qua IP của node và một cổng tĩnh
  • Luồng request: node:nodeport → svc:svcport → pod:containerport
LoadBalancer
  • Sử dụng load balancer của cloud provider để expose dịch vụ ra ngoài
  • Có thể route đến NodePort và ClusterIP service

1.4. Thực hành

Tạo Service loại ClusterIP
#Tạo deployment và để Service proxy các Pod
[root@master ~]# cat service-clusterip.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deploy
  namespace: production
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: web-container
        image: docker.io/library/nginx 
        imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
  name: web-service
  namespace: production
spec:
  type: ClusterIP
  ports: 
  - targetPort: 80
    port: 80
  selector:
    app: webapp

#Kiểm tra Service
[root@master ~]# kubectl get svc -n production
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
web-service    ClusterIP   10.108.45.201   <none>        80/TCP    2h15m

#Kiểm tra endpoints
[root@master ~]# kubectl get endpoints -n production
NAME           ENDPOINTS                            AGE
web-service    10.244.125.8:80,10.244.167.19:80     2h15m

#Kiểm tra Pod
[root@master ~]# kubectl get pod -n production -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
web-deploy-8f7cd4-rnkdm    1/1     Running   0          2h    10.244.167.19    node1   <none>           <none>
web-deploy-8f7cd4-xklpt    1/1     Running   0          2h    10.244.125.8     node2   <none>           <none>

#Truy cập vào Pod để test
[root@master ~]# kubectl exec -it -n production web-deploy-8f7cd4-rnkdm -- /bin/bash
curl web-service.production.svc.cluster.local
Tạo Service loại NodePort
#ClusterIP chỉ truy cập được từ trong cluster, còn NodePort cho phép truy cập từ bên ngoài

[root@master ~]# cat service-nodeport.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deploy
  namespace: production
spec:
  replicas: 2
  selector:
    matchLabels:
      api: apiserver
  template:
    metadata:
      labels:
        api: apiserver
    spec:
      containers:
      - name: api-container
        image: docker.io/library/nginx 
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: api-service
  namespace: production
spec:
  type: NodePort
  ports:
  - targetPort: 80
    port: 80
    nodePort: 30080
  selector:
    api: apiserver

#Request sẽ được chuyển từ node:30080 → service:80 → Pod
[root@master ~]# kubectl get svc -n production
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
api-service    NodePort    10.99.147.221   <none>        80:30080/TCP   1h30m
Tạo Service loại ExternalName
#Truy cập cross-namespace: client trong namespace default truy cập nginx trong namespace backend

[root@master ~]# cat service-external.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: client-deploy
  namespace: default 
spec:
  replicas: 2
  selector:
    matchLabels:
      app: clientapp
  template:
    metadata:
      labels:
        app: clientapp
    spec:
      containers:
      - name: client-container
        image: docker.io/library/busybox:1.28 
        imagePullPolicy: IfNotPresent
        command: ["/bin/sh","-c","sleep 3600"]
---
apiVersion: v1
kind: Service
metadata:
  name: client-service
  namespace: default
spec:
  type: ExternalName
  externalName: nginx-service.backend.svc.cluster.local
  ports:
  - targetPort: 80
    port: 80
    name: http

#Khi truy cập client-service sẽ được ánh xạ đến nginx-service
[root@master ~]# kubectl get svc -n default 
NAME             TYPE           CLUSTER-IP   EXTERNAL-IP                              PORT(S)   AGE
client-service   ExternalName   <none>       nginx-service.backend.svc.cluster.local 80/TCP    2m10s
kubernetes       ClusterIP      10.96.0.1    <none>                                   443/TCP   7d2h

#Vào Pod trong namespace default, truy cập domain service, request sẽ được forward sang Pod trong namespace backend
[root@master ~]# kubectl exec -it -n default client-deploy-5f8d9-abcd1  -- /bin/sh
/ # cat /etc/resolv.conf 
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5

/ # wget -q -O - client-service.default.svc.cluster.local

Loại Service ExternalName cho phép truy cập cross-namespace. Khi ánh xạ Service bên ngoài vào Service nội bộ, khi truy cấp domain của Service sẽ được chuyển tiếp đến Service bên ngoại. Domain mặc định của Service có dạng: servicename.namespace.svc.cluster.local

Thẻ: Kubernetes Service Networking Kubectl ClusterIP

Đăng vào ngày 17 tháng 7 lúc 19:46