第10章-其他控制器-以及标签表达式
原创
本博客原创文章,转载请注明出处
- name: 原创
desc: 本博客原创文章,转载请注明出处
bgColor: '#F0DFB1'
textColor: '#1078E6'
2
3
4
# 第10章-其他控制器
本章要点 |
---|
了解 DaemonSet 的作用,掌握其创建和删除 |
了解四种控制器的作用,以及它们之间的区别 |
掌握标签表达式(选择算符)的语法和使用 |
# 11. 控制器DaemonSet(DS)
# 1.11.1 概念
DaemonSet 和 Deployment 一样,都是用于控制 Pod 的控制器。两者的区别:
- Deployment 运行多个 Pod,这些 Pod 被随机调度到任意工作节点上运行,这些 Pod 一般和业务有关
- DaemonSet 在每个节点上只运行一个 Pod,这些 Pod 一般和集群自身有关
例如,在命名空间kube-system
中有几个默认的 DaemonSet 控制器:
kubectl get daemonsets -n kube-system
kubectl get pods -n kube-system -o wide
2
当前各有两个 DaemonSet,它们控制的 Pod 副本数皆为三个:
- 控制器
kube-proxy
是在部署集群时自动创建的,它会在每个节点上运行一个带有相应前缀的 Pod,用于维持节点之间的通信 - 控制器
calico-node
则是在安装 calico 网络插件时创建的,它同样在每个节点上运行一个 Pod,用于实现 Pod 之间的跨主机通信
DaemonSet 一般用于监控主机信息、或实现某些集群功能等。单个 DaemonSet 只会为每个节点创建一个 Pod,有几个节点就有几个 Pod,单个节点上的 Pod 不会多于两个。
# 1.21.2 创建和删除DaemonSet
DaemonSet 无法直接通过命令行创建,只能先编写 yaml 配置文件然后apply
。DaemonSet 的 yaml 配置项和 Deployment 有点类似,但是内容比较少,编写起来相对简单。
1、先基于 Deployment 快速生成一个 yaml 配置文件,然后使用 vim 对其进行编辑:
kubectl create deployment ds-test --image nginx --dry-run=client -o yaml > ds-test.yaml
vim ds-test.yaml
2
3
2、两者的 yaml 文件有四个不同点,我们需要进行编辑或删减:
- 将
kind
字段改为DaemonSet
- DaemonSet 没有 “副本数” 这个概念,因为每个节点上至多只有一个 Pod,所以删除
spec.replicas
字段 - 删除
spec.strategy
字段 - 删除最后一行的
status
字段
还有一件事,记得添加镜像下载策略IfNotPresent
。
修改过后的 yaml 配置文件如下所示:
apiVersion: apps/v1
kind: DaemonSet # 修改资源名称
metadata:
creationTimestamp: null
labels:
app: ds-test
name: ds-test
spec: # 删除副本数 replicas 和策略 strategy
selector:
matchLabels:
app: ds-test
template:
metadata:
creationTimestamp: null
labels:
app: ds-test
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent # 镜像下载策略(不是必须的)
name: nginx
resources: {}
# 删除 status
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
3、创建这个控制器:
kubectl apply -f ds-test.yaml
创建成功。
4、查看控制器以及所创建的 Pod:
kubectl get daemonsets -o wide
kubectl get pods -o wide
2
你可能会感到困惑,为什么只有两个 Pod?
节点 worker01 和 worker02 都运行了由ds-test
创建出来的 Pod,那么 master 为什么没有呢?
还记得我们在第 7 章的 “4.1” 小节中讲过的污点吗,master 节点默认是具有污点的。
5、查看 master 节点的污点:
kubectl describe nodes www.k10.com | grep Taint
由于 master 具有污点,而 DaemonSet 中的 Pod 模板没有配置容忍污点,所以这些 Pod 不会在 master 上运行。
而对于之前提到的 DaemonSet kube-proxy
和calico-node
,这两个控制器已经为他们的 Pod 配置过容忍污点了。你可以通过以下命令查看 DaemonSet kube-proxy
的配置信息:
kubectl get -n kube-system daemonsets kube-proxy -o yaml | less
# 之后按字母 q 键即可退出视图
2
3
找到配置项spec.template.spec.tolerations
即可看到有关于容忍污点的设置,这个控制器的 Pod 模板通过operator: Exists
来容忍所有污点。
6、删除刚刚创建的 DaemonSet:
kubectl delete daemonsets ds-test
# 或
kubectl delete -f ds-test.yaml
2
3
4
# 22. 控制器ReplicationController(RC)
RC 的作用和使用方式与 Deployment 基本一致。
1、查看 RC:
# 简写
kubectl get rc
# 全称
kubectl get replicationcontrollers
2
3
4
5
2、RC 也无法直接通过命令行来创建,所以要先生成一个 Deployment 的配置文件,然后编辑:
kubectl create deployment rc-test --image nginx --dry-run=client -o yaml > rc-test.yaml
vim rc-test.yaml
2
3
3、RC 的配置项和 Deployment 基本相同,需要修改的点:
- RC 的
apiVersion
应该为v1
- 对应的
kind
(资源名称) - RC 的
spec.selector
字段下没有matchLabels
字段,可以直接填写标签 - 没有
spec.strategy
字段
修改过后:
# apiVersion: apps/v1
# kind: Deployment
apiVersion: v1
kind: ReplicationController
metadata:
creationTimestamp: null
labels:
app: rc-test
name: rc-test
spec:
replicas: 1
selector:
# matchLabels: 没有该字段
app: rc-test
# strategy: {} 没有该字段
template:
metadata:
creationTimestamp: null
labels:
app: rc-test
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent # 镜像下载策略
name: nginx
resources: {}
status: {}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
4、创建这个 RC:
kubectl apply -f rc-test.yaml
5、编辑 RC 的副本数:
kubectl scale rc rc-test --replicas=5
6、变更 RC 的镜像:
kubectl set image rc rc-test nginx=nginx:1.7.9
7、RC 暂不支持查看镜像历史变更记录:
kubectl rollout history rc rc-test
没有历史变更记录,自然也不支持回滚。
8、删除 RC:
kubectl delete rc rc-test
# 或
kubectl delete -f rc-test.yaml
2
3
4
你看出 RC 和 Deployment 之间的区别了吗?
- RC 不支持策略字段
spec.strategy
,说明不支持滚动更新 - 也不支持镜像历史变更记录,更没有回滚
- ......等
其实从 RC 的apiVersion
就能够看出一些眉目。
# 33. 控制器ReplicaSet(RS)
RS 的名称和 RC 很像,他们俩有什么关系?——RS 是 RC 的升级版,是下一代的 RC。
1、查看 RC:
# 简写
kubectl get rs
# 全称
kubectl get replicasets
2
3
4
5
2、RS 也必须通过 yaml 来创建......
kubectl create deployment rs-test --image nginx --dry-run=client -o yaml > rs-test.yaml
vim rs-test.yaml
2
3
3、RS 文件需要修改的点:
- 修改资源名称
kind
- 删除字段
spec.strategy
修改过后:
# 别忘了添加镜像下载策略
apiVersion: apps/v1
kind: ReplicaSet
metadata:
creationTimestamp: null
labels:
app: rs-test
name: rs-test
spec:
replicas: 1
selector:
matchLabels:
app: rs-test
# strategy: {} # 没有该字段
template:
metadata:
creationTimestamp: null
labels:
app: rs-test
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
resources: {}
status: {}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
4、创建这个 RS:
kubectl apply -f rs-test.yaml
5、编辑 RS 的副本数:
kubectl scale rs rs-test --replicas=5
6、变更 RS 的镜像:
kubectl set image rs rs-test nginx=nginx:1.8
RS 同样不支持镜像的历史变更记录。
7、删除 RS:
kubectl delete rs rs-test
# 或
kubectl delete -f rs-test.yaml
2
3
4
RS 也不支持滚动更新,官方文档原话:若想要以可控的方式更新 Pod 的规模,可以使用 Deployment 资源,因为 ReplicaSet 并不直接支持滚动更新。
# 44. 四种控制器之间的区别
其实 k8s 中的控制器不止这四种,更多的控制器将在后续章节中进行介绍。
控制器 | apiVersion | 是否支持标签表达式 | 简要说明 |
---|---|---|---|
Deployment | apps/v1 | ✔ | 用于控制业务 Pod 的主要控制器 |
DaemonSet | apps/v1 | ✔ | 用于控制集群 Pod 的主要控制器 |
ReplicaSet | apps/v1 | ✔ | 一般不会直接使用 RS。 --- RS 是 Deploy 的一部分,当你创建一个 Deploy 的时候,这个 Deploy 的内部其实隐式包含了一个 RS。 --- RS 可用于维持 Pod 数量,并提供了 Pod 的扩缩功能。 --- 而 Deploy 用于操控这个内部 RS,同时为其提供更多的功能特性,例如镜像历史变更记录、滚动更新等。 |
ReplicationController | v1 | ✖ | 基本被淘汰,请改为使用 ReplicaSet(下一代的 RC) |
学习更多
# 55. 标签表达式(选择算符)
在使用 RC 的时候,它的spec.selector
字段是这样的:
...
spec:
selector:
<键>: <值>
2
3
4
而在使用 Deploy、DaemonSet 和 RS 的时候,它们的spec.selector
字段是这样的:
...
spec:
selector:
matchLabels:
<键>: <值>
2
3
4
5
一般情况下,我们可以通过一个或多个标签来追踪 Pod。但如果某些 Pod 的标签是run=abc
,而另一些 Pod 的标签是run=xyz
,这两批 Pod 具有相同的键,不同的值,这该如何匹配呢?
你可能会这样想:
spec:
selector:
matchLabels:
run: abc
run: xyz
2
3
4
5
这个 Deployment 可以被成功创建,但是当你查看其信息时你会发现,由于两个匹配键run
的名称重复了,所以前一个规则会被覆盖。
匹配 “同键同值” 很容易,但匹配 “同键不同值” 却无法实现。
又或者,你想匹配的 Pod 必须不带有status=bad
标签,这又该如何实现呢?
- 匹配某个标签很容易
- 但 拒绝某个标签 却很难
# 5.15.1 控制器追踪
在 Deploy、DaemonSet 和 RS 中,则可以通过selector.matchLabels
来匹配单个标签的键值:
...
spec:
selector:
matchLabels:
<键>: <值>
2
3
4
5
如果你想实现 “匹配同键不同值” 或者 “拒绝某个标签” 等功能,则需要用到标签表达式(又被称为选择算符):
key
:标签键名operator
:要进行的匹配操作,In
表示匹配其中任意一个values
:多个标签值
...
spec:
selector:
matchExpressions:
- { key: run, operator: In, values: [abc, xyz] }
2
3
4
5
以上标签表达式的意思是:匹配run=abc
和run=xyz
中的任意一个。
# 5.1.15.1.1 示例一(同键不同值)
1、基于之前的示例,编写以下 yaml 文件:
- 操作
In
,匹配run=abc
或run=xyz
或run=jkl
标签 - 操作
NotIn
,不匹配(拒绝)run=jkl
标签
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: d1
name: d1
spec:
replicas: 3
selector:
# matchLabels:
# run: abc
# run: xyz
matchExpressions:
- { key: run, operator: In, values: [abc, xyz, jkl] }
- { key: run, operator: NotIn, values: [jkl] }
strategy: {}
template:
metadata:
labels:
run: abc
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
resources: {}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
你可能会很疑惑,为什么这里既要接受run=jkl
又要拒绝run=jkl
标签呢?——如果只匹配abc
和xyz
的话,那么就算你不拒绝run=jkl
,控制器也追踪不到这个 Pod。
为了让示例更加清晰,这里通过run=jkl
来追踪 Pod,同时拒绝这个标签,看看控制器会做出什么反应。
2、创建这个控制器:
kubectl apply -f d1.yaml
创建成功,现在这个 Deployment 将会根据标签表达式来追踪 Pod。
3、修改其中某个 Pod 的标签为run=xyz
,观察控制器还能否追踪到:
kubectl label pods <Pod名称> run=xyz --overwrite=true
这里有个小知识点,由控制器所创建出来的 Pod,这些 Pod 的标签默认是只读的,不允许被修改。如果你想修改只读标签,则需要添加--overwrite=true
选项,将修改标签的权限设置为允许。
当第一个 Pod 的标签被修改为run=xyz
之后,一切正常,控制器的副本数还是3
个。控制器并没有丢失这个 Pod,然后另外创建一个新的 Pod,而是正确地追踪到了run=xyz
标签。
4、然后修改其中某个 Pod 的标签为run=jkl
:
- 由于
In
(匹配)操作的存在,所以控制器会追踪这个 Pod - 同时又由于
NotIn
(不匹配)操作的存在,所以控制器会拒绝这个 Pod
到底谁的优先级更高?
kubectl label pods <Pod名称> run=jkl --overwrite=true
答案很明了,控制器放弃了这个 Pod,并另外创建了一个新的 Pod。
与大多数计算机规则一样,“拒绝” 的优先级总是大于 “允许”。
另外,如果你不喜欢这种一字排开的 yaml 编写格式,也可以将其转换为标准的 yaml 格式:
spec:
selector:
matchExpressions:
# - { key: run, operator: In, values: [abc, xyz, jkl] }
# - { key: run, operator: NotIn, values: [jkl] }
- key: run
operator: In
values:
- abc
- xyz
- jkl
- key: run
operator: NotIn
values:
- jkl
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我个人还是比较喜欢一字排开的那种格式。
# 5.1.25.1.2 示例二(某个键是否存在/不存在)
除了In
(匹配)和NotIn
(不匹配)操作之外,选择算符还支持Exists
(存在)和DoesNotExist
(不存在)这两种匹配操作。
注意
Exists
后面有字母s
,而DoesNotExist
后面是没有的。
1、编写以下 yaml 文件:
- 追踪标签键名为
healthy
的 Pod - 拒绝带有
bad
标签的 Pod
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: d2
name: d2
spec:
replicas: 3
selector:
matchExpressions:
- { key: healthy, operator: Exists}
- { key: bad, operator: DoesNotExist}
strategy: {}
template:
metadata:
labels:
healthy: ""
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
resources: {}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2、运行这个控制器:
kubectl apply -f d2.yaml
可以看到bad
规则前面具有一个符号!
,有编程基础的人应该都知道这是 “非”(取反)运算符,而!bad
的意思就是拒绝bad
标签。
3、修改任意 Pod 的标签healthy
为任意值:
kubectl label pods <Pod名称> healthy=good --overwrite=true
一切正常,控制器可以追踪这个 Pod。
4、为任意 Pod 添加bad
标签:
kubectl label pods <Pod名称> bad=no
和上一个示例相同,“拒绝” 的优先级大于 “允许”。
# 5.25.2 Pod的节点亲和性
在第 7 章 “Pod 与节点” 当中,我们曾通过spec.nodeSelector
来为 Pod 指定节点位置。例如:
# 这个 Pod 将运行在具有 look=good 标签的节点上
spec:
nodeSelector:
look: good
2
3
4
Pod 中的spec.nodeSelector
字段和控制器中的spec.selector.matchLabels
字段一样,只能匹配单个标签键值。
如果你想在 Pod 中使用标签表达式(选择算符)来指定节点位置,则需要用到节点亲和性:
apiVersion: v1
kind: Pod
metadata:
labels:
run: pod1
name: pod1
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- { key: look, operator: In, values: [good] }
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: pod1
resources: {}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
如你所见,Pod 使用标签表达式的 yaml 语法层级较为复杂。
Pod 亲和性的使用场景较少,用得最多的还是spec.nodeSelector
。所以你只需要做一个简单了解,知道有这个东西即可。
# 66. 小结
虽然本章讲了很多,但只有少部分内容是需要你记住和掌握的:
- DaemonSet 概念
- 四种控制器之间的区别
- 创建和删除 DaemonSet
- 通过标签表达式(选择算符)来追踪 Pod
本章内容挺简单的,对于聪明的你来说小菜一碟,去看看练习吧(练习题-8)