【转】Kubelet 重启导致宿主重启的经验总结

在更新Kubelet以支持NBD功能时,遇到重启Kubelet导致宿主机重启的问题。通过调整KillMode参数和storageClass配置,解决了rdb-nbd进程异常退出引起的死机。

提要

线下集成测试时,尝试更新 Kubelet 的新版本。针对新增功能中支持 NBD,我们遇到 Kubelet 重启会导致宿主机重启的问题。最终问题定位至 rdb-nbd 进程异常退出导致死机。通过修改 KillMode 参数和 storageClass 配置,修复了问题。

问题描述

在新版本 Kubelet 中新增了支持 NBD 的相关功能,我们在线下测试集群中尝试更新 Kubelet 来研究其功能。

在 2018-02-23 15:46:56 时,我们通过发布系统灰度更新 kubelet 时,发现部署超时,最终导致部署失败,再次尝试部署,可以部署成功,登录已部署的宿主机查看,发现宿主机重启了,然后暂停余下部署。

紧接着,我们围绕 NDB 进行排查, 最后发现,只要挂载了 NBD 设备的宿主,只要重启 Kubelet 就会死机,然后经过手动测试该特性发现,如果杀死了 rbd-nbd map 的进程其实也会导致死机。

所以将问题定位至:

  1. 重启 Kubelet 为什么导致 rbd-nbd map 的进程也被退出了?
  2. Rbd-nbd map 的进程退出为什么导致死机?

Rbd-nbd 被动退出问题

Kubelet 服务是由 systemd 托管的,而 rbd-nbd map 进程是由 Kubelet 运行的,rbd-nbd map 进程则成为 Kubelet 的控制组内的进程了, 如下:

当停止 Kubelet 服务的时候,systemd 会首先给 Kubelet 发送杀死信号,然后会给其它进程也发杀死信号,导致问题 1 的发生,事后尝试完全把 rbd-nbd map 这个逻辑从 Kubelet 自身脱离出来,由外部服务来执行和托管,这应该也是 CSI 的思想,但是对于我们现在来说管理成本太高了, 那么还是从 systemd 入手查看,看能否做到杀死 Kubelet 时不给其它进程发杀死信号机制,果然有:

KillMode=XXX 可以设置执行 systemctl stop 时的姿势,比如: KillMode=process:If set to process, only the main process itself is killed,默认是 control-group。

其它姿势可以看 systemd.kill 手册:

死机问题

对于死机问题,第一时间是查日志,查日志有两个地方:

  1. /var/log/messages
  2. /var/crash

Messages 里没发现什么异常信息,直接查看 crash,发现有几次 crash,根据故障特点,查看重点信息:

从 Oops 信息查看貌似是触发了 ext4 文件系统的底层 BUG, 回想一下 kubelet 通过 storageclass 挂载 ceph 设备的流程,并没有指定 mount 到本地的文件系统类型,那么默认使用的就是 ext4, 所以,更新 storageclass 配置,增加 fsType 参数,并设置为 xfs,比如:

然后再重新测试整个创建容器,重启 Kubelet 服务流程,不存在 rbd-nbd 程序退出和宿主死机重启的问题了。

总结

对于上面的问题的解决方案, 目前看需要弹性云线上集群做如下修改:

  1. 优化 Kubelet 支持 NBD 的代码,使用最新的 patch;
  2. 修改 Kubelet 服务配置文件,增加 Killmode=process;
  3. 修改 storageClass 配置, 增加文件系统类型参数 fsType:xfs。

扩展思考

如果 rbd-nbd 被意外 Kill 掉,结果会怎么样呢?

经过测试发现,如果 rbd-nbd 被 Kill 掉,导致该容器的 ceph 盘读写错误 (IO Error),但是容器还正常运行,暂时没有恢复方案,所以需要加监控;针对 ceph 和 Kubernetes 的集成,需要更加详细的测试。

<think>我们面对的问题是:在Android 13分屏模式下,当宿主Activity因配置变更(如屏幕旋)而重启时,如何避免嵌入的Activity也跟随重启。 根据引用[1]中的信息,我们可以通过设置Activity的`android:configChanges`来避免Activity的重建。但是,我们需要区分宿主Activity和嵌入的Activity。 关键点: 1. 宿主Activity:即分屏模式下的一个窗口中的Activity,当它因配置变更(如旋)而重启时,我们希望它不重启,这样嵌入的Activity就不会被重启。 2. 嵌入的Activity:在分屏模式下,两个Activity是并存的,它们都有自己的生命周期,但宿主Activity的重建可能会导致嵌入的Activity也被重建(因为嵌入的Activity是宿主Activity所在任务的一部分)。 然而,在分屏模式下,每个Activity都是独立的,它们分别处理自己的配置变更。因此,我们可以为宿主Activity设置`android:configChanges`来避免宿主Activity重启,从而避免整个任务栈的重建,进而避免嵌入的Activity重启。 具体步骤: - 在宿主Activity的AndroidManifest.xml中,声明处理特定配置变更,例如屏幕方向、屏幕大小等。 ```xml <activity android:name=".HostActivity" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|density" ... > </activity> ``` 这样,当发生这些配置变更时,宿主Activity不会重启,而是调用`onConfigurationChanged()`方法。 - 在宿主Activity中重写`onConfigurationChanged()`方法,以处理配置变更: ```java @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // 在这里更新布局,例如重新设置布局方向等 } ``` 效果: 宿主Activity不会重启,因此它所在的窗口不会重建,那么嵌入在同一个任务栈中的其他Activity也不会被销毁重建。但是注意,嵌入的Activity可能也会因为自己的配置变更而重启,所以我们也需要在嵌入的Activity中做同样的配置。 另外,根据引用[2]中的权限限制,我们不需要担心系统权限问题,因为这是应用内Activity的配置。 但是,如果嵌入的Activity是另一个应用(比如通过Intent启动的),那么我们不能控制另一个应用的配置处理。因此,这个方法适用于同一个应用内的Activity分屏。 总结: 为了避免宿主Activity重启导致嵌入的Activity重启,我们可以通过设置宿主Activity的`android:configChanges`属性来避免宿主Activity的重建,从而避免连带的重建。 注意:在分屏模式下,如果两个Activity属于同一个应用,那么我们可以分别设置它们的`android:configChanges`来避免各自的重启。如果属于不同应用,则只能控制自己应用内的Activity。 潜在问题: 如果我们在`onConfigurationChanged()`中没有正确处理配置变更,可能会导致UI布局错乱。因此,我们需要在这个方法中手动调整布局。 相关问题: §§相关问题§§ 1. 在分屏模式下如何处理配置变更以避免Activity重建? 2. 如何为分屏模式下的Activity设置不同的布局? 3. 在分屏模式下,如何保持两个Activity之间的数据同步? 4. 如果嵌入的Activity是其他应用的Activity,如何避免它重启? </think>### Android 13分屏模式下避免嵌入Activity重启的解决方案 在Android 13分屏场景中,宿主Activity重启时可能导致嵌入Activity意外重启,可通过以下方法避免: #### 1. **配置变更处理**(核心方案) 在宿主Activity的`AndroidManifest.xml`中声明处理配置变更: ```xml <activity android:name=".HostActivity" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|density"> </activity> ``` - **原理**:声明后配置变更时不会重建Activity,而是触发`onConfigurationChanged()`[^1] - **效果**:宿主Activity不重启 → 嵌入Activity保持运行状态 - **注意**:需处理屏幕方向/尺寸变化的UI适配 #### 2. **状态保存与恢复** 在嵌入Activity中覆盖生命周期方法: ```kotlin // 保存状态 override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString("KEY_DATA", criticalData) } // 恢复状态 override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) criticalData = savedInstanceState.getString("KEY_DATA") } ``` - 即使意外重启也能恢复关键数据 - 适用场景:轻量级数据恢复 #### 3. **ViewModel持久化** ```kotlin class EmbeddedViewModel : ViewModel() { val liveData = MutableLiveData<String>() } // 在Fragment/Activity中 private val viewModel by viewModels<EmbeddedViewModel>() ``` - **优势**:配置变更时自动保留数据 - **生命周期**:与Activity/Fragment解耦 #### 4. **分屏状态感知** ```kotlin override fun onMultiWindowModeChanged(isInMultiWindow: Boolean) { if (isInMultiWindow) { // 分屏模式特殊处理 } } ``` - 通过API检测分屏状态变化 - 可暂停非必要操作降低重启影响[^3] #### 5. **进程间通信优化(跨应用场景)** ```kotlin // 宿主Activity private val remoteConnection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName, service: IBinder) { val binder = service as EmbeddedService.LocalBinder embeddedService = binder.getService() } } ``` - 使用Bound Service保持跨进程状态 - 需配合`<service android:process=":remote">`声明[^2] > ⚠️ **注意事项** > 1. 系统强制重启场景(如内存不足)无法完全避免 > 2. 跨应用嵌入需处理权限问题`MANAGE_ACTIVITY_TASKS`[^2] > 3. 复杂场景建议结合Fragment实现模块化管理[^3][^4] --- ### 配置变更处理流程对比 | 场景 | 未处理配置变更 | 已处理配置变更 | |------------------------------|---------------------|----------------------| | **宿主Activity生命周期** | 销毁重建 | 保持运行 | | **嵌入Activity受影响程度** | 可能跟随重启 | 保持稳定运行 | | **数据保留方式** | 依赖onSaveInstanceState | ViewModel持久化 | | **UI适配工作** | 自动重建布局 | 需手动处理配置变更 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值