1 ReplicationController简介
1.1 Replication Controller简介
Replication Controller简称RC,它能够保证Pod持续运行,并且在任何时候都有指定数量的Pod副本,在此基础上提供一些高级特性,其主要的功能如下:
- 确保pod数量:它会确保Kubernetes中有指定数量的Pod在运行。如果少于指定数量的pod,Replication Controller会创建新的,反之则会删除掉多余的以保证Pod数量不变。
- 确保pod健康:当pod不健康,运行出错或者无法提供服务时,Replication Controller也会杀死不健康的pod,重新创建新的。
- 弹性伸缩 :在业务高峰或者低峰期的时候,可以通过Replication Controller动态的调整pod的数量来提高资源的利用率。同时,配置相应的
- 监控功能(Hroizontal Pod Autoscaler),会定时自动从监控平台获取Replication Controller关联pod的整体资源使用情况,做到自动伸缩。
- 滚动升级:滚动升级为一种平滑的升级方式,通过逐步替换的策略,保证整体系统的稳定,在初始化升级的时候就可以及时发现和解决问题,避免问题不断扩大。
它在k8s中的架构如图:
RC会在每个节点上创建Pod,Pod上如果有相应的Images可以直接创建,如果没有,则会拉取这个镜像再进行创建。
1.2 ReplicationController作用说明
ReplicationController是一种Kubernetes资源对象,也是一类控制器,可确保它的pod始终保持运行状态。如果pod因任何原因消失(例如节点从集群中消失或由于该pod已从节点中逐出),则ReplicationController会注意到缺少了pod并创建替代pod。
下图显示了当一个节点下线且带有两个pod时会发生什么。pod A是被直接创建的,因此是非托管的pod,而pod B由ReplicationController管理。节点异常退出后,ReplicationController会创建一个新的pod(pod B2)来替换缺少的pod B,而pod A完全丢失 —— 没有东西负责重建它。
图中的ReplicationController只管理一个pod,但一般而言,ReplicationController旨在创建和管理一个pod的多个副本(replicas)。这就是ReplicationController名字的由来。
节点故障时,只有ReplicationController管理的pod被重新创建。
1.3 ReplicationController工作原理解析
ReplicationController会持续监控正在运行的pod列表,并保证相应“类型”的pod的数目与期望相符。如正在运行的pod太少,它会根据pod模板创建新的副本。如正在运行的pod太多,它将删除多余的副本。你可能会对有多余的副本感到奇怪。这可能有几个原因:
- 有人会手动创建相同类型的pod。
- 有人更改现有的pod的“类型”(标签?)。
- 有人减少了所需的pod的数量,等等。
1.3.1 控制器的协调流程
ReplicationController的工作是确保pod的数量始终与其标签选择器匹配。如果不匹配,则ReplicationController将根据所需,采取适当的操作来协调pod的数量。下图显示了ReplicationController的操作。
一个ReplicationController的协调流程
1.3.2 ReplicationController的三部分
一个ReplicationController有三个主要部分(如下图所示):
- label selector(标签选择器),对应spec.selector属性,用于确定ReplicationController作用域中有哪些pod;
- replica count(副本个数),对应spec.replicas属性,指定应运行的pod数量;
- pod template(pod模板),对应spec.template属性,用于创建新的pod副本;
ReplicationController的三个关键部分(pod选择器、副本个数和pod模板)
ReplicationController的副本个数、标签选择器,甚至是pod模板都可以随时修改,但只有副本数目的变更会影响现有的pod。
1.3.3 更改控制器的标签选择器或pod模板的效果
更改标签选择器和pod模板对现有pod没有影响。更改标签选择器会使现有的pod脱离ReplicationController的范围,因此控制器会停止关注它们。在创建pod后,ReplicationController也不关心其pod的实际“内容”(容器镜像、环境变量及其他)。因此,该模板仅影响由此ReplicationController创建的新pod。可以将其视为创建新pod的曲奇切模(cookie cutter)。
1.3.4 使用ReplicationController的好处
像Kubernetes中的许多事物一样,ReplicationController尽管是一个令人难以置信的简单概念,却提供或启用了以下强大功能:
- 确保一个pod(或多个pod副本)持续运行,方法是在现有pod丢失时启动一个新pod。
- 集群节点发生故障时,它将为故障节点上运行的所有pod(即受ReplicationController控制的节点上的那些pod)创建替代副本。
- 它能轻松实现pod的水平伸缩 —— 手动和自动都可以(参见第15章中的pod的水平自动伸缩)。
注意:pod实例永远不会重新安置到另一个节点。相反,ReplicationController会创建一个全新的pod实例,它与正在替换的实例无关。
2 RC常用管理
2.1 创建一个ReplicationController
让我们了解一下如何创建一个ReplicationController,然后看看它如何让你的pod运行。就像pod和其他Kubernetes资源,可以通过上传JSON或YAML描述文件到Kubernetes API服务器来创建ReplicationController。
你将为你的ReplicationController创建名为kubia-rc.yaml的YAML文件,如下面的代码清单所示。
代码清单2.1 ReplicationController的YAML定义:kubia-rc.yaml
上传文件到API服务器时,Kubernetes会创建一个名为kubia的新ReplicationController,它确保符合标签选择器app=kubia的pod实例始终是三个。当没有足够的pod时,根据提供的pod模板创建新的pod。模板的内容与前一章中创建的pod定义几乎相同。
模板中的pod标签显然必须和ReplicationController的标签选择器匹配,否则控制器将无休止地创建新的容器。因为启动新pod不会使实际的副本数量接近期望的副本数量。为了防止出现这种情况,API服务会校验ReplicationController的定义,不会接收错误配置。
根本不指定选择器也是一种选择。在这种情况下,它会自动根据pod模板中的标签自动配置。
提示 定义ReplicationController时不要指定pod选择器,让Kubernetes从pod模板中提取它。这样YAML更简短。
要创建ReplicationController,请使用已知的kubectl create命令:
代码语言:javascript复制$ kubectl create -f kubia-rc.yaml
一旦创建了ReplicationController,它就开始工作。让我们看看它都会做什么。
2.2 使用ReplicationController
由于没有任何pod有app=kubia标签,ReplicationController会根据pod模板启动三个新的pod。列出pod以查看ReplicationController是否完成了它应该做的事情:
代码语言:javascript复制$ kubectl get pods
它确实创建了三个pod。现在ReplicationController正在管理这三个pod。接下来,你将通过稍稍破坏它们来观察ReplicationController如何响应。
2.2.1 查看ReplicationController对已删除的pod的响应
首先,你将手动删除其中一个pod,以查看ReplicationController如何立即启动新容器,从而将匹配容器的数量恢复为三:
代码语言:javascript复制$ kubectl delete pod kubia-53thy
重新列出pod会显示四个,因为你删除的pod已终止,并且已创建一个新的pod:
代码语言:javascript复制$ kubectl get pods
ReplicationController再次完成了它的工作。这是非常有用的。
2.2.2 获取有关ReplicationController的信息
通过kubectl get命令显示的关于ReplicationController的信息:
代码语言:javascript复制$ kubectl get rc
注意:使用rc作为replicationcontroller的简写。
你会看到三列显示了所需的pod数量,实际的pod数量,以及其中有多少pod已准备就绪(当我们在下一章谈论准备就绪探针时,你将了解这些含义)。可以通过kubectl describe命令看到ReplicationController的附加信息。
代码清单2.2 显示使用kubectl describe的ReplicationController的详细信息
代码语言:javascript复制# kubectl describe rc kubia-rc
Name: kubia-rc
Namespace: test
Selector: app=kubia
Labels: app=kubia
Annotations: <none>
Replicas: 3 current / 3 desired Pods
Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed Pod
Template:
Labels: app=kubia
Containers:
kubia:
Image: luksa/kubia
Port: 8080/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events: Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 6m24s
replication-controller Created pod: kubia-rc-hvx2m Normal SuccessfulCreate 6m24s replication-controller Created pod: kubia-rc-6zkpd Normal SuccessfulCreate 6m24s replication-controller Created pod: kubia-rc-x97fm Normal SuccessfulCreate 3m56s replication-controller Created pod: kubia-rc-kkpzv
当前的副本数与所需的数量相符,因为控制器已经创建了一个新的pod。它显示了四个正在运行的pod,因为被终止的pod仍在运行中,尽管它并未计入当前的副本个数中。底部的事件列表显示了ReplicationController的行为—— 它到目前为止创建了四个pod。
2.3 控制器如何创建新的pod
控制器通过创建一个新的替代pod来响应pod的删除操作(见下图)。从技术上讲,它并没有对删除本身做出反应,而是针对由此产生的状态 —— pod数量不足。
虽然ReplicationController会立即收到删除pod的通知(API服务器允许客户端监听资源和资源列表的更改),但这不是它创建替代pod的原因。该通知会触发控制器检查实际的pod数量并采取适当的措施。
如果一个pod消失,ReplicationController将发现pod数目更少并创建一个新的替代pod。
2.4 应对节点故障
看着ReplicationController对手动删除pod做出响应没什么意思,所以我们来看一个更好的示例。如果使用Google Kubernetes Engine来运行这些示例,那么已经有一个三节点Kubernetes集群。你将从网络中断开其中一个节点来模拟节点故障。
注意:如果使用Minikube,则无法做这个练习,因为只有一个节点同时充当主节点和工作节点。
如果节点在没有Kubernetes的场景中发生故障,运维人员需要手动将节点上运行的应用程序迁移到其他机器。而现在,Kubernetes会自动执行此操作。在ReplicationController检测到它的pod已关闭后不久,它将启动新的pod以替换它们。
让我们在实践中看看这个行为。需要使用gcloud compute ssh命令ssh进入其中一个节点,然后使用sudo ifconfig eth0 down关闭其网络接口,如下面的代码清单所示。
注意:通过使用-o wide选项列出pod,选择至少运行一个pod的节点。
代码清单2.3 通过关闭网络接口来模拟节点故障
代码语言:javascript复制$ gcloud compute ssh gke-kubia-default-pool-b46381f1-xwko
当你关闭网络接口时,ssh会话将停止响应,所以需要打开另一个终端或强行退出ssh会话。在新终端中,可以列出节点以查看Kubernetes是否检测到节点下线。这需要一分钟左右的时间。然后,该节点的状态显示为NotReady:
代码语言:javascript复制$ kubectl get node
如果你现在列出pod,那么你仍然会看到三个与之前相同的pod,因为Kubernetes在重新调度pod之前会等待一段时间(如果节点因临时网络故障或Kubelet重新启动而无法访问)。如果节点在几分钟内无法访问,则调度到该节点的pod的状态将变为Unknown。此时,ReplicationController将立即启动一个新的pod。可以通过再次列出pod来看到这一点:
注意:pod的存活时间,你会发现kubia-dmdck pod是新的。你再次拥有三个运行的pod实例,这意味着ReplicationController再次开始它的工作,将系统的实际状态置于所需状态。
如果一个节点不可用(发生故障或无法访问),会发生同样的情况。立即进行人为干预就没有必要了。系统会自我修复。要恢复节点,需要使用以下命令重置它:
代码语言:javascript复制$ gcloud compute instances reset gke-kubia-default-pool-b46381f1-xwko
当节点再次启动时,其状态应该返回到Ready,并且状态为Unknown的pod将被删除。
2.5 将pod移入或移出ReplicationController的作用域
由ReplicationController创建的pod并不是绑定到ReplicationController。在任何时刻,ReplicationController管理与标签选择器匹配的pod。通过更改pod的标签,可以将它从ReplicationController的作用域中添加或删除。它甚至可以从一个ReplicationController移动到另一个。
提示:尽管一个pod没有绑定到一个ReplicationController,但该pod在metadata.ownerReferences字段中引用它,可以轻松使用它来找到一个pod属于哪个ReplicationController。
如果你更改了一个pod的标签,使它不再与ReplicationController的标签选择器相匹配,那么该pod就变得和其他手动创建的pod一样了。它不再被任何东西管理。如果运行该节点的pod异常终止,它显然不会被重新调度。但请记住,当你更改pod的标签时,ReplicationController发现一个pod丢失了,并启动一个新的pod替换它。
让我们通过你的pod试试看。由于你的ReplicationController管理具有app=kubia标签的pod,因此需要删除这个标签或修改其值以将该pod移出ReplicationController的管理范围。添加另一个标签并没有用,因为ReplicationController不关心该pod是否有任何附加标签,它只关心该pod是否具有标签选择器中引用的所有标签。
1. 给ReplicationController管理的pod加标签
需要确认的是,如果你向ReplicationController管理的pod添加其他标签,它并不关心:
代码语言:javascript复制$ kubectl label pod kubia-dmdck type=special $ kubectl get pods --show-labels
给其中一个pod添加了type=special标签,再次列出所有pod会显示和以前一样的三个pod。因为从ReplicationController角度而言,没发生任何更改。
2. 更改已托管的pod的标签
现在,更改app=kubia标签。这将使该pod不再与ReplicationController的标签选择器相匹配,只剩下两个匹配的pod。因此,ReplicationController会启动一个新的pod,将数目恢复为三:
代码语言:javascript复制$ kubectl label pod kubia-dmdck app=foo --overwrite
--overwrite参数是必要的,否则kubectl将只打印出警告,并不会更改标签。这样是为了防止你想要添加新标签时无意中更改现有标签的值。再次列出所有pod时会显示四个pod:
注意:使用-L app选项在列中显示app标签。
你现在有四个pod:一个不是由你的ReplicationController管理的,其他三个是。其中包括新建的pod。
下图说明了当你更改pod的标签,使得它们不再与ReplicationController的pod选择器匹配时,发生的事情。可以看到三个pod和ReplicationController。在将pod的标签从app=kubia更改为app=foo之后,ReplicationController就不管这个pod了。由于控制器的副本个数设置为3,并且只有两个pod与标签选择器匹配,所以ReplicationController启动kubia-2qneh pod,使总数回到了三。kubiadmdck pod现在是完全独立的,并且会一直运行直到你手动删除它(现在可以这样做,因为你不再需要它)。
通过更改标签从ReplicationController的作用域中删除一个pod
3. 从控制器删除pod
当你想操作特定的pod时,从ReplicationController管理范围中移除pod的操作很管用。例如,你可能有一个bug导致你的pod在特定时间或特定事件后开始出问题。如果你知道某个pod发生了故障,就可以将它从Replication-Controller的管理范围中移除,让控制器将它替换为新pod,接着这个pod就任你处置了。完成后删除该pod即可。
4. 更改ReplicationController的标签选择器
这里有个练习,看看你是否完全理解了ReplicationController:如果不是更改某个pod的标签而是修改了ReplicationController的标签选择器,你认为会发生什么?
如果你的答案是“它会让所有的pod脱离ReplicationController的管理,导致它创建三个新的pod”,那么恭喜你,答对了。这表明你了解了ReplicationController的工作方式。Kubernetes确实允许你更改ReplicationController的标签选择器,但这不适用于本章后面介绍的其他资源(也是用来管理pod的)。
你永远不会修改控制器的标签选择器,但你会时不时会更改它的pod模板。就让我们来了解一下吧。
2.6 修改pod模板
ReplicationController的pod模板可以随时修改。更改pod模板就像用一个曲奇刀替换另一个。它只会影响你之后切出的曲奇,并且不会影响你已经剪切的曲奇(见下图)。要修改旧的pod,你需要删除它们,并让ReplicationController根据新模板将其替换为新的pod。
更改ReplicationController的pod模板只影响之后创建的pod,并且不会影响现有的pod
可以试着编辑ReplicationController并向pod模板添加标签。使用以下命令编辑ReplicationController:
代码语言:javascript复制$ kubectl edit rc kubia
这将在你的默认文本编辑器中打开ReplicationController的YAML配置。找到pod模板部分并向元数据添加一个新的标签。保存更改并退出编辑器后,kubectl将更新ReplicationController并打印以下消息:
代码语言:javascript复制replicationcontroller "kubia" edited
现在可以再次列出pod及其标签,并确认它们未发生变化。但是如果你删除了这个pod并等待其替代pod创建,你会看到新的标签。
像这样编辑一个ReplicationController,来更改容器模板中的容器图像,删除现有的容器,并让它们替换为新模板中的新容器,可以用于升级pod,但你将在第9章学到更好的方法。
配置kubectl edit使用不同的文本编辑器
可以通过设置KUBE_EDITOR环境变量来告诉kubectl使用你期望的文本编辑器。例如,如果你想使用nano编辑Kubernetes资源,请执行以下命令(或将其放入~/.bashrc或等效文件中):
代码语言:javascript复制export KUBE_EDITOR="/usr/bin/nano"
如果未设置KUBE_EDITOR环境变量,则kubectl edit会回退到使用默认编辑器(通常通过EDITOR环境变量进行配置)。
2.7 水平缩放pod
你已经看到了ReplicationController如何确保持续运行的pod实例数量保持不变。因为改变副本的所需数量非常简单,所以这也意味着水平缩放pod很简单。
放大或者缩小pod的数量规模就和在ReplicationController资源中更改Replicas字段的值一样简单。更改之后,ReplicationController将会看到存在太多的pod并删除其中的一部分(缩容时),或者看到它们数目太少并创建pod(扩容时)。
2.7.1 命令行方式实现Pod扩容
ReplicationController一直保持三个pod实例在运行的状态。现在要把这个数字提高到10。你可能还记得,已经在第2章中扩容了ReplicationController。可以使用和之前相同的命令:
代码语言:javascript复制$ kubectl scale rc kubia --replicas=10
2.7.2 通过编辑定义文件实现缩放Pod
不使用kubectl scale命令,而是通过以声明的形式编辑ReplicationController的定义对其进行缩放:
代码语言:javascript复制$ kubectl edit rc kubia
当文本编辑器打开时,找到spec.replicas字段并将其值更改为10,如下面的代码清单所示。
代码清单2.4 运行kubectl edit在文本编辑器中编辑RC
保存该文件并关闭编辑器,ReplicationController会更新并立即将pod的数量增加到10:
代码语言:javascript复制$ kubectl get rc
就是这样。如果 kubectl scale 命令看起来好像是你在告诉Kubernetes要做什么,现在就更清晰了,你是在声明对ReplicationController的目标状态的更改,而不是告诉Kubernetes它要做的事情。
2.7.3 用kubectl scale命令缩容
现在将副本数目减小到3。可以使用 kubectl scale 命令:
代码语言:javascript复制$ kubectl scale rc kubia --replicas=3
所有这些命令都会修改ReplicationController定义的spec.replicas字段,就像通过 kubectl edit 进行更改一样。
2.7.4 伸缩集群的声明式方法
在Kubernetes中水平伸缩pod是陈述式的:“我想要运行x个实例。”你不是告诉Kubernetes做什么或如何去做,只是指定了期望的状态。
这种声明式的方法使得与Kubernetes集群的交互变得容易。设想一下,如果你必须手动确定当前运行的实例数量,然后明确告诉Kubernetes需要再多运行多少个实例的话,工作更多且更容易出错,改变一个简单的数字要容易得多。在第15章中,你会发现如果启用pod水平自动缩放,那么即使是Kubernetes本身也可以完成。
2.8 删除一个ReplicationController
当你通过 kubectl delete 删除ReplicationController时,pod也会被删除。但是由于由ReplicationController创建的pod不是ReplicationController的组成部分,只是由其进行管理,因此可以只删除ReplicationController并保持pod运行,如下图所示。
当你最初拥有一组由ReplicationController管理的pod,然后决定用ReplicaSet( 你接下来会知道)替换ReplicationController时,这就很有用。可以在不影响pod的情况下执行此操作,并在替换管理它们的ReplicationController时保持pod不中断运行。
使用--cascade=false删除ReplicationController使托架不受管理
当使用kubectl delete删除ReplicationController时,可以通过给命令增加--cascade=false选项来保持pod的运行。马上试试看:
代码语言:javascript复制$ kubectl delete rc kubia --cascade=false
你已经删除了ReplicationController,所以这些pod独立了,它们不再被管理。但是你始终可以使用适当的标签选择器创建新的ReplicationController,并再次将它们管理起来。
参考链接
replication controller_fightingwy的博客-CSDN博客
Kubernetes核心概念之Replication Controller详解_linux运维技术的技术博客_51CTO博客
ReplicationController
如何理解ReplicationController及其配置 - 云计算 - 亿速云
kubernetes概念之四:Replication Controller&Replica Sets&Deployments_ITPUB博客
4.2 了解ReplicationController - 知乎
K8s控制器ReplicationController(RC)_bjgaocp的博客-CSDN博客
k8s入门-Replication Controller控制器_wc1695040842的博客-CSDN博客
3.2 控制器——副本控制器(ReplicationController)_jacksonary的博客-CSDN博客_replicationcontroller