K8s的测试和使用

调整下方式,大而全的文章少一点吧。很多细节说不清楚,只能是徒增将来要填的坑了。

K8s也是如此。所以,今天先缩小下范围,先说我们怎么用的,然后再来用几篇文章慢慢补设计的架构这些。能说明白就不错了。

开始。

K8s在项目中的引入

K8s是容器编排的事实标准, 是Google的Borg系统系统的开源版本。行吧这种提法一搜到处都是。

那既然是管理容器的,那么我们首先得有容器。我们在实际工作中,使用的第一个Docker镜像是php-nginx的,针对PHP的一个版本,内部使用了Nginx+PHP-FPM,前者是HTTP及反向代理服务器,后者用于PHP的进程池管理,会启动一个master进程和多个worker进程的程序来处理PHP的请求,master负责配置worker进程以及转发转发请求。所以,我们的Web服务是基于PHP的,当然还有其它的语言也有使用,比如Java/Python等等。

当时的情况是,基于OpenStack的云基础架构还不稳定,我们的服务器往往会碰到莫名其妙的挂掉的情况,而且在项目初期,我们连Ansible这种东西都没有用,每次服务器的配置安装非常的麻烦,机器挂掉了,重新开系统,重新装系统,重新装Apache,PHP,做配置,然后部署代码之后才能回复正常,用户体验实在是有点差了。在下决心解决这个问题的时候,Docker/K8s都已经开始火了,想着团队的技术栈总是要跟上时代的脚步,就开始使用了Docker,走容器编排。一开始也曾考虑过使用Docker swarm,比较轻量级,但是毕竟不是行业标准,所以最终还是要采用K8s。 总体来说,我们的技术栈距离互联网大厂还是有些差距,就算到了现在都是如此。好吧这是后话。

初期的状态

在Docker引入之后,系统的分布式部署基本全部采用了Docker,而且开发测试环境与产品环境做了详细的区分,另外还做了用于快速验证代码的单机环境,都是基于Docker。Docker的Image放在了公司内部的Artifactory之上,取用比较方便,不受公网限制,速度也很快。 Docker的管理很长时间并没有使用K8s编排,一开始用了docker-compose来管理一个host之上的一组容器,包括chatbot/testline/redis以及主web服务器等,对于mariadb数据库这些,则是使用了独立的host来运行容器,然后使用了NFS的方式来存储关键数据,实际使用中,数据库的连接速度还是受了些影响,毕竟Dcoker volume的存取又多了一层Union FS,它的速度并不快。所以是期望将来取消数据库的Docker部署方式,转为使用专用的主机来运行。在K8s之中,数据库这些都算是有状态的了。

好的绕回来,使用docker-compose的部署方式实际上与K8s的yaml文件方式已经有些相似之处了。我们也测试了Docker swarm的使用,因为都是容器编排,所以用法上很是相似。

集群搭建

最开始的时候,本来是想要在公司的云基础之上自行搭建K8s集群的。在这里不得不提一下Rancher,没错就是那个刚刚把自己卖给Suse的那个Rancher。Rancher本身作为集成了K8s在内的企业级容器管理平台来讲,它的界面易用性非常高,安装也很少简单,使用方便,管理也方便。所以,在开始时在公司云上对Rancher进行了试用,然后发现了一些问题,Rancher当时安装的定制话貌似还不够完整,docker安装完成后的,docker bridge的网络段可以用没问题,但Rancher安装完成后,pod所需的网络地址与公司云的内部私有地址冲突了,导致worker节点安装的过程中始终找不到master节点,集群成了一个个的孤岛。也可能是公司内部的呼声比较高,后来公司云专门架设了基于Rancher的容器服务平台,当然做了大量的定制化,IP地址段发生了变化,而且在平台上还同时安装了Elastic stack, Promethus以及Grafana,这对我们来说真的是相当的方便了,但是唯一不足的地方,则是我们丧失了对与集群的控制权,所有的配置信息我们都无法得到,只能够被动的使用。当然,如果只是单纯使用没有问题,只是我们没有了动手测试配置等等的机会,所以心里是有些失落的。

在后来,K3s出现之后,我们使用这种简化版的Kubernetes再次搭建了集群,作为我们的测试环境之一,也算是圆满了。

测试和使用

根据我们的业务情况和需求,我们在我们的环境下测试和使用了如下资源/REST 对象:

  • Deployment

    用来做无状态的服务部署。我们的Web服务用这个,然后会有一组Pod的地址,使用相同的标签,端口一般都是一致的端口,比如80。每个Pod会有自己的Name,可以通过kubectl get pods -o wide 来查询详细信息,包括Pod网络的IP地址。

  • Service

    用来做服务发现。我们使用了NodePort类型,使用Label选择已经部署在Deployment中的一组Pod,将Pod的IP地址和端口,映射到对应的Service网络层的端口和地址,同时起到了Load Banlancer的作用。不使用label的话,需要自己添加一种Endpoint的对象来做手动的映射。Service的地址是由Node上的kube-proxy模块来实现和管理的。这个地址仍然不可以被集群外部访问到,按照官方文档,Load Banlance类型的Service可以被外部访问,但是公司的环境下测试失败,只好用Ingress。

  • Ingress

    这是用来对集群外部暴露服务的一个对象,同时可以提供负载均衡,SSL终结等功能。我们使用Ingress来提供Service在外部的访问接口,通常建成后,IP地址是host主机所在的ip地址,端口是可配置的,同时也可以用来实现业务的路由,不同的service,可以配置在不同的rules/http(s)/paths/path下来实现这一需求。比如,我们的utilization和inventory是可以采用这种方式来完成的。

  • ConfigMap

    ConfigMap主要是用来将服务或者程序的配置信息与服务/程序本身分割开来,一个目的是为了安全,一个目的则是为了修改和调整方便。这样的例子就很多了,比如Nginx的私有配置,MariaDB的私有配置,服务自定义的配置选项,Python脚本的配置信息等等,都可以用它。生产ConfigMap时K8s兼顾了旧有配置信息文件,可以通过这些文件直接生成配置项,也可以选定其中的Key只使用其中的部分配置,还是比较灵活的。

  • Secret

    这个可以算作配置项ConfigMap的一个特殊情况,涉及账号密码等信息配置的存储。在创建时,K8s会对账号密码进行base64的加密处理,使用时与ConfigMap也很相似。我们使用Secret存储了Artifactory的信息,这样从上面获取Docker Image的时候就不需要手动输入了,而且也不是明码,相对安全。

  • PV/PVC

    这两个是用来控制存储和用来申请存储的两个,前者定义存储,后者用来Claim。 按照我的理解,如果是无状态的,那这个可能不需要,如果是有状态的,也许可以使用NFS形式的PV,实际测试也可以用。但是NFS还有一种直接在deployment中指定的volumeMountes的方式,使用PV的好处在于可以控制Claim,需要多少必须申请,对我们的业务暂时没有什么意义。一种可能的用途也许是集群多用户的存储控制? 比如卖VPS之类的?行吧,这个暂时没啥想法。

  • HPA

    HPA得算是一种缩扩容的方式了,Horiziontal Pod Autoscaller, Pod的水平伸缩。要注意的是,这种伸缩完全是自动的,不需要人工的干预,只需要在建立时,指定CPU/Mem/等的条件范围,大于极大值,则扩容,小于极小值则缩容。这种方式对于突发性的流量增长导致的问题是个很好的解决方案。目前我们的业务应该是用不到的,不过测试还是可以做一下,可以达到要求,哈哈。

其他的部分其实还挺多的, 而且我们的测试也受限于我们的环境和业务需求,没有对K8s的集群做压测。从网上公开的资料看,K8s的性能方面远远超出我们现实的业务需求,足够足够用了,甚至到可预见的将来,效率方面都不会有任何问题。很好很好呀~~


这几天事情有点多了,要准备很多,静下心来写东西的时间偏少,断断续续的在写,今天终于算是完成了。下一个要填的坑是Docker,嗯嗯。

updatedupdated2020-08-052020-08-05