Pod进阶篇:污点-容忍度-亲和性-Affinity-调度(5)
作者:互联网
一、Pod资源清单详细解读
apiVersion: v1 #版本号,例如 v1 kind: Pod #资源类型,如 Pod metadata: #元数据 name: string # Pod 名字 namespace: string # Pod 所属的命名空间 labels: #自定义标签 name: string #自定义标签名字 annotations: #自定义注释列表 name: string spec: # Pod 中容器的详细定义 containers: # Pod 中容器列表 name: string #容器名称 image: string #容器的镜像名称 imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys 表示下载镜像 IfnotPresent 表示优先使用本地镜像,否则下载镜像,Nerver 表示仅使用本地镜像 command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令 args: [string] #容器的启动命令参数列表 workingDir: string #容器的工作目录 volumeMounts: #挂载到容器内部的存储卷配置 name: string #引用 pod 定义的共享存储卷的名称,需用 volumes[]部分定义的的卷名 mountPath: string #存储卷在容器内 mount 的绝对路径,应少于 512 字符 readOnly: boolean #是否为只读模式 ports: #需要暴露的端口库号 - name: string #端口号名称 containerPort: int #容器需要监听的端口号 hostPort: int #容器所在主机需要监听的端口号,默认与 Container 相同 protocol: string #端口协议,支持 TCP 和 UDP,默认 TCP env: #容器运行前需设置的环境变量列表 - name: string #环境变量名称 value: string #环境变量的值 resources: #资源限制和请求的设置 limits: #资源限制的设置 cpu: string #cpu 的限制,单位为 core 数 memory: string #内存限制,单位可以为 Mib/Gib requests: #资源请求的设置 cpu: string #cpu 请求,容器启动的初始可用数量 memory: string #内存请求,容器启动的初始可用内存 livenessProbe: #对 Pod 内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有 exec、httpGet 和tcpSocket,对一个容器只需设置其中一种方法即可 exec: #对 Pod 容器内检查方式设置为 exec 方式 command: [string] #exec 方式需要制定的命令或脚本 httpGet: #对 Pod 内个容器健康检查方法设置为 HttpGet,需要制定 Path、port path: string port: number host: string scheme: string HttpHeaders: - name: string value: string tcpSocket: #对 Pod 内个容器健康检查方式设置为 tcpSocket 方式 port: number initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒 timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认 1 秒 periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认 10 秒一次 successThreshold: 0 failureThreshold: 0 securityContext: privileged:false restartPolicy: [Always | Never | OnFailure]#Pod 的重启策略,Always 表示一旦不管以何种方式终止运行,kubelet 都将重启,OnFailure 表示只有 Pod 以非 0 退出码退出才重启,Nerver 表示不再重启该 Pod nodeSelector: obeject #设置 NodeSelector 表示将该 Pod 调度到包含这个 label 的 node上,以 key:value 的格式指定 imagePullSecrets: #Pull 镜像时使用的 secret 名称,以 key:secretkey 格式指定 - name: string hostNetwork:false #是否使用主机网络模式,默认为 false,如果设置为 true,表示使用宿主机网络 volumes: #在该 pod 上定义共享存储卷列表 - name: string #共享存储卷名称 (volumes 类型有很多种) emptyDir: {} #类型为 emtyDir 的存储卷,与 Pod 同生命周期的一个临时目录。为空值 hostPath: string #类型为 hostPath 的存储卷,表示挂载 Pod 所在宿主机的目录 path: string #Pod 所在宿主机的目录,将被用于同期中 mount 的目录 secret: #类型为 secret 的存储卷,挂载集群与定义的 secre 对象到容器内部 scretname: string items: - key: string path: string configMap: #类型为 configMap 的存储卷,挂载预定义的 configMap 对象到容器内部 name: string items: - key: string path: string
二、node节点选择器
我们在创建 pod 资源的时候,pod 会根据 schduler 进行调度,那么默认会调度到随机的一个工作节点,如果我们想要 pod 调度到指定节点或者调度到一些具有相同特点的 node 节点,怎么办呢? 可以使用 pod 中的 nodeName 或者 nodeSelector 字段指定要调度到的 node 节点 .
2.1 nodeName: 指定pod节点运行在哪个具体node上
[root@master node]# cat pod-node.yaml apiVersion: v1 kind: Pod metadata: name: demo-pod namespace: default labels: app: myapp env: dev spec: nodeName: monitor containers: - name: tomcat-pod-java ports: - containerPort: 8080 image: tomcat:8.5-jre8-alpine imagePullPolicy: IfNotPresent - name: busybox image: busybox:latest command: - "/bin/sh" - "-c" - "sleep 3600" [root@master node]# kubectl apply -f pod-node.yaml # 如果demo-pod已经存在可以删除或者改变metadata.name名称 [root@master node]# kubectl delete pods -n default demo-pod pod "demo-pod" deleted # 查看创建的容器 [root@master node]# kubectl get pods -n default NAME READY STATUS RESTARTS AGE demo-pod 2/2 Running 0 14s # 可以看到demo-pod所在的node为monitor [root@master node]# kubectl get pods -n default -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES demo-pod 2/2 Running 0 2m9s 10.244.75.202 monitor <none> <none>
2.2 nodeSelector
指定pod调度到具有哪些标签的node节点上
# 给 node3 节点打标签,打个具有 disk=ceph 的标签 # 查看node3节点详细信息 [root@master node]# kubectl describe nodes node3 # 给node3打上disk=ceph标签 [root@master node]# kubectl label nodes node3 disk=ceph node/node3 labeled #定义 pod 的时候指定要调度到具有 disk=ceph 标签的node上 [root@master node]# cat pod-1.yaml apiVersion: v1 kind: Pod metadata: name: demo-pod-1 namespace: default labels: app: myapp env: dev spec: nodeSelector: disk: ceph # 如果monitor和node3节点都有disk=ceph,k8s会根据服务器情况在其中一台服务器上生成 containers: - name: tomcat-pod-java ports: - containerPort: 8080 image: tomcat:8.5-jre8-alpine imagePullPolicy: IfNotPresent [root@master node]# kubectl get pods -n default -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES demo-pod-1 1/1 Running 0 18s 10.244.135.10 node3 <none> <none>
三、Pod节点选择器
[root@master node]# kubectl explain pods.spec.affinity KIND: Pod VERSION: v1 RESOURCE: affinity <Object> DESCRIPTION: If specified, the pod's scheduling constraints Affinity is a group of affinity scheduling rules. FIELDS: nodeAffinity <Object> Describes node affinity scheduling rules for the pod. podAffinity <Object> Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). podAntiAffinity <Object> Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)).
3.1 Pod亲和性--node节点亲和性(pod选择机器)
[root@master node]# kubectl explain pods.spec [root@master node]# kubectl explain pods.spec.affinity [root@master node]# kubectl explain pods.spec.affinity. [root@master node]# kubectl explain pods.spec.affinity.nodeAffinity KIND: Pod VERSION: v1 RESOURCE: nodeAffinity <Object> DESCRIPTION: Describes node affinity scheduling rules for the pod. Node affinity is a group of node affinity scheduling rules. FIELDS: preferredDuringSchedulingIgnoredDuringExecution <[]Object> requiredDuringSchedulingIgnoredDuringExecution <Object> prefered 表示有节点尽量满足这个位置定义的亲和性,这不是一个必须的条件,软亲和性 require 表示必须有节点满足这个位置定义的亲和性,这是个硬性条件,硬亲和性
[root@master node]# kubectl explain pods.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution FIELDS: nodeSelectorTerms <[]Object> -required- [root@master node]# kubectl explain pods.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms FIELDS: matchExpressions <[]Object> matchFields <[]Object> matchExpressions:匹配表达式的 matchFields: 匹配字段的 [root@master node]# kubectl explain pods.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchExpressions FIELDS: key <string> -required- operator <string> -required- values <[]string> key:检查 label operator:做等值选则还是不等值选则 values:给定值
硬亲和性测试:
apiVersion: v1 kind: Pod metadata: name: pod-node-affinity-demo namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: zone operator: In values: - foo - bar # 我们检查当前节点中有任意一个节点拥有 zone 标签的值是 foo 或者 bar,就可以把 pod 调度到这个 node 节点的 foo 或者 bar 标签上的节点上
master上查看结果:kubectl -f pod-nodeaffinity-demo.yaml
[root@master node]# kubectl get pods -o wide -n default NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES demo-pod 2/2 Running 32 3d11h 10.244.75.202 monitor <none> <none> demo-pod-1 1/1 Running 0 3d10h 10.244.135.10 node3 <none> <none> nginx-7f466444dc-ndp5t 1/1 Running 0 4d 10.244.75.198 monitor <none> <none> nginx-7f466444dc-qbxfn 1/1 Running 0 4d 10.244.135.3 node3 <none> <none> nginx-test-75c685fdb7-92w5b 1/1 Running 0 3d20h 10.244.135.6 node3 <none> <none> nginx-test-75c685fdb7-9mkzf 1/1 Running 0 3d20h 10.244.75.199 monitor <none> <none> pod-node-affinity-demo 0/1 Pending 0 77s <none> <none> <none> <none> pod-run 0/1 ImagePullBackOff 0 3d18h 10.244.135.8 node3 <none> <none> pod-test 1/1 Running 0 3d18h 10.244.75.200 monitor <none> <none> tomcat-test 1/1 Running 0 3d18h 10.244.135.7 node3 <none> <none>
# status 的状态是 pending,上面说明没有完成调度,因为没有一个拥有 zone 的标签的值是 foo 或 者 bar,而且使用的是硬亲和性,必须满足条件才能完成调度,没有分配节点与IP
# 给一个节点打上标签foo,然后查看
[root@master node]# kubectl label nodes node3 zone=foo node/node3 labeled [root@master node]# kubectl get pods -o wide -n default NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES demo-pod 2/2 Running 32 3d11h 10.244.75.202 monitor <none> <none> demo-pod-1 1/1 Running 0 3d10h 10.244.135.10 node3 <none> <none> nginx-7f466444dc-ndp5t 1/1 Running 0 4d 10.244.75.198 monitor <none> <none> nginx-7f466444dc-qbxfn 1/1 Running 0 4d 10.244.135.3 node3 <none> <none> nginx-test-75c685fdb7-92w5b 1/1 Running 0 3d20h 10.244.135.6 node3 <none> <none> nginx-test-75c685fdb7-9mkzf 1/1 Running 0 3d20h 10.244.75.199 monitor <none> <none> pod-node-affinity-demo 1/1 Running 0 6m35s 10.244.135.11 node3 <none> <none> pod-run 0/1 ImagePullBackOff 0 3d18h 10.244.135.8 node3 <none> <none> pod-test 1/1 Running 0 3d18h 10.244.75.200 monitor <none> <none> tomcat-test 1/1 Running 0 3d18h 10.244.135.7 node3 <none> <none>
软亲和性测试:
apiVersion: v1 kind: Pod metadata: name: pod-node-affinity-demo-2 namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - preference: matchExpressions: - key: zone1 operator: In values: - foo1 - bar1 weight: 60 [root@master node]# kubectl apply -f pod-nodeaffinity-demo-2.yaml pod/pod-node-affinity-demo-2 created [root@master node]# kubectl get pods -o wide -n default NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES demo-pod 2/2 Running 32 3d11h 10.244.75.202 monitor <none> <none> demo-pod-1 1/1 Running 0 3d10h 10.244.135.10 node3 <none> <none> nginx-7f466444dc-ndp5t 1/1 Running 0 4d 10.244.75.198 monitor <none> <none> nginx-7f466444dc-qbxfn 1/1 Running 0 4d 10.244.135.3 node3 <none> <none> nginx-test-75c685fdb7-92w5b 1/1 Running 0 3d20h 10.244.135.6 node3 <none> <none> nginx-test-75c685fdb7-9mkzf 1/1 Running 0 3d20h 10.244.75.199 monitor <none> <none> pod-node-affinity-demo 1/1 Running 0 11m 10.244.135.11 node3 <none> <none> pod-node-affinity-demo-2 1/1 Running 0 8s 10.244.135.12 node3 <none> <none> pod-run 0/1 ImagePullBackOff 0 3d18h 10.244.135.8 node3 <none> <none> pod-test 1/1 Running 0 3d18h 10.244.75.200 monitor <none> <none> tomcat-test 1/1 Running 0 3d18h 10.244.135.7 node3 <none> <none>
# 上面说明软亲和性是可以运行这个 pod 的,尽管没有运行这个 pod 的节点定义的 zone1 标签
# Node 节点亲和性针对的是 pod 和 node 的关系,Pod 调度到 node 节点的时候匹配的条件
3.2 Pod节点亲和性
pod 自身的亲和性调度有两种表示形式 podaffinity:pod 和 pod 更倾向腻在一起,把相近的 pod 结合到相近的位置,例如功能相似,如有调用关系,如同一区域,同一机架,这样的话 pod 和 pod 之间更好通信,比方说有两个机房,这两个机房部署的集群有 1000 台 主机,那么我们希望把 nginx 和 tomcat 都部署同一个地方的 node 节点上,可以提高通信效率; podunaffinity 反亲和性:pod 和 pod 更倾向不腻在一起,如果部署两套程序,没多大关系,那么这两套程序更倾向于反亲和性,这样相互之间不会有影响。 第一个 pod 随机选则一个节点,做为评判后续的 pod 能否到达这个 pod 所在的节点上的运行方式,这就称为 pod 亲和性;
我们怎么判定哪些节点是相同位置的,哪些节点是不同位置的;
我们在定义 pod 亲和性时需要有一个前提,哪些 pod 在同一个位置,哪些 pod 不在同一个位置,这个位置是怎么定义的,标准是什么?
以节点名称为标准,这个节点名称相同的表示是同一个位置,节点名称不相同的表示不是一个位置。
[root@master node]# kubectl explain pods.spec.affinity.podAffinity
FIELDS: preferredDuringSchedulingIgnoredDuringExecution <[]Object> 软亲和性 requiredDuringSchedulingIgnoredDuringExecution <[]Object> 硬亲和性 [root@master node]# kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution FIELDS: labelSelector <Object> namespaces <[]string> topologyKey <string> -required- topologyKey:位置拓扑的键,这个是必须字段
怎么判断是不是同一个位置: rack=rack1 row=row1 使用 rack 的键是同一个位置 使用 row 的键是同一个位置 labelSelector: 我们要判断 pod 跟别的 pod 亲和,跟哪个 pod 亲和,需要靠 labelSelector,通过 labelSelector选则一组能作为亲和对象的 pod 资源
namespace: labelSelector 需要选则一组资源,那么这组资源是在哪个名称空间中呢,通过 namespace 指定,如果不指定 namespaces,那么就是当前创建 pod 的名称空间
[root@master node]# kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.labelSelector FIELDS: matchExpressions <[]Object> matchLabels <map[string]string>
# 查看所有k8s的node节点标签 [root@master node]# kubectl get nodes --show-labels NAME STATUS ROLES AGE VERSION LABELS master Ready control-plane,master 13d v1.20.7 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master= monitor Ready <none> 13d v1.20.7 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=monitor,kubernetes.io/os=linux node3 Ready <none> 13d v1.20.7 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disk=ceph,kubernetes.io/arch=amd64,kubernetes.io/hostname=node3,kubernetes.io/os=linux,zone=foo
# 查看单个节点标签
[root@master node]# kubectl get nodes node3 --show-labels
NAME STATUS ROLES AGE VERSION LABELS
node3 Ready <none> 13d v1.20.7 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disk=ceph,kubernetes.io/arch=amd64,kubernetes.io/hostname=node3,kubernetes.io/os=linux,zone=foo
# 查看某个标签下有多少节点
[root@master node]# kubectl get pods -l app1=myapp1
NAME READY STATUS RESTARTS AGE
pod-first 1/1 Running 0 11m
# 定义2个pod,第一个 pod 做为基准,第二个 pod 跟着它走 [root@master node]# cat pod-required-affinity-demo-1.yaml apiVersion: v1 kind: Pod metadata: name: pod-first labels: app2: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 --- apiVersion: v1 kind: Pod metadata: name: pod-second labels: app: backend tier: db spec: containers: - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent command: ["sh","-c","sleep 3600"] affinity: podAffinity: # 亲和性 requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - {key: app, operator: In, values: ["myapp"]} topologyKey: kubernetes.io/hostname # 基于主机名做为位置,pod-first调度到哪个点,pod-second也跟着调度到哪个点 # 上面表示创建的 pod 必须与拥有 app=myapp 标签的 pod 在一个节点上
# --- 表示链接第二个pod,2个yaml互不影响,但相关的写在一起可以更清晰
[root@master node]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-first 1/1 Running 0 105s 10.244.75.204 monitor <none> <none>
pod-second 1/1 Running 0 105s 10.244.75.203 monitor <none> <none>
3.3 Pod反亲和性
# 先删除上面亲和性的2个pod [root@master node]# kubectl delete -f pod-required-affinity-demo-1.yaml pod "pod-first" deleted pod "pod-second" deleted # 软亲和性:尽可能不在一起 [root@master node]# kubectl explain pods.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution FIELDS: podAffinityTerm <Object> -required- weight <integer> -required-
# 定义两个 pod,第一个 pod 做为基准,第二个 pod 跟它调度节点相反
[root@master node]# cat pod-required-anti-affinity-demo.yaml apiVersion: v1 kind: Pod metadata: name: pod-first labels: app1: myapp1 tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 --- apiVersion: v1 kind: Pod metadata: name: pod-second labels: app: backend tier: db spec: containers: - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent command: ["sh","-c","sleep 3600"] affinity: podAntiAffinity: # 反亲和性 requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - {key: app1, operator: In, values: ["myapp1"]} topologyKey: kubernetes.io/hostname
[root@master node]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-first 1/1 Running 0 10s 10.244.75.205 monitor <none> <none>
pod-second 1/1 Running 0 10s 10.244.135.13 node3 <none> <none>
# 如果有问题,就查看下标签下是否有重复命名 kubectl get pods -l app1=myapp1
位置拓扑键topologykey
# 添加标签,如果已经有标签需要在命令末尾加上--overwrite [root@master node]# kubectl label nodes monitor zone=foo node/monitor labeled [root@master node]# kubectl label nodes node3 zone=foo --overwrite node/node3 not labeled # 现在2个节点都有zone=foo标签 [root@master node]# cat myapp.yaml apiVersion: v1 kind: Pod metadata: name: pod-first labels: app3: myapp3 tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 [root@master node]# cat backend.yaml apiVersion: v1 kind: Pod metadata: name: pod-second labels: app: backend tier: db spec: containers: - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent command: ["sh","-c","sleep 3600"] affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - {key: app3, operator: In, values: ["myapp3"]} topologyKey: zone [root@master node]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-first 1/1 Running 0 2m28s 10.244.135.14 node3 <none> <none> pod-second 0/1 Pending 0 12s <none> <none> <none> <none>
第二个节点现是 pending,因为两个节点是同一个位置,现在没有不是同一个位置的了,而且我们 要求反亲和性,所以就会处于 pending 状态,
如果在反亲和性这个位置把 required 改成 preferred,那么也会运行。
podaffinity:pod 节点亲和性,pod 倾向于哪个 pod
nodeaffinity:node 节点亲和性,pod 倾向于哪个 node
四、污点、容忍度
给了节点选则的主动权,我们给节点打一个污点,不容忍的 pod 就运行不上来,污点就是定义在节点上的键值属性数据,可以定决定拒绝那些 pod; taints 是键值数据,用在节点上,定义污点; tolerations 是键值数据,用在 pod 上,定义容忍度,能容忍哪些污点
pod 亲和性是 pod 属性;但是污点是节点的属性,污点定义在 nodeSelector 上
# 默认情况只有master节点有污点,工作节点是没有的 [root@master node]# kubectl get nodes master -o yaml | grep taints taints: - effect: NoSchedule key: node-role.kubernetes.io/master [root@master node]# kubectl explain nodes.spec.taints FIELDS: effect <string> -required- Required. The effect of the taint on pods that do not tolerate the taint. Valid effects are NoSchedule, PreferNoSchedule and NoExecute. key <string> -required- timeAdded <string> NoSchedule: 仅影响 pod 调度过程,当 pod 能容忍这个节点污点,就可以调度到当前节点,后来这个节点的污点改了,加了一个新的污点,使得之前调度的 pod 不能容忍了,那这个 pod 会怎么处理,对现存的 pod 对象不产生影响 NoExecute: 既影响调度过程,又影响现存的 pod 对象,如果现存的 pod 不能容忍节点后来加的污点,这个 pod就会被驱逐 PreferNoSchedule: 最好不,也可以,是 NoSchedule 的柔性版本
在 pod 对象定义容忍度的时候支持两种操作: 1.等值密钥:key 和 value 上完全匹配 2.存在性判断:key 和 effect 必须同时匹配,value 可以是空 在 pod 上定义的容忍度可能不止一个,在节点上定义的污点可能多个,需要琢个检查容忍度和污点能否匹配,每一个污点都能被容忍,才能完成调度,如果不能容忍怎么办,那就需要看 pod 的容忍度了
kubectl taint --help
kubectl taint nodes foo dedicated=special-user:NoSchedule 打上污点
kubectl taint nodes foo dedicated:NoSchedule- 删除污点
示例:
# 打上污点 [root@master node]# kubectl taint node node3 node-type=production:NoSchedule node/node3 tainted [root@master taint]# kubectl apply -f pod-taint.yaml pod/taint-pod created [root@master taint]# kubectl get pods -o wide -n default NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES taint-pod 1/1 Running 0 3m29s 10.244.75.206 monitor <none> <none> # taint-pod 认为node3节点有污点,不能容忍所以不会在node3上建立 # 将monitor打上污点并设置为NoExecute会发现,monitor上原来存在的pod都变为了Pending状态了 [root@master taint]# kubectl taint node monitor node-type=dev:NoExecute node/monitor tainted [root@master taint]# kubectl get pods -o wide -n default NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-7f466444dc-hrx7w 0/1 Pending 0 2m59s <none> <none> <none> <none> nginx-7f466444dc-qbxfn 1/1 Running 0 4d4h 10.244.135.3 node3 <none> <none> nginx-test-75c685fdb7-92w5b 1/1 Running 0 4d 10.244.135.6 node3 <none> <none> nginx-test-75c685fdb7-mlnjg 0/1 Pending 0 2m59s <none> <none> <none> <none>
示例:
apiVersion: v1 kind: Pod metadata: name: myapp-deploy namespace: default labels: app: myapp release: canary spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 tolerations: - key: "node-type" operator: "Equal" value: "production" effect: "NoSchedule" # effect: "NoExecute" #如果是这个查看的时候会发现Ponding状态 # tolerationSeconds: 3600 # NoExecute可以存在,NoSchedule就不能使用这个 [root@master taint]# kubectl apply -f pod-demo-1.yaml pod/myapp-deploy created [root@master taint]# kubectl get pods -n default -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-deploy 1/1 Running 0 5m59s 10.244.135.15 node3 <none> <none>
# 修改容忍度
tolerations:
- key: "node-type"
operator: "Exists"
value: ""
effect: ""
[root@master taint]# kubectl get pods -n default -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-deploy 1/1 Running 0 6s 10.244.75.207 monitor <none> <none>
# 删除污点
[root@master taint]# kubectl taint nodes monitor node-type:NoExecute-
node/monitor untainted
[root@master taint]# kubectl taint nodes node3 node-type-
node/node3 untainted
五、Pod常见的状态和重启策略
5.1 常见的pod状态
Pod 的 status 定义在 PodStatus 对象中,其中有一个 phase 字段。它简单描述了 Pod 在其生命周期的阶段。熟悉 Pod 的各种状态对我们理解如何设置 Pod 的调度策略、重启策略是很有必要的。 下面是 phase 可能的值,也就是 pod 常见的状态: 挂起(Pending):我们在请求创建 pod 时,条件不满足,调度没有完成,没有任何一个节点能满足调度条件,已经创建了 pod 但是没有适合它运行的节点叫做挂起,调度没有完成,
处于 pending的状态会持续一段时间:包括调度 Pod 的时间和通过网络下载镜像的时间。 运行中(Running):Pod 已经绑定到了一个节点上,Pod 中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。 成功(Succeeded):Pod 中的所有容器都被成功终止,并且不会再重启。 失败(Failed):Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非 0 状态退出或者被系统终止。 未知(Unknown):未知状态,所谓 pod 是什么状态是 apiserver 和运行在 pod 节点的 kubelet 进行通信获取状态信息的,如果节点之上的 kubelet 本身出故障,
那么 apiserver 就连不上kubelet,得不到信息了,就会看 Unknown 扩展:还有其他状态,如下: Evicted 状态:出现这种情况,多见于系统内存或硬盘资源不足,可 df-h 查看 docker 存储所在目录的资源使用情况,如果百分比大于 85%,就要及时清理下资源,尤其是一些大文件、docker 镜像。 CrashLoopBackOff:容器曾经启动了,但可能又异常退出了 Error 状态:Pod 启动过程中发生了错误
5.2 Pod重启策略
Pod 的重启策略(RestartPolicy)应用于 Pod 内的所有容器,并且仅在 Pod 所处的 Node 上由kubelet 进行判断和重启操作。当某个容器异常退出或者健康检查失败时,kubelet 将根据 RestartPolicy 的设置来进行相应的操作。 Pod 的重启策略包括 Always、OnFailure 和 Never,默认值为 Always。 Always:当容器失败时,由 kubelet 自动重启该容器。 OnFailure:当容器终止运行且退出码不为 0 时,由 kubelet 自动重启该容器。 Never:不论容器运行状态如何,kubelet 都不会重启该容器。
apiVersion: v1 kind: Pod metadata: name: demo-pod namespace: default labels: app: myapp spec: restartPolicy: Always # 默认一般也是Always containers: - name: tomcat-pod-java ports: - containerPort: 8080 image: tomcat:8.5-jre8-alpine imagePullPolicy: IfNotPresent
六. Pod生命周期
6.1 Init container容器
Pod 里面可以有一个或者多个容器,部署应用的容器可以称为主容器,在创建 Pod 时候,Pod 中可以有一个或多个先于主容器启动的 Init 容器,这个 init 容器就可以成为初始化容器,初始化容 器一旦执行完,它从启动开始到初始化代码执行完就退出了,它不会一直存在,所以在主容器启动之前执行初始化,初始化容器可以有多个,多个初始化容器是要串行执行的,先执行初始化容器
1,在执行初始化容器 2 等,等初始化容器执行完初始化就退出了,然后再执行主容器,主容器一退出,pod 就结束了,主容器退出的时间点就是 pod 的结束点,它俩时间轴是一致的; Init 容器就是做初始化工作的容器。可以有一个或多个,如果多个按照定义的顺序依次执行,只有所有的初始化容器执行完后,主容器才启动。由于一个 Pod 里的存储卷是共享的,所以 Init Container 里产生的数据可以被主容器使用到,Init Container 可以在多种 K8S 资源里被使用到,如 Deployment、DaemonSet, StatefulSet、Job 等,但都是在 Pod 启动时,
在主容器启动前执行,做初始化工作。 Init 容器与普通的容器区别是: 1、Init 容器不支持 Readiness,因为它们必须在 Pod 就绪之前运行完成 2、每个 Init 容器必须运行成功,下一个才能够运行 3、如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止,然而,如果 Pod 对应的 restartPolicy 值为 Never,它不会重新启动。 初始化容器的官方地址: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/#init-containersin-use
查看启动容器的信息
kubectl logs myapp-pod # 日志信息
kubectl describe pods myapp-pod
6.2 主容器
6.2.1 容器钩子:
初始化容器启动之后,开始启动主容器,在主容器启动之前有一个 post start hook(容器启动后钩子)和 pre stop hook(容器结束前钩子),无论启动后还是结束前所做的事我们可以把它放两个钩子,
这个钩子就表示用户可以用它来钩住一些命令,来执行它,做开场前的预设,结束前的清理,如 awk 有 begin,end,和这个效果类似; postStart:该钩子在容器被创建后立刻触发,通知容器它已经被创建。如果该钩子对应的 hook handler 执行失败,则该容器会被杀死,并根据该容器的重启策略决定是否要重启该容器,这个钩子不需要传递任何参数。 preStop:该钩子在容器被删除前触发,其所对应的 hook handler 必须在删除该容器的请求发送给 Docker daemon 之前完成。在该钩子对应的 hook handler 完成后不论执行的结果如何,
Docker daemon 会发送一个 SGTERN 信号量给 Docker daemon 来删除该容器,这个钩子不需要传递任何参数。 在 k8s 中支持两类对 pod 的检测,第一类叫做 livenessprobe(pod 存活性探测): 存活探针主要作用是,用指定的方式检测 pod 中的容器应用是否正常运行,如果检测失败,则认为容器不健康,
那么 Kubelet 将根据 Pod 中设置的 restartPolicy 来判断 Pod 是否要进行重启操作,如果容器配置中没有配置 livenessProbe,Kubelet 将认为存活探针探测一直为成功状态。
第二类是状态检 readinessprobe(pod 就绪性探测):用于判断容器中应用是否启动完成,当探测成功后才使 Pod 对外提供网络访问,设置容器 Ready 状态为 true,如果探测失败,则设置容器的Ready 状态为 false。
NAME READY STATUS RESTARTS AGE
pod-second 0/1 Running 0 153m
# Ready 容器中的应用没有启动,Running容器创建成功并启动
6.3 创建pod需要经过哪些阶段?
1.当用户创建 pod 时,这个请求给 apiserver,apiserver 把创建请求的状态保存在 etcd 中; 2.接下来 apiserver 会请求 scheduler 来完成调度,如果调度成功,会把调度的结果(如调度到哪个节点上了,运行在哪个节点上了,把它更新到 etcd 的 pod 资源状态中)保存在 etcd 中, 3.一旦存到 etcd 中并且完成更新以后,如调度到 node1上,那么 node1节点上的kubelet 通过 apiserver 当中的状态变化知道有一些任务被执行了,所以此时此 kubelet 会拿到用户创建时所提交的清单,
这个清单会在当前节点上运行或者启动这个 pod, 4.如果创建成功或者失败会有一个当前状态,当前这个状态会发给 apiserver,apiserver 在存到 etcd 中; 5.在这个过程中,etcd 和 apiserver 一直在打交道,不停的交互,scheduler 也参与其中,负责调度 pod 到合适的 node 节点上,这个就是 pod 的创建过程 pod 在整个生命周期中有非常多的用户行为: 1、初始化容器完成初始化 2、主容器启动后可以做启动后钩子 3、主容器结束前可以做结束前钩子 4、在主容器运行中可以做一些健康检测,如 liveness probe,readness probe
标签:node,容器,进阶篇,Affinity,master,Pod,root,pod 来源: https://www.cnblogs.com/yangmeichong/p/16496400.html