某不知名博客 某不知名博客
首页
  • 《vulcat文档》
  • Web安全

    • 《BurpSuite及官方实验室》
    • 《OSWE学习历程》
  • 云原生安全

    • 《Docker命令大全》
    • 《CKS考试学习指南》
    • 《旧-Kubernetes教程》
漏洞库
  • 《渗透工具大全》
  • 《云安全》
事件库
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carsaid

安全界的小学生
首页
  • 《vulcat文档》
  • Web安全

    • 《BurpSuite及官方实验室》
    • 《OSWE学习历程》
  • 云原生安全

    • 《Docker命令大全》
    • 《CKS考试学习指南》
    • 《旧-Kubernetes教程》
漏洞库
  • 《渗透工具大全》
  • 《云安全》
事件库
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前言

  • 学习建议

  • Docker命令大全
  • Kubernetes教程

    • Kubernetes(K8s)学习教程 - 前言
    • 第1章-Kubernetes集群部署
    • 第2章-便捷性设置以及集群插件的安装
    • 第3章-基础操作
    • 第4章-集群升级
    • 第5章-Pod
    • 第6章-Pod生命周期与资源限制
    • 第7章-Pod与节点
    • 第8章-控制器Deployment
    • 第9章-Deployment镜像变更和滚动更新
    • 第10章-其他控制器-以及标签表达式
      • 1. 控制器DaemonSet(DS)
        • 1.1 概念
        • 1.2 创建和删除DaemonSet
      • 2. 控制器ReplicationController(RC)
      • 3. 控制器ReplicaSet(RS)
      • 4. 四种控制器之间的区别
      • 5. 标签表达式(选择算符)
        • 5.1 控制器追踪
        • 5.1.1 示例一(同键不同值)
        • 5.1.2 示例二(某个键是否存在/不存在)
        • 5.2 Pod的节点亲和性
      • 6. 小结
    • 第11章-控制器与节点驱逐
    • 暂缓更新
    • 练习题

    • 常用命令及yaml配置

  • CKS教程

  • 云原生安全
  • Kubernetes教程
carsaid
2023-11-22
目录

第10章-其他控制器-以及标签表达式

原创

本博客原创文章,转载请注明出处

- name: 原创
  desc: 本博客原创文章,转载请注明出处
  bgColor: '#F0DFB1'
  textColor: '#1078E6'
1
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
1
2

当前各有两个 DaemonSet,它们控制的 Pod 副本数皆为三个:

  • 控制器kube-proxy是在部署集群时自动创建的,它会在每个节点上运行一个带有相应前缀的 Pod,用于维持节点之间的通信
  • 控制器calico-node则是在安装 calico 网络插件时创建的,它同样在每个节点上运行一个 Pod,用于实现 Pod 之间的跨主机通信
Not Found Image

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
1
2
3

2、两者的 yaml 文件有四个不同点,我们需要进行编辑或删减:

  • 将kind字段改为DaemonSet
  • DaemonSet 没有 “副本数” 这个概念,因为每个节点上至多只有一个 Pod,所以删除spec.replicas字段
  • 删除spec.strategy字段
  • 删除最后一行的status字段

还有一件事,记得添加镜像下载策略IfNotPresent。

Not Found Image Not Found Image

修改过后的 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
1
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
1

创建成功。

Not Found Image

4、查看控制器以及所创建的 Pod:

kubectl get daemonsets -o wide
kubectl get pods -o wide
1
2

你可能会感到困惑,为什么只有两个 Pod?

节点 worker01 和 worker02 都运行了由ds-test创建出来的 Pod,那么 master 为什么没有呢?

Not Found Image

还记得我们在第 7 章的 “4.1” 小节中讲过的污点吗,master 节点默认是具有污点的。

5、查看 master 节点的污点:

kubectl describe nodes www.k10.com | grep Taint
1

由于 master 具有污点,而 DaemonSet 中的 Pod 模板没有配置容忍污点,所以这些 Pod 不会在 master 上运行。

Not Found Image

而对于之前提到的 DaemonSet kube-proxy和calico-node,这两个控制器已经为他们的 Pod 配置过容忍污点了。你可以通过以下命令查看 DaemonSet kube-proxy的配置信息:

kubectl get -n kube-system daemonsets kube-proxy -o yaml | less

# 之后按字母 q 键即可退出视图
1
2
3

找到配置项spec.template.spec.tolerations即可看到有关于容忍污点的设置,这个控制器的 Pod 模板通过operator: Exists来容忍所有污点。

Not Found Image

6、删除刚刚创建的 DaemonSet:

kubectl delete daemonsets ds-test

# 或
kubectl delete -f ds-test.yaml
1
2
3
4
Not Found Image

# 22. 控制器ReplicationController(RC)

RC 的作用和使用方式与 Deployment 基本一致。

1、查看 RC:

# 简写
kubectl get rc

# 全称
kubectl get replicationcontrollers
1
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
1
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: {}
1
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
1
Not Found Image

5、编辑 RC 的副本数:

kubectl scale rc rc-test --replicas=5
1
Not Found Image

6、变更 RC 的镜像:

kubectl set image rc rc-test nginx=nginx:1.7.9
1
Not Found Image

7、RC 暂不支持查看镜像历史变更记录:

kubectl rollout history rc rc-test
1

没有历史变更记录,自然也不支持回滚。

Not Found Image

8、删除 RC:

kubectl delete rc rc-test

# 或
kubectl delete -f rc-test.yaml
1
2
3
4
Not Found Image

你看出 RC 和 Deployment 之间的区别了吗?

  • RC 不支持策略字段spec.strategy,说明不支持滚动更新
  • 也不支持镜像历史变更记录,更没有回滚
  • ......等

其实从 RC 的apiVersion就能够看出一些眉目。

# 33. 控制器ReplicaSet(RS)

RS 的名称和 RC 很像,他们俩有什么关系?——RS 是 RC 的升级版,是下一代的 RC。

1、查看 RC:

# 简写
kubectl get rs

# 全称
kubectl get replicasets
1
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
1
2
3

3、RS 文件需要修改的点:

  • 修改资源名称kind
  • 删除字段spec.strategy
Not Found Image

修改过后:

# 别忘了添加镜像下载策略
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: {}
1
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
1
Not Found Image

5、编辑 RS 的副本数:

kubectl scale rs rs-test --replicas=5
1
Not Found Image

6、变更 RS 的镜像:

kubectl set image rs rs-test nginx=nginx:1.8
1
Not Found Image

RS 同样不支持镜像的历史变更记录。

7、删除 RS:

kubectl delete rs rs-test

# 或
kubectl delete -f rs-test.yaml
1
2
3
4
Not Found Image

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)

学习更多

  • 官方文档-Deployment (opens new window)
  • 官方文档-DaemonSet (opens new window)
  • 官方文档-ReplicaSet (opens new window)
  • 官方文档-ReplicationController (opens new window)

# 55. 标签表达式(选择算符)

学习更多

官方文档-标签和选择算符 (opens new window)

在使用 RC 的时候,它的spec.selector字段是这样的:

...
spec:
  selector:
    <键>: <值>
1
2
3
4

而在使用 Deploy、DaemonSet 和 RS 的时候,它们的spec.selector字段是这样的:

...
spec:
  selector:
    matchLabels:
      <键>: <值>
1
2
3
4
5

一般情况下,我们可以通过一个或多个标签来追踪 Pod。但如果某些 Pod 的标签是run=abc,而另一些 Pod 的标签是run=xyz,这两批 Pod 具有相同的键,不同的值,这该如何匹配呢?

你可能会这样想:

spec:
  selector:
    matchLabels:
      run: abc
      run: xyz
1
2
3
4
5
Not Found Image

这个 Deployment 可以被成功创建,但是当你查看其信息时你会发现,由于两个匹配键run的名称重复了,所以前一个规则会被覆盖。

匹配 “同键同值” 很容易,但匹配 “同键不同值” 却无法实现。

Not Found Image

又或者,你想匹配的 Pod 必须不带有status=bad标签,这又该如何实现呢?

  • 匹配某个标签很容易
  • 但 拒绝某个标签 却很难

# 5.15.1 控制器追踪

在 Deploy、DaemonSet 和 RS 中,则可以通过selector.matchLabels来匹配单个标签的键值:

...
spec:
  selector:
    matchLabels:
      <键>: <值>
1
2
3
4
5

如果你想实现 “匹配同键不同值” 或者 “拒绝某个标签” 等功能,则需要用到标签表达式(又被称为选择算符):

  • key:标签键名
  • operator:要进行的匹配操作,In表示匹配其中任意一个
  • values:多个标签值
...
spec:
  selector:
    matchExpressions:
    - { key: run, operator: In, values: [abc, xyz] }
1
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: {}
1
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
1

创建成功,现在这个 Deployment 将会根据标签表达式来追踪 Pod。

Not Found Image

3、修改其中某个 Pod 的标签为run=xyz,观察控制器还能否追踪到:

kubectl label pods <Pod名称> run=xyz --overwrite=true
1

这里有个小知识点,由控制器所创建出来的 Pod,这些 Pod 的标签默认是只读的,不允许被修改。如果你想修改只读标签,则需要添加--overwrite=true选项,将修改标签的权限设置为允许。

当第一个 Pod 的标签被修改为run=xyz之后,一切正常,控制器的副本数还是3个。控制器并没有丢失这个 Pod,然后另外创建一个新的 Pod,而是正确地追踪到了run=xyz标签。

Not Found Image

4、然后修改其中某个 Pod 的标签为run=jkl:

  • 由于In(匹配)操作的存在,所以控制器会追踪这个 Pod
  • 同时又由于NotIn(不匹配)操作的存在,所以控制器会拒绝这个 Pod

到底谁的优先级更高?

kubectl label pods <Pod名称> run=jkl --overwrite=true
1

答案很明了,控制器放弃了这个 Pod,并另外创建了一个新的 Pod。

与大多数计算机规则一样,“拒绝” 的优先级总是大于 “允许”。

Not Found Image

另外,如果你不喜欢这种一字排开的 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

我个人还是比较喜欢一字排开的那种格式。

Not Found Image

# 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: {}
1
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
1

可以看到bad规则前面具有一个符号!,有编程基础的人应该都知道这是 “非”(取反)运算符,而!bad的意思就是拒绝bad标签。

Not Found Image

3、修改任意 Pod 的标签healthy为任意值:

kubectl label pods <Pod名称> healthy=good --overwrite=true
1

一切正常,控制器可以追踪这个 Pod。

Not Found Image

4、为任意 Pod 添加bad标签:

kubectl label pods <Pod名称> bad=no
1

和上一个示例相同,“拒绝” 的优先级大于 “允许”。

Not Found Image

# 5.25.2 Pod的节点亲和性

在第 7 章 “Pod 与节点” 当中,我们曾通过spec.nodeSelector来为 Pod 指定节点位置。例如:

# 这个 Pod 将运行在具有 look=good 标签的节点上
spec:
  nodeSelector:
    look: good
1
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: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

如你所见,Pod 使用标签表达式的 yaml 语法层级较为复杂。

Pod 亲和性的使用场景较少,用得最多的还是spec.nodeSelector。所以你只需要做一个简单了解,知道有这个东西即可。

学习更多

官方文档-Pod 亲和性与反亲和性 (opens new window)

# 66. 小结

虽然本章讲了很多,但只有少部分内容是需要你记住和掌握的:

  • DaemonSet 概念
  • 四种控制器之间的区别
  • 创建和删除 DaemonSet
  • 通过标签表达式(选择算符)来追踪 Pod

本章内容挺简单的,对于聪明的你来说小菜一碟,去看看练习吧(练习题-8)

编辑 (opens new window)
第9章-Deployment镜像变更和滚动更新
第11章-控制器与节点驱逐

← 第9章-Deployment镜像变更和滚动更新 第11章-控制器与节点驱逐→

最近更新
01
API测试笔记
04-30
02
msfvenom
03-29
03
Metasploit
03-29
更多文章>
Theme by Vdoing | Copyright © 2023-2024 Carsaid | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式