# 控制器 - ReplicaSet
Kubernetes 中,ReplicaSet 用来维护一个数量稳定的 Pod 副本集合,可以保证某种定义一样的 Pod 始终有指定数量的副本数在运行。
# ReplicaSet的工作方式
ReplicaSet的定义中,包含:
selector
: 用于指定哪些 Pod 属于该 ReplicaSet 的管辖范围replicas
: 副本数,用于指定该 ReplicaSet 应该维持多少个 Pod 副本template
: Pod模板,在 ReplicaSet 使用 Pod 模板的定义创建新的 Pod
ReplicaSet 控制器将通过创建或删除 Pod,以使得当前 Pod 数量达到 replicas
指定的期望值。ReplicaSet 创建的 Pod 中,都有一个字段 metadata.ownerReferences 用于标识该 Pod 从属于哪一个 ReplicaSet。
ReplicaSet 通过 selector
字段的定义,识别哪些 Pod 应该由其管理。如果 Pod 没有 ownerReference 字段,或者 ownerReference 字段指向的对象不是一个控制器,且该 Pod 匹配了 ReplicaSet 的 selector
,则该 Pod 的 ownerReference 将被修改为 该 ReplicaSet 的引用。
# 何时使用 ReplicaSet
ReplicaSet 用来维护一个数量稳定的 Pod 副本集合。Deployment 是一个更高级别的概念,可以管理 ReplicaSet,并提供声明式的更新,以及其他的许多有用的特性。因此,推荐用户总是使用 Deployment,而不是直接使用 ReplicaSet,除非您需要一些自定义的更新应用程序的方式,或者您完全不更新应用。
这也意味着,您也许永远不会直接操作 ReplicaSet 对象。但是,对其有一定的理解是有必要的,这样您才能更好的理解和使用 Deployment。
# Example
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
执行命令以创建该 YAML 对应的 ReplicaSet
kubectl apply -f https://kuboard.cn/statics/learning/replicaset/frontend.yaml
执行命令,查看刚才创建的ReplicaSet:
kubectl get rs
输出结果如下所示:
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 6s
2
执行命令,查看刚才创建的RelicaSet的详情:
kubectl describe rs/frontend
输出结果如下所示:
Name: frontend
Namespace: default
Selector: tier=frontend,tier in (frontend)
Labels: app=guestbook
tier=frontend
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=guestbook
tier=frontend
Containers:
php-redis:
Image: nginx:latest
Port: 80/TCP
Requests:
cpu: 100m
memory: 100Mi
Environment:
GET_HOSTS_FROM: dns
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-qhloh
1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-dnjpy
1m 1m 1 {replicaset-controller }
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
28
执行命令,查看有哪些 Pod 被创建:
kubectl get pods
输出结果如下所示:
NAME READY STATUS RESTARTS AGE
frontend-9si5l 1/1 Running 0 1m
frontend-dnjpy 1/1 Running 0 1m
frontend-qhloh 1/1 Running 0 1m
2
3
4
执行命令,查看 Pod 的 ownerReference:
# 替换成你自己的 Pod 名称
kubectl get pods frontend-9si5l -o yaml
2
输出结果如下所示,其中 metadata.ownerReferences
字段指向了 ReplicaSet frontend
:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: 2019-11-08T17:20:41Z
generateName: frontend-
labels:
tier: frontend
name: frontend-9si5l
namespace: default
ownerReferences:
- apiVersion: extensions/v1beta1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: frontend
uid: 892a2330-257c-11e9-aecd-025000000001
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 获取Non-Template Pod
由于您可以直接创建 Pod,Kubernetes 中强烈建议在您直接创建的 Pod 中,其标签不会与任何一个 ReplicaSet 的标签匹配。原因在于,ReplicaSet 不仅仅只管理通过其 podTemplate(.spec.template
字段)创建的Pod,ReplicaSet 也可能将不是由其创建的 Pod 纳入到自己的管理中。
假设有两个 Pod,其 YAML 文件如下所示:
apiVersion: v1
kind: Pod
metadata:
name: pod1
labels:
tier: frontend
spec:
containers:
- name: hello1
image: nginx:1.7.9
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
labels:
tier: frontend
spec:
containers:
- name: hello2
image: nginx:1.8.0
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
这些 Pod 没有对应的控制器(或者任何其他对象)作为其 ownerReference,且他们都匹配了 ReplicaSet frontend
中的选择器(selector),此时他们将立刻被 ReplicaSet frontend
接管。
假设您先创建了上面例子中的 ReplicaSet(其 replicas
为 3),此时再执行命令,以创建上面YAML文件中的两个 Pod:
kubectl apply -f https://kuboard.cn/statics/learning/replicaset/pod-rs.yaml
新建的 Pod 将立刻被该 ReplicaSet 接管,并且立刻被终止,否则 ReplicaSet 中的副本数量将超过 replicas
指定的值。
执行命令查看 Pod:
kubectl get pods
输出结果显示了新创建的 Pod 要么已经被终止了,要么正在终止过程中:
NAME READY STATUS RESTARTS AGE
frontend-9si5l 1/1 Running 0 1m
frontend-dnjpy 1/1 Running 0 1m
frontend-qhloh 1/1 Running 0 1m
pod2 0/1 Terminating 0 4s
2
3
4
5
清理
执行后面的命令时,可先清理已经创建的 ReplicaSet 和 Pod
kubectl delete -f https://kuboard.cn/statics/learning/replicaset/frontend.yaml
kubectl delete -f https://kuboard.cn/statics/learning/replicaset/pod-rs.yaml
2
如果您先创建 Pod:
kubectl apply -f https://kuboard.cn/statics/learning/replicaset/pod-rs.yaml
然后创建 ReplicaSet:
kubectl apply -f https://kuboard.cn/statics/learning/replicaset/frontend.yaml
您将看到 ReplicaSet 将接管您手工创建的 Pod,并且按照自己的 podTemplate 只创建一个新的 Pod,以达到 replicas
字段中指定的副本数量。此时执行命令查看 Pod:
kubectl get pods
输出结果如下:
NAME READY STATUS RESTARTS AGE
frontend-pxj4r 1/1 Running 0 5s
pod1 1/1 Running 0 13s
pod2 1/1 Running 0 13s
2
3
4
这种情况下,ReplicaSet 包含了多个不一样的 Pod
# ReplicaSet的定义
与其他 Kubernetes 对象一样,ReplicaSet需要的字段有:
apiVersion
:apps/v1kind
:始终为 ReplicaSetmetadata
spec
: ReplicaSet 的详细定义
# PodTemplate
.spec.template
字段是一个 Pod Template,为必填字段,且其中必须定义 .spec.template.metadata.labels
字段。在前面的ReplicaSet例子中,定义了 label 为 tier: frontend
。请小心该字段不要与其他控制器的 selector 重合,以免这些控制器尝试接管该 Pod。
.spec.template.spec.restartPolicy
的默认值为 Always
# Pod Selector
.spec.selector
字段为一个 标签选择器,用于识别可以接管哪些 Pod。在前面的例子中,标签选择器为:
matchLabels:
tier: frontend
2
在 ReplicaSet 中, .spec.template.metadata.labels
必须与 .spec.selector
匹配,否则将不能成功创建 ReplicaSet。
TIP
如果两个 ReplicaSet 指定了相同的 .spec.selector
但是不同的 .spec.template.metadata.labels
和不同的 .spec.tempalte.spec
字段,两个 ReplicaSet 都将忽略另外一个 ReplicaSet 创建的 Pod
# Replicas
.spec.replicas
字段用于指定同时运行的 Pod 的副本数。ReplicaSet 将创建或者删除由其管理的 Pod,以便使副本数与该字段指定的值匹配。
如果不指定,默认值为 1
# 使用 ReplicaSet
# 删除ReplicaSet及其Pod
使用 kubectl delete
可删除 ReplicaSet, Garbage Collector 将自动删除该 ReplicaSet 所有从属的 Pod。
如果使用 REST API 或者 client-go
代码库调用 apiserver 来删除 ReplicaSet,则必须通过 -d 参数指定 propagationPolicy
为 Background
或 Foreground
,例如:
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
> -H "Content-Type: application/json"
2
3
4
# 只删除ReplicaSet
使用 kubectl delete --cascade=false
命令,可以删除 ReplicaSet,但是仍然保留其 Pod。如果使用 REST API 或者 client-go
代码库调用 apiserver 来删除 ReplicaSet,则必须通过 -d 参数指定 propagationPolicy
为 Orphan
,例如:
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
> -H "Content-Type: application/json"
2
3
4
一旦原来的 ReplicaSet 被删除,您可以创建新的 ReplicaSet 作为替代。只要新 ReplicaSet 的 .spec.selector
字段与旧 ReplicaSet 的 .spec.selector
字段相同,则新的 ReplicaSet 将接管旧 ReplicaSet 遗留下来的 Pod。但是,新的 ReplicaSet 中定义的 .spec.template
对遗留下来的 Pod 不会产生任何影响。如果要更新 Pod 的 .spec.template
内容,请使用 Deployment,ReplicaSet 并不直接支持滚动更新。
# 将Pod从ReplicaSet中隔离
修改 Pod 的标签,可以使 Pod 脱离 ReplicaSet 的管理。这个小技巧在如下场景可能非常有用:
- 将 Pod 从 Service 中移除,以便 Debug 或者做数据恢复
- 其他
通过这种方式从 ReplicaSet 移除了 Pod 之后,ReplicaSet 将立刻自动创建一个新的 Pod 以维持其指定的 replicas
副本数。
# 伸缩ReplicaSet
ReplicaSet可以轻易的 scale up 或者 scale down,只需要修改 .spec.replicas
字段即可。ReplicaSet 控制器将确保与其标签选择器 .spec.selector
匹配的 Pod 数量与 replicas
指定的数量相等。
# ReplicaSet的自动伸缩
可以使用 Horizontal Pod Autoscalers(HPA) (opens new window) 对 ReplicaSet 执行自动的水平伸缩。下面例子中的 HPA 可以用来对前面例子中的 ReplicaSet 执行自动的水平伸缩:
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: frontend-scaler
spec:
scaleTargetRef:
kind: ReplicaSet
name: frontend
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 50
2
3
4
5
6
7
8
9
10
11
执行命令可创建该 HPA,该HPA将根据CPU的使用情况对ReplicaSet进行自动伸缩
kubectl apply -f https://kuboard.cn/statics/learning/replicaset/hpa-rs.yaml
此外,您也可以使用 kubectl autoscale
命令达到相同的效果:
kubectl autoscale rs frontend --max=10
# ReplicaSet的替代选项
# Deployment(推荐)
Deployment 对象包含 ReplicaSet 作为从属对象,并且可通过声明式、滚动更新的方式更新 ReplicaSet 及其 Pod。尽管 ReplicaSet 可以单独使用,但是 ReplicaSet 现在主要是被用作 Deployment 中负责 Pod 创建、删除、更新的一种手段。当您使用 Deployment 时,您无需关心 由 Deployment 创建的 ReplicaSet,Deployment 将处理所有与之相关的细节。
推荐
请始终使用 Deployment,而不是 ReplicaSet
# Bare Pods
与用户直接创建的 Pod 不同,ReplicaSet 在 Pod 由于任何原因被删除或终止时(例如,节点故障或者节点升级)将创建新的 Pod 作为其替代。不推荐您直接使用 Pod,即便您的应用程序只需要一个 Pod 副本,请使用 Deployment。
# Job
使用 Job 执行批处理任务
# DaemonSet
当您需要提供机器级别的功能时(例如监控节点、收集节点上的日志),使用 DaemonSet。
# ReplicationController
ReplicaSet 是 ReplicationController 的后继者。它们的用途相同,行为相似,区别在于:
- ReplicationController 不支持 基于集合的选择器,因此,推荐使用 ReplicaSet 而不是 ReplicationController
微信群
赞赏
← 控制器_概述 介绍 Deployment →