Manual Scheduling trong K8S

Trong bài viết này, hãy cùng mình tìm hiểu cách thực hiện Manual Scheduling trong K8s.

1. Cách Scheduling hoạt động

Trường Node Name: Mỗi pod trong k8s có một trường Node Name. Scheduler sẽ điền vào trường này khi nó gán một pod cho một node.

Quá trình lập lịch: Scheduler kiểm tra các pods chưa có Node Name và áp dụng các thuật toán lập lịch để chọn node phù hợp nhất. Sau đó, nó tạo một đối tượng Binding để liên kết pod với node đã chọn.

Manual Scheduling

2. Vai trò của scheduling

Thông thường, Kubernetes sử dụng scheduling để tự động gán pods cho các nodes dựa trên nhiều yếu tố như sẵn có tài nguyên và các ràng buộc khác.

Architecture K8S

3. Manual Scheduling Pod

3.1 Không có Scheduler

Nếu không có scheduler, pods sẽ ở trạng thái “Pending” bởi vì chúng không thể được gán cho các node tự động.

– File POD nginx.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  -  image: nginx
     name: nginx

– Trạng thái của POD:

NAME    READY   STATUS    RESTARTS   AGE
nginx   0/1     Pending   0          44s

3.2 Manual Scheduling Pod

Bạn có thể manunal scheduling pod bằng cách trực tiếp chỉ định “Node Name” trong tệp định nghĩa pod khi tạo pod. Điều này buộc Kubernetes phải gán pod cho node đã chỉ định.

– Manunal Scheduling Pod cho node01:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: node01
  containers:
  -  image: nginx
     name: nginx
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          23s

Hạn chế: Phương pháp này chỉ hoạt động trong quá trình tạo pod. Bạn không thể sửa đổi “Node Name” của một pod đã được tạo.

4. Scheduling Pod already exits

Đối tượng Binding: Để gán một node cho một pod đã tồn tại, bạn cần tạo một đối tượng “Binding” và gửi một yêu cầu POST đến API binding của pod.

Nội dung của Đối tượng Binding: Đối tượng binding chỉ định “Target Node” với tên node mong muốn.

Định dạng JSON: Yêu cầu POST yêu cầu gửi đối tượng binding ở định dạng JSON.

5. Pod Scheduling sử dụng Node Name và Node Selector

Mô hình demo

Giả sử cluster của mình có 2 node:

  • Một node tên là masternode
  • Một node tên là node1

Mục tiêu của bài này là:

  1. Tạo một Pod chạy trên node node1 bằng cách chỉ định trực tiếp tên node.
  2. Tạo một Pod khác chạy trên node masternode bằng cách gắn nhãn và chọn theo nhãn (label).

Pod Scheduling sử dụng Node Name và Node Selector

Sử dụng Node Name

Bước 1: Xử lý node master (gỡ taint)

Mặc định node master có một cái gọi là taint, nghĩa là không cho Pod thường chạy trên nó. Nên trước khi gán Pod lên master, mình sẽ xóa taint đó đi bằng lệnh:

kubectl get node
kubectl taint nodes master node-role.kubernetes.io/master-

Hoặc bạn có thể dùng lệnh kubectl edit node master và xóa phần taints: trong file YAML.

truongnt@masternode:~$ kubectl get node
NAME         STATUS   ROLES           AGE     VERSION
masternode   Ready    control-plane   3d10h   v1.31.10
node1        Ready    <none>          3d10h   v1.31.10
node2        Ready    <none>          3d10h   v1.31.10

truongnt@masternode:~$ kubectl describe node master | grep -i taint
Taints:             node-role.kubernetes.io/control-plane:NoSchedule

truongnt@masternode:~$ kubectl patch node masternode -p '{"spec":{"taints":[]}}'
node/masternode patched


Bước 2: Tạo namespace để quản lý Pod

Để dễ quản lý, mình tạo một namespace riêng:

kubectl create namespace pod-to-node-ns

Bước 3: Tạo Pod bằng nodeName

kubectl -n pod-to-node-ns run podnode-using-nodename --image nginx --dry-run=client -oyaml > podnode-using-nodename.yaml

sudo vi podnode-using-nodename.yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: podnode-using-nodename
  name: podnode-using-nodename
  namespace: pod-to-node-ns
spec:
  nodeName: node1
  containers:
  - image: nginx
    name: podnode-using-nodename
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

Sau đó apply file:

kubectl create -f podnode-using-nodename.yaml

Kiểm tra xem Pod đã chạy đúng node chưa:

kubectl -n pod-to-node-ns get pods -owide
truongnt@masternode:~$ kubectl -n pod-to-node-ns run podnode-using-nodename --image nginx --dry-run=client -oyaml > podnode-using-nodename.yaml
truongnt@masternode:~$ sudo vi podnode-using-nodename.yaml
truongnt@masternode:~$ kubectl create -f podnode-using-nodename.yaml
pod/podnode-using-nodename created
truongnt@masternode:~$ kubectl -n pod-to-node-ns get pods -owide
NAME                     READY   STATUS    RESTARTS   AGE   IP                NODE    NOMINATED NODE   READINESS GATES
podnode-using-nodename   1/1     Running   0          47s   192.168.166.132   node1   <none>           <none>

Sử dụng Node Selector

Bước 1: Gắn label cho node master

Để sử dụng nodeSelector, ta cần gắn nhãn cho node. Ví dụ:

kubectl get nodes --show-labels
kubectl label nodes masternode disktype=ssd

Kiểm tra nhãn đã được gắn:

kubectl get nodes --show-labels
truongnt@masternode:~$ kubectl get nodes --show-labels
NAME         STATUS   ROLES           AGE     VERSION    LABELS
masternode   Ready    control-plane   3d11h   v1.31.10   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=masternode,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
node1        Ready    <none>          3d11h   v1.31.10   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1,kubernetes.io/os=linux
node2        Ready    <none>          3d11h   v1.31.10   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node2,kubernetes.io/os=linux

truongnt@masternode:~$ kubectl label nodes masternode disktype=ssd
node/masternode labeled

truongnt@masternode:~$ kubectl get nodes --show-labels
NAME         STATUS   ROLES           AGE     VERSION    LABELS
masternode   Ready    control-plane   3d11h   v1.31.10   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=masternode,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
node1        Ready    <none>          3d11h   v1.31.10   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1,kubernetes.io/os=linux
node2        Ready    <none>          3d11h   v1.31.10   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node2,kubernetes.io/os=linux

Bước 2: Tạo Pod bằng nodeSelector

truongnt@masternode:~$ kubectl get namespace
NAME              STATUS   AGE
default           Active   3d11h
kube-node-lease   Active   3d11h
kube-public       Active   3d11h
kube-system       Active   3d11h
pod-to-node-ns    Active   26m

truongnt@masternode:~$ kubectl -n pod-to-node-ns run podnode-using-nodeslector --image nginx --dry-run=client -oyaml > podnode-using-nodeslector.yaml

truongnt@masternode:~$ sudo vi podnode-using-nodeslector.yaml

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: podnode-using-nodeslector
  name: podnode-using-nodeslector
  namespace: pod-to-node-ns
spec:
  nodeSelector:
    disktype: ssd
  containers:
  - image: nginx
    name: podnode-using-nodeslector
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

truongnt@masternode:~$ kubectl create -f podnode-using-nodeslector.yaml
pod/podnode-using-nodeslector created



#CLEANUP

kubectl -n pod-to-node-ns delete --all all
kubectl delete ns pod-to-node-ns

Apply:

kubectl create -f podnode-using-nodeselector.yaml

Kiểm tra Pod:

kubectl get pod -n pod-to-node -o wide

Bạn sẽ thấy pod-node-selector đang chạy trên node master.

truongnt@masternode:~$ kubectl -n pod-to-node-ns get pods -owide
NAME                        READY   STATUS    RESTARTS   AGE   IP                NODE         NOMINATED NODE   READINESS GATES
podnode-using-nodename      1/1     Running   0          31m   192.168.166.132   node1        <none>           <none>
podnode-using-nodeslector   1/1     Running   0          13m   192.168.181.4     masternode   <none>           <none>

Hy vọng rằng qua bài viết này, bạn đã hiểu rõ hơn về vai trò và cách hoạt động của Manual Scheduling trong K8s. Cảm ơn bạn đã tham khảo kubernetes cơ bản trên ttnguyen.net.

Nguyễn Tiến Trường

Mình viết về những điều nhỏ nhặt trong cuộc sống, Viết về câu chuyện những ngày không có em