searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Kubernetes 上运行有状态应用的实践总结

2023-07-28 08:25:28
18
0

有状态应用允许用户重复返回该应用并恢复之前的操作,比如电子邮件或者网上银行应用。有状态的应用会记录之前事务的上下文,这些上下文可能会对当前或未来事务产生影响。所以,有状态的应用必须确保每个用户始终访问同一个应用程序实例,或者有某种在实例之间同步数据的机制。

本文通过在分布式数据库在kubernetes的实践,总结如下有状态应用的注意点。

 

稳定且唯一的标识符

kubernetes中支持稳定且唯一的标识符的workload是StatefulSet。StatefulSet 中的 Pod 都是有序号的,从 0 开始一直到定义的 replica 数量减一。配合headless service, 可以让StatefulSet的pod在整个k8s集群中有稳定且唯一的域名。

对于部分分布式数据库或者存储,除了要去pod有唯一的域名或者hostname外,还要求pod有不变的ip。解决ip不变的问题有如下两种方法:

  1. 选择hostnetwork,可以让pod使用node 的网络,可以保证ip不变,不过需要nodeSelector或者绑定pv保证pod不会在node间漂移;
  2. 选择pod的ip不变的网络插件:
    1. 开源网络插件Calico:支持IPIP和BGP两种协议,同时也支持给特定pod指定ip
    2. 阿里巴巴开源网络插件hybridnet: 支持针对StatefulSet pod保留ip

 

数据可持久化

Kubernetes 中的常规存储卷会有一个确定的生命周期:每个卷都与 pod 的生命周期绑定。当 pod 处于活跃状态的时候,卷会保持在 pod 内,如果重启 pod 的话,卷会被重置。所以针对有状态的应用,需要pod能够挂载持久卷(Persistent Volume)。

针对持久卷,可以根据不同环境使用不同的StorageClass。在公有云环境,可以使用云厂商提供的云盘。如果没有云盘,可以使用本地盘,详解 云原生本地磁盘管理-天翼云开发者社区 - 天翼云 (ctyun.cn)

Pod绑定PV,除了能保证数据的可持久化,另外可以通过PV的稳定性,保证pod不会因为重启、删除而出现漂移的现象。

驱逐管理

Kubernetes在节点收到压力后, kubelet 主动终止 Pod 以回收节点上资源。如果遇到流量高峰,可能出现雪崩效应。有状态应该由于无法漂移,可能会出现被驱逐后无法再被调度。

在针对分布式数据库或存储应用的pod,可以选择较高QoS的资源分配,而且其他无状态或者指标采集应用可以选择较低QoS的资源分配。

合理的分配节点资源,如docker 运行时的磁盘空间或者容器挂载的目录不要使用系统盘资源。

如果时对有状态应用独占情况,可以调高驱逐的条件或删除kubelet驱逐的特性。

kubelet 具有以下默认硬驱逐条件:

  • memory.available<100Mi
  • nodefs.available<10%
  • imagefs.available<15%
  • nodefs.inodesFree<5%(Linux 节点)

容器生命周期管理

不同于无状态应用,有状态应用一般需要上下文信息需要在启动加载或者停止时分发。如分布式数据库需要在启动服务时加载分片信息,在停止服务时把分片的信息分发给其他节点。

Kubernetes 提供了两种容器钩子(hook)来实现容器启动后和容器关闭前需要执行任务:

PostStart: 这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器ENTRYPOINT之前运行,因为没有参数传递给处理程序。主要用于资源部署、环境准备等。不过需要注意的是如果钩子花费太长时间以至于不能运行或者挂起, 容器将不能达到running状态。

PreStop:这个钩子在容器终止之前立即被调用。它是阻塞的,意味着它是同步的, 所以它必须在删除容器的调用发出之前完成。主要用于优雅关闭应用程序、通知其他系统等。如果钩子在执行期间挂起, Pod阶段将停留在running状态并且永不会达到failed状态。

有两种方式来实现上面的钩子:

  1. Exec - 用于执行一段特定的命令,不过要注意的是该命令消耗的资源会被计入容器。
  2. HTTP - 对容器上的特定的端点执行HTTP请求。

原地重启和服务探针

Pod的重启需要重新花费调度、分配 IP、分配、挂载盘 等额外的操作和代价,原地重启可以极大的加快有状态应用恢复的速度,也可以避免一些不必要的上下文重新加载。
 
实现原地重启可以通过加载一个sidecar服务,去控制主容器类服务的启动、关闭、探活。另外,也可以选择开源框架,如openkruise,使用openkruise定义的StatefulSet实现原地重启或者升级的功能。
 
在无状态应用中,LivenessProbe是服务必要的探针,可以帮助服务出现故障时重构pod并恢复服务。而对于有状态应用,需要注意LivenessProbe带来的副作用。有状态服务需要在启动时加载上下文信息,可能需要一些时间才能恢复服务,如果配置的探针不合理,可能出现pod的循环重启。
0条评论
0 / 1000
s****n
4文章数
0粉丝数
s****n
4 文章 | 0 粉丝
原创

Kubernetes 上运行有状态应用的实践总结

2023-07-28 08:25:28
18
0

有状态应用允许用户重复返回该应用并恢复之前的操作,比如电子邮件或者网上银行应用。有状态的应用会记录之前事务的上下文,这些上下文可能会对当前或未来事务产生影响。所以,有状态的应用必须确保每个用户始终访问同一个应用程序实例,或者有某种在实例之间同步数据的机制。

本文通过在分布式数据库在kubernetes的实践,总结如下有状态应用的注意点。

 

稳定且唯一的标识符

kubernetes中支持稳定且唯一的标识符的workload是StatefulSet。StatefulSet 中的 Pod 都是有序号的,从 0 开始一直到定义的 replica 数量减一。配合headless service, 可以让StatefulSet的pod在整个k8s集群中有稳定且唯一的域名。

对于部分分布式数据库或者存储,除了要去pod有唯一的域名或者hostname外,还要求pod有不变的ip。解决ip不变的问题有如下两种方法:

  1. 选择hostnetwork,可以让pod使用node 的网络,可以保证ip不变,不过需要nodeSelector或者绑定pv保证pod不会在node间漂移;
  2. 选择pod的ip不变的网络插件:
    1. 开源网络插件Calico:支持IPIP和BGP两种协议,同时也支持给特定pod指定ip
    2. 阿里巴巴开源网络插件hybridnet: 支持针对StatefulSet pod保留ip

 

数据可持久化

Kubernetes 中的常规存储卷会有一个确定的生命周期:每个卷都与 pod 的生命周期绑定。当 pod 处于活跃状态的时候,卷会保持在 pod 内,如果重启 pod 的话,卷会被重置。所以针对有状态的应用,需要pod能够挂载持久卷(Persistent Volume)。

针对持久卷,可以根据不同环境使用不同的StorageClass。在公有云环境,可以使用云厂商提供的云盘。如果没有云盘,可以使用本地盘,详解 云原生本地磁盘管理-天翼云开发者社区 - 天翼云 (ctyun.cn)

Pod绑定PV,除了能保证数据的可持久化,另外可以通过PV的稳定性,保证pod不会因为重启、删除而出现漂移的现象。

驱逐管理

Kubernetes在节点收到压力后, kubelet 主动终止 Pod 以回收节点上资源。如果遇到流量高峰,可能出现雪崩效应。有状态应该由于无法漂移,可能会出现被驱逐后无法再被调度。

在针对分布式数据库或存储应用的pod,可以选择较高QoS的资源分配,而且其他无状态或者指标采集应用可以选择较低QoS的资源分配。

合理的分配节点资源,如docker 运行时的磁盘空间或者容器挂载的目录不要使用系统盘资源。

如果时对有状态应用独占情况,可以调高驱逐的条件或删除kubelet驱逐的特性。

kubelet 具有以下默认硬驱逐条件:

  • memory.available<100Mi
  • nodefs.available<10%
  • imagefs.available<15%
  • nodefs.inodesFree<5%(Linux 节点)

容器生命周期管理

不同于无状态应用,有状态应用一般需要上下文信息需要在启动加载或者停止时分发。如分布式数据库需要在启动服务时加载分片信息,在停止服务时把分片的信息分发给其他节点。

Kubernetes 提供了两种容器钩子(hook)来实现容器启动后和容器关闭前需要执行任务:

PostStart: 这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器ENTRYPOINT之前运行,因为没有参数传递给处理程序。主要用于资源部署、环境准备等。不过需要注意的是如果钩子花费太长时间以至于不能运行或者挂起, 容器将不能达到running状态。

PreStop:这个钩子在容器终止之前立即被调用。它是阻塞的,意味着它是同步的, 所以它必须在删除容器的调用发出之前完成。主要用于优雅关闭应用程序、通知其他系统等。如果钩子在执行期间挂起, Pod阶段将停留在running状态并且永不会达到failed状态。

有两种方式来实现上面的钩子:

  1. Exec - 用于执行一段特定的命令,不过要注意的是该命令消耗的资源会被计入容器。
  2. HTTP - 对容器上的特定的端点执行HTTP请求。

原地重启和服务探针

Pod的重启需要重新花费调度、分配 IP、分配、挂载盘 等额外的操作和代价,原地重启可以极大的加快有状态应用恢复的速度,也可以避免一些不必要的上下文重新加载。
 
实现原地重启可以通过加载一个sidecar服务,去控制主容器类服务的启动、关闭、探活。另外,也可以选择开源框架,如openkruise,使用openkruise定义的StatefulSet实现原地重启或者升级的功能。
 
在无状态应用中,LivenessProbe是服务必要的探针,可以帮助服务出现故障时重构pod并恢复服务。而对于有状态应用,需要注意LivenessProbe带来的副作用。有状态服务需要在启动时加载上下文信息,可能需要一些时间才能恢复服务,如果配置的探针不合理,可能出现pod的循环重启。
文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0