01. kube-scheduler 启动及前期调试准备
kube-scheduler (调度器)是控制平面的组件, 负责监视新创建的、未指定运行节点(node)的 Pods, 并选择节点来让 Pod 在上面运行。 调度决策考虑的因素包括单个 Pod 及 Pods 集合的资源需求、软硬件及策略约束、 亲和性及反亲和性规范、数据位置、工作负载间的干扰及最后时限。
kube-scheduler 启动的参数可以参考:https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-scheduler/
我们知道 kube-scheduler 本质上是利用 client-go 和 kube-apiserver 交互,监听 Pod 资源的创建,并为其调度到相应的 Node 上。
因此,kube-scheduler 启动的关键就是为其配置 kubeconfig ,使其可以连接上 kube-apiserver 。在我们之前两回讲 client-go 的使用时,其实一直使用到了 kubeconfig ,但我们并没有讲这个配置文件是哪来的。
实际在我们配置 kubectl 的时候:
# 添加新集群(apiserver地址和ca证书)
kubectl config set-cluster devk8s --server=https://127.0.0.1:6443 --certificate-authority=cert/ca.crt
# 添加用户(客户端证书)
kubectl config set-credentials devk8s --client-certificate=cert/client.crt --client-key=cert/client.key
# 添加上下文(绑定集群和用户)
kubectl config set-context devk8s --user=devk8s --cluster=devk8s
# 切换当前上下文
kubectl config use-context devk8s
就会在 ~/.kube/config
生成 kubeconfig ,或者也可以通过 kubectl config view
查看该配置。对于我们本地启动,可以直接复用该 kubeconfig 。
也就是说,我们的 kube-scheduler 启动参数可以配置为(这里我配置了完整路径,并且将日志等级设为 4 ,方便调试观察):
--kubeconfig=/root/.kube/config -v=4
启动 kube-scheduler :
查看组件状态,scheduler 已正常运行:
$ kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
controller-manager Unhealthy Get "https://127.0.0.1:10257/healthz": dial tcp 127.0.0.1:10257: connect: connection refused
scheduler Healthy ok
etcd-0 Healthy {"health":"true","reason":""}
当创建一个 Pod 时:
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
EOF
kube-scheduler 日志:
Pod 事件:
$ kubectl describe pod nginx
Name: nginx
Namespace: default
......
Status: Pending
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 32s default-scheduler no nodes available to schedule pods
可以看到,因为没有 Node ,kube-scheduler 无法调度 Pod 。
因为我们是本地调试,如果额外部署 kubelet 来注册 Node ,就比较麻烦了。
有一个简单的办法,我们可以直接利用 https://github.com/kubernetes-sigs/kwok 来模拟一些 Nodes 。
首先启动 kwok ,管理集群的所有 Node :
$ kwok --kubeconfig=/root/.kube/config --manage-all-nodes=true
Watch all nodes
创建 1 个 Node :
kubectl apply -f - <<EOF
apiVersion: v1
kind: Node
metadata:
annotations:
node.alpha.kubernetes.io/ttl: "0"
kwok.x-k8s.io/node: fake
labels:
beta.kubernetes.io/arch: amd64
beta.kubernetes.io/os: linux
kubernetes.io/arch: amd64
kubernetes.io/hostname: kwok-node-0
kubernetes.io/os: linux
kubernetes.io/role: agent
node-role.kubernetes.io/agent: ""
type: kwok
name: kwok-node-0
spec: {}
status:
allocatable:
cpu: 32
memory: 256Gi
pods: 110
capacity:
cpu: 32
memory: 256Gi
pods: 110
nodeInfo:
architecture: amd64
bootID: ""
containerRuntimeVersion: ""
kernelVersion: ""
kubeProxyVersion: fake
kubeletVersion: fake
machineID: ""
operatingSystem: linux
osImage: ""
systemUUID: ""
phase: Running
EOF
kwok 会监听到 Node 资源的创建,并将其设置成 Ready 状态:
$ kubectl get node
NAME STATUS ROLES AGE VERSION
kwok-node-0 Ready agent 15s fake
但此时我们的 kwok-node-0 还存在 污点(Taint),我们需要手动删除该污点,使 Pod 可以调度到该 Node 上:
kubectl edit node kwok-node-0
删除污点后保存:
spec:
taints:
- effect: NoSchedule
key: node.kubernetes.io/not-ready
# 将以上内容改为以下内容
spec: {}
此时,Pod 可以正常调度到虚拟的 kwok-node-0 节点:
$ kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 30m 10.0.0.1 kwok-node-0 <none> <none>
$ kubectl describe pod nginx
Name: nginx
Namespace: default
......
Node: kwok-node-0/
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 30m default-scheduler no nodes available to schedule pods
Normal Scheduled 43s default-scheduler Successfully assigned default/nginx to kwok-node-0
kube-scheduler 日志就不贴出了。
这样,我们前期的准备工作就完成了,利用 kwok 创建 Node,后续我们就可以更方便地调试 kube-scheduler 。
微信公众号
更多内容请关注微信公众号:gopher云原生