以控制器的视角看pod的删除过程
控制器收到的事件
client-go中的informer通过reflector watch到的事件对象,类型可以是:Add、Modify、Delete,分别代表对象的增加、更新和删除事件
以删除pod为例,当用户尝试删除一个pod时,外部控制器将能够获取到该pod的4个相关事件(force则是2个),如下:
-
用户发出删除pod请求,api收到该请求之后判断出pod支持优雅删除,将更新etcd中该pod的DeletionTimestamp、DeletionGracePeriodSeconds字段,etcd中该pod的rv变化,此时控制器reflector收到一个Modify event
-
kubelet reflector watch到上述update事件,开始kill pod中的容器,完成后请求api更新pod的status信息,api将更新etcd中该pod 的condition和containerStatuses等字段,etcd中该pod的rv变化,此时控制器reflector收到一个Modify event
-
kubelet完成上述过程之后,会向api再次发送一个delete pod请求,希望api直接删除该pod,api将更新etcd中该pod的DeletionGracePeriodSeconds字段为0, etcd中该pod的rv变化,此时控制器收到一个Modify event
-
api把etcd中的pod的记录删除,但etcd中仍然会记录该pod并更新其rv,此时无法通过api获取到该pod的信息,控制器此时可以收到一个Delete event
问题思考
如果controller发生故障,用户在控制器恢复之前删除资源,那么控制器可以获取到删除的相关事件吗?
-
如果控制器因为网络原因无法连接api,会尝试re-watch,连接api正常之后通过较小的rv记录可以watch到删除资源的事件(etcd会缓存资源的历史版本),因为watch关注的是资源的变化。给定的 Kubernetes 服务器只会保留一定的时间内发生的历史变更列表。 使用 etcd3 的集群默认保存过去 5 分钟内发生的变更。
-
如果控制器挂了,则重启之后会先进行list,此时拿到的是全量的当前状态的资源列表,通过list对象的objectMeta中的rv来进行接下来的watch(list对象在查询的时候生成,所以rv的值与当前时间成正比),因此watch不到历史pod的Delete事件,就可能导致丢失Delete事件,可以通过给控制器关注的资源增加Finalizer来保证资源不会立即从etcd中删除,这样控制器就能重新list到该资源做reconcile后再移除finalizer。
理解finalizer的作用
https://kubernetes.io/blog/2021/05/14/using-finalizers-to-control-deletion/
apiserver通过deletionGracePeriodSeconds表示资源是否需要优雅的删除(如果支持),如pod被删除时因为deletionGracePeriodSeconds不为0,则通过配置deletionTimestamp字段将删除动作转换为更新,由kubelet watch到更新做具体的资源清理之后再设置deletionGracePeriodSeconds为0来确认删除pod。
如果资源上配置了finalizer,那么api收到请求之后都不会立即在etcd删除资源,同样是配置deletionTimestamp转换为更新动作,即使deletionGracePeriodSeconds设置的是0。当所有的finalizer都被移除之后,该资源会被自动删除
理解ownerReferences作用
https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/
当尝试删除一个owner资源对象如rs时,会检查是否有其他资源对象如pod的owner是自己,可以配置删除owner资源时是否级联删除关联的dependent依赖对象
支持的级联cascade策略有:background、foreground、orphaned
foreground:删除owner对象时apiserver在对象上更新deletionTimestamp和foregroundDeletion finalizers字段,gc controller watch到更新之后把所有会阻塞owner对象删除的依赖对象进行删除(配置了ownerReference.blockOwnerDeletion=true[admission controller自动配置]的依赖对象会阻塞owner对象),之后移除finalizer,gc controller再次触发删除owner对象
background:kubectl默认策略,立即删除owner对象,依赖对象由controller-manager的gc controller删除
orphaned:删除owner对象时不会删除依赖对象,依赖对象会一直存在