Kubernetes在企业级架构中的实践分享

本文是9月24日时速云技术沙龙大连站的演讲干货分享,内容源自时速云联合创始人兼技术总监杨乐的现场演讲录音整理。

以下为主要内容:

演讲提纲

20161009173141

1、Docker与容器技术

20161009173201

Docker跟VM的区别:VM每次起一个实例,实际上包括三层,整个操作系统、中间层内部以及其他应用,全部都包括从OS kernel到应用态的全部,容器技术把kernel层共享给所有的实例。

容器实例仅仅是应用态各不相同,而底层的操作系统内核是共享的,这样就带来一个好处: 所有运行的应用,都是进程粒度,轻量级,采用Namespace、Cgroup等隔离技术,同时 Docker所定义的标准镜像模式,让我们可以对容器和镜像进行非常快速的迁移。

Docker容器可以 build once、run anywhere,一次构建,可以随意运行。

2、Kubernetes架构及特性

20161009173207

Kubernetes是容器集群编排系统。例如10台机器都装了Docker,我们可以用Kubernetes把这些机器都编排起来,统一成一个集群来处理。

这种生产系统已经是生产级别的了,kubernetes最早的技术理念是源于谷歌的borg系统,而这种borg系统已经在谷歌内部稳定运行很多年了。

Kubernetes是2014年6月开源的,采用Golang的语言开发,每一个组件互相之间使用的是Master API的方式,Kubernetes的架构模式是用Master-slave模式,并且支持多种的联机网络,支持多种的分布式的存储架构。

Master的核心组件是API server,对外提供REST API服务接口。kubernetes所有的信息都存储在ETCD. Scheduler是kubernetes的调度器,用于调度集群的主机资源。Controller用于管理节点注册以及容器的副本个数等控制功能。

在Node上的核心组件是kubelet,它是任务的执行者,它会跟apiserver进行交互,获取资源调度信息。 kubelet会根据资源和任务的信息和调度状态与Docker去交互,调用Docker的API, 创建,删除与管理容器,而kube-Proxy可以根据从API里获取的信息以及整体的Pod架构状态组成虚拟NAT网络。

20161009173215

Pod 是Kubernetes可调度的最小单元,一个Pod里面可以有多个容器,容器与容器之间可以用Local host的方式去沟通,共享网络共享存储,也就是实现在pod内的资源共享。

Replication Controller  是Pod的一个控制,可以控制Pod副本和状态,就可以做手动的弹性伸缩.也可以利用hpa去通过CPU,或者是内存, 设定阈值去弹性伸缩。label是对Pod或其他的资源像Node, Service打标签,通过标签使不同层次的组件发生联系。可以用一个选择器把想要的资源选择出来,然后对他们进行操作。

Service  定义了服务虚拟IP与容器实例间的影射关系,同时定义了服务暴露给用户的方式。

Daemon Set  可以给每一个节点去分发应用容器,并以守护进程的方式运行,比如希望在每个节点上有一个组件,这个组件可以监控我的节点的健康状态,可以用Daemon set的方式来部署运行。

Config Map  可以做非常灵活的配置管理,容器本身运行过程中,不建议去更改里边的文件,不建议去开SSH登陆端口,但是程序运行起来以后需要知道如何去连接数据库,如何去访问配置文件。可以去把配置文件定义到Kubernetes的Config Map中,然后它会帮去分发配置到相应的容器,即在Pod里面挂载到指定的位置,应用仅仅是需要去已知路径获取。

3、Kubernetes应用实践

这部分主要介绍在实际生产或在企业落地过程中,企业用户比较关注的问题。

20161009173222

 

在部署或要运行时,关键节点需要具备高可用性,排出单点故障问题。在kubernetes 中给Master设置多个实例,所有实例通过loadbalancer 对外提供apiserver 的服务。Salve 在连接时,只与loadbalancer对应。Podmaster 可以保证在同一时刻,仅有一对controller和scheduler存在在集群内。当其中一个master节点出现问题时,其它的节点通过loadbalancer依然可用,如果controller或scheduler出现故障,也会在其它可用的master节点上启动新的controller或scheduler.

◆  Network

20161009173228

Docker原生的网络是bridge的方式,原理在主机上面去创建一个docker0的bridge,相当于虚拟交换机,每一个容器会在该bridge上挂接一个端口,并与容器网卡联通。但在kubernetes 中跨主机网络一般采用flannel工具来搭建 vxlan,即叠加的隧道网络。

20161009173236

对与企业内部典型的三层网络,即每个区域限定不同的使用目的,相邻的网络区域间由防火墙隔离。 采用vxlan的方式可以轻松跨越网络区域和防火墙,flannel对外的开发端口时8285(或其它可选),网络IP包在流出该端口前会被flannel 加封一层IP包头,作为vxlan的包头协议,在穿越防火墙后,进入目的主机时会被flannel拆解掉包头并还原,这样多层区域的主机可以被打通成集群资源使用。这种使用方法的前提是对防火墙的规则并不严格。

20161009173243

对于隔离要求较高的场景需求,采用calico是比较合适的选择。calico会帮助容器在主机间搭建纯二层的网络,在每个主机上维护一个路由表,用来获取目标容器所在主机的可达路径,以及本机容器的路有项。利用iptables的防火墙机制去做隔离。

容器之间跨主机进行交互时,IP包从容器出发,经过本地路有表选路,通过目标网段所在主机的路有项,到达目标主机,然后在目标主机内,进入路有选路前,先经由iptables隔离规则(如果设置过的话)进行判断决定是否丢弃或返回,然后再经路有选路到目标容器,最终到达目标容器。整个过程没有任何封包解包的过程,传输效率较高。

隔离规则可以设定在同一用户名下的哪些容器可以被隔离成一组,被隔离的容器间可通信,而与其它容器不可通信。或者设置规则来组成更加丰富的隔离效果。

◆  Storage

20161009173252

Kubernetes存储接口可以支持多种的存储,在使用场景角度,可以分为可共享存储和非共享存储。举例来说,多个容器之间可能需要共同读写文件,可以将相同的存储卷挂载到不同的容器上,比如使用nfs。对于非共享存储,比如mysql, 数据库进程在启动后,会对库文件加锁,以免其它数据库进程进行读取时产生同步操作问题,这种互斥排他的资源可以采用非共享存储的方式,比如rdb.

20161009173301

在对分布式存储卷的插件支持上, kubernetes 的接口形式上很简化,首先在kubelet/app/plugins.go中注册自定义插件的引用。并在实现代码中继承相应的interface接口。定义如何初始化Init, 如何启动或挂载SetUp, 如何去关闭Teardown,定义支持标志CanSupport.

20161009173309

CI/CD持续部署可以加快企业内部的开发测试以及部署的生产整个交付流程,在企业使用场景中,开发人员首先提交代码到代码库,例如gitlab,svn等,在项目编译之前,可以进行代码扫描。比如利用SonaQube来进行分析, 获取项目代码UT的覆盖率。

在编译完成项目之后,获得文件输出,并可分享到不同的集成镜像中。当通过Dockerfile构建成镜像后,可以将镜像推送到Dev-Docker registry。然后在测试环境中,可以用手动或者自动的方式部署到云环境。当镜像通过测试团队的测试以及相关审核之后,可以同步到指定的生产环境的镜像中心,通过部署服务把镜像部署到生产或者对已有的服务进行滚动升级。

20161009173316

这个是一个CI/CD的一个实践例子。CMDB是做企业的资产管理的,onecmdb是开源的一个组件。在众多子项目中,其中的一个项目只有Dockerfile, 没有代码文件,它要做的工作是将代码文件构建到容器镜像中。其它的几个项目是onecmdb的代码文件,但没有Dockerfile。这样在做持续集成时,拥有代码文件的项目通过关联构建的方式,将编译号的war包共享给Dockerfile 的项目,而Dockerfile 的工作仅仅是构建镜像。

◆  Configrate management

20161009173322

当服务运行在容器中时,有时需要访问外部的变量,或者需要根据环境的不同更改配置文件,比如,DB以传统的方式运行在容器云之外,当服务启动时,需要初始化包含DB信息的配置文件。当需要切换db时,就需要更改配置文件, 当容器中有服务在运行时, 并不推荐登陆到容器内进行文件配置更改。合理的方式是利用kubernetes的配置管理,将配置信息写入到ConfigMap, 并挂载到对应的pod中。 服务在pod容器内只需要读取固定位置的配置文件, 当配置需要改变时, 更新ConfigMap并重新分发到pod内,这样重启容器后,容器内所挂载的配置也会相应更新。当需要pod容器同时使用一个ConfigMap 时,更新ConfigMap内容的同时,可以批量更新容器的配置。

4、Kubernetes管理与运维

20161009173330

◆  监控与报警

监控与报警是云平台在企业运行过程中比较重要的环节,运维人员需要实时获知系统是否运行正常,Apiserver是否健康,节点应用是否出现问题,服务的QPS是否过载等等。例如在kubernetes中,Node Problem Detector可以探测到主机的健康状况并以事件的方式发送到Apiserver中,这个detector 组件可以采用Deamon set的方式来推送到每个节点上。 报警系统如果发现服务出现异常将以邮件和页面列表两种方式通知用户。

◆  操作

20161009173337

对于运维操作来说,kubectl是一个很便利的命令行工具,首先可以对各种资源进行操作,比如添加、获取、删除,通过更多命令参数得到指定的信息。

当需要对节点进行操作时,比如由于配置升级需要对节点主机进行重启。首先将节点主机设置成不可调度模式,kubectl cordon[nodeid], 然后需要将主机上的正在运行的容器驱赶到其它可用节点,使用命令kubectl drain [nodeid], 当容器迁移完毕后,运维人员可以对该主机进行操作,配置升级性能参数调优等等。

当对主机的维护操作完毕后, 再将主机设置成可调度模式,kubectl uncordon [nodeid], 这样新创建的容器即可以分配到该主机。可以通过kubectl patch 对资源对象进行实时修改,比如为service增加端口,为pod修改容器镜像版本。Annotation 可以帮助用户更好的设置kubernete自定义插件。

用户可以在自建组件中获取资源中对应的annotation以此进行操作。通过kubectl label可以方便的对资源打标签,比如对node打标签,然后容器调度时可指定分配到对应标签的主机。

◆  升级

20161009173345

最后一个问题时系统升级,kubernetes的版本定义分为产品版本和API版本,产品版本是常用的格式[major.minor.patch] ,由于在kubernetes版本迭代过程中经历了API版本的变动,比如v1beta3到v1, 当跨越API版本号升级时,需要先将版本的kubernets升级到API兼容的版本,然后再升级到高版本。

比如v0.17.x版本的API是v1beta3,而v1.x的API是v1版本,此时直接升级会造成数据的混乱和丢失,需要经历兼容版本的升级,比如v0.19.x可以同时支持API v1beta3和API v1,因此先将v0.17.x升级到v0.19.x,当数据正常升级后,再从v0.19.x升级到v1.x.