04 kubernetes 控制器

ReplicaSet

ReplicaSet 副本控制器。用 Deployments 控制 ReplicaSet ,用 ReplicaSet 控制 Pod 的副本数量。

ReplicaSet 的作用是维护集群中 Pod 数量的稳定。

工作原理

ReplicaSet 是通过一组字段来定义的,包括一个用来可识别可获得的 Pod 集合的运算符,一个用来标明应该维护的副本个数,一个用来指定应该创建新 Pod 以满足副本个数条件时要使用的 Pod 模板。每个 ReplicaSet 都通过根据需要创建和删除 Pod 以使得副本个数达到期望值,进而实现其存在价值。当 ReplicaSet 需要创建新 Pod 时,会使用所提供的 Pod 模板。

ReplicaSet 通过 Pod 上的 metadata.ownerReferences 字段连接到附属 Pod ,该字段给出当前对象的属主资源。ReplicaSet 所获得的 Pod 都在其 ownerReferences 字段中包含了属主 ReplicaSet 的标识信息。正是通过这一连接,ReplicaSet 知道它所维护的 Pod 集合的状态,并据此计划其操作行为。

如何使用

虽然 ReplicaSet 可以独立使用,但它主要被 Deployments 用作协调 Pod 创建、删除和更新的机制。当创建 Deployments 时,会自动创建 ReplicaSet 。

创建一个 ReplicaSet

vim replicaset.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: nginx
    tier: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: nginx
        image: nginx
kubectl create -f replicaset.yaml

可以看到

replicaset.apps/frontend created

查看

kubectl get all
NAME                                    READY   STATUS        RESTARTS   AGE
pod/frontend-4t9sl                      1/1     Running       0          28s
pod/frontend-c85k7                      1/1     Running       0          28s
pod/frontend-j4vd9                      1/1     Running       0          28s

NAME                       DESIRED   CURRENT   READY   AGE
replicaset.apps/frontend   3         3         3       28s

可以看到,创建了一个 replicaset 和 三个 Pod 。这时如果删除一个 Pod ,那么 replicaset 会维持三个 Pod ,所以会创建一个新的 Pod 。

Deployment

一个 Deployment 控制器为 Pods 和 ReplicaSet 提供声明式的更新能力。

Deployment 的使用场景

  • 创建 Deployment 以将 ReplicaSet 上线。ReplicaSet 在后台创建 Pods 。检查 ReplicaSet 的上线状态,查看是否成功。
  • 通过更新 Deployment 的 PodTemplateSpec ,声明 Pod 的新状态。新的 RepicaSet 会被创建,Deployment 以受控速率将 Pod 从旧 ReplicaSet 迁移到新 ReplicaSet 。每个新的 ReplicaSet 都会更新 Deployment 的修订版本。
  • 如果 Deployment 的当前状态不稳定,回滚到较早的 Deployment 版本。每次回滚都会更新 Deployment 的修订版本。
  • 扩大 Deployment 规模以承担更多负载。
  • 暂停 Deployment 以应用对 PodTemplateSpec 所做的多项修改,然后恢复其执行以启动新的上线版本。
  • 使用 Deployment 状态来判断上线过程是否出现停滞。
  • 清理不再需要的 ReplicaSet 。

创建 Deployment

vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
    # deployment 的名称
  name: nginx-deployment
  labels:
    app: nginx
spec:
    # deployment 由 replicas 指定创建 pod 的数量
  replicas: 3
  # deployment 匹配要管理的 Pods
  selector:
    # 根据标签匹配
    matchLabels:
      app: nginx
  # pod 模板
  template:
    metadata:
        # 标签,deployment 会根据这个标签来匹配要管理的 pod
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

创建

kubectl apply -f deployment.yaml
kubectl get all

可以看到,创建了三个 pod

NAME                                    READY   STATUS        RESTARTS   AGE
pod/nginx-deployment-66b6c48dd5-h85lf   1/1     Running       0          3m3s
pod/nginx-deployment-66b6c48dd5-rtm28   1/1     Running       0          3m3s
pod/nginx-deployment-66b6c48dd5-xxjcm   1/1     Running       0          3m3s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   3/3     3            3           3m3s

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deployment-66b6c48dd5   3         3         3       3m3s

调整 pod 的数量,只需要修改 replicas 字段的值。

有状态的应用 StatefulSets

StatefulSet 是用来管理有状态应用的工作负载 API 对象。

StatefulSet 用来管理 Deployment 和扩展一组 Pod ,并且能为这些 Pod 提供序号和唯一性保证。和 Deployment 相同的是,StatefulSet 管理了基于相同容器定义的一组 Pod。不同的是,StatefulSet 为每个 Pod 维护了一个固定的 ID 。这些 Pod 是基于相同的声明来创建的,但是不能相互替换,无论怎么调度,每个 Pod 都有一个永久不变的 ID 。

StatefulSet 和其他控制器使用相同的工作模式。

vim statefulset.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
  name: datadir1
  labels:
    type: local
spec:
  storageClassName: my-storage-class
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/tmp/data1"
---
kind: PersistentVolume
apiVersion: v1
metadata:
  name: datadir2
  labels:
    type: local
spec:
  storageClassName: my-storage-class
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/tmp/data2"
---
kind: PersistentVolume
apiVersion: v1
metadata:
  name: datadir3
  labels:
    type: local
spec:
  storageClassName: my-storage-class
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/tmp/data3"
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx 
  serviceName: "nginx"
  replicas: 3 
  template:
    metadata:
      labels:
        app: nginx 
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: registry.cn-beijing.aliyuncs.com/qingfeng666/nginx:latest
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "my-storage-class"
      resources:
        requests:
          storage: 1Gi
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: my-storage-class
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete

创建

kubectl apply -f statefulset.yaml
kubectl get all

可以看到

NAME                                    READY   STATUS        RESTARTS   AGE
pod/web-0                               1/1     Running       0          2m2s
pod/web-1                               1/1     Running       0          119s
pod/web-2                               1/1     Running       0          116s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/nginx        ClusterIP   None         <none>        80/TCP    2m2s

NAME                   READY   AGE
statefulset.apps/web   3/3     2m2s

查看 pod

kubectl get pod web-0 -o widr

可以看到

NAME    READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES
web-0   1/1     Running   0          8m26s   10.244.1.72   node1   <none>           <none>

DaemonSet 后台任务

DaemonSet 确保所有(或者某些)节点上运行一个 Pod 副本。当有节点加入集群时,也会为它们新增一个 Pod 。当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它所创建的所有 Pod 。

DaemonSet 的典型用法

  • 在集群的每个节点上运行 Daemon ,比如 glusterd 或 ceph
  • 在每个节点上运行日志收集 Daemon ,比如 flunentd 或 logstash
  • 在每个节点上运行监控 Daemon ,比如 Prometheus Node Exporter 或 collected

编写 DaemonSet Spec

创建 DaemonSet

vim daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: registry.cn-beijing.aliyuncs.com/qingfeng666/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

创建

kubectl apply -f daemonset.yaml

可以看到

daemonset.apps/fluentd-elasticsearch created

查看运行的 daemonset

kubectl -n kube-system get po -o wide | grep fluentd

可以看到

fluentd-elasticsearch-7b8jx      1/1     Running   0          5m32s   10.244.0.22       master   <none>           <none>
fluentd-elasticsearch-wfm9v      1/1     Running   0          5m32s   10.244.2.12       node2    <none>           <none>
fluentd-elasticsearch-x2mn9      1/1     Running   0          5m32s   10.244.1.78       node1    <none>           <none>

Daemon Pods 是如何调度的

DaemonSet 确保所有符合条件的节点都运行该 Pod 的一个副本。通常,运行 Pod 的节点有 kubernetes 调度器选择。不过 DaemonSet Pods 由 DaemonSet 控制器创建和调度。这就带来了以下问题:

  • Pod 行为的不一致性。正常 Pod 在被创建后等待调度时处于 Pending 状态,DaemonSet Pod 创建后不会处于 pending 状态下
  • Pod 抢占由默认调度器处理。启用抢占后,DaemonSet 控制器将不再不考虑 Pod 优先级和抢占的情况下制定调度决策

ScheduleDaemonSetPods 允许使用默认调度器而不是 DaemonSet 控制器来调度 DaemonSets ,方法是将 NodeAffinity 条件不是 .spec.nodeName 条件添加到 DaemonSet Pods 。默认调度器接下来将 Pod 绑定到模板主机。如果 DaemonSet Pod 的节点亲和性配置已存在,则被替换。DaemonSet 控制器仅在创建或修改 DaemonSet Pod 时执行这些操作,并且不会更改 DaemonSet 的 .spec.template 。

与 Daemon Pods 通信

与 DaemonSet 中的 Pod 通信的几种模式

  • NodeIP 和已知端口:DaemonSet 中的 Pod 可以使用 hostPort ,从而可以通过节点 IP 访问到 Pod。客户端能通过某种方法获取节点 IP 列表,并且基于此也可以获取到响应的端口。
  • DNS:创建具有相同 Pod 选择器的无头服务通过使用 endpoints 资源或从 DNS 中检索到多个 A 记录来发现 DaemonSet。
  • Service:创建具有相同 Pod 选择器的服务,并使用该服务随机访问到某个节点上的守护进程(没有办法访问到特定节点)

更新 DaemonSet

如果节点的标签被修改,DaemonSet 将立刻向新匹配上的节点添加 Pod ,同时删除不匹配的节点上的 Pod。

和 Deployments 的区别

DaemonSet 和 Deployment 非常类似,它们都能创建 Pod,并且 Pod 中的进程都不希望被终止(比如 web 服务器、存储服务器)。建议为无状态的服务使用 Deployment ,比如前段服务。对于这些服务而言,对副本的数量进行扩容、缩容、平滑升级,比精确控制 Pod 运行在某个主机上要重要的多。当需要 Pod 副本总是运行在全部或特定主机上,并需要它们先于其他 Pod 启动时,应该使用 DaemonSet。

Job

Job 会创建一个或多个 Pod ,并确保指定数量的 Pod 成功终止。随着 Pod 成功结束,Job 跟踪记录成功完成的 Pod 个数。当数量达到指定的成功个数阈值时,任务(即 Job)结束。删除 Job 的操作会清除所创建的所有 Pod。

Job 可以用来执行一次或多次有限次数的,或者定期每天执行的业务。

定义一个 job ,计算 π 到小数点后100位,并将结果打印出来

vim job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(100)"]
      restartPolicy: Never
  backoffLimit: 4
kubectl apply -f job.yaml

可以看到

job.batch/pi created
kubectl get job

可以看到

NAME   COMPLETIONS   DURATION   AGE
pi     0/1           46s        46s
kubectl describe pod pi-h9ww5

可以看到

Name:         pi-h9ww5
Namespace:    default
Priority:     0
Node:         node2/192.168.190.133
Start Time:   Thu, 25 Mar 2021 15:15:26 +0800
Labels:       controller-uid=16ba5e81-8b9e-4515-904b-013535baa2a6
              job-name=pi
Annotations:  <none>
Status:       Succeeded
IP:           10.244.2.14
IPs:
  IP:           10.244.2.14
Controlled By:  Job/pi
Containers:
  pi:
    Container ID:  docker://573f0764e80f87bd457a06ff81c65d3982b6478a452d6ad3535718601bc9eb1a
    Image:         registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26
    Image ID:      docker-pullable://registry.cn-beijing.aliyuncs.com/google_registry/perl@sha256:97821e418498785bb995b2c7609841ac57df0cc0156a761875db60403be0e1d8
    Port:          <none>
    Host Port:     <none>
    Command:
      perl
      -Mbignum=bpi
      -wle
      print bpi(100)
    State:          Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Thu, 25 Mar 2021 15:18:38 +0800
      Finished:     Thu, 25 Mar 2021 15:18:38 +0800
    Ready:          False
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-c9dkq (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
Volumes:
  default-token-c9dkq:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-c9dkq
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  3m36s  default-scheduler  Successfully assigned default/pi-h9ww5 to node2
  Normal  Pulling    3m36s  kubelet            Pulling image "registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26"
  Normal  Pulled     26s    kubelet            Successfully pulled image "registry.cn-beijing.aliyuncs.com/google_registry/perl:5.26" in 3m10.737708126s
  Normal  Created    25s    kubelet            Created container pi
  Normal  Started    25s    kubelet            Started container pi

从所有 pod 里面选择 jobname 是 pi 的 pod

pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath='{.items[*].metadata.name}')
echo $pods

可以看到

pi-h9ww5
kubectl logs pi-h9ww5

可以看到

3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,534评论 0 11
  • 彩排完,天已黑
    刘凯书法阅读 4,167评论 1 3
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 123,151评论 2 7