ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Pod进阶篇:污点-容忍度-亲和性-Affinity-调度(5)

2022-07-26 15:35:10  阅读:129  来源: 互联网

标签:node 容器 进阶篇 Affinity master Pod root pod


一、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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有