kubernetes简介
kubernetes,简称K8s,是用8代替8个字符“ubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。
Pod简介
Pod是Kubernetes创建或部署的最小/最简单的基本单位,一个Pod代表集群上正在运行的一个进程。
一个Pod封装一个应用容器(也可以有多个容器),存储资源、一个独立的网络IP以及管理控制容器运行方式的策略选项。Pod代表部署的一个单位:Kubernetes中单个应用的实例,它可能由单个容器或多个容器共享组成的资源。
通常情况下,使用的都是k8s默认的调度调度方式,但是在有些情况下,我们需要将pod运行在具有特点的标签的node上才能都运行,这个时候,pod的调度策略就不能使用k8s默认的调度策略了,这个时候,就需要指定调度策略,告诉k8s需要将pod调度到那些node(节点)上。
nodeSelector
常规情况下,会直接使用nodeSelector这种调度策略。labels(标签) 是k8s里面用来编标记资源的一种常用的方式,我们可以给node标记特殊的标签,然后nodeSelector会将pod调度到带有指定labels的node上的。
下面看个示例:
首先,查看node的label信息,通过下面的命令查看的 node 的 label:
$ kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
master Ready master 147d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master=
node02 Ready <none> 67d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,course=k8s,kubernetes.io/hostname=node02
node03 Ready <none> 127d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,jnlp=haimaxy,kubernetes.io/hostname=node03
然后,可以给node02节点新增一个label:
$ kubectl label nodes node02 com=yijiadashuju
node "node02" labeled
然后通过上面的--show-labels参数可以查看上述标签是否生效。当 node 被打上了相关标签后,在调度的时候就可以使用这些标签了,只需要在 Pod 的spec字段中添加nodeSelector字段,里面是我们需要被调度的节点的 label 即可。比如,要将 Pod 我们要强制调度到 node02 这个节点上去,可以使用 nodeSelector 来表示了:(pod-selector-demo.yaml)
apiVersion: v1
kind: Pod
metadata:
labels:
app: busybox-pod
name: test-busybox
spec:
containers:
- command:
- sleep
- "3600"
image: busybox
imagePullPolicy: Always
name: test-busybox
nodeSelector:
com: yijiadashuju
然后,执行pod-selector-demo.yaml文件后,可以通过下面的命令查看pod运行的节点信息
kubectl get pod -o wide -n default
也可以使用description命令查看pod被调度到哪个节点上:
$ kubectl create -f pod-selector-demo.yaml
pod "test-busybox" created
$ kubectl describe pod test-busybox
Name: test-busybox
Namespace: default
Node: node02/10.151.30.63
......
QoS Class: BestEffort
Node-Selectors: com=youdianzhishi
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulMountVolume 55s kubelet, node02 MountVolume.SetUp succeeded for volume "default-token-n9w2d"
Normal Scheduled 54s default-scheduler Successfully assigned test-busybox to node02
Normal Pulling 54s kubelet, node02 pulling image "busybox"
Normal Pulled 40s kubelet, node02 Successfully pulled image "busybox"
Normal Created 40s kubelet, node02 Created container
Normal Started 40s kubelet, node02 Started container
从上面的执行结果可以看出,pod 通过默认的 default-scheduler 调度器到了node02节点上。不过,这种调度方式属于强制性的。如果node02上的资源不足,那么pod的状态将会一直是pending状态。这就是nodeselector的用法了。
通过上面的介绍,可以看出nodeselector使用起来非常方便,但是还有很多的不足,那就是不够灵活,控制粒度偏大,在实际使用中还是有许多的不便。接下来一起看先亲和性和反亲和性调度。
亲和性和反亲和性调度
k8s的默认调度流程实际上是经过了两个阶段:predicates 和 priorities 。使用默认的调度流程的话,k8s会将pod调度到资源充裕的节点上,使用nodeselector的调度方法,又会将pod调度具有指定标签的pod上。然后在实际生产环ongoing境中,我们需要将pod调度到具有默些label的一组node才能满足实际需求,这个时候就需要nodeAffinity(节点亲和性)、podAffinity(pod 亲和性) 以及 podAntiAffinity(pod 反亲和性)。
亲和性可以分为具体可以细分为硬和软两种亲和性,
软亲和性:如果调度的时候,没有满足要求,也可以继续调度,即能满足最好,不能也无所谓
硬亲和性:是指调度的时候必须满足特定的要求,如果不满足,那么pod将不会被调度到当前node
规则可以设置:
软策略: preferredDuringSchedulingIgnoredDuringExecution
硬策略: requiredDuringSchedulingIgnoredDuringExecution
nodeAffinity 节点亲和性
节点亲和性主要是用来控制 pod 能部署在哪些节点上,以及不能部署在哪些节点上的。它可以进行一些简单的逻辑组合了,不只是简单的相等匹配。
接下来看一个示例,使用 Deployment 来管理3个 pod 副本,使用nodeAffinity控制 pod 的调度,如下例子:(node-affinity-demo.yaml)
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: affinity
labels:
app: affinity
spec:
replicas: 3
revisionHistoryLimit: 15
template:
metadata:
labels:
app: affinity
role: test
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: nginxweb
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node03
preferredDuringSchedulingIgnoredDuringExecution: # 软策略
- weight: 1
preference:
matchExpressions:
- key: com
operator: In
values:
- yijiadashuju
这个pod调度的时候,首先要求不能运行在node03节点上,但是如果有节点满足labels为com:yijiadashuju 的话,就会优先调度到这个节点上。
接下来看下节点信息:
$ kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
master Ready master 154d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master=
node02 Ready <none> 74d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,com=yijiadashuju,course=k8s,kubernetes.io/hostname=node02
node03 Ready <none> 134d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,jnlp=haimaxy,kubernetes.io/hostname=node03
可以看到 node02 节点有com=yijiadashuju的 label,按要求会优先调度到这个节点,接下来创建 pod,然后使用descirbe命令查看调度情况。
$ kubectl create -f node-affinity-demo.yaml
deployment.apps "affinity" created
$ kubectl get pods -l app=affinity -o wide
NAME READY STATUS RESTARTS AGE IP NODE
affinity-7b4c946854-5gfln 1/1 Running 0 47s 10.244.4.214 node02
affinity-7b4c946854-l8b47 1/1 Running 0 47s 10.244.4.215 node02
affinity-7b4c946854-r86p5 1/1 Running 0 47s 10.244.4.213 node02
从结果可以看到 pod 均被部署到了 node02节点。
现在Kubernetes提供的操作符有下面的几种
In:label 的值在某个标签中
NotIn:label 的值不在某个标签中
Gt:label 的值大于某个值
Lt:label 的值小于某个值
Exists:某个 label 存在
DoesNotExist:某个 label 不存在
如果nodeSelectorTerms下面有多个选项的话,满足任何一个条件就可以了;如果matchExpressions有多个选项的话,则必须同时满足这些条件才能正常调度 POD。
podAffinity pod亲和性
pod的亲和性主要用来解决pod可以和哪些pod部署在同一个集群里面,即拓扑域(由node组成的集群)里面;而pod的反亲和性是为了解决pod不能和哪些pod部署在一起的问题,二者都是为了解决pod之间部署问题。需要注意的是,Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度,不建议在具有几百个节点的集群中使用,而且Pod 反亲和需要对节点进行一致的标记,即集群中的每个节点必须具有适当的标签能够匹配 topologyKey。如果某些或所有节点缺少指定的 topologyKey 标签,可能会导致意外行为。
下面是pod间亲和的示例:
pods/pod-with-pod-affinity.yaml:
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: failure-domain.beta.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: failure-domain.beta.kubernetes.io/zone
containers:
- name: with-pod-affinity
image: k8s.gcr.io/pause:2.0
podAntiAffinity pod反亲和性
下面是一个pod反亲和yaml文件示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cache
spec:
selector:
matchLabels:
app: store
replicas: 3
template:
metadata:
labels:
app: store
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
containers:
- name: redis-server
image: redis:3.2-alpine