其他分享
首页 > 其他分享> > Pod进阶篇:污点-容忍度-亲和性-Affinity-调度(5)

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