k8s的控制器实践

kubernetes的控制器实践


使用ReplicaSet控制副本

ReplicaSet

Replicaset 的目的是维护一组在任何时候都处于运行状态的Pod 副本的稳定集合。因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。

工作原理

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

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

如何使用

虽然 ReplicaSets 可以独立使用,但今天它主要被Deployments 用作协调Pod 创建、删除和更新的机制。当您使用 Deploymer时,您不必担心还要管理它们创建的 ReplicaSet。 Deployment 会拥有并管理它们的 ReplicaSet.

创建 replicaSet.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: nginx
    tier: frontend
spec:
  # modify replicas according to your case
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: nginx
        image: nginx
kubectl create -f replicaSet.yaml

深入理解deployment

Deployments

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

你负责描述 Deployment 中的 目标状态,而 Deployment 控制器可 以更改实际状态,使其变为期望状态。你可以定义 Deployment 以创建新的 ReplicaSet, 或删除现有 Deployment, 并通过新的 Deployment 适配其资源。

使用场景

以下是 Deplovments 的典型使用场景:

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

创建Deployment

下面是 Deployment 示例。其中创建了一个 ReplicaSet, 负责启动三个nginx Pods: nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

在该例中:

创建名为 nginx-deployment(由 •metadata.name 字段标明)的Deployment。该Deployment 创建三个(由replicas 字段标明)Pod 副本。

selector 字段定义 Deployment 如何查找要管理的 Pods。在这里,你只需选择在 Pod 模板中定义的标签 (app: nginx)。不过,更复杂的选择规则是也可以的,只要Pod 模板本身满足所给规则即可。

通过运行以下命令创建 Deployment

kubectl apply -f nginx-deployment.yaml

说明:你可以设置-record 标志将所执行的命令写入资源注解 kubernetes.io/change-cause 中。这对于以后的检查是有用的。

例如,要查看针对每个 Deployment 修订版本所执行过的命令。

运行 kubectl get deployments 检查 Deployment 是否已创建。如果仍在创建 Deployment,则输出类似于:

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE

nginx-deployment 3 0 0 0 1s

有状态的应用StatefulSets

StatefulSets

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

Statefulset 用来管理 Deployment 和扩展一组Pod,并且能为这些 Pod 提供序号和唯一性保证。

和 Deployment 相同的是,Statefulset 管理了基于相同容器定义的一组 Pod。但和 Deployment 不同的是,StatefulSet 为它们的每个 Pod 维护了一个固定的 D。这些Pod 是基于相同的声明来创建的,但是不能相互替换:无论怎么调度,每个Pod 都有一个永久不变的ID。

Statefuiset 和其他控制器使用相同的工作模式。你在 Statetuiset 对象 中定义你期望的状态,然后 Staterulset的 控制器 就会運过各种更新来达到那种你想要的状态。

使用StatefulSets

StatefulSets 可以满足以下一个或多个需求的应用程序:

  • 稳定的、唯一的网络标识符。
  • 稳定的、持久的存储。
  • 有序的、优雅的部署和缩放。
  • 有序的、自动的滚动更新。
    稳定意味着 Pod 调度或重调度的整个过程是有持久性的。如果应用程序不需要任何稳定的标识符或有序的部署、删除或伸缩,则应该使用由一组无状态的副本控制器提供的工作负载来部署应用程序,比如 Deployment 或者 ReplicaSet 可能更适用于您的无状态应用部署需要。

限制

  • 给定Pod 的存储必须由 PersistentVolume 驱动 基于所请求的storage class 来提供,或者由管理员预先提供。
  • 删除或者收缩 Staterulset 并不会删除它关联的存储卷。这样做是为了保证数据安全,它通常比自动清除 Statefulset 所有相关的资源更有价值。
  • StatefuSet 当前需要headless 服务来负责 Pod 的网络标识。您需要负责创建此服务。

注意:headless使用场景:有时候我们创建的服务不想走负载均衡,想直接通过pod-ip链接后端,怎么办呢,使用heaclless service接可以解决。headlless service 是将service的发布文件中的clusterip=none,不让其获取clusterip, DNS

解析的时候直接走pod。

•当删除 StatefulSets 时,Statefulset 不提供任何终止 Pod 的保证。-为了实现 StatefulSet 中的Pod 可以有序和优雅的终止,可以在删除之前将 Statefulset 缩放为 0。

下面的示例演示了 Statefulset 的组件(注意:实际创建请使用 git 中的配套 7-3-statefulset.yaml的完整代码)

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 # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: registry.cn-beijing.aliyuncs.com/qingfeng666/nginx
        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
  • 名为nginx 的 Headless Service 用来控制网络域名。
  • 名为web 的 StatefulSet 有一个Spec,它表明将在独立的 3个 Pod 副本中启动nginx 容器。
  • volumeClaim Templates 将通过 Persistentvolumes 驱动提供的 - PersistentVolumes 来提供稳定的存储。

实践

  1. 创建持久化存储以及statefuisets
kubectl apply -f 7-3-statefulset.yaml
  1. 查看 pod:
kc get po -o wide

Statefulsets 会为你创建 3个副本,每个副本都使用独立的存储-data1-3 目录,并挂载在/usr/share/nginx/html路径。

  1. 验证存储的独立性
kubectl exec -it web-0 sh
  1. 进入目录
cd /usr/share/nginx/html

当前没有任何文件。此时新开一个 terrninal, ssh登录 node1,在/Atmp/data1 目录下创建一个文件 1.txt.

此时再回到web-0 pod的/usr/share/nginx/html目录,1s 查看文件,会看到目录下自动多了 1.txt 文件,也就是文件挂载成功。

再登录 web-1 pod,进入相同目录,会发现该目录并没有 1.txt 文件,此时就证明了 statetulset 的 pod 存储是互相独立的。

  1. 访问该nginx 服务:
curl 10.244.1.67

Daemonset后台任务

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

Daemonset 的一些典型用法:

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

实践

创建DaemonSet

你可以在 YAML 文件中描述 DaemonSet。例如,下面的daemonset.yamnl 文件描述了一个运行 tluentd-elasticsearch Docker 镜像的 DaemonSet:

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:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can't run pods
      - 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

基于 YAML 文件创建 DaemonSet:

kubectl apply -f 7-4-daemonset.yaml

通过命令查看运行的 DaemonSet:

kubectl -n kube-system get po -o wide I grep fluentd
必需字段

和所有其他 Kubernetes 配置一样,DaemonSet 需要 apiVersionkindmetadata 字段。有关配置文件的基本信息。

Daemonset 对象的名称必须是一个合法的。

DaemonSet 也需要一个.spec配置段。

Pod模板

.spec 中唯一必需的宇段是 。.spec . template

.spec .template是一个Pod 模板,除了它是嵌套的,因而不具有 apiVersionkind 字段之外,它与Pod 具有相同的schema.

除了Pod 必需字段外,在 DaemonSet 中的 Pod 模板必须指定合理的标签

在 Daemonset 中的 Pod 模板必须具有一个值为 Always 的 RestartPolicy。 当该值未指定时,默认是 Always

Pod选择器

.spec .selector 字段表示Pod 选择器,它与Job的.spec. selector 的作用是相同的。

从Kubernetes 1.8 开始,您必须指定与 。.spec .template 的标签匹配的Pod 选择器。用户不指定 Pod 选择器时,该字段不再有默认值。选择器的默认值生成结果与kubectl apply 不兼容。此外,一旦创建了Daemonset, 它的 。.spec .selector 就不能修改。修改Pod 选择器可能导致 Pod 意外悬浮,并且这对用户来说是费解的。

spec.selector 是一个对象,如下两个字段组成:

  • matchLabels-与 ReplicationGontroller的 。.spec.selector 的作用相同。
  • matchExpressions-允许构建更加复杂的选择器,可以通过指定 key、value 列表以及将 key 和value 列表关联起来的
    operator.

当上述两个字段都指定时,结果会按逻辑与 (AND)操作处理。

如果指定了 .spec.selector,必须与.spec.template.metadata. labels 相匹配。如果与后者不匹配,则 Deamonset 会被 API拒绝。

另外,通常不应直接通过另一个 Daemonset 或另一个工作负载资源(例如 Feplicaset)来创建其标签与该选择器匹配的任何

Pod。否则,Daemonset 控制器会认为这些Pod 是由它创建的。Kubernetes 不会阳止你这样做。你可能要执行此操作的一种情况是,手动在节点上创建具有不同值的 Pod 进行测试。

仅在某些节点上运行Pod

如果指定了 .spec. template.spec.nodeSelector,DaemonSet 控制器将在能够与 Node 选择器 匹配的节点上创建 Pod。类似这种情況,可以指定 .spec.template.spec.attinity,之后 Daemonset 控制器 将在能够与节点亲和性 匹配的节点上创建 Pod。如果根本就没有指定,则 DaemonSet Controller 将在所有节点上创建 Pod。

Daemon Pods是如何被调度的

通过默认调度器调度

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

  • Pod 行为的不一致性:正常Pod 在被创建后等待调度时处于 Pend ing 状态,DaemonSet Pods 创建后不会处于 Pending
    状态下。这使用户感到困惑。
  • Pod 抢占1 由默认调度器处理。启用抢占后,Daemonset 控制器将在不考虑Pod 优先级和抢占 的情況下制定调度决策。

ScheduleDaemonsetPods 允许您使用默认调度器而不是 DaemonSet 控制器来调度 DaemonSets, 方法是将 NodeAffinity

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

nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchFields:
      - key: metadata.name
        operator: In
        values:
        - target-host-name

此外,系统会自动添加 node. kube rnetes . io/unschedulable : Noschedule 容忍度到 DaemonSet Pods。在调度DaeronSet Pod 时,默认调度器会忽略 unschedulable 节点。

与Daemon Pods通信

与 Daemonset 中的 Pod 进行通信的几种可能模式如下:

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

更新DaemonSet

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

你可以修改 DaemonSet 创建的 Pod。不过并非 Pod 的所有字段都可更新。下次当某节点(即使具有相同的名称)被创建时,DaemonSet 控制器还会使用最初的模板。

您可以删除一个 Daemonset。如果使用 kubectl 并指定 --cascade=false 选项,则Pod 将被保留在节点上。接下来如果创建使用相同选择器的新 DaemonSet, 新的DaemonSet 会收养已有的Pod。如果有 Pod 需要被替换,Daemonset 会根据其updatest rategy 来替换。

DaemonSet的替代方案

init 脚本

直接在节点上启动守护进程(例如使用 init、upstartd 或 systemd)的做法当然是可行的。不过,基于 Daemonset 来运

行这些进程有如下一些好处:

  • 像所运行的其他应用一样,Daemonset 具备为守护进程提供监控和日志管理的能力。
  • 为守护进程和应用所使用的配置语言和工具(如Pod模板、kubectI)是相同的。
  • 在资源受限的容器中运行守护进程能够增加守护进程和应用容器的隔离性。然而,这一点也可以通过在容器中运行守护进程
  • 但却不在 Pod 中运行之来实现。例如,直接基于 Docker启动。
和Deployments的区别

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

Job任务实战

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

一种简单的使用场景下,你会创建一个Job 对象以便以一种可靠的方式运行某 Pod 直到完成。当第一个 Pod 失败或者被删除(比如因为节点硬件失效或者重启) 时,Job对象会启动一个新的Pod。你也可以使用 Job以并行的方式运行多个 Pod。

运行示例 Job

下面是一个Job 配置示例。它负责计算厂到小数点后 100位,并将结果打印出来。

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值