探索云原生技术之容器编排引擎-Kubernetes/K8S详解(4)

发布于:2023-01-22 ⋅ 阅读:(16) ⋅ 点赞:(0) ⋅ 评论:(0)

❤️作者简介:2022新星计划第三季云原生与云计算赛道Top5🏅、华为云享专家🏅、云原生领域潜力新星🏅

💛博客首页:C站个人主页🌞

💗作者目的:如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门,共同进步!

基本理论介绍

什么是云原生

Pivotal公司的Matt Stine于2013年首次提出云原生(Cloud-Native)的概念;2015年,云原生刚推广时,Matt Stine在《迁移到云原生架构》一书中定义了符合云原生架构的几个特征:12因素、微服务、自敏捷架构、基于API协作、扛脆弱性;到了2017年,Matt Stine在接受InfoQ采访时又改了口风,将云原生架构归纳为模块化、可观察、可部署、可测试、可替换、可处理6特质;而Pivotal最新官网对云原生概括为4个要点:DevOps+持续交付+微服务+容器

总而言之,符合云原生架构的应用程序应该是:采用开源堆栈(K8S+Docker)进行容器化,基于微服务架构提高灵活性和可维护性,借助敏捷方法、DevOps支持持续迭代和运维自动化,利用云平台设施实现弹性伸缩、动态调度、优化资源利用率。

此处摘选自《知乎-华为云官方帐号》

在这里插入图片描述

什么是kubernetes

kubernetes,简称K8s,是用8代替8个字符"ubernete"而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了应用部署,规划,更新,维护的一种机制

传统的应用部署方式:是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚拟机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。

新的部署方式:是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的,所以它能在不同云、不同版本操作系统间进行迁移。

容器占用资源少、部署快,每个应用可以被打包成一个容器镜像,每个应用与容器间成一对一关系也使容器有更大优势,使用容器可以在build或release 的阶段,为应用创建容器镜像,因为每个应用不需要与其余的应用堆栈组合,也不依赖于生产环境基础结构,这使得从研发到测试、生产能提供一致环境。类似地,容器比虚拟机轻量、更"透明",这更便于监控和管理。

Kubernetes是Google开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。在生产环境中部署一个应用程序时,通常要部署该应用的多个实例以便对应用请求进行负载均衡。

在Kubernetes中,我们可以创建多个容器,每个容器里面运行一个应用实例,然后通过内置的负载均衡策略,实现对这一组应用实例的管理、发现、访问,而这些细节都不需要运维人员去进行复杂的手工配置和处理。

此处摘选自《百度百科》

kubernetes核心功能

  • 存储系统挂载(数据卷):pod中容器之间共享数据,可以使用数据卷
  • 应用健康检测:容器内服务可能进程阻塞无法处理请求,可以设置监控检查策略保证应用健壮性
  • 应用实例的复制(实现pod的高可用):pod控制器(deployment)维护着pod副本数量(可以自己进行设置,默认为1),保证一个pod或一组同类的pod数量始终可用,如果pod控制器deployment当前维护的pod数量少于deployment设置的pod数量,则会自动生成一个新的pod,以便数量符合pod控制器,形成高可用。
  • Pod的弹性伸缩:根据设定的指标(比如:cpu利用率)自动缩放pod副本数
  • 服务发现:使用环境变量或者DNS插件保证容器中程序发现pod入口访问地址
  • 负载均衡:一组pod副本分配一个私有的集群IP地址,负载均衡转发请求到后端容器。在集群内部其他pod可通过这个clusterIP访问应用
  • 滚动更新:更新服务不会发生中断,一次更新一个pod,而不是同时删除整个服务。
  • 容器编排:通过文件来部署服务,使得应用程序部署变得更高效
  • 资源监控:node节点组件集成cAdvisor资源收集工具,可通过Heapster汇总整个集群节点资源数据,然后存储到InfluxDb时序数据库,再由Grafana展示。
  • 提供认证和授权:支持角色访问控制(RBAC)认证授权等策略

Pod详解

Pod的调度

概述
  • 当我们通过kubernetes客户端(例如kubectl)发送一个创建Pod的请求给ApiServer,Scheduler就会自动计算出这个Pod将要被调度到哪个节点上(这个计算出来的结果是不能人为控制的,是由Scheduler计算而来)。如果我们需要Pod被调度到指定的节点上,就不能使用默认的调度机制,kubernetes一共提供了4种调度方式,分别是:

    • 自动调度:Pod将被调度到哪个node节点上都是由Scheduler计算而得,无法人为干预。(默认方式
    • 定向调度:
      • 1:nodeName。
      • 2:nodeSelector。
    • 亲和性调度:
      • 1:nodeAffinity(node亲和性调度)
      • 2:podAffinity(Pod亲和性调度)
      • 3:podAntiAffinity(Pod反亲和性调度)
    • 污点、容忍调度
      • 1:Taints。
      • 2:tolerations。
  • 关于亲和性和反亲和性的使用场景的说明:

    • 亲和性:如果两个应用频繁交互,那么就有必要利用亲和性让两个应用尽可能的靠近,这样可以较少因网络通信而带来的性能损耗。

    • 反亲和性:当应用采用多副本部署的时候,那么就有必要利用反亲和性让各个应用实例打散分布在各个Node上,这样可以提高服务的高可用性。

定向调度
nodeName定向调度

nodeName定向调度是强制把某个Pod定向调度到节点名称为nodeName所指定的值的节点上,不管这个节点存不存在都会调度上去。

  • 先查看所有节点:
[root@k8s-master ~]# kubectl get nodes
NAME          STATUS   ROLES    AGE     VERSION
k8s-master    Ready    master   6d19h   v1.17.4
k8s-slave01   Ready    <none>   6d19h   v1.17.4
k8s-slave02   Ready    <none>   6d19h   v1.17.4
  • 比如我们指定调度到node名称为:k8s-slave01上

  • 创建yaml文件

vim nodeName.yaml
  • 内容如下:(错误的配置文件)
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: v1
kind: Pod
metadata: 
   labels:
     app: nodeName-label
   name: nodeName
   namespace: test
spec:
  containers:
     - image: nginx:1.17
       name: nginx-container
       ports:
         - name: nginx-port
           containerPort: 80
           protocol: TCP
  nodeName: k8s-slave01 
  • 创建Pod
[root@k8s-master ~]# kubectl apply -f nodeName.yaml 
namespace/test unchanged
The Pod "nodeName" is invalid: metadata.name: Invalid value: "nodeName": a DNS-1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')
  • 发现报错。下面才是正确的配置文件因为kubernetes中的yaml配置文件要用小写,不能含有大写):
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: v1
kind: Pod
metadata: 
   labels:
     app: nodename-label
   name: nodename
   namespace: test
spec:
  containers:
     - image: nginx:1.17
       name: nginx-container
       ports:
         - name: nginx-port
           containerPort: 80
           protocol: TCP
  nodeName: k8s-slave01 #指定这个Pod调度到节点名称为k8s-slave01的节点上
  • 再次运行即可:
[root@k8s-master ~]# kubectl apply -f nodeName.yaml 
namespace/test unchanged
pod/nodename created
  • 查看Pod列表,发现该Pod被调度到k8s-slave01上了:
[root@k8s-master ~]# kubectl get pods -n test -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
nodename   1/1     Running   0          8s    10.244.1.20   k8s-slave01   <none>           <none>
nodeSelector定向调度

nodeSelector定向调度所指定的是一对标签label键值对,通过这个指定的label去匹配k8s节点,当k8s中的某个节点有这个label则会把Pod调度到这个节点上去。

  • 给k8s-slave01打上标签:
kubectl label node k8s-slave01 role=user
  • 给k8s-slave02打上标签:
kubectl label node k8s-slave02 role=admin
  • 创建yaml文件
vim nodeselector.yaml
  • 内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: v1
kind: Pod
metadata: 
   labels:
     app: nodeselector-label
   name: nodeselector
   namespace: test
spec:
  containers:
     - image: nginx:1.17
       name: nginx-container
       ports:
         - name: nginx-port
           containerPort: 80
           protocol: TCP
  nodeSelector: #筛选节点有role=admin这个标签,并调度到这个节点上
      role: admin
  • 运行这个配置文件:
kubectl apply -f nodeselector.yaml
  • 再次查看一下:
[root@k8s-master ~]# kubectl get pods -n test -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
nodeselector   1/1     Running   0          9s    10.244.2.26   k8s-slave02   <none>           <none>
亲和性调度
  • 亲和性调度可以说是nodeSelector的升级版,区别如下:

    • nodeSelector的特点是不管存不存在符合条件的节点都会调度上去,这样就会导致调度上去的Pod无法使用。
    • 而亲和性调度的特点是如果存在符合条件的节点就会调度上去,如果不存在符合条件的节点的话也会调度到其他不符合条件的节点上去,这样就能保证Pod无论什么情况都能够正常运行。
  • 查看一下亲和性调度的种类:

[root@k8s-master ~]# kubectl explain pods.spec.affinity
KIND:     Pod
VERSION:  v1
RESOURCE: affinity <Object>
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)).
nodeAffinity(requiredDuringSchedulingIgnoredDuringExecution硬限制类型)

nodeAffinity:让Pod调度到符合标签的node节点上。(说白了就是靠近符合标签的node)

  • nodeAffinity的可配置项:
pod.spec.affinity.nodeAffinity
  requiredDuringSchedulingIgnoredDuringExecution # Node节点必须满足指定的所有规则才可以,相当于硬限制
    nodeSelectorTerms # 节点选择列表
      matchFields  # 按节点字段列出的节点选择器要求列表  
      matchExpressions  # 按节点标签列出的节点选择器要求列表(推荐)
        key   # 键
        values # 值
        operator # 关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
  preferredDuringSchedulingIgnoredDuringExecution # 优先调度到满足指定的规则的Node,相当于软限制 (倾向)     
    preference   # 一个节点选择器项,与相应的权重相关联
      matchFields # 按节点字段列出的节点选择器要求列表
      matchExpressions   # 按节点标签列出的节点选择器要求列表(推荐)
        key # 键
        values # 值
        operator # 关系符 支持In, NotIn, Exists, DoesNotExist, Gt(大于), Lt(小于) 
    weight # 倾向权重,在范围1-100(值越大,优先级越高)
  • 关系符:
- matchExpressions:
	- key: nodeenv # 匹配存在标签的key为nodeenv的节点
	  operator: Exists   
	- key: nodeenv # 匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点
	  operator: In    
      values: ["xxx","yyy"]
    - key: nodeenv # 匹配标签的key为nodeenv,且value大于"xxx"的节点
      operator: Gt   
      values: "xxx"
  • 我们已经给slave01和slave2分别打上role=user和role=admin标签
[root@k8s-master ~]# kubectl get nodes -o wide --show-labels
NAME          STATUS   ROLES    AGE   VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION           CONTAINER-RUNTIME   LABELS
k8s-master    Ready    master   9d    v1.17.4   192.168.184.100   <none>        CentOS Linux 7 (Core)   3.10.0-1160.el7.x86_64   docker://18.6.3     beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/master=
k8s-slave01   Ready    <none>   9d    v1.17.4   192.168.184.101   <none>        CentOS Linux 7 (Core)   3.10.0-1160.el7.x86_64   docker://18.6.3     beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-slave01,kubernetes.io/os=linux,role=user
k8s-slave02   Ready    <none>   9d    v1.17.4   192.168.184.102   <none>        CentOS Linux 7 (Core)   3.10.0-1160.el7.x86_64   docker://18.6.3     beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-slave02,kubernetes.io/os=linux,role=admin
  • 创建yaml文件
vim nodeaffinity-required.yaml
  • 内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: v1
kind: Pod
metadata: 
   labels:
     app: nodeaffinity-required-label
   name: nodeaffinity-required
   namespace: test
spec:
  containers:
     - image: nginx:1.17
       name: nginx-container
       ports:
         - name: nginx-port
           containerPort: 80
           protocol: TCP
  affinity: # 亲和性配置
    nodeAffinity: # node亲和性配置
      requiredDuringSchedulingIgnoredDuringExecution: # Node节点必须满足指定的所有规则才可以,相当于硬规则,类似于定向调度
        nodeSelectorTerms: # 节点选择列表
          - matchExpressions:
              - key: role # 匹配存在标签的key为role的节点,并且value是"user111"或"admin111"的节点
                operator: In
                values:
                  - "user111"
                  - "admin111"
  • 执行配置文件:
[root@k8s-master ~]# kubectl apply -f nodeaffinity-required.yaml 
namespace/test unchanged
pod/nodeaffinity-required created
  • 下面可以看到3 node(s) didn’t match node selector(调度失败),因为上面的条件是调度到node节点含有role=user111或者role=admin111标签,而我们的slave01节点和slave02节点含有role=user和role=admin标签。
[root@k8s-master ~]# kubectl get pods -n test 
NAME                    READY   STATUS    RESTARTS   AGE
nodeaffinity-required   0/1     Pending   0          11s
[root@k8s-master ~]# kubectl describe pods nodeaffinity-required -n test
Name:         nodeaffinity-required
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  27s (x2 over 27s)  default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.
  • 修改配置文件:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: v1
kind: Pod
metadata: 
   labels:
     app: nodeaffinity-required-label
   name: nodeaffinity-required
   namespace: test
spec:
  containers:
     - image: nginx:1.17
       name: nginx-container
       ports:
         - name: nginx-port
           containerPort: 80
           protocol: TCP
  affinity: # 亲和性配置
    nodeAffinity: # node亲和性配置
      requiredDuringSchedulingIgnoredDuringExecution: # Node节点必须满足指定的所有规则才可以,相当于硬规则,类似于定向调度
        nodeSelectorTerms: # 节点选择列表
          - matchExpressions:
              - key: role # 匹配存在标签的key为role的节点,并且value是"user111"或"admin111"的节点
                operator: In
                values:
                  - "user"
                  - "admin666"
  • 重新执行配置文件:
[root@k8s-master ~]# kubectl delete -f nodeaffinity-required.yaml 

[root@k8s-master ~]# kubectl apply -f nodeaffinity-required.yaml 
  • 可以看到我们的Pod节点成功调度到slave01节点上了,因为我们上面定义的规则slave01是满足的。
[root@k8s-master ~]# kubectl describe pods nodeaffinity-required -n test
Name:         nodeaffinity-required
Events:
  Type    Reason     Age   From                  Message
  ----    ------     ----  ----                  -------
  Normal  Scheduled  43s   default-scheduler     Successfully assigned test/nodeaffinity-required to k8s-slave01
  Normal  Pulled     42s   kubelet, k8s-slave01  Container image "nginx:1.17" already present on machine
  Normal  Created    42s   kubelet, k8s-slave01  Created container nginx-container
  Normal  Started    42s   kubelet, k8s-slave01  Started container nginx-container
nodeAffinity(preferredDuringSchedulingIgnoredDuringExecution软限制类型)
  • required(硬限制)和preferred(软限制)两种类型的区别就是:
    • required(硬限制):1种情况
      • 1:required(硬限制)如果找不到符合定义的条件的Pod或者node,则直接调度失败。
    • preferred(软限制):3种情况
      • 1:preferred(软限制)如果找不到符合定义的条件的Pod或者node,则也会将Pod调度到不符合条件的节点上。
      • 2:如果找到符合定义的条件的Pod或者node,并且只有一个Pod或者node满足条件,则直接调度上去。
      • 3:如果找到符合定义的条件的Pod或者node,并且如果定义了多个条件都是同时满足的话,就会通过weight(权值)进行筛选,挑选出Pod或者node满足的条件对应的weight值最大的那一个。
podAffinity

podAffinity:让Pod调度到符合标签的Pod所在的node节点上。(说白了就是靠近符合标签的Pod)

  • podAffinity的可选配置项:
pod.spec.affinity.podAffinity
  requiredDuringSchedulingIgnoredDuringExecution  硬限制
    namespaces 指定参照pod的namespace
    topologyKey 指定调度作用域
    labelSelector 标签选择器
      matchExpressions  按节点标签列出的节点选择器要求列表(推荐)
        key    键
        values 值
        operator 关系符 支持In, NotIn, Exists, DoesNotExist.
      matchLabels    指多个matchExpressions映射的内容  
  preferredDuringSchedulingIgnoredDuringExecution 软限制    
    podAffinityTerm  选项
      namespaces
      topologyKey
      labelSelector
         matchExpressions 
            key    键  
            values 值  
            operator
         matchLabels 
    weight 倾向权重,在范围1-100(权值越大,优先级越高)
  • topologyKey用于指定调度的作用域,例如:

    • 如果指定为kubernetes.io/hostname,那就是以Node节点为区分范围。说白了就是调度到目标Pod相同的node节点上。(常用)

    • 如果指定为beta.kubernetes.io/os,则以Node节点的操作系统类型来区分。

案例:创建一个targetPod,打上podrole: pod-admin标签,并且定向调度到slave02节点上,再创建一个新的Pod使用Pod亲和性调度匹配podrole标签值为user111或者pod-admin,符合上面的条件则调度到这个targetPod所在的node上。如果案例实验成功,则会出现podaffinity-required的Pod调度到了slave02上。

  • 创建yaml文件
vim podaffinity-required.yaml
  • 内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: v1
kind: Pod
metadata: 
   labels:
     podrole: pod-admin
   name: targetpod
   namespace: test
spec:
  containers:
     - image: nginx:1.17
       name: nginx-container
       ports:
         - name: nginx-port
           containerPort: 80
           protocol: TCP
  nodeName: k8s-slave02 
---
apiVersion: v1
kind: Pod
metadata: 
   labels:
     app: podaffinity-required-label
   name: podaffinity-required
   namespace: test
spec:
  containers:
     - image: nginx:1.17
       name: nginx-container
       ports:
         - name: nginx-port
           containerPort: 80
           protocol: TCP
  affinity: # 亲和性配置
    podAffinity: # Pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        - labelSelector:
            matchExpressions: 
              - key: podrole
                operator: In
                values:
                  - "user111"
                  - "pod-admin"
          topologyKey: kubernetes.io/hostname
          namespaces: 
              - "test" #参照(target)Pod所在的namespace
  • 执行配置文件:
[root@k8s-master ~]# kubectl apply -f podaffinity-required.yaml 
namespace/test unchanged
pod/targetpod unchanged
pod/podaffinity-required created
  • 查看Pod:(成功)
[root@k8s-master ~]# kubectl get pods -n test -o wide
NAME                    READY   STATUS    RESTARTS   AGE    IP            NODE          NOMINATED NODE   READINESS GATES
podaffinity-required    1/1     Running   0          23s    10.244.2.28   k8s-slave02   <none>           <none>
targetpod               1/1     Running   0          2m9s   10.244.2.27   k8s-slave02   <none>           <none>
podAntiAffinity

podAntiAffinity:让Pod调度到不符合标签的Pod所在的node节点上。(说白了就是远离符合标签的Pod)

案例:创建一个targetPod,打上podrole: pod-admin标签,并且定向调度到slave02节点上,再创建一个新的Pod使用Pod的反亲和性调度匹配podrole标签值为user111或者pod-admin,符合上面的条件则调度到这个targetPod相反(不同)的node上。如果案例实验成功,则会出现podaffinity-required的Pod调度到了slave01上。

  • 创建yaml文件
vim podantiaffinity-required.yaml
  • 内容如下:
apiVersion: v1
kind: Namespace
metadata:
  name: test
---
apiVersion: v1
kind: Pod
metadata: 
   labels:
     podrole: pod-admin
   name: targetpod
   namespace: test
spec:
  containers:
     - image: nginx:1.17
       name: nginx-container
       ports:
         - name: nginx-port
           containerPort: 80
           protocol: TCP
  nodeName: k8s-slave02 
---
apiVersion: v1
kind: Pod
metadata: 
   labels:
     app: podantiaffinity-required-label
   name: podantiaffinity-required
   namespace: test
spec:
  containers:
     - image: nginx:1.17
       name: nginx-container
       ports:
         - name: nginx-port
           containerPort: 80
           protocol: TCP
  affinity: # 亲和性配置
    podAntiAffinity: # Pod的反亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        - labelSelector:
            matchExpressions: 
              - key: podrole
                operator: In
                values:
                  - "user111"
                  - "pod-admin"
          topologyKey: kubernetes.io/hostname
          namespaces: 
              - "test" #参照(target)Pod所在的namespace
  • 执行配置文件:
[root@k8s-master ~]# kubectl apply -f podantiaffinity-required.yaml 
namespace/test created
pod/targetpod created
pod/podantiaffinity-required created
  • 查看Pod:(成功)
[root@k8s-master ~]# kubectl get pods -n test -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
podantiaffinity-required   1/1     Running   0          33s   10.244.1.23   k8s-slave01   <none>           <none>
targetpod                  1/1     Running   0          33s   10.244.2.31   k8s-slave02   <none>           <none>
污点、容忍调度
Taints
  • 污点与亲和性调度有什么区别?

    • 亲和性调度的作用范围可以是node和Pod。而污点的作用范围只能是node我们只能通过给node打上污点(和label不同,污点是taint)
    • 污点说白了就是node的一种驱赶策略。除了PreferNoSchedule类型,其他类型的情况下,Pod如果想要调度到有污点的node上,需要进行容忍这个污点,否则Pod将无法调度上去。
  • 污点的格式为:key=value:effect ,key=value是污点标签,effect是污点的类型。污点有三种类型,分为三个等级,第1级最友好,第3级最不友好。

    • 1(最低级):PreferNoSchedule:kubernetes将尽量避免把Pod调度到具有该污点的Node上,除非没有其他节点可以调度。
    • 2(中等):NoSchedule:kubernetes将不会把Pod调度到具有该污点的Node上,但是不会影响当前Node上已经存在的Pod。
    • 3(最高级):NoExecute:kubernetes将不会把Pod调度到具有该污点的Node上,同时也会将Node上已经存在的Pod驱逐。

设置污点:

格式:

kubectl taint node node节点名称 key=value:effect

去除污点:

格式:

kubectl taint node node节点名称 key:effect-

去除所有污点:

kubectl taint node node节点名称 key-

查看指定节点上的污点:

kubectl describe node node节点名称

案例要求:

1:关闭slave02服务器,只保留master和slave01服务器。

2:给slave01打上PreferNoSchedule污点(taintkey=taintvalue),再创建一个Pod或者Pod控制器,查看pod调度情况。

3:取消slave01的污点,再给slave01打上NoSchedule污点(taintkey=taintvalue),再创建一个Pod或者Pod控制器,查看pod调度情况。

4:取消slave01的污点,再给slave01打上NoExecute污点(taintkey=taintvalue),再创建一个Pod或者Pod控制器,查看pod调度情况。

  • 创建一个命名空间:
kubectl create ns dev
  • 给k8s-slave01打上污点(PreferNoSchedule):
kubectl taint node k8s-slave01 taintkey=taintvalue:PreferNoSchedule
  • 运行一个Pod控制器(自动会产生Pod并调度到节点上):
[root@k8s-master ~]# kubectl run pod1 --image=nginx:1.17 -n dev
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/pod1 created
  • 查看Pod调度情况:
[root@k8s-master ~]# kubectl get pods -n dev -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
pod1-65b5d99b46-5cj47   1/1     Running   0          32s   10.244.1.25   k8s-slave01   <none>           <none>
  • 删除slave01的污点
[root@k8s-master ~]# kubectl taint node k8s-slave01 taintkey:PreferNoSchedule-
node/k8s-slave01 untainted
  • 给slave01打上NoSchedule污点(taintkey=taintvalue)
[root@k8s-master ~]# kubectl taint node k8s-slave01 taintkey=taintvalue:NoSchedule
node/k8s-slave01 tainted
  • 运行一个Pod控制器:
kubectl run pod2 --image=nginx:1.17 -n dev
  • 查看Pod,发现我们的pod2没有成功调度。
[root@k8s-master ~]# kubectl get pods -n dev -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
pod1-65b5d99b46-5cj47   1/1     Running   1          18h   10.244.1.26   k8s-slave01   <none>           <none>
pod2-d68559894-j2f5t    0/1     Pending   0          73s   <none>        <none>        <none>           <none>
  • 使用describe查看Pod2,因为我们只有一个node节点,而那个节点却被打上了NoSchedule污点,所以无法调度上去,但是我们可以从上面看到pod1处于(Running状态)正常运行中。
[root@k8s-master ~]# kubectl describe pods pod2-d68559894-j2f5t -n dev
Name:           pod2-d68559894-j2f5t
Events:
  Type     Reason            Age        From               Message
  ----     ------            ----       ----               -------
  Warning  FailedScheduling  <unknown>  default-scheduler  0/3 nodes are available: 3 node(s) had taints that the pod didn't tolerate.
  Warning  FailedScheduling  <unknown>  default-scheduler  0/3 nodes are available: 3 node(s) had taints that the pod didn't tolerate.
  • 删除slave01的污点
kubectl taint node k8s-slave01 taintkey:NoSchedule-
  • 给slave01打上NoExecute污点(taintkey=taintvalue)
kubectl taint node k8s-slave01 taintkey=taintvalue:NoExecute
  • 查看Pod:
[root@k8s-master ~]# kubectl get pods -n dev
NAME                    READY   STATUS    RESTARTS   AGE
pod1-65b5d99b46-tvzcg   0/1     Pending   0          10s
pod2-d68559894-268mr    0/1     Pending   0          10s

我们发现之前被成功调度到slave01的pod1从Running变成了Pending!!!

  • 运行一个Pod控制器:
kubectl run pod3 --image=nginx:1.17 -n dev
[root@k8s-master ~]# kubectl get pods -n dev
NAME                    READY   STATUS    RESTARTS   AGE
pod1-65b5d99b46-tvzcg   0/1     Pending   0          112s
pod2-d68559894-268mr    0/1     Pending   0          112s
pod3-5fc49f964b-pqsmx   0/1     Pending   0          2s

可以发现NoExecute类型的污点不仅仅会把已经被调度到该节点的Pod赶走,还会让其他新创建的Pod调度失败。

tolerations
  • 容忍的作用是什么?
    • 当我们想让Pod可以调度到被打上污点的node节点上的时候,我们就需要使用容忍机制。
    • 如果不使用容忍机制的话,我们创建的Pod是无法被调度到打了污点(除了PreferNoSchedule类型的污点)的node节点上的,只有当我们的Pod容忍这个污点的时候我们才可以调度到这些node节点上去。
  • **使用kubeadm构建的kubernetes集群,默认会把我们的master节点打上NoSchedule污点,这也是为什么我们的Pod只会调度到node工作节点上,而不会被调度到master管理节点上的原因。**这些后面再讲。

容忍的配置:

[root@k8s-master ~]# kubectl explain pods.spec.tolerations
KIND:     Pod
VERSION:  v1
RESOURCE: tolerations <[]Object>
FIELDS:
  key       # 对应着要容忍的污点的键,空意味着匹配所有的键
  value     # 对应着要容忍的污点的值
  operator  # key-value的运算符,支持Equal和Exists(默认)
  effect    # 对应污点的effect,空意味着匹配所有影响
  tolerationSeconds   # 容忍时间, 当effect为NoExecute时生效,表示pod在Node上的停留时间

配置容忍的几种情况:

  • 当operator为Equal的时候:

    • 1:如果Node节点有多个Taint污点,那么Pod每个Taint污点都需要被容忍才能部署上去。
  • 当operator为Exists的时候:

    • 1:容忍指定的污点,污点带有指定的effect:
      tolerations: # 容忍
        - key: "tag" # 要容忍的污点的key
          operator: Exists # 操作符
          effect: NoExecute # 添加容忍的规则,这里必须和标记的污点规则相同
    
    • 2:容忍指定的污点,不考虑具体的effect:
      tolerations: # 容忍
        - key: "tag" # 要容忍的污点的key
          operator: Exists # 操作符
    
    • 3:容忍一切污点:(小心使用)
     tolerations: # 容忍
        - operator: Exists # 操作符
    

案例过程:

1:先给k8s-slave01打上NoExecute污点,这样所有节点都无法调度上去。

2:创建一个Pod,设置其能够容忍NoExeucute污点。

3:查看Pod调度情况。

  • 1:先给k8s-slave01打上NoExecute污点,这样所有节点都无法调度上去。
kubectl taint node k8s-slave01 taintkey=taintvalue:NoExecute
  • 2:创建一个Pod,设置其能够容忍NoExeucute污点。

创建配置文件:

vim podtoleration.yaml

文件内容:

apiVersion: v1
kind: Namespace
metadata:
  name: dev
---
apiVersion: v1
kind: Pod
metadata:
  name: podtoleration
  namespace: dev
spec:
  containers: 
    - name: nginx
      image: nginx:1.17
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  tolerations: # 配置容忍
    - key: "taintkey" # 要容忍的污点的key
      operator: Equal # 操作符
      value: "taintvalue" # 要容忍的污点的value
      effect: NoExecute # 添加容忍的规则,这里必须和标记的污点规则相同

执行配置文件:

[root@k8s-master ~]# kubectl apply -f podtoleration.yaml 
namespace/dev created
pod/podtoleration created
  • 3:查看Pod调度情况。
[root@k8s-master ~]# kubectl get pods -n dev -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
podtoleration   1/1     Running   0          75s   10.244.1.32   k8s-slave01   <none>           <none>

可以看到虽然我们的k8s-slave01被打上了NoExecute污点,但是由于我们新创建的Pod容忍了这个污点,所以才可以调度上去。

为什么Master节点不会被调度
  • 使用describe查看master节点:
[root@k8s-master ~]# kubectl describe node k8s-master
Name:               k8s-master
Roles:              master
Taints:             node-role.kubernetes.io/master:NoSchedule
......
  • 可以看到我们的master节点默认就被打上了NoSchedule类型的污点,所以我们的Pod是不会被调度到这个master节点上的。

❤️💛🧡本章结束,我们下一章见❤️💛🧡


网站公告

欢迎关注微信公众号

今日签到

点亮在社区的每一天
签到