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.

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.

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à:
- Tạo một Pod chạy trên node
node1bằng cách chỉ định trực tiếp tên node. - Tạo một Pod khác chạy trên node
masternodebằng cách gắn nhãn và chọn theo nhãn (label).

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.