尊敬的各位同行大家下午好,我叫做邹辉,来自腾讯公司云平台部。我们容器服务也是采用的Kubernetes.近几年容器技术是最热门的技术之一,很多公司或者行业已经把容器作为自己的测试环境以及正式环境,正式上跑一些业务。而腾讯也不例外,早在三年之前腾讯基础平台部门已经开始容器方面的技术,经过三年时间的积累,腾讯很多业务已经跑在容器平台上,所以说腾讯内部对容器这块也积累了很多经验和教训。差不多2016年下半年开始我们决定把这些经验以及容器方面的技术放在云上,为云上的客户提供容器方面的解决方案。我这次分享的主题,当我们把容器服务放在云上的时候,我们碰到的一些问题,以及我们针对这些问题的解决方案。
当我们决定在云上提供我们容器服务的时候,实际上我们内部面临两种选择去做一个技术选型的时候。第一种选择,因为腾讯内部已经有一个容器平台,我们通过自研把腾讯内部容器平台做一个修改,放在云上去,对腾讯云上客户提供解决方案。第二个选择开源解决方案,跟行业一起快速把容器服务放在云上,对用户提供这样一个服务。之所以有这样两种选择,如果放在前几年大概是2012年之前的腾讯,可能我们好不容易选择自研,已经撸起袖子开始写代码了,为什么有这样一个选择?因为腾讯内部近几年开始流行开源意识和文化。所以第二种选择,就是我们使用开源的解决方案。
最终我们衡量一下这两种选择之后我们选择了开源,有两种原因。原因之一:腾讯内部客户对容器诉求更多关注在计算资源成本上,以及计算资源快速伸缩,快速起停这一块。经过我们调研,腾讯外部公有云的客户,关注计算资源和起停之外,更重要解决软件上的一些问题。如果直接搬到云上,开发点不一样,以后可能受到制约。我们有很多开源方案供我们选择,我们根据用户需求和实际情况,最终选择Kubernetes作为我们容器的服务解决方案。
当我们选择Kubernetes作为我们容器服务解决方案之后,我们投入研发人员做一些研究。结果发现一个问题,我们研发人员把Kubernetes集群搭建起来,构建起来网络方案,花了差不多一周的时间,我们研发人员可能研究一下Kubernetes的概念,同时把它存储,最终使用Kubernetes去搭建一个完整服务的时候,又花了几周时间,一个完整流程下来,我们开发人员花了差不多接近一个多月的时候完全把Kubernetes上手。我们用Kubernetes对外部客户提供服务的时候,我们担心上手门槛很高,所以我们解决第一个问题,就是应用性方面的问题。我们希望腾讯云的容器服务能够简化弱化Kubernetes的概念,让大部分客户使用容器服务的时候,可以更简便。容器更多像黑盒,用户登录虚拟机跟登录物理机一样,定位你问题可能难度比较高,在易用性上我们更希望把容器黑盒打开,让更多用户更多看到容器里面的东西,比如说登录、监控。还有一些高级用户,使用更高级的功能,我们希望容器把Kubernetes架构放开出去,让我们高级用户完全使用Kubernetes的功能。所以关于易用性和开放性的考虑,我们设计容器里面是第一个需要解决的问题。
接下来看我们在架构怎么解决这样的问题的,这是典型的容器集群,在外面我们加了一层管控系统,管控系统两个目的:第一个它会把Kubernetes一些概念封装成用户更加容易理解的概念开放给用户。第二管控系统跟腾讯一些Iaas资源打交道。经过封装之后用户创建一个web服务,用户可能简单理解我需要镜像是什么?我需要多少计算资源?大小是多少?我对外开放还是对内开放?就可以完成这样一个服务申请,由我们管控系统负责跟Kubernetes集群里面的API,申请一些概念。当我们做了一段时间之后我们发现如果把KubernetesAPI对外提供出去可能存在一些问题,所以我们做了改进,把所有跟腾讯iaas层打交道的工作放在到了Kubernetes的插件里面去,由插件跟腾讯云IaaS资源做交互,然后我们KubernetesAPI完全开放出去,这样用户既可以使用腾讯云的管控平台,又非常方便使用容器服务,又可以Kubernetes的API完全操控Kubernetes里面所有的功能,这是我们易用性和开放性方面的考虑。另外易用性方面我们借助开源一些组件,让用户非常方便登录到容器里面去,去定位问题,察看问题,支持直接从SHELL上传和下载文件。举个例子,如果我们容器服务运行过程当中发现一个网络问题,我们需要抓包实现,这时候我们怎么操作?很简单直接登录Shell抓包,然后通过下载工具直接把文件下载到本地,然后做一些深入的分析。关于上传和下载,我们借助Shell的本身,把文件完成上传下载的操作。
除了登录容器这块我们还做了其他的操作,在页面上把容器标准输入、标准输出、标准试错的日志输出到页面,这样可以很方便察看。另外我们把容器的监控数据也跟我们一些监控系统打通,在每个容器的节点上部署一个功能,采集容器方面监控信息,比如说CPU、内存、网络、带宽这样的信息,采集完成之后这些信息上报到我们监控系统,这个监控系统也是有kaFka等一些开源软件构成,这一套系统出来以后,用户可以把监控异常点进行一些报警,同时可以用API察看容器的应用信息,这是我们在易用性和开放性在容器落地方面的考量。
另外大家也知道容器技术本身上就是linux (英文)技术,跟其他虚拟化的技术相比,在隔离性和安全性天生具备一些弱势,所以如果我们把容器服务对外开放,提供给我们用户用,在隔离性和安全性也是我们必须解决的第二方面的问题。隔离性上我们这样考虑的,首先我们认为一个集群属于一个用户,不同的用户去使用不同的集群,一个集群是构建在用户自己的Iaas层基础资源之上。而用户具备操作Iaas层所有的权限,通过这样一个划分,我们就保证了用户之间通过物理机或者资源虚拟机的来达到隔离性的效果。其次在实际使用经验中我们建议同一个用户他们测试环境以及运行环境也通过不同的集群做区分和隔离,达到安全方面的效果。
每个用户有不同的集群,这时候我们面临另外一个问题解决,当一个用户初始设立一个集群,我们怎么样在我们平台上把Kubernetes搭建起来,集群需要升级的时候,我们又怎么样把集群升级到一个新版本。在每个机器上有一个AgeNt,除了监控数据采集,还具备创建集群和集群升级的功能。当这个启动的时候,Agent去拉去这台机器属于哪个集群,证书的信息。拉取以后这个Agent是常用的进程,这个ETC库里面存储所有集群的节点,包括版本信息和状态信息,当我们需要为Kubernetes进程进行升级的时候,我们跟新一些任务信息。分三种,一种是下载任务,从远端下载,第二个删除任务,第三个启动一些执行的命令。所以通过Etcd Jod库,我们可以很方便用Agent进行创建,完成整个集群的创建和操作。这是我们在单租户集群问题解决方案。
刚才更多谈到隔离性方面的问题,接下来看我们安全性问题怎么解决的。首先我们把Kubernetes的API开放给用户,让用户访问Kubernetes集群的时候,我们设置双向的HPS证书加密码,用户访问这个集群首先下载这个集群证书和使用密码。其次一个集群里面Mest部署对用户不感知的,MEST一旦被损害造成不可逆的结果出来,MEST部署对用户不可见,但是用户可以通过KubernetesAPI,完全操作Kubernetes里面的资源。其次当我们插件访问IaaS基础资源,我们根据来源AP做一些操作,只有属于本用户的机器才能访问对应IaaS的资源。最后我们把ETC集群独立出去,Mast访问集群的时候,保证本集群只能访问Etc本地的资源,同时这个只能在Mast发起,不能从其他地方访问。
除了集群的访问上,在镜像仓库访问上我们也做了一些措施。我们镜像仓库为每个镜像做一个权限控制。比如说这里一个公司的负责人,他为他的员工A分配镜像A的访问权限,这时候员工A用自己账号拉取镜像,上传镜像时候,权限通过员工才有拉取的权限,我们镜像仓库授权达到最小。这是隔离性和安全性方面腾讯做的考量。当这个解决之后我们面临第三个问题是什么?这个问题也是我们投入时间最长的问题,我们需要把Kubernetes和腾讯一些基础的IaaS的资源打通,比如说负载均衡、网络、存储等其他一些资源,这个章节我重点说一下网络方面,存储方面,Kubernetes怎么样跟腾讯内部资源进行打通。
网络方面有五种场景:第一种场景容器之间的互访是怎么设计的?第二种场景集群内部的服务之间互访是怎么设计的?第三种跨集群之间的服务之间它又是怎么互访的。第四种从外部访问集群内部的服务是怎么完成的?最后一种如果从外部去访问集群内部多个服务又是怎么完成的?
接下来首先看一下容器之间互访我们是怎么设计的?做这个设计根据我们需求有一个基本诉求。第一容器距离独立的IP,第二容器与Node节点之间也可以通信,第三容器可以访问外网。第四从容器外面集群方面跨网络都会有一些访问到容器里面。
我们基于这样一个诉求我们把容器网络跟腾讯的VPC网络打通。我们把容器网段跟腾讯VPC的网段打通做了一个扁平化的网络。我们从LE2想访问到NODE2,在node上完成一个查找过程,查找我容器网段位于哪一个节点上,查这个路由节点做一个封装包,包含原容器IP,目标容器的IP,外网包含原容器IP,目标容器的IP,转发到node节点上,在node节点上把这个包发送到里面去。通过这样一个设计整个容器网络是扁平化网络。另外我们借助VPC的网关,来自我们外部访问请求,来自不同APC的访问请求,都可以通过不同网关访问到容器,或者对应的VPC里面,这是容器互通我们设计的理念。除了容器之间的互通、服务之间的互通基本上采用了Kubernetes的原生方案,通过server去做一些转发操作。
接下来我们看一下除了容器内部服务的访问,从外部如何访问到集群里面的服务的。这会涉及到另外一个概念负载均衡,我们把腾讯内部负载均衡跟容器网络打通分两层。第一层外乎访问一个容器服务的时候,我们为这个容器服务分一个域名IP,用户可以通过这个域名IP到腾讯接入层AB,AB这边有一个路由表做一些封装,把这些请求按照负载均衡的算法落到集群里面每个node节点上,这是第一层用户一个请求怎么样到达主机。到达主机之后后面转发工作就是Kubernetes原生的基础方案,Kubernetes把这个请求做一个原目标的存储,把请求平均分发到容器所在节点上去,这是负载均衡实现的原理。
除了说是容器外部用户直接访问集群里面的服务之外,还有一种场景,这种场景当然比较少,就是说根据域名转发,这要求我一个web用户访问一个容器访问一个域名根据不同的地址转发到不同的场景里面去。我们采用了Kubernetes node的方案。当一个访问到达LB,LB根据不同的路径,把这些请求转发到不同的node Port上,这些nodeIP和节点有可能在一个集群里面,当然也可能在多个集群上面,这样解决了跨集群部署问题,通过跟Kubernetes的打通,实现一对多的解决方案。除了网络的解决方案还有一个比较关键的点就是存储侧的解决方案。在存储侧相对比较简单。我们腾讯做了两件事,用户创建容器的时候,我给用户指定一个网络磁盘,这时候我们创建容器之前,在本地去率先把网盘部署在node节点上,然后容器可以使用本地磁盘使用网盘。如果容器发生一些故障需要做迁移,我们也会做这样的操作,首先把故障机器路由节点网盘做处理,新的起点上我们把容器启用,同时做一遍启用方案。我们把IaaS层的加入到CNCF社区,深度参与,推进社区的发展。谢谢大家,今天我演讲就结束了。谢谢。