K8s学习笔记 (5)
@ wgjak47 | 星期六,七月 27 日,2019 年 | 6 分钟阅读 | 更新于 星期六,七月 27 日,2019 年

k8s学习笔记

控制器(二)

StatefulSet

StatefulSet为Pod提供唯一标识,可以保证部署和scale的顺序。

特点

  • 稳定的持久存储,基于PVC(PersistentVolumeClaim)
  • 稳定的网络标志,既PodName和HostNmae不变,基于Headless Service实现,DNS格式为:$(pod 名称).$(管理服务域),其中{0..N-1},为分配给每个Pod的序数,唯一
  • 有序部署,根据定义的顺序依此启动,基于initContainer
  • 有序收缩,有序删除

使用

适用场景

  • 稳定,唯一的网络标志。
  • 稳定,持久化存储。
  • 有序,优雅地部署和 scale。
  • 有序,优雅地删除和终止。
  • 有序,自动的滚动升级。

限制

  • 给定 Pod 的存储必须由 PersistentVolume Provisioner 根据请求的 storage class 进行配置,或由管理员预先配置。
  • 删除或 scale StatefulSet 将不会删除与 StatefulSet 相关联的 volume。 这样做是为了确保数据安全性,这通常比自动清除所有相关 StatefulSet 资源更有价值。
  • StatefulSets 目前要求 Headless Service 负责 Pod 的网络身份。 您有责任创建此服务。

组件

下面的示例中描述了 StatefulSet 中的组件。

  • 一个名为 nginx 的 headless service,用于控制网络域。
  • 一个名为 web 的 StatefulSet,它的 Spec 中指定在有 3 个运行 nginx 容器的 Pod。
  • volumeClaimTemplates 使用 PersistentVolume Provisioner 提供的 PersistentVolumes 作为稳定存储。
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: gcr.io/google_containers/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
annotations:
volume.beta.kubernetes.io/storage-class: anything
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi

部署和 Scale 保证

  • 对于有 N 个副本的 StatefulSet,Pod 将按照 {0..N-1} 的顺序被创建和部署。
  • 当 删除 Pod 的时候,将按照逆序来终结,从{N-1..0}
  • 对 Pod 执行 scale 操作之前,它所有的前任必须处于 Running 和 Ready 状态。
  • 在终止 Pod 前,它所有的继任者必须处于完全关闭状态。

Pod管理策略

StatefulSet 允许用户放开顺序保证,同时通过 .spec.podManagementPolicy 字段保证身份的唯一性。默认值为OrderedReady,即顺序其的启动保证。也可以改为Parallel,即不会等待其它pod启动完成

更新策略

通过.spec.updateStrategy字段配置StatefulSet 中的容器、label、resource request/limit、annotation 的滚动更新。

  • 当StatefulSet 的 .spec.updateStrategy.type 设置为 OnDelete 时,StatefulSet 控制器将不会自动更新 StatefulSet 中的 Pod。 用户必须手动删除 Pod 以使控制器创建新的 Pod
  • 当StatefulSet的 .spec.updateStrategy.type 设置为 RollingUpdate 时,StatefulSet 控制器将在 StatefulSet 中删除并重新创建每个 Pod。 它将以与 Pod 终止相同的顺序进行(从最大的序数到最小的序数),每次更新一个 Pod。 在更新其前身之前,它将等待正在更新的 Pod 状态变成正在运行并就绪。
  • 可以通过指定 .spec.updateStrategy.rollingUpdate.partition 来对 RollingUpdate 更新策略进行分区。如果指定了分区,则当 StatefulSet 的 .spec.template 更新时,具有大于或等于分区序数的所有 Pod 将被更新。具有小于分区的序数的所有 Pod 将不会被更新,即使删除它们也将被重新创建。如果 StatefulSet 的 .spec.updateStrategy.rollingUpdate.partition 大于其 .spec.replicas,则其 .spec.template 的更新将不会传播到 Pod。

例子:https://kubernetes.io/docs/tutorials/stateful-application/zookeeper/

DaemonSet

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

使用场景

  • 运行集群存储 daemon,例如在每个 Node 上运行 glusterd、ceph。
  • 在每个 Node 上运行日志收集 daemon,例如fluentd、logstash。
  • 在每个 Node 上运行监控 daemon,例如 Prometheus Node Exporter、collectd、Datadog 代理、New Relic 代理,或 Ganglia gmond

Spec

格式基本与Deployment相同,但对以下字段有特殊需求:

  1. .spec.template.RestartPolicy必须为Always
  2. .spec.template.spec.nodeSelector & .spec.template.spec.affinity, 在符合需求的Node上创建Pod,如果没有指定,则在所有的Node节点上创建Pod

调度DaemonPod

  • DaemonSet Controller 并不关心一个 Node 的 unschedulable 字段。
  • DaemonSet Controller 可以创建 Pod,即使调度器还没有被启动,这对集群启动是非常有帮助的。
  • Taint和Toleration对DaemonSet生效,一些Tolearation会在特殊条件下自动添加到DaemonSet

与DaemonPod通讯

  • Push:配置 DaemonSet 中的 Pod 向其它 Service 发送更新,例如统计数据库。它们没有客户端。
  • NodeIP 和已知端口:DaemonSet 中的 Pod 可以使用 hostPort,从而可以通过 Node IP 访问到 Pod。客户端能通过某种方法知道 Node IP 列表,并且基于此也可以知道端口。
  • DNS:创建具有相同 Pod Selector 的 Headless Service,然后通过使用 endpoints 资源或从 DNS 检索到多个 A 记录来发现 DaemonSet。
  • Service:创建具有相同 Pod Selector 的 Service,并使用该 Service 访问到某个随机 Node 上的 daemon。(没有办法访问到特定 Node)

更新DaemonSet

1.6+版本之后DaemonSet也是默认使用滚动升级的策略进行升级了。

与其他方式比较

init

也可以的通过使用systemd等启动daemon进程来达到相似的效果。但是使用DaemonSet来运行这些进程的好处在于:

  • k8s可以为daemon提供与application相同的日志和监控能力
  • 为Daemon和应用使用相同的管理工具,节约管理成本
  • 增加应用容器和Daemon的隔离性(在systemd/openrc等支持namespace的init程序上优势不明显)

单Pod

直接创建Pod,缺点很明显,如果Node遇到问题下线,不会有DaemonSet来替换被删除和中止的Pod

静态Pod

很可能,通过在一个指定目录下编写文件来创建 Pod,该目录受 Kubelet 所监视。这些 Pod 被称为 静态 Pod。 不像 DaemonSet,静态 Pod 不受 kubectl 和 其它 Kubernetes API 客户端管理。静态 Pod 不依赖于 apiserver,这使得它们在集群启动的情况下非常有用。 而且,未来静态 Pod 可能会被废弃掉。

Replication Controller

DaemonSet 与 Replication Controller 非常类似,它们都能创建 Pod,这些 Pod 都具有不期望被终止的进程(例如,Web 服务器、存储服务器)。 为无状态的 Service 使用 Replication Controller,像 frontend,实现对副本的数量进行扩缩容、平滑升级,比之于精确控制 Pod 运行在某个主机上要重要得多。需要 Pod 副本总是运行在全部或特定主机上,并需要先于其他 Pod 启动,当这被认为非常重要时,应该使用 Daemon Controller。