1,前言

入职大概有四个月了,中间一直在做监控告警相关的任务,使用到的三方组件是,Prometheus和alertmanager,在整个使用过程中,对Prometheus和kubernetes都有了一定了解,今天打算说说在k8s集群中使用local storage存储数据的问题。

2,抛出问题。

在k8s集群中,pod是可以在各个node之间调度的,当某个node的资源不够用的时候,pod就有可能被调度到别的node上去。那么问题来了,如果使用本地存储的Prometheus被调度到别的node上,使用新节点的本地存储,这时就会出现数据到处跑,每个node上都是唯一的一份,所有node合并起来才是完整的数据,并且如果repcaset设置为多个,那么就会出现多写的情况,这时,当我们再从Prometheus中查询数据的时候,可能得到额数据不准确,比如第一个请求打到nodeA上PrometheusA,第二个请求打到nodeB上的PrometheusB上,那么这两次查询的结果就是不一样的。如何解决这个问题呢?

3,问题分析

3.1,首先需要指明一点的是,假设我们没有设置污点trains,也就是默认,业务pod不可以运行在master node上,master node上跑的都是k8s集群用到的基础pod。(ps,简单说一下trains污点,trains是node的一个属性,当pod不能容忍污点的时候,pod就不会被调度到词node上,设置pod容忍也很简单,官方有专门的文档。pod容忍度更新为亲和和反亲和(也叫亲缘性与非亲缘性),可使用nodeName,nodeSelector,affinity设置)。
3.2,我们先来分析单写的情况,如上所说pod可以被调度在任意一台非master的node上,那么只要保证集群中只有一台非master节点不就好了,讲真,逻辑上来说,是可以的,但问题是生产环境肯定有多台master node和多台非master node毕竟要保证高可用,当一台master节点挂了, 可以从非master中选举出新的master,当一台非master节点挂了,可以将原来在此节点上的业务pod调度到别的非master节点上,以实现高可用。所以只有一台非master节点不可行。
3.3,接着分析单写,前边已经说到调度问题了,所以如果将Prometheus固定调度到某一个节点不就好了,然后在此node上使用本地存储就可以了,但是为了解耦,我们还是使用pv和pvc比较合适,自定义一个storageClass,pv使用此storageClass,并且对node申请磁盘资源,可设置访问模式,多写,多读,单写,并且可以设置数据保留方式,pv杀掉后,数据要不要清理,然后pvc绑定pv,并且向pv申请资源,感觉一个pv可以被多个pvc绑定,相当于pv是一个资源池,pvc通过绑定的方式从资源池拿数据,然后pod使用pvc做存储即可。所以关键是要将存储绑定在某一台机器上,而不是pod。至此,解决方案已经出来了,将pv和node绑定即可。并且通过实验得知,当pod使用pvc使用pv时,pod会被调度到pv所绑定的那一台机器上。而如果强制将pod调度到别的node上,是会直接报错的。
3.4,单写的问题可以使用pv绑定node解决,那么多写问题怎么解呢,不是很简单,kubernetes虽然提供了statefulSet,也就是使用有状态的pod,每个pod都是独一无二的,这时可以通过template对每个pod设置单独的存储pv,但是这样有个问题就是大家都是独立的,而一个写请求只会打到一个pod上,如果可以实现一个写请求固定打到所有pod上,而读请求随机打到任意一台pod上就好了,不知道有没有这样的设置办法,ingress也许可以,但是没试过。
3.5,这时候就会有机灵的小伙伴说,可以使用replicaSet或者statefulSet,从而使用多个pvc,而这多个pvc使用一个pv不就行了,但实际上,之前已经说了,虽然是一个pv,但是每个pvc会申请单独的空间,所以此法不可行哦。想了一想,其实可以使用三方存储,比入nfs,或者Kafka,但是笔者懒得折腾,不然也许可以做个实验验证一下。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐