kubernetes 污点与容忍
<h1 id="前言">前言</h1><p>本文通过自身理解进行述说,如有不准确的地方,请指正。</p>
<p>在讲述一系列相关专业术语之前,先尝试用一个通俗易懂的故事来说明 Kubernetes 中 <code>node</code> 与 <code>pod</code> 之间的爱恨情仇。</p>
<blockquote>
<p>雄性(node)| 雌性(pod)</p>
<p>在银河系以外的一个星球上,有着一群两性生物,分别是雌性(pod)和雄性(node)。雌性生物居多,而雄性生物由于优胜劣汰,只剩下3只优质的雄性生物(node)。雄雌在一起就容易产生吸引,就会有以下的情况产生:</p>
<p>(1)雄(node)少雌(pod)多,而这三只优质的雄性生物性格、优点都是一致的,雌性生物选谁都一样。于是,雌性生物就分为均等分为三列和三只雄性生物在一起。这种类似于平均分配的原则。</p>
<p>k8s中的概念:在k8s中是最常见最普通的 pod 分布方式,常用与 deployment 和 daemonset 控制器。</p>
</blockquote>
<p><img src="https://img2020.cnblogs.com/blog/828019/202112/828019-20211223173119553-190355701.png" alt="image-20211217112559093" loading="lazy"></p>
<blockquote>
<p>(2)时间一长,生物开始了进化。三只雄性(node)生物各自有了不一样的地方,编号1的雄性学会了种植(node01 label skill='grow');编号2的雄性学会了打猎(node02 label skill='hunt');编号3的雄性啥也没学会(没学会就保持默认)。普通的雌性(pod)仍然保持着平均分配的原则。而一些进化快的雌性(pod)生物发现了三只优质雄性(node)生物各自的不同,各自也开始有了一些选择。一些雌性更加青睐学会种植的雄性生物(nodeSelector skill='grow') ;一些雌性更加青睐学打猎的雄性生物(nodeSelector skill='hunt') ;而有些雌性生物喜欢的特点很奇特,它们喜欢会飞的雄性,而仅存的三只雄性生物都无法满足这一特点。如果有天一只雄性生物进化会飞了,它们就会依附与会飞的雄性生物,如果始终没有进化出会飞的雄性生物,则它们一直等下去这在 k8s 中,就是 <code>yaml</code> 文件中 <code>nodeSelector</code> 的使用。</p>
<p>k8s中的概念:当 node 打上特定的标签后,会出现如下情况:</p>
<ol>
<li>pod 中未指定 <code>nodeSelector</code> ,则保持默认 schedule 调度算法的方式;</li>
<li>pod 中指定了 <code>nodeSelector</code> ,且指定 nodeSelector 中的 key、value 符合某一个 node 中的某一个key、value,则这个pod 直接调度到该node;</li>
<li>pod 中指定了 <code>nodeSelector</code> ,指定 nodeSelector 中的 key、value 不包含在任何一个 node 中,则这个 pod 会一直处于 padding 状态。</li>
</ol>
</blockquote>
<p><img src="https://img2020.cnblogs.com/blog/828019/202112/828019-20211223173119264-1922537147.png" alt="image-20211217113535679" loading="lazy"></p>
<blockquote>
<p>(3)三只雄性(node)不仅优点增长了,缺点也随之而来。编号1的雄性喜欢打脸(node01 taint hobby='face');编号2的雄性喜欢打屁股(node01 taint hobby='hunkers');编号3的雄性喜欢踩脚(node01 taint hobby='foot');普通的雌性(pod)生物仍然保持平均分配的原则,而一些再次进化的雌性生物也有了自己的性格。能够容忍打脸的雌性则和编号1的雄性在一起(tolerations hobby='face'),但是这个容忍可能是永久,也可能是1天(tolerationSeconds=86400)。而这三只雄性生物偶尔会在一起鬼混,编号1的雄性生物说不定哪天就嗜好就变为了喜欢睡懒觉。而一些无法容忍它睡懒觉嗜好的雌性生物就会隔一段时间或者马上就离开它。</p>
<p>k8s中的概念:这就是 <strong>污点</strong> 与 <strong>容忍</strong>。</p>
</blockquote>
<p><img src="https://img2020.cnblogs.com/blog/828019/202112/828019-20211223173118871-89763600.png" alt="image-20211217114605243" loading="lazy"></p>
<p><strong>污点和容忍还有其他的选项参数,后文展开解说。</strong></p>
<h1 id="nodeselector">nodeSelector</h1>
<blockquote>
<p>将 pod 分配给指定的节点。</p>
</blockquote>
<p>集群如下:</p>
<pre><code class="language-shell"># kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 20h v1.19.7
k8s-node01 Ready <none> 20h v1.19.7
k8s-node02 Ready <none> 20h v1.19.7
</code></pre>
<p>为 <code>k8s-node01</code> 添加一个标签</p>
<pre><code class="language-shell"># kubectl label nodes k8s-node01 disktype=ssd
node/k8s-node01 labeled
</code></pre>
<p>查看标签</p>
<pre><code class="language-shell"># kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready master 20h v1.19.7 ..., kubernetes.io/hostname=k8s-master
k8s-node01 Ready <none> 20h v1.19.7 ..., disktype=ssd,kubernetes.io/hostname=k8s-node01
k8s-node02 Ready <none> 20h v1.19.7 ..., kubernetes.io/hostname=k8s-node02
</code></pre>
<p>可以看到 <code>k8s-node01</code> 节点标签:<code>disktype=ssd</code></p>
<p><strong>创建一个调度到 选择节点的 Pod</strong></p>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ngx
name: ngx
spec:
replicas: 2
selector:
matchLabels:
app: ngx
template:
metadata:
labels:
app: ngx
spec:
containers:
- image: nginx:alpine-arm64
name: nginx
nodeSelector:
disktype: ssd ### 选择服务 key: value 的节点
</code></pre>
<p>创建pod 查看是否调度到指定的节点</p>
<pre><code class="language-shell"># kubectl apply -fngx.yaml
deployment.apps/ngx created
# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ngx-5f4df66559-hjmzg 1/1 Running 0 10s 10.244.1.13 k8s-node01 <none> <none>
ngx-5f4df66559-wqgdb 1/1 Running 0 10s 10.244.1.14 k8s-node01 <none> <none>
</code></pre>
<h1 id="k8s-亲和性">k8s 亲和性</h1>
<blockquote>
<p>说道亲和性,亲和性主要分为两类:<code>nodeAffinity</code> 和 <code>podAffinity</code> 。</p>
</blockquote>
<h2 id="nodeaffinity">nodeAffinity</h2>
<p><code>nodeAffinity</code> 就是节点亲和性,调度可以分成软策略和硬策略两种方式,软策略就是如果你没有满足调度要求的节点的话,POD 就会忽略这条规则,继续完成调度过程,说白了就是<strong>满足条件最好了,没有的话也无所谓了</strong>的策略;而硬策略就比较强硬了,如果没有满足条件的节点的话,就不断重试直到满足条件为止,简单说就是<strong>你必须满足我的要求,不然我就不干</strong>的策略。<code>nodeAffinity</code>就有两上面两种策略:</p>
<ul>
<li>
<p>requiredDuringSchedulingIgnoredDuringExecution :硬策略</p>
</li>
<li>
<p>preferredDuringSchedulingIgnoredDuringExecution : 软策略</p>
</li>
</ul>
<h3 id="硬策略">硬策略</h3>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ngx
name: ngx
spec:
replicas: 2
selector:
matchLabels:
app: ngx
template:
metadata:
labels:
app: ngx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype # key 的值
operator: In # 包括
values:
- ssd # value
containers:
- image: nginx:alpine-arm64
name: nginx
nodeSelector:
disktype: ssd
</code></pre>
<p>上面这两个 <code>pod</code> 只会运行在 满足 <code>node label disktype=value</code> 的节点上,如果没有节点满足这个条件,则一直处于 <code>pending</code> 状态。</p>
<pre><code class="language-shell"># kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ngx-7b65b44bc-gff9x 1/1 Running 0 3m53s 10.244.1.15 k8s-node01 <none> <none>
ngx-7b65b44bc-w7bsf 1/1 Running 0 3m53s 10.244.1.16 k8s-node01 <none> <none>
# kubectl get nodes k8s-node01 --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-node01 Ready <none> 22h v1.19.7 ..., disktype=ssd,kubernetes.io/arch=arm64,kubernetes.io/hostname=k8s-node01
</code></pre>
<h3 id="软策略">软策略</h3>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ngx
name: ngx
spec:
replicas: 2
selector:
matchLabels:
app: ngx
template:
metadata:
labels:
app: ngx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 10
preference:
matchExpressions:
- key: disktype
operator: In
values:
- hdd
containers:
- image: nginx:alpine-arm64
name: nginx
</code></pre>
<p>软策略就是,第一选择是 <code>node label disktype=hdd</code> 的节点,如果没有,就采用默认 scheduler 的调度策略,没有强制性。</p>
<pre><code class="language-shell"># kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ngx-d4754b6fd-lr96g 1/1 Running 0 2m55s 10.244.2.13 k8s-node02 <none> <none>
ngx-d4754b6fd-ns7hs 1/1 Running 0 2m55s 10.244.1.28 k8s-node01 <none> <none>
</code></pre>
<p><code>operator</code> 提供如下几种操作:</p>
<ul>
<li>In:label 的值在某个列表中</li>
<li>NotIn:label 的值不在某个列表中</li>
<li>Gt:label 的值大于某个值</li>
<li>Lt:label 的值小于某个值</li>
<li>Exists:某个 label 存在</li>
<li>DoesNotExist:某个 label 不存在</li>
</ul>
<blockquote>
<p>如果<code>nodeSelectorTerms</code>下面有多个选项的话,满足任何一个条件就可以了;如果<code>matchExpressions</code>有多个选项的话,则必须同时满足这些条件才能正常调度 POD。</p>
</blockquote>
<h1 id="污点和容忍">污点和容忍</h1>
<p>在 Kubernetes 中,节点亲和性 <code>NodeAffinity</code> 是 Pod 上定义的一种属性,能够使 <code>Pod</code> 按我们的要求调度到某个节点上,而 <code>Taints</code>(污点) 则恰恰相反,它是 <code>Node</code> 上的一个属性,可以让 Pod 不能调度到带污点的节点上,甚至会对带污点节点上已有的 Pod 进行驱逐。当然,对应的 <code>Kubernetes</code> 可以给 <code>Pod</code> 设置 <code>Tolerations</code>(容忍) 属性来让 <code>Pod</code> 能够容忍节点上设置的污点,这样在调度时就会忽略节点上设置的污点,将 <code>Pod</code> 调度到该节点。一般时候 <code>Taints</code> 通常与 <code>Tolerations</code> 配合使用。</p>
<p><img src="https://img2020.cnblogs.com/blog/828019/202112/828019-20211223173118370-495260349.png" alt="image-20211217165001702" loading="lazy"></p>
<h2 id="污点taints">污点(Taints)</h2>
<h3 id="查看污点">查看污点</h3>
<p><strong>查看node 的污点</strong></p>
<pre><code class="language-shell"># kubectl describe nodes k8s-master
...
Taints: node-role.kubernetes.io/master:NoSchedule
...
也可通过下面操作查看:
# kubectl get nodes k8s-master -o go-template={{.spec.taints}}
]
</code></pre>
<p>污点内容一般组成为 key、value 及一个 effect 三个元素,表现为:</p>
<pre><code class="language-shell"><key>=<value>:<effect>
</code></pre>
<p>这里的 value 可以为空,表现形式为:</p>
<pre><code class="language-shell">node-role.kubernetes.io/master:NoSchedule
- key: node-role.kubernetes.io/master
- value: 空
- effect: NoSchedule
</code></pre>
<h3 id="设置污点">设置污点</h3>
<p>一般我们需要想要设置某个节点只允许特定的 <code>Pod</code> 进行调度,这时候就得对节点设置污点,可以按 <code>kubectl taint node key=value</code> 格式进行设置,其中 <code>effect</code> 可取值如下:</p>
<ul>
<li><strong>PreferNoSchedule:</strong> 尽量不要调度。</li>
<li><strong>NoSchedule:</strong> 一定不能被调度。</li>
<li><strong>NoExecute:</strong> 不仅不会调度, 还会驱逐 Node 上已有的 Pod。</li>
</ul>
<p>一般时候我们设置污点,就像下面例子一样对齐进行设置:</p>
<pre><code class="language-bash">## 设置污点并不允许 Pod 调度到该节点
$ kubectl taint node k8s-master key1=value1:NoSchedule
## 设置污点尽量阻止污点调度到该节点
$ kubectl taint node k8s-master key2=value2:PreferNoSchedule
## 设置污点,不允许普通 Pod 调度到该节点,且将该节点上已经存在的 Pod 进行驱逐
$ kubectl taint node k8s-master key3=value3:NoExecute
</code></pre>
<h3 id="删除污点">删除污点</h3>
<p>上面说明了如何对 <code>Node</code> 添加污点阻止 <code>Pod</code> 进行调度,下面再说一下如何删除节点上的污点,可以使用下面命令:</p>
<pre><code class="language-bash">kubectl taint node -
</code></pre>
<p>上面语法和创建污点类似,不过需要注意的是删除污点需要知道 key 和最后面设置一个 "-" 两项将污点删除,示例如下:</p>
<p>为了方便演示,先给节点设置污点:</p>
<pre><code class="language-bash">## 设置污点1
# kubectl taint node k8s-master key1=value1:PreferNoSchedule
node/k8s-master tainted
## 设置污点2
# kubectl taint node k8s-master key2=value2:NoSchedule
node/k8s-master tainted
## 设置污点3,并且不设置 value
# kubectl taint node k8s-master key2=:PreferNoSchedule
node/k8s-master tainted
</code></pre>
<p>查看污点,可以看到上面设置的三个值:</p>
<pre><code class="language-bash"># kubectl describe nodes k8s-master
...
Taints: key2=value2:NoSchedule
node-role.kubernetes.io/master:NoSchedule
key1=value1:PreferNoSchedule
key2:PreferNoSchedule
...
</code></pre>
<p>然后删除污点</p>
<pre><code class="language-bash">## 删除污点,可以不指定 value,指定 值就可删除该 key 的污点
# kubectl taint node k8s-master key1:PreferNoSchedule-
## 也可以根据 key 直接将该 key2 的所有 都删除:
# kubectl taint node k8s-master key2-
</code></pre>
<p>再次查看污点,可以看到以上污点都被删除:</p>
<pre><code class="language-bash"># kubectl describe nodes k8s-master
...
Taints: node-role.kubernetes.io/master:NoSchedule
...
</code></pre>
<h2 id="容忍toleratints">容忍(toleratints)</h2>
<h3 id="pod-设置容忍">Pod 设置容忍</h3>
<p>为了使某些 <code>Pod</code> 禁止调度到某些特定节点上,就可以对节点设置污点 <code>taints</code>。当然,如果希望有些 <code>Pod</code> 能够忽略节点的污点,继续能够调度到该节点,就可以对 <code>Pod</code> 设置容忍,让 <code>Pod</code> 能够容忍节点上设置的污点,例如:</p>
<p><strong>对一个节点设置污点:</strong></p>
<pre><code class="language-bash">kubectl taint node k8s-node01 key=value:NoSchedule
</code></pre>
<p>对于Pod 设置容忍, 以下两种方式都可以:</p>
<pre><code class="language-bash">## 容忍的 key、value 和对应 effect 也必须和污点 taints 保持一致
......
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
## 容忍 tolerations 的 key 和要污点 taints 的 key 一致,且设置的 effect 也相同,不需要设置 value
......
tolerations:
- key: "key"
operator: "Exists"
effect: "NoSchedule"
</code></pre>
<h3 id="node-和-pod-对于污点与容忍基本概念">Node 和 Pod 对于污点与容忍基本概念</h3>
<p><font size="5">概念</font></p>
<ul>
<li>一个 node 可以有多个污点;</li>
<li>一个 pod 可以有多个容忍;</li>
<li>kubernetes 执行多个污点和容忍方法类似于过滤器</li>
</ul>
<p>如果一个 node 有多个污点,且 pod 上也有多个容忍,只要 pod 中容忍能包含 node 上设置的全部污点,就可以将 pod 调度到该 node上。如果 pod 上设置的容忍不能够包含 node 上设置的全部污点,且 node 上剩下不能被包含的污点 effect 为 PreferNoSchedule,那么也可能会被调度到该节点。</p>
<p><font size="5">注意</font></p>
<p><font color="blue">当 pod 总存在 容忍,首先 pod 会选择没有污点的节点,然后再次选择容忍污点的节点。</font></p>
<ul>
<li>如果 node 上带有污点 effect 为 NoSchedule,而 pod 上不带响应的容忍,kubernetes 就不会调度 pod 到这台 node 上。</li>
<li>如果 Node 上带有污点 effect 为 PreferNoShedule,这时候 Kubernetes 会努力不要调度这个 Pod 到这个 Node 上。</li>
<li>如果 Node 上带有污点 effect 为 NoExecute,这个已经在 Node 上运行的 Pod 会从 Node 上驱逐掉。没有运行在 Node 的 Pod 不能被调度到这个 Node 上。 <font color="blue">一般使用与当某个节点处于 NotReady 状态下,pod 迅速在其他正常节点启动。</font></li>
</ul>
<h3 id="deployment-中设置容忍">Deployment 中设置容忍</h3>
<p>在 kubernetes 中 deployment 设置容忍,示例如下:</p>
<pre><code class="language-yaml">apiVersion: apps/vl
kind: Deployment
metadata:
name: example
spec:
replicas: 5
template:
spec:
......
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
</code></pre>
<h3 id="设置容忍时间">设置容忍时间</h3>
<p>正常情况下, 如果一个污点带有 <code>effect=NoExecute</code> 被添加到了这个 <code>Node</code>。那么不能容忍这个污点的所有 <code>Pod</code> 就会立即被踢掉。而带有容忍标签的 <code>Pod</code> 就不会踢掉。然而,一个带有 <code>effect=Noexecute</code> 的容忍可以指定一个 <code>tolerationSeconds</code> 来指定当这个污点被添加的时候在多长时间内不被踢掉。例如:</p>
<pre><code class="language-yaml">tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "Noexecute"
tolerationSeconds: 3600
</code></pre>
<blockquote>
<p>如果这个 Pod 已经在这个带污点且 effect 为 NoExecute 的 node 上。这个 pod 可以一直运行到 3600s 后再被踢掉。如果这时候 Node 的污点被移除了,这个 Pod 就不会被踢掉。</p>
</blockquote>
<h3 id="容忍示例">容忍示例</h3>
<p><code>Operator</code> 默认是 <code>Equal</code>,可设置为 <code>Equal</code> 与 <code>Exists</code> 两种,按这两种进行示例:</p>
<p><font size="5">Operator 是 Exists</font></p>
<p><strong>容忍任何污点</strong></p>
<p>例如一个空的key,将匹配所有的key、value、effect。即容忍任何污点。</p>
<pre><code class="language-yaml">tolerations:
- operator: "Exists"
</code></pre>
<p><strong>容忍某 key 值的污点</strong></p>
<p>例如一个空的 effect,并且 key 不为空,那么将匹配所有与 key 相同的 effect:</p>
<pre><code class="language-yaml">tolerations:
- key: "key"
operator: "Exists"
</code></pre>
<p><font size="5">Operator 是 Equal</font></p>
<p><strong>node 上有一个污点</strong></p>
<p>Node 和 Pod 的 key 为 key1、value1 与 effect 相同则能调度:</p>
<pre><code class="language-yaml">#污点
key1=value1:NoSchedule
#Pod设置
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
</code></pre>
<p><strong>node 上有多个污点</strong></p>
<p>Node 的污点的 key、value、effect 和 Pod 容忍都相同则能调度:</p>
<pre><code class="language-yaml"># 设置污点
key1=value1:NoSchedule
key2=value2:NoExecute
# Pod设置容忍
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key2"
operator: "Equal"
value: "value2"
effect: "NoExecute"
</code></pre>
<p>Node 的污点和 Pod 的大部分都相同,不同的是 Node 污点 effect 为 PreferNoSchedule 的,可能会调度:</p>
<pre><code class="language-yaml"># 污点
key1=value1:NoSchedule
key2=value2:NoExecute
key3=value3:PreferNoSchedule
# Pod设置容忍
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key2"
operator: "Equal"
value: "value2"
effect: "NoExecute"
</code></pre>
<p>Node 的污点和 Pod 的大部分都相同,不同的是 Node 污点 effect 为 NoSchedule 和 NoExecute 的,不会被调度:</p>
<pre><code class="language-yaml"># 污点
key1=value1:NoSchedule
key2=value2:NoExecute
key3=value3:PreferNoSchedule
# Pod设置容忍
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key3"
operator: "Equal"
value: "value3"
effect: "PreferNoSchedule"
</code></pre>
<p><strong>对比理解 Exists 和 Equal 之间的区别:</strong></p>
<ul>
<li>Exists 是包含,Equal 是等于,Exists 使用范围更广,而 Equal 则是精准匹配。</li>
<li>当污点中存在 NoExecute 时,而容忍中不存在 NoExecute时,不会被调度到该节点。</li>
<li>Exists 可以不写 value , 而 Equal 则一定要指定对应的 value</li>
</ul>
<h1 id="污点驱逐">污点驱逐</h1>
<blockquote>
<p>在使用 kubernetes 时,会遇到 某个 node 节点明明已经 宕机了,查看 node 状态从 Ready 状态变为 NotReady 状态,但是 节点所在的 pod 却已经处于 running 状态,过了很长一段时间才会转为 Terminating 状态,这是为什么呢?</p>
</blockquote>
<p>污点是对于 node 节点来讲,如果 node 节点 effect 设置为 NoExecute ,它会影响节点上已经运行的 Pod,如下所示:</p>
<ul>
<li>立即将没有匹配容忍的 pod 驱逐。</li>
<li>设置容忍但是没有指定 tolerationSeconds 参数的,那么该容忍永久生效,不会被驱逐。</li>
<li>设置容忍但是有指定 tolerationSeconds 参数的,那么在指定的时间内容忍有效,超过指定时间后将被剔除。 (pod 默认设置,tolerationSeconds = 300s)</li>
</ul>
<p>此外,当某些条件为 true 时,节点控制器会自动污染节点。内置以下污点:</p>
<table>
<thead>
<tr>
<th>key</th>
<th>注释</th>
</tr>
</thead>
<tbody>
<tr>
<td>node.kubernetes.io/not-ready</td>
<td>节点尚未准备好。这对应于 NodeCondition Ready 为 false。</td>
</tr>
<tr>
<td>node.kubernetes.io/unreachable</td>
<td>无法从节点控制器访问节点。这对应于 NodeCondition Ready 为 Unknown。</td>
</tr>
<tr>
<td>node.kubernetes.io/out-of-disk</td>
<td>节点磁盘不足。</td>
</tr>
<tr>
<td>node.kubernetes.io/memory-pressure</td>
<td>节点有内存压力。</td>
</tr>
<tr>
<td>node.kubernetes.io/disk-pressure</td>
<td>节点有磁盘压力。</td>
</tr>
<tr>
<td>node.kubernetes.io/network-unavailable</td>
<td>节点的网络不可用。</td>
</tr>
<tr>
<td>node.kubernetes.io/unschedulable</td>
<td>节点不可调度。</td>
</tr>
<tr>
<td>node.cloudprovider.kubernetes.io/uninitialized</td>
<td>当 kubelet 从 "外部" 云提供程序开始时,此污点在节点上设置为将其标记为不可用。来自 cloud-controller-manager 的控制器初始化此节点后,kubelet 删除此污点。</td>
</tr>
</tbody>
</table>
<p>通过上面知识的铺垫,当一个节点宕机时,kubernetes集群会给它打上什么样的污点呢?</p>
<p>一个 Ready 状态的节点</p>
<pre><code class="language-shell">#kubectl get node k8s-node02 -o go-template={{.spec.taints}}
<no value>
</code></pre>
<p>一个 NotReady 状态的节点</p>
<pre><code class="language-bash">#kubectl get node k8s-node02 -o go-template={{.spec.taints}}
map]
</code></pre>
<p>处于 NotReady 状态的节点被打上了下面两个污点:</p>
<pre><code class="language-bash">Taints: node.kubernetes.io/unreachable:NoExecute
node.kubernetes.io/unreachable:NoSchedule
</code></pre>
<p>接下来测试 kubernetes 集群会给 Pod 分配什么样的容忍。</p>
<pre><code class="language-bash">#kubectl get po nginx-745b4df97d-mgdmp -o yaml
...
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300# 300/60=5min
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300 # 300/60=5min
...
</code></pre>
<p>看到这里,Pod 的失效机制已经很明白了, 当 node 节点处于 NotReady 状态或者 unreachable 状态时,Pod 会容忍它 5 分钟,然后被驱逐。而这 5 分钟内就算 Pod 处于 running 状态,也是无法正常提供服务的。因此,可以在 yaml 清单中 手动指明 0 容忍,清单文件如下:</p>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 4
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 0
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 0
containers:
- image: nginx:alpine
name: nginx
</code></pre>
<p>生成Pod</p>
<pre><code class="language-bash">#kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-84f6f75c6-c76fm 1/1 Running 0 6s 10.244.3.16 k8s-node02 <none> <none>
nginx-84f6f75c6-hsxq5 1/1 Running 0 6s 10.244.3.15 k8s-node02 <none> <none>
nginx-84f6f75c6-wkt52 1/1 Running 0 6s 10.244.1.63 k8s-node01 <none> <none>
nginx-84f6f75c6-xmkjs 1/1 Running 0 6s 10.244.3.17 k8s-node02 <none> <none>
</code></pre>
<p>接下来强制关闭 k8s-node02 节点,查看 Pod是否转移。</p>
<pre><code class="language-bash">#kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-84f6f75c6-c76fm 1/1 Terminating 0 116s 10.244.3.16 k8s-node02 <none> <none>
nginx-84f6f75c6-csqf4 1/1 Running 0 13s 10.244.1.66 k8s-node01 <none> <none>
nginx-84f6f75c6-hsxq5 1/1 Terminating 0 116s 10.244.3.15 k8s-node02 <none> <none>
nginx-84f6f75c6-r2v4p 1/1 Running 0 13s 10.244.1.64 k8s-node01 <none> <none>
nginx-84f6f75c6-v4knq 1/1 Running 0 13s 10.244.1.65 k8s-node01 <none> <none>
nginx-84f6f75c6-wkt52 1/1 Running 0 116s 10.244.1.63 k8s-node01 <none> <none>
nginx-84f6f75c6-xmkjs 1/1 Terminating 0 116s 10.244.3.17 k8s-node02 <none> <none>
</code></pre>
<p>在 node 节点转为 NotReady 状态后,Pod 立刻进行了转移。这是通过 在yaml清单文件中明确指定 容忍时间。还可以直接修改 apiserver 配置来修改默认容忍时间。</p>
<pre><code class="language-bash">vim /etc/kubernetes/manifests/kube-apiserver.yaml
...
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=192.168.1.11
- --default-not-ready-toleration-seconds=1 # 新增行
- --default-unreachable-toleration-seconds=1# 新增行
...
</code></pre>
<p>修改保存后, <code>kube-apiserver-k8s-master </code>pod 会自动重载最新配置。</p>
<pre><code class="language-bash">#kubectl get po nginx-84f6f75c6-wkt52 -o yaml
...
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 0
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 0
...
</code></pre>
<p>对于小型集群,可以直接设置全局变量。</p>
<p><font color="red">注意:当kubernetes集群只有一个 node 节点时,无法做到 Pod 转移,因为 Pod 已经无路可退了。</font></p>
<p><strong>参考链接:</strong><br>
http://www.mydlq.club/article/69/</p>
<center><font style="font-weight: bold; color: rgba(255, 0, 0, 1)">--- EOF ---</font></center><br><br>
来源:https://www.cnblogs.com/hukey/p/15724506.html
頁:
[1]