ReplicaSet

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

ReplicaSet 的工作原理

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

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

ReplicaSet 使用其选择算符来辨识要获得的 Pod 集合。如果某个 Pod 没有 OwnerReference 或者其 OwnerReference 不是一个 控制器,且其匹配到 某 ReplicaSet 的选择算符,则该 Pod 立即被此 ReplicaSet 获得。

怎样使用 ReplicaSet

大多数支持 Replication Controllers 的kubectl命令也支持 ReplicaSets。但rolling-update 命令是个例外。如果您想要滚动更新功能请考虑使用 Deployment。rolling-update 命令是必需的,而 Deployment 是声明性的,因此我们建议通过 rollout命令使用 Deployment。

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

什么时候使用 ReplicaSet

ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。 然而,Deployment 是一个更高级的概念,它管理 ReplicaSet,并向 Pod 提供声明式的更新以及许多其他有用的功能。 因此,我们建议使用 Deployment 而不是直接使用 ReplicaSet,除非您需要自定义更新业务流程或根本不需要更新。

这实际上意味着,您可能永远不需要操作 ReplicaSet 对象:而是使用 Deployment,并在 spec 部分定义您的应用。

示例

controllers/frontend.yaml ReplicaSet - 图1

  1. apiVersion: apps/v1
  2. kind: ReplicaSet
  3. metadata:
  4. name: frontend
  5. labels:
  6. app: guestbook
  7. tier: frontend
  8. spec:
  9. # modify replicas according to your case
  10. replicas: 3
  11. selector:
  12. matchLabels:
  13. tier: frontend
  14. template:
  15. metadata:
  16. labels:
  17. tier: frontend
  18. spec:
  19. containers:
  20. - name: php-redis
  21. image: gcr.io/google_samples/gb-frontend:v3

将此清单保存到 frontend.yaml 中,并将其提交到 Kubernetes 集群,应该就能创建 yaml 文件所定义的 ReplicaSet 及其管理的 Pod。

  1. $ kubectl create -f http://k8s.io/examples/controllers/frontend.yaml
  2. replicaset.apps/frontend created
  3. $ kubectl describe rs/frontend
  4. Name: frontend
  5. Namespace: default
  6. Selector: tier=frontend,tier in (frontend)
  7. Labels: app=guestbook
  8. tier=frontend
  9. Annotations: <none>
  10. Replicas: 3 current / 3 desired
  11. Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
  12. Pod Template:
  13. Labels: app=guestbook
  14. tier=frontend
  15. Containers:
  16. php-redis:
  17. Image: gcr.io/google_samples/gb-frontend:v3
  18. Port: 80/TCP
  19. Requests:
  20. cpu: 100m
  21. memory: 100Mi
  22. Environment:
  23. GET_HOSTS_FROM: dns
  24. Mounts: <none>
  25. Volumes: <none>
  26. Events:
  27. FirstSeen LastSeen Count From SubobjectPath Type Reason Message
  28. --------- -------- ----- ---- ------------- -------- ------ -------
  29. 1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-qhloh
  30. 1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-dnjpy
  31. 1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-9si5l
  32. $ kubectl get pods
  33. NAME READY STATUS RESTARTS AGE
  34. frontend-9si5l 1/1 Running 0 1m
  35. frontend-dnjpy 1/1 Running 0 1m
  36. frontend-qhloh 1/1 Running 0 1m

编写 ReplicaSet Spec

与所有其他 Kubernetes API 对象一样,ReplicaSet 也需要 apiVersionkind、和 metadata 字段。有关使用清单的一般信息,请参见 使用 kubectl 管理对象

ReplicaSet 也需要 .spec 部分。

Pod 模版

.spec.template.spec 唯一需要的字段。.spec.templatePod 模版。它和 Pod 的语法几乎完全一样,除了它是嵌套的并没有 apiVersionkind

除了所需的 Pod 字段之外,ReplicaSet 中的 Pod 模板必须指定适当的标签和适当的重启策略。

对于标签,请确保不要与其他控制器重叠。更多信息请参考 Pod 选择器

对于 重启策略.spec.template.spec.restartPolicy 唯一允许的取值是 Always,这也是默认值.

对于本地容器重新启动,ReplicaSet 委托给了节点上的代理去执行,例如Kubelet 或 Docker 去执行。

Pod 选择器

.spec.selector 字段是标签选择器。ReplicaSet 管理所有标签匹配与标签选择器的 Pod。它不区分自己创建或删除的 Pod 和其他人或进程创建或删除的pod。这允许在不影响运行中的 Pod 的情况下替换副本集。

.spec.template.metadata.labels 必须匹配 .spec.selector,否则它将被 API 拒绝。

Kubernetes 1.9 版本中,API 版本 apps/v1 中的 ReplicaSet 类型的版本是当前版本并默认开启。API 版本 apps/v1beta2 被弃用。

另外,通常您不应该创建标签与此选择器匹配的任何 Pod,或者直接与另一个 ReplicaSet 或另一个控制器(如 Deployment)标签匹配的任何 Pod。 如果你这样做,ReplicaSet 会认为它创造了其他 Pod。Kubernetes 并不会阻止您这样做。

如果您最终使用了多个具有重叠选择器的控制器,则必须自己负责删除。

Replicas

通过设置 .spec.replicas 您可以指定要同时运行多少个 Pod。 在任何时间运行的 Pod 数量可能高于或低于 .spec.replicas 指定的数量,例如在副本刚刚被增加或减少后、或者 Pod 正在被优雅地关闭、以及替换提前开始。

如果您没有指定 .spec.replicas, 那么默认值为 1。

使用 ReplicaSets 的具体方法

删除 ReplicaSet 和它的 Pod

要删除 ReplicaSet 和它的所有 Pod,使用kubectl delete 命令。 默认情况下,垃圾收集器 自动删除所有依赖的 Pod。

当使用 REST API 或 client-go 库时,您必须在删除选项中将 propagationPolicy 设置为 BackgroundForeground。例如:

  1. kubectl proxy --port=8080
  2. curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
  3. > -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
  4. > -H "Content-Type: application/json"

只删除 ReplicaSet

您可以只删除 ReplicaSet 而不影响它的 Pod,方法是使用kubectl delete 命令并设置 --cascade=false 选项。

当使用 REST API 或 client-go 库时,您必须将 propagationPolicy 设置为 Orphan。例如:

  1. kubectl proxy --port=8080
  2. curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
  3. > -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
  4. > -H "Content-Type: application/json"

一旦删除了原来的 ReplicaSet,就可以创建一个新的来替换它。 由于新旧 ReplicaSet 的 .spec.selector 是相同的,新的 ReplicaSet 将接管老的 Pod。 但是,它不会努力使现有的 Pod 与新的、不同的 Pod 模板匹配。 若想要以可控的方式将 Pod 更新到新的 spec,就要使用 滚动更新的方式。

将 Pod 从 ReplicaSet 中隔离

可以通过改变标签来从 ReplicaSet 的目标集中移除 Pod。这种技术可以用来从服务中去除 Pod,以便进行排错、数据恢复等。 以这种方式移除的 Pod 将被自动替换(假设副本的数量没有改变)。

缩放 RepliaSet

通过更新 .spec.replicas 字段,ReplicaSet 可以被轻松的进行缩放。ReplicaSet 控制器能确保匹配标签选择器的数量的 Pod 是可用的和可操作的。

ReplicaSet 作为水平的 Pod 自动缩放器目标

ReplicaSet 也可以作为 水平的 Pod 缩放器 (HPA) 的目标。也就是说,ReplicaSet 可以被 HPA 自动缩放。 以下是 HPA 以我们在前一个示例中创建的副本集为目标的示例。

controllers/hpa-rs.yaml ReplicaSet - 图2

  1. apiVersion: autoscaling/v1
  2. kind: HorizontalPodAutoscaler
  3. metadata:
  4. name: frontend-scaler
  5. spec:
  6. scaleTargetRef:
  7. kind: ReplicaSet
  8. name: frontend
  9. minReplicas: 3
  10. maxReplicas: 10
  11. targetCPUUtilizationPercentage: 50

将这个列表保存到 hpa-rs.yaml 并提交到 Kubernetes 集群,就能创建它所定义的 HPA,进而就能根据复制的 Pod 的 CPU 利用率对目标 ReplicaSet进行自动缩放。

  1. kubectl create -f https://k8s.io/examples/controllers/hpa-rs.yaml

或者,可以使用 kubectl autoscale 命令完成相同的操作。 (而且它更简单!)

  1. kubectl autoscale rs frontend

ReplicaSet 的替代方案

Deployment (推荐)

Deployment 是一个高级 API 对象,它以 kubectl rolling-update 的方式更新其底层副本集及其Pod。 如果您需要滚动更新功能,建议使用 Deployment,因为 Deployment 与 kubectl rolling-update 不同的是:它是声明式的、服务器端的、并且具有其他特性。 有关使用 Deployment 来运行无状态应用的更多信息,请参阅 使用 Deployment 运行无状态应用

裸 Pod

与用户直接创建 Pod 的情况不同,ReplicaSet 会替换那些由于某些原因被删除或被终止的 Pod,例如在节点故障或破坏性的节点维护(如内核升级)的情况下。 因为这个好处,我们建议您使用 ReplicaSet,即使应用程序只需要一个 Pod。 想像一下,ReplicaSet 类似于进程监视器,只不过它在多个节点上监视多个 Pod,而不是在单个节点上监视单个进程。 ReplicaSet 将本地容器重启的任务委托给了节点上的某个代理(例如,Kubelet 或 Docker)去完成。

Job

使用Job 代替ReplicaSet,可以用于那些期望自行终止的 Pod。

DaemonSet

对于管理那些提供主机级别功能(如主机监控和主机日志)的容器,就要用DaemonSet 而不用 ReplicaSet。 这些 Pod 的寿命与主机寿命有关:这些 Pod 需要先于主机上的其他 Pod 运行,并且在机器准备重新启动/关闭时安全地终止。