Kubernetes Pod调度入门
2017-06-01
最近两周一直没有抽出时间写点Kubernetes的东西,这篇学习一下Kubernetes对Pod的调度。我们先来复习一下Kubernetes的一些基本概念。
Kubernetes的基本概念 #
Kubernetes是一个基于容器技术的分布式架构平台,它首先是一个开源的容器集群管理系统,又是一个分布式系统开发、运维和支撑平台。 Kubernetes为容器应用提供了服务注册和发现、负载均衡、服务部署和运行、服务滚动升级、在线扩容和缩容、资源调度、资源配额管理等功能。 可以说Kubernetes具备完备的集群管理能力,贯串分布式系统开发、测试、部署、运维监控各个环节。
Kubernetes中的绝大部分概念都抽象成Kubernetes管理的一种资源对象,下面我们一起复习一下这些基本概念:
- Master:Master节点是Kubernetes集群的控制节点,负责整个集群的管理和控制。Master节点上包含以下组件:
kube-apiserver
:集群控制的入口,提供HTTP REST服务kube-controller-manager
:Kubernetes集群中所有资源对象的自动化控制中心kube-scheduler
:负责Pod的调度,我们本篇将主要学一下kube-scheduler
的调度功能
- Node: Node节点是Kubernetes集群中的工作节点,Node上的工作负载由Master节点分配,工作负载主要是运行容器应用。Node节点上包含以下组件:
kubelet
:负责Pod的创建、启动、监控、重启、销毁等工作,同时与Master节点协作,实现集群管理的基本功能。kube-proxy
:实现Kubernetes Service的通信和负载均衡- 运行运行容器化(Pod)应用
- Pod: Pod是Kubernetes最基本的部署调度单元。每个Pod可以由一个或多个业务容器和一个根容器(Pause容器)组成。一个Pod表示某个应用的一个实例
- ReplicaSet:是Pod副本的抽象,用于解决Pod的扩容和伸缩
- Deployment:Deployment表示部署,在内部使用ReplicaSet来实现。可以通过Deployment来生成相应的ReplicaSet完成Pod副本的创建
- Service:Service是Kubernetes最重要的资源对象。Kubernetes中的Service对象可以对应微服务架构中的微服务。Service定义了服务的访问入口,服务的调用者Pod通过这个地址访问Service后端的Pod副本实例。 Service通过Label Selector同后端的Pod副本建立关系,Deployment保证后端Pod副本的数量,也就是保证服务的伸缩性
kube-scheduler调度过程 #
Master节点上的kube-scheduler
负责Pod的调度,kube-scheduler
将Pod安置到目标Node上,之后将Pod交给目标Node上的kubelet,Pod生命周期后续的部分由kubelet接管。
kube-scheduler
使用特定的调度算法和调度策略将等待调度的Pod调度到某个合适的Node上。等待调度的Pod包含使用API创建的Pod,也包含ControllerManager为补足副本而创建的Pod。具体过程为kube-scheduler
会从待调度Pod列表中取出每个Pod,并根据调度算法和调度策略从Node列表中选出一个最合适的Node,将Pod和目标Node绑定(Binding),同时将绑定信息写入到etcd中。目标Node上的kubelet通过kube-apiserver
监听到kube-scheduler
触发的Pod和目标Node的绑定事件,就会pull镜像和启动容器。
预选(Predicates)和优选(Priorites)步骤 #
kube-scheduler
当前提供的调度过程包含预选(Predicates)和优选(Priorites)两步:
- 预选(Predicates):将根据配置的预选策略(Predicates Policies)过滤掉不满足这些策略的Node,剩下的Node将作为候选Node成为优选过程的输入。
- 优选(Priorites):根据配置的优选策略(Priorities Policies)计算出每个候选Node的积分,按积分排名,得分最高的Node胜出,Pod会和该Node绑定。
kube-scheduler
进程的--algorithm-provider
参数用于指定调度算法,当前Kubernetes版本1.6默认配置的是DefaultProvider。
plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go中包含了默认的Predicates Policies和Priorities Policies。
Scheduler Algorithm in Kubernetes中包含全部的Predicates Policies和Priorities Policies。
另外kube-scheduler
可以通过--policy-config-file
参数指定想要启用的Predicates Policies和Priorities Policies。例如:
1{
2"kind" : "Policy",
3"apiVersion" : "v1",
4"predicates" : [
5 {"name" : "PodFitsHostPorts"},
6 {"name" : "PodFitsResources"},
7 {"name" : "NoDiskConflict"},
8 {"name" : "NoVolumeZoneConflict"},
9 {"name" : "MatchNodeSelector"},
10 {"name" : "HostName"}
11 ],
12"priorities" : [
13 {"name" : "LeastRequestedPriority", "weight" : 1},
14 {"name" : "BalancedResourceAllocation", "weight" : 1},
15 {"name" : "ServiceSpreadingPriority", "weight" : 1},
16 {"name" : "EqualPriority", "weight" : 1}
17 ],
18"hardPodAffinitySymmetricWeight" : 10
19}
Pod调度入门 #
接下来我们先通过几个例子来学习一下基于预选策略(Predicates Policies)和优选策略(Priorities Policies)实现的Pod调度。 我们可以使用这些策略实现将Pod调度到某个或某些特别的Node上。
我们使用前面在Kubernetes 1.6 高可用集群部署部署的集群作为试验环境。
1192.168.61.11 node1
2192.168.61.12 node2
3192.168.61.13 node3
4192.168.61.14 node4
MatchNodeSelector #
MatchNodeSelector是一个预选策略,用于判断候选Node是否包含Pod的spec.nodeSelector
指定的标签。
我们先来看看当前集群中的Node具有的标签:
1kubectl get nodes --show-labels
2NAME STATUS AGE VERSION LABELS
3node1 Ready 34d v1.6.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node1
4node2 Ready 32d v1.6.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node2
5node3 Ready 32d v1.6.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node3
6node4 Ready 29d v1.6.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node4
可以看到每个Node上都有kubernetes.io/hostname=xxx
这个label,我们可以使用Pod的spec.nodeSelector
指定这个label将Pod调度具体的某个Node上。例如我们创建一个如下的Deployment,nginx-deployment.yaml
:
1apiVersion: apps/v1beta1
2kind: Deployment
3metadata:
4 name: nginx-deployment
5spec:
6 replicas: 2
7 template:
8 metadata:
9 labels:
10 app: nginx
11 spec:
12 containers:
13 - name: nginx
14 image: nginx
15 imagePullPolicy: IfNotPresent
16 ports:
17 - containerPort: 80
18 nodeSelector:
19 kubernetes.io/hostname: node4
1kubectl create -f nginx-deployment.yaml
2deployment "nginx-deployment" created
3
4kubectl get deploy
5NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
6nginx-deployment 2 2 2 2 1m
7
8kubectl get pod -o wide
9NAME READY STATUS RESTARTS AGE IP NODE
10nginx-deployment-1270158812-9qh1v 1/1 Running 0 1m 10.244.3.5 node4
11nginx-deployment-1270158812-f5k7h 1/1 Running 0 1m 10.244.3.6 node4
可以看到这个Pod的两个副本都被调度到node4上。下面继续试验,假设我们要将Pod调度到磁盘类型为ssd并且专门用来跑Web应用的Node上。 我们先删除前面创建的Deployment:
1kubectl delete deploy nginx-deployment
我们给node1, node2, node3标记如下:
1kubectl label node node1 disktype=ssd apptype=web
2kubectl label node node2 disktype=ssd
3kubectl label node node3 disktype=ssd apptype=web
4kubectl label node node4 apptype=web
5
6kubectl get nodes --show-labels
7NAME STATUS AGE VERSION LABELS
8node1 Ready 34d v1.6.2 apptype=web,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=node1
9node2 Ready 32d v1.6.2 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=node2
10node3 Ready 32d v1.6.2 apptype=web,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=node3
11node4 Ready 29d v1.6.2 apptype=web,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node4
修改前面的nginx-deployment.yaml
文件:
1apiVersion: apps/v1beta1
2kind: Deployment
3metadata:
4 name: nginx-deployment
5spec:
6 replicas: 2
7 template:
8 metadata:
9 labels:
10 app: nginx
11 spec:
12 containers:
13 - name: nginx
14 image: nginx
15 imagePullPolicy: IfNotPresent
16 ports:
17 - containerPort: 80
18 nodeSelector:
19 disktype: ssd
20 apptype: web
1kubectl create -f nginx-deployment.yaml
2deployment "nginx-deployment" created
3
4kubectl get deploy
5NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
6nginx-deployment 2 2 2 0 45s
7
8kubectl get pod -o wide
9NAME READY STATUS RESTARTS AGE IP NODE
10nginx-deployment-908661896-pzs2z 1/1 Running 0 2m 10.244.0.69 node1
11nginx-deployment-908661896-wvd9p 1/1 Running 0 2m 10.244.2.51 node3
可以看到Pod被调度到了node1和node3上,而node1和node3上我们前面标记了disktype=ssd和apptype=web。
NodeAffinityPriority #
NodeAffinityPriority是一个优选策略,是Kubernetes 1.2开始提供的Kubernetes调度中的亲和性机制。NodeAffinityPriority的Node选择器不再限于对Node Label的精确匹配,而支持多种操作符(如In, NotIn, Exists, DoesNotExist, Gt, Lt)。支持两种类型的选择器,一种是requiredDuringSchedulingIgnoredDuringExecution
,它保证所选的Node必须满足Pod对Node的所有要求,这种更像前面的MatchNodeSelector
;另外一种是preferresDuringSchedulingIgnoredDuringExecution
,它对kube-scheduler
提出需求,kube-scheduler
会尽量但不保证满足NodeSelector的要求。
例如:
1apiVersion: v1
2kind: Pod
3metadata:
4 name: with-pod-affinity
5spec:
6 affinity:
7 podAffinity:
8 requiredDuringSchedulingIgnoredDuringExecution:
9 - labelSelector:
10 matchExpressions:
11 - key: security
12 operator: In
13 values:
14 - S1
15 topologyKey: failure-domain.beta.kubernetes.io/zone
16 podAntiAffinity:
17 preferredDuringSchedulingIgnoredDuringExecution:
18 - weight: 100
19 podAffinityTerm:
20 labelSelector:
21 matchExpressions:
22 - key: security
23 operator: In
24 values:
25 - S2
26 topologyKey: kubernetes.io/hostname
27 containers:
28 - name: with-pod-affinity
29 image: gcr.io/google_containers/pause:2.0