广告

干货PPT | Kubernetes在vivo容器云平台中的实践

  • 浏览(1,683)
  • 评论(0)
  • 译者:k8s

干货视频:https://v.qq.com/x/page/o0505i8279t.html

2017年11月4日,CNCF Meetup——K8S GeekGathering 深圳站圆满落幕,本次活动由K8S技术社区、腾讯云、EasyStack、灵雀云联合主办,特邀vivo共同参与,由IT大咖说、开源云中文社区提供技术支持与推广。当前日趋火热的Kubernetes技术主题以及干货十足的实践分享吸引深圳地区近150+容器技术关注者到场参与!

vivo资深云计算工程师王涛

vivo资深云计算工程师王涛分享了技术主题 :Kubernetes在vivo容器云平台中的应用与实践 以下是他的演讲内容整理:


(获取深圳站全套PPT打包,文末添加K8S技术社区小助手!)

大家好,今天下午主要从这几个方面和大家交流,一是整个的架构;二是很多人关心集群的HA和安全方面的配置;三是网络方案是什么样的;四是Ingress的方案;四是灰度发布方案;五是集群设置的最佳配置;六是tensorflow on Kubernetes;七是经验和坑和大家交流。

这是我们Kubernetes技术栈(见PPT)。

Architecture,这是简化版数据中心的架构,整个数据中心除了传统物理服务器,最边上的Node节点部署的应用,这边是CaaS集群,一个数据中心有多套K8S集群,每个集群的规模控制在2000个节点以内。我们专门会画出一部分节点来做应用的Proxy Node上面只部署nginx Ingress Controller。这上面不会跑别的应用,这是用来做代理的。监控节点用来部署普罗米修斯等。还有Master的Keepalived和haproxy用来做K8S Master的HA。每个K8S集群Master会有三个副本。我们每个计算节点还会部署一个自己开发的caas-agent,主要是用来做容器的Web Console。

    

第二部分是集群的Master HA安全方面的东西。HA主要涉及的方面,上面肯定有LB,有两个节点做LB,LB1、LB2。你可以通过Pod部署,如果用Pod部署就用kubelet来保证Pod高可用。上面LB过来,下面是三个Master,每个Master都部署了API server、controller-manager、scheduler,controller-manager和scheduler只连接到本机的APIserver上,它不会连后面的Master上面的server,只连本地127.0.0.1上面的API server。上面LB是代理下面三个Master上面的API server。controller-manager他们有自己的HA方法,通过自身leader选举做的,会选一个leader出来。Master上面的组件可以通过Pod部署,我们现在还是以二进制进程的方式部署,LB这里我们做了TLS Termination。更多关于Kubernetes cluster HA方案可以去我的博客查看更多的信息。

    

这是集群需要考虑和关注的安全方面的配置,在传统企业对安全方面的要求还是比较高的。我主要考虑所有组件,整个集群所有组件交互的TLS认证,包括kubelet作为客户端,还有scheduler、controller-manager也作为客户端去访问API-server需要配置TLS认证。其实Node 上的kubelet本身也是有一个server,这个server主要是用来暴露监控信息的,所以Api server做client时候去访问kubelet server也有一个认证的过程,就是绿色的线。另外整个Api server和etcd集群之间的交互也可以配置TLS论证,怎么配这里画出来了,是蓝色的这条线。整个集群里面部署的Pod要访问Api server可能也需要配置TLS论证,怎么配?要配置添加SA的方式去配置TLS认证。

   

第三部分是网络方案,刚才灵雀云的老师分享了他们做的网络方案,我觉得做得很好。我们用的是也是CNI的标准,使用的插件是思科contiv netplugin的,有几个组件:一个是agent,每个节点都有agent。二是一个控制端,netmaster,主要是用来管理整个IP等网络资源。netplugin组件主要是用来跟ovs通信,通过ovs创建ovs为网桥,来设置后面的东西。通过ovs manager去连接OVS,所有Pod的网络,虚拟网卡一端打到Pod里面,一端打到Ovs网桥对上面的网卡进行绑定,我们这边的网络方案做了数据平面和控制平面的网络分离。一个服务器有四个网卡,两个万兆网卡、两个千兆网卡,两个万兆网卡作Bond作为一个数据平面,两个千兆网卡做Bond作为一个控制平面。这是CNI里面两个动作,创建Pod和删除Pod,间Pod和删除Pod的时候大概做什么事呢?这里有一个图大家可以参考。简单说一下创建Pod,用户说现在创建一个Pod,Kubelet监控到有一个Pod掉落到我这个Kubelet上了,Kubelet就创建Pod,因为配置了CNI插件的路径,就去执行CNI的命令,把环境变量设进去,到CNI插件里面,然后去Master里面去请求IP。IP也是存在etcd里面的,它就去里面拿一个可用的IP反馈给它,最终再netplugin去调OVS,创建虚拟网卡,一端插到OVS网桥上面,另外一端插入pause容器里面,再设置IP、网关等。整个流程其实是比较清晰的。第二部分是删除Pod,我就不讲了。

   

 Ingress,我们用官方原生的Ingress,首先介绍一下Ingress基本的概念,Ingress主要是用来用户在集群外部访问集群内应用的方式。比如现在有两个应用,通过这个IP暴露出去,比如说foo.bar.com、bar.foo.com,Ingress通过这个IP让它进来,进来之后最后定位到集群里面哪个服务里面去,这个规则就可以对应到右边的图里面。host:foo.bar.com对应后端的ServicePort是80,bar.foo.com对应的ServicePort是80,其实就是集群外部的用户要访问集群内用户应用的路由。

    

我们用的是nginx,你看代码也会发现这个东西还是比较复杂的,它的配置下面有二三四项这样的配置。我这里列的几个配置,如果需要使用这个东西,要注意的配置,一个是apiserver-host,apiserver-host是用来配置连接这个集群的api server,暴露出来Master IP、端口号,如果没有配这个,K8S通过discover自己发现,它就会连集群里面名叫Kubernetes的服务的ip。

   

第二个是default backend  service,如果用户访问的这个服务在集群里面没有,就全部导到这个服务里面去。后面两个配置是比较重要的,因为在我们数据中心里面会有很多的用户代理节点,有几个节点会用来装nginx-ingress-controller,但是每个代理的namespace是不一样的。如果一个nginx-ingress-controller是watch整个集群里面的namespace会怎么样?如果一个集群有上万个service,就集群里面所有的service都watch,肯定导致整个nginx的配置非常庞大。一旦这个集群里面要有一个service,Service下面的endpoints有些变化,你去更新的时候,这个时间会非常的长。所以配置这个nginx-ingress,去watch-namespace,我只watch哪几个namespace,它就只更新这几个namespace下面的Service等信息。配这个的时候,一定要加上force-namespace-isolatio,是做namespace的隔离,这是大家使用时候需要注意的地方。

    

这是没有容器化之前,我们数据中心大概的代理的方案。前端LVS集群,它的流量再到后端的Nginx server集群,每个Nginx运维会配置,具体要带你后端的服务是哪个。这些操作都需要运维手动做,现在有个应用上线,上线要选择使用哪个LVS集群,这个LVS集群对应哪个Nginx集群,然后再调用CMDB查出来应用配置在哪些服务器上,然后放到nginx conf。容器化之后要做成的样子,LVS还是不变,中间层Nginx server,运维管的还是用服务器部署的Nginx,我们慢慢的把运维的Nginx server减少,通过右下角的方式进行切换,下面有些用户使用的代理节点,上面只部署Nginx Ingress Controller。上面还是通过LVS流量分流到里面。这里面每个Nginx单独部署,每个应用对一个name space。  


这个方案的工作原理,CaaS平台里面部署的应用,都是通过Ingress的方式部署到集群外部的,后端由Nginx Ingress controller实现Ingress Rules,如果只是通过API server创建一些Ingress其实是没有意义的,你必须要真正实现这些Ingress Rules的后端组件。部署的时候是通过DaemonSet的方式部署的,应用访问是请求经LVSNginx Ingress controllerPod。因为这个节点只部署了Nginx  Ingress,不部署应用。这里要注意的是,因为这个节点只部署了Nginx Ingress,所以尽量把这些Pod的使用它的Host网络,因为做流量带宽性能应该是第一位的,所以这里没有做网络虚拟化。所以Ingress暴露的IP就是这个宿主机的IP。

    这是具体部署方法,部署的时候主要用K8S的三个特性:一是通过DaemonSet、Taint/tolerations 、NodeSelector去打一些Taints和Labels,打了之后,配Pod要加上对应的nodeSelector,调度到我配置的node上面,Nginx Ingress controller调度到我配置的nodeSelector上面,但是又要防止其他的容器跑在这个nod上面,所以必须要加上一些污点,你调进来的Pods就加tolerations。具体的部署可以看后面的链接。

    

灰度发布方案。关于Deployment可能是大家自以为比较熟悉,一开始没有收集之前可能会觉得对Deployment比较了解,但是真正深入看的时候,你会发现很多地方没有注意到,比如我定义一个Deployment的时候,大家都知道replicas这个东西,有多少人知道配置滚动更新策略的时候要配置maxSurge和maxUnavailable,有没有人配置过这几项?maxSurge有人配过,maxUnavailable有人配吗?Deployment相信大家都用过。还有一个配置是minreadyseconds,是说Pod起来之后,有Readyness探针,之前宇澄讲过,它会检测到Pod ready之后,就加入LB里面。但是如果你设置了minreadyseconds,比如设置等于5,他会说Pod通过这个检测到ready之后再等待5秒,然后再加入LB。这个也可以配,配的时间比较短,但是也可以不配,意义不是很大。第二个是maxSurge,滚动更新的过程中,可以允许超过期望的副本数多少个,如果这个副本数期望值是25,这里配置的是maxSurge是3,意味着滚动更新的过程中,允许集群里面的Deployment的副本数是28个,但是一定不能超过28个,我可以允许你往上面浮动3个。第三个配置maxUnavailable,滚动过程中,必须保证我最大的不可用的Pod是多少,最大不可用的副本数是2,不是ready状态的Pod副本数是2。这里有更详细的,比如计算到小数点,有小数的时候怎么向上取整、向下取整。

    

总结,我们在Deployment rollout时,需要保证Available(Ready)Pods额数不低于desired Pods number-maxUnavailable;保证所有的Pods数不多于desired Pods number-maxUnavailable,保证所有的Pods数不多于desired pods number+maxSurge。只有了解Deployment每个配置、每个细节的时候,才是有信心的。


通过kubectl set image这样的命令触发一个Deployment滚动更新的流程,Deployment一旦触发滚动更新,会通过创建一个新的RS,根据老的RS进行滚动,还是按照前面的配置为例,期望副本数是25,最大允许的超过数是3,maxUnavailable是2,首先它会创建一个新的RS,它的期望值是0,紧接着,因为你这里允许它最大超过值是3,马上创建3个副本,现在的副本是25+3就是28个。老的副本数,因为你可以允许它maxUnavailable是2,所以on ready的Pod是可以减2,这里变成23,新的RS就变成副本期望值3,老的RS期望值是23,它就等待他们的Pod的状态,3的Pod慢慢会起来几个,起来几个就可以删除几个,但是一定要在这个范围之内。后面滚动的流程都是不固定的,有几个Pod起来就会删几个Pod。有些人到现在可能还以为滚动更新的策略是创一个删一个。前面讲的是Deployment使用的时候需要注意的配置。

    

其实我们用的时候也是做了一些方案,第一个方案,用户提出来最保守的一个方案,用户要求每次升级的时候,我们先创建一个新的Deployment,还是对应那个应用,一个应用创建一个新的Deployment,并且指定新的Deployment的副本数多少个,默认是一个,用新创建的Deployment来验证这个服务新发布的版本是不是OK的,当验证通过之后,你再把这个新的副本数,新的Deployment的副本数慢慢增加,老的就慢慢减少,通过两个Deployment进行滚动的方式来去进行应用的滚动更新。这是整个示意图(见PPT)。第一步是创建新的Deployment,原来上面一个应用有一个service,比如应用10个副本,现在创建一个新的Deployment,比如现在创建两个实例,用户验证这两个是OK的,验证通过之后,这个应用是正常的,可以发布了,再去创建新的,新创建4个副本,OK之后再去删除老的Deployment,删除4个,慢慢滚动新的和老的Deployment。直到这个新的Deployment副本数是我期望的Deployment副本数,就可以干掉老的Deployment,干掉之后流量就自动切换过来。这个方案有一个问题,现在整个应用的滚动更新流程都是需要自己写代码控制,因为这个方案不是Kubernetes支持的滚动方案,所以滚动流程的控制需要重新设计实现。这是这个方案的问题。


第二个相对简单的方案,像方案一一样的创建新的Deployment,不一样的是这个新的Deployment创建两个副本之后,验证应用可以正常发布之后,不是通过新的Deployment增加它的副本数来进行升级的,还是通过老的Deployment和K8S原生的rollout进行滚动更新,老的Deployment滚动更新完了之后,再把之前创建的Deployment删掉,这样也是比较安全的方案。新创一个新的,验证完了之后,还是通过K8S原生的方案滚动那个老的Deployment。

    

K8S的5个组件,其实它的配置已经非常复杂了。Kubelet是其中一个最复杂的组件,Kubelet有130多项配置,API server在1.6版本有90多项配置,controller managee是第三多配置,有70多项配置。所有组件加起来的配置可能有300、400项这么多,是不是每个用户都要理解K8S这么多项配置每项的意义呢?我觉得是需要的,如果你不想理解的话,我这里列出来一些你一定要考虑的配置,我没有完全列出来,没有把所有的组件最佳配置都列出来,列了两个重要组件,Kubelet和controller manager。我们上线的时候要考虑配这么一些东西。这个节点上可以最大允许跑的Pod数量是多少,默认值是110,如果不改,这个节点最多可以跑110个Pod,有些用户跑200个Pod,有时候他不改,他怎么调度、怎么跑都跑不到200个Pod,所以要改这个值。一般的应用部署,一个物理服务器部署的Pod是10个左右。但是对于AI情况就不是这样子,我们现在tensorFlow做的训练,一个节点的服务器最多跑80个Pod。这80个和应用部署的Pod不一样,先部署几个副本,流量上来再扩容,扩到这个节点,对AI训练就不是这样,而AI训练是瞬间下发这个节点跑80个Pod。这样的情况下,对并发的考验很大,尤其对Docker,因为Docker的并发能力很差。另外,很重要的是配置eviction,eviction主要是用来垃圾回收,整个节点的垃圾回收,比如死亡的容器,你长时间不做一些eviction,这个节点上会有成千上万的死亡的东西在里面,这些死亡的东西会占用你的存储。还要注意给系统预留的资源,不能所有的资源都让Kubelet跑应用,如果有些应用有bug,把整个物理服务器的内存都压榨完了,你整个节点就挂了,必须给这个节点预留一些资源,再怎么样给两个CPU,这两个CPU和16G的内存打死也不会给你,你拿不到的。有些垃圾镜像都会有些垃圾镜像,你要注意垃圾镜像不回收会占用很大的磁盘空间,你要配置image-gc,当磁盘空间已经大于60%的时候,就必须触发执行垃圾镜像回收,释放空间。


controller-manager组件,这要关注的比Kubelet还要多,K8S最有意思的组件就是controller-manager,K8S自动驾驶的功能基本都是来自controller-manager,里面有30、40个控制器。resource-quota,比如有一个集群在线上,用户说分配的配额不够了,马上给我改一下,现在申请配额,把配额扩大,加20个CPU和100G的内存,批完之后就处理了这个resource-quota加了CPU和对应的内存,加完了发现还是不能创建,原因是有这么一个周期在里面,它的一个服务周期,它不是那么实时的,你弄完之后,最差的情况是需要等5分钟,resource-quota才会生效。你只有知道其中每项的意思之后才能解释用户遇到的问题。这个过程是非常耗时的,我大概花了一周到两周时间把所有的配置项过了一遍,光看官方文档有些配置是不知道意思的,有些配置必须看代码。但这些工作是非常有意义的工作。


比如说现在有一个集群出现了网络分裂,现在有100个节点,然后有20个节点的网络连不上Master,这时候Kubernetes会做什么操作呢?大面积的节点网络连不上,你不看这些配置也不知道。这里列了一些,controller-manager有很重要的一个控制器,叫节点控制器,其中的一部分工作就是用来处理节点网络的情况,比如node-eviction-rate,这个节点网络连不上,它要把这个节点剔除,剔除不是现在20个节点网络连不上,一下把20个节点全部剔除,这是有风险的,万一这个网络只是抖动而已呢?它有一个剔除速度,这里默认是0.1,每10秒钟剔除一个节点,但是它并不是按照0.1一直剔除下去的。这里配了一个第二梯度,集群规模不健康节点达到一个规模的时候,按这个速度下降,每100秒剔除一个节点,达到什么值触发第二梯度的数据呢?集群里面不健康的节点占据了55%以上的时候,就开始按照每100秒剔除一个节点的速度剔除这个节点。这些配置都是很重要的。这里只是抛砖引玉,希望引起大家对每个组件配置的重视。因为它直接关系到节点的稳定性和集群的稳定性。

   

 

最后聊一下tensorFlow on K8S项目把tensorFlow部署到K8S里面。现场有没有用过tensorFlow的人?tensorFlow有一个特性是分布式tensorFlow,模型里面有几个点要注意,拆分的组件,一个是PS,一个是worker,PS存储训练参数,叫参数服务器,worker负责训练任务。定义tensorFlow的集群,通过clusterSpec来定义,写现在要有几个worker,对应的IP或者域名是多少,每个worker对应的信息,每个PS对应的信息,这里有2个PS、3个worker,PS和worker里面就可以在ClusterSpec创建一个tensorFlow的集群,这是tensorFlow原生的东西。它在K8S里面我们怎么做?

首先讲一下为什么要做这个事情,为什么要把tensorFlow放在K8S里面?其实分布式tensorFlow有些非常大的缺点,比如它没有做资源的隔离,tensorFlow里面的训练任务非常重,把节点的CPU内存都榨干,别的也有训练任务,也影响别人的训练。很重要的问题是没有做资源的隔离。它本身也没有做GPU的调度,如果说不用K8S,tensorFlow用户要创建一个使用GPU做训练的任务,你需要主动去算法里面配置用哪个节点的哪个CPU做什么样的训练,要细到这个程度,有K8S,GPU的调度就交给K8S。K8S应该在1.4的时候就支持GPU的调度,它有很重要一点需要做的事情是K8S对GPU支持很弱,一块GPU只能一个容器使用,不能现在有多个容器要共用一个GPU。GPU很昂贵,用户是希望把GPU尽量榨干,通常情况下,一个容器不能榨干一个GPU。tensorFlow集群规模很大的时候,Task的管理很麻烦。不方便查看日志,用户要在节点查看日志,原生支持主要是做Hdfs,HDFS 随机读性能很低。为什么Kubernetes很适合这个场景呢?资源隔离这块提供resourceQuota,Pod提供了LimitRanger等多种资源管理机制。K8S1.4的时候,支持GPU配置(only limits)和调度。容器运行训练任务,K8S提供全套的容器PLEG接口。对接成熟的EFK日志方案。支持Read性能更棒的分布式存储,Glusterfs、Ceph。通过K8S可以轻松快捷的创建一个大规模的tensorFlow集群。基于这样的考虑把tensorFlow放到K8S上面。

高性能方案,主要是存储这块,对比HDFS、GlusterFS,随机读性能上,GlusterFS是最高的。用大数据的数据,一般企业都放在HDFS上面,所以我们需要把HDFS的数据导入到GlusterFS,训练数据在这里之后,GlusterFS通过Heketi,对外创建PV,一个data、一个log,分别对应到Pod里面去,对worker是用job部署的。对PS是用Deployment部署的。每个worker,每个Job对应一个Service,每个Deployment也对应一个Service,这个Service是用Headless Service做的。这个Service是没有集群IP,正常Service创建的时候会分配一个ClusterIP,这样就不会分配对应的VIP,它直接对应到后端的POD里面去,没有Service这层。目前上线的方案是简单方案,我们的数据还是从K8S上面直接读HDFS上的数据,然后直接拿去训练。K8S本身没有HDFS的插件,1.7的时候支持27种volume plugin,但是就没有 HDFS的插件。我们现在只能通过HDFS暴露的接口直接访问对应的训练数据,所有的流量都是走网络流量,所以对网络性能要求还是比较高的。所以我们的数据流量这块都是走的2万兆网卡做的bond。

   

 这是整个项目部署的架构,是我们用到的组件,其他都是和CaaS一样的(见PPT)。TensorFlow用的相对比较新的1.3.0。如果有谁对TensorFlow或者这个项目感兴趣可以关注我的文章。


我们公司做这个东西时间也不是很长,启动这个项目大概7、8个月,过程中我们遇到很多问题,有些不是问题,也有一些经验。Headless Service为什么在tensorFlow项目里面比较合适。前面讲了Headless Service是什么东西。Headless Service怎么选后端的pod?也是一样的,通过Label Selector对应的label进行匹配,匹配上了就是对应的Service。左边半部分是DNS的架构,这个是DNS1.3的架构,KubeDNS在1.2版本和1.3版本之间做了重构,我不知道后面有没有改,当时调研的时候是1.3的DNS架构,如果使用Headless Service就没有Service IP这层,workers之间交互少一层转化,它对DNS解析的时候直接发域名过去解析,返回IP直接就是根据POD的IP,不是Service的VIP,直接少了一层路由。这个性能是最重要的一部分,这方面也是考虑性能的一方面。

    

大家一定要小心Dockerfile里面的ENV,大家注意红色标的字体,前面标的是要执行这个命令,传到Docker里面去,创建这个容器之后,看到这个env,你传进去是什么就是是什么,它没有去执行这个命令,执行这个命令之后,其实最终会解析到一大堆Jar的例子,再拼装到里面去。这种环境变量的方式是以前我们非常常用的一种方式,Dockerfile不支持这种方式,让你执行这个命令,解析ENV然后再放进去。我们做这个项目的时候,因为tensorFlow里面的Headless Service服务进不来,最后造成这样的问题,它不会解析这个Dockerfile ENV,这个只能walkaround,只能在command中export classpath,export就会解析到出来的一大串的jar。目前就是这么规避这个问题的。


Reuse PV,重用PV,现在有一个PV,用户用来训练数据,用户训练完了之后,删除对应的PVC,不用这个PVC,但是PV还在那里,下次训练的时候或者另外一个用户想用之前的PVC的训练数据做训练,想重用以前的PV,怎么办?K8S不支持PV重用,因为考虑数据安全的问题,我创建PV可能会有些隐秘的数据,不允许别的用户用,现在确实想用,数据比较大,再搞一份比较麻烦,怎么办?例子,最开始有一个PV、PVC,它做了一个bound,如果用户删除了PVC的时候,PVC删除了就没有了,它对应PV的状态就变成released,released你不能直接用它,现在要用它怎么办?你kubectl edit这个PV,看到这里有一段引用ClaimRef,把这段引用直接删掉,那这个PV就可以重用了。

    

这是垃圾IP,灵雀云的老师已经讲过了,垃圾回收的问题,我们遇到很多垃圾IP的问题。问题发现是这个样子,但是在容器里面跑的时候,容器启动之后,发现网络不可达。我们看到auto allocation failed- address exhaustion in subnet,意思是我的IP地址已经用完了,拿不到IP,这里就有问题。为什么拿不到IP呢?出乎意料的是,太多垃圾IP,IP没有释放,整个IP地址池用光了。如果是这样也没什么,最可恶的是把这个节点给弄挂了,这个节点变成NotReady,问题大了。然后我们看到日志,为什么notready?最后定位到是Kubelet,会最终调CNI的接口,去获取每个Pod IP的状态,拿不到IP的时候。拿IP的过程,如果3分钟没有拿到IP,没有返回出来,这个Kubelet就认为这个节点是不健康的,Kubelet就会认为这个节点notready。所以这个垃圾IP的问题很严重,直接导致这个节点已经挂了。这个节点从K8S集群里面剔除了。这是Kubelet对应的代码,Kubelet集中容器的时候会拿对应Pod的信息,包括Pod的网络状态,获取Pod的网络状态,调插件,3分钟可以拿到IP反馈给我,认为这个节点有问题,挂了,认为这个节点notready。解决方案是通过CronJob,凌晨时间进行垃圾回收,对应的IP回收回来,回收的过程是通过对网络插件对应的IP定时,和K8S分配的IP地址进行对比,对比出来之后,哪些IP是垃圾IP,然后再去执行,这是我们自己开发的一个组件。希望大家对垃圾IP引起重视,因为它的问题是很严重的。

    

第五个是说Job,用户写一个Job,这个Job有问题,也没有对这个Job做过多的配置,会导致有问题,Pod会不断的创建Pod。正常的让Pod运行成功一次就可以,但是这个Pod成功不了一次,每次失败,就不断的重复这个Job,这里有一个节点,发现这个节点,退出这个容器,有1万多个容器,就是因为这个Job,Job做AI训练的时候有问题,导致它创建了1万多个Docker容器。有没有解决办法呢?如果是用Kubernetes1.8版本之前的版本可以做这么一些配置来减轻这样的状况,Kubelet配置加是maximum-dead-containers,这个节点上最大允许的死亡容器是多少,比如100,它就绝对不会超过,如果超过怎么办?它会触发回收的pod。如果对业务熟悉甚至可以设置Job启动多长时间就可以干掉,不管成功不成功都干掉,防止它重新创建pod,不断重复两天,这个业务是10分钟完成的,你就可以设置为10秒之后干掉,前提是你对你跑的业务比较熟悉,不然业务正在跑,没有跑完,你就把人家干掉了,这是Kubernetes1.7。Kubernetes1.8,Job上可以配置backofflimit,Job重新创建Pod的过程可以创建几次,默认是6次,正常情况下,一个业务一直失败重复3次,你可以认为这个业务已经有问题了。这个配置是很重要的,也是我后面的考虑。

以上是我分享的全部内容。

提问:王老师,您讲的过程中我突然想到一个问题,我们公司也是从原来的平台迁了7、8个月时间,这个过程中,你以前的流程和规范,还有组织以前的做法,有什么调整?为了适应K8S。

王涛:就是DevOps文化问题,这个问题已经超出技术人讨论的范畴。说实话,我们组织结构没有什么变动,组织上没有任何变动,我们推行过程中,也不是说非常顺利。

提问:我刚刚看到你用到分布式网络存储,我们这边工作有些节点比较庞大,有几百G的数据,我们也想用K8S做解决方案,但是我们担心的是它的IO怎么样,也是在研讨当中,因为我看到vivo这边已经用了,能不能给我们分享一下这块的性能表现?

王涛:首先glasterfs还没有在生产环境用,只是做这样的对比测试,我们对比的时候是调研了一些资料,主要是对Glusterfs、Cephfs、Hdfs三种不同的文件系统做了对比,结论是Glusterfs随机读的性能比Cefs和Hdfs要高很多。如果说你的日志平台,写的量很大,这种场景是不建议用的,我建议用Ceph RBD。因为Glusterfs不适合大量小文件的读写操作,大量小文件读写操作用Gulsterfs性能是很低的。

K8S技术社区粉丝:您之前说的K8S没有HDFS的Volume插件,你们没有考虑过用Flex Volume去解决吗?

王涛:你可以通过Flex Volume自己写一个插件,现在还没有这样做,这个项目现在还是处于初步阶段,现在HDBS通过网络读取的方式还不是瓶颈,用户觉得不是瓶颈,还可以满足需求。所以一切都是需求推动,我们还没有这样的瓶颈。

K8S技术社区粉丝你们训练数据是直接通过网络来读取?

王涛:对。

K8S技术社区粉丝会不会要求应用单独配置比如网络的权限控制?

王涛:这个要做,因为整个AI项目里面只有一个用户,没有别的用户,还没有做网络权限的控制。这个想法后续可能要做。

K8S技术社区粉丝你网络插件的选择,你们用的是思科Contiv,你们选择的依据和考虑重点是?

王涛:其实我们当时做网络选型的时候可选的不多,当时Flannel性能非常差,主要是UDP为主,然后VXlan,主要是对交换机有些依赖、要求,没有选。UDP性能太差,我们服务器的规模量是比较大的,可能后续会有上万台的服务器,所以没有选Flannel。另外就是Calico,它主要是BGP协议,对交换机程序做一些配置,需要推动运维做配置比交换机,最好是新机房建设时候可以考虑。我们还是用contiv netplugin,主要是支持这种OVS+Vlan 网络方案,这种网络方案是非常成熟的,OpenStack是用这种网络方案,它足够成熟,刚好适合我们这样的方式,就选用了这个网络方案。

K8S技术社区粉丝生产环境跑的服务器是不是都是无状态?

王涛:对,主要是无状态,有状态的还在做,包括mysql, redis等。

K8S技术社区粉丝无状态这种有没有遇到过在一个Node上出现IO抢占,需要考虑IO隔离或者是IO这块的?IO磁盘。

王涛:没有做这方面的事情,也没有遇到这样的问题。

K8S技术社区粉丝应用上没有分IO密集型?

王涛:现在还没有分,我们主要是通用的。

K8S技术社区粉丝如果对小文件写和读都要求比较高,有没有您觉得比较不错的文件系统?

王涛:存储不是特别懂,以我现有的了解,Ceph会是不错的选择,Glusterfs对小文件的读写性能是很差的。

K8S技术社区粉丝老师,你们这边用JOB的时候,JOB编排是业务团队自己运营的吗?K8S的JOB,我们这边给他们提供JOB的调度,JOB和JOB之间可能有依赖关系,这个是他们自己提供的吗?

王涛:Job和Job之间的依赖,调用的依赖吗?

K8S技术社区粉丝对,一个JOB完成执行下一个JOB或者这个Job会等待前面多个JOB,这种能力是他们业务团队自己建的吗?

王涛:我们CaaS没有提供这种能力,Netflix开源了一个东西Spinaker,通过定义各个stage来支持工作流,这个stage执行完之后再执行下一个stage,你可以参考一下,目前我们也使用了Spinaker做任务调度系统。K8S还没有能力支持你这种需求。

K8S技术社区粉丝你们Master节点是用了三个集群的集群方案,你们具体实现是怎么样的,在API server上做的改编码吗?

王涛:Master不需要改任何代码。

K8S技术社区粉丝K8S目前支持集群化方案吗?

王涛:支持,现在K8S官方也有HA的文档,那个文档是针对用户在GKE上部署的HA解决方案,是不适合在私有云部署的,要做私有云可以按照前面介绍的做。

K8S技术社区粉丝目前你们HA有没有遇到一些坑?

王涛:没有,前面给API server做了LB,然后通过LB做代理和分发,减轻API server的流量,其他两个Master都是通过K8S自己的leader选举机制做HA的,这三个组件可以保证HA,原理很成熟的。

K8S技术社区粉丝Pod访问API server也是通过LB吗?

王涛:是。

K8S技术社区粉丝外网还是内网?

王涛:在一个数据中心内,意义上是一个内网,Pod IP和Node IP是互通的。

K8S技术社区粉丝你觉得公司服务器达到多少台以上用K8S比较合适?

王涛:我们没有做过这样的测试,官方现在是5000台服务器,我没有计划说用到五千台服务器做一个集群。我现在计划的是两千个节点。


添加K8S技术社区小助手,进群获取

深圳站全套PPT打包资料!


  • 分享到:
  • icon
  • icon
  • icon
  • icon
箭头