【编者的话】当前,是不是使用容器已经不是一个被讨论的重点;热点已然成为企业如何高效使用容器、如何利用容器给企业带来切实的收益。从底层的Docker到优秀的容器编排Kubernetes,都给我们带来了令人心动的基础。今天分享的OpenShift实践(基于Docker和Kubernetes的容器PaaS云平台),希望可以给大家基于Docker和Kubernetes构建自己的容器云带来一点儿思路。
概述与实践背景
OpenShift是红帽的云开发平台即服务(PaaS)。 通过OpenShift,企业可以快速搭建稳定、安全、高效的容器应用平台。在这个平台上:
- 可以构建企业内部的容器应用市场,为开发人员快速提供应用开发所依赖的中间件、数据库等服务。
- 通过自动化的流程,开发人员可以快速进行应用的构建、容器化及部署。
- 通过OpenShift,用户可以贯通从应用开发到测试,再到上线的全流程,开发、测试和运维等不同的角色可以在一个平台上进行协作。
- 支持LDAP用户权限管理,支持细粒度的权限资源管理。
- OpenShift可以提高应用从研发到上线的效率和速度,缩短产品上市的时间,可以有效地帮助企业推进DevOps,提高资源利用率,提升生产效率。
当前公司业务和产品处于快速迭代和扩展阶段,每个月平均新增10多个新服务,迭代速度越来越快,同时废弃的老服务服务也越来越多。新技术发展也比较快,在旧方式的基础上我们尝试新技术的成本也比较高,维护成本也比较高。如何提高我们的生产效率,如何提高我们适应新时代的能力,越来越重要。
在此背景下,我们先列出以下几个比较明显的问题:
- 阿里云上的资源利用率比较低
- 临时扩容比较慢,在运营活动的时候经常资源不足,需要升级配置,活动结束后资源利用率回归较低水平
- 新服务增加快,新机器、SLB等越来越多,越来越不好维护
- 微服务治理的重要性越来越突出
为了解决这些问题,我们调研了多个解决方案,最终选择了OpenShift作为PaaS平台;截止目前已有70多个项目、100多个服务、上千个pod运行在PaaS平台里(包括Python27、Python36、Java、Golang、Nodejs等类型服务)。
OpenShift结构
OpenShift层级自底而上,分为:基础架构层、容器引擎层、容器编排层、PaaS服务层、界面及工具层。
Docker
优势:构建一个隔离的、稳定的、安全的、高性能的容器运行环境;很多开源项目都做了自己的官方镜像,使用和维护更方便。
Kubernetes
容器编排。
- 容器调度:按业务的需求快速部署容器到指定的目标
- 弹性伸缩:按业务的需求快速扩展或收缩容器的运行实例数量
- 异常自愈:当容器实例运行异常,集群能自动感知、处理并恢复服务状态
- 持久化卷:为散布在集群不同机器上的容器提供持久化的智能对接
- 服务发现:为业务为服务化提供服务发现及负载均衡等功能
- 配置管理:为业务应用提供灵活的配置管理及分发规则
OpenShift
容器云,在Docker和Kubernetes的基础上提供了各种功能,以满足业务应用、研发用户及运维用户在生产效率上的诉求。
1)应用开发框架及中间件
OpenShift提供了丰富的开箱即用的编程开发框架及中间件,如Java、PHP、Ruby、Python、JBossEAP、Tomcat、MySQL、MongoDB及JBoss系列中间件等。
2)应用及服务目录
OpenShift提供了如软件市场式的服务及应用目录,可以实现用户一键部署各类应用及服务,比如一键部署Hadoop集群和Spark集群。
3)自动化流程及工具
OpenShift内置了自动化流程工具S2I(SourcetoImage),帮助用户自动化完成代码的编译、构建及镜像发布。
4)软件自定义网络
通过OpenVSwitch,OpenShift为用户提供了灵活强健的软件定义网络。实现跨主机共享网络及多租户隔离网络模式。
5)性能监控及日志管理
OpenShift提供了开箱可用的性能监控及日志管理的组件。通过平台,业务能快速获取运行状态指标,对业务日志进行收集及分析。
6)多用户接口
OpenShift提供了友好的Web用户界面、命令行工具及RESTfulAPI。
7)自动化集群部署及管理
OpenShift通过Ansible实现了集群的自动化部署,为集群的自动化扩容提供了接口。
OpenShift核心流程
一、应用构建
第1步,部署应用。流程的开始是用户通过OpenShift的Web控制台或命令行ocnew-app创建应用。根据用户提供的源代码仓库地址及Builder镜像,平台将生成构建配置(BuildConfig)、部署配置(DeploymentConfig)、Service及Route等对象。
第2步,触发构建。应用相关的对象创建完毕后,平台将触发一次S2I构建。
第3步,实例化构建。平台依据应用的BuildConfig实例化一次构建,生成一个Build对象。Build对象生成后,平台将执行具体的构建操作,包括下载源代码、实例化Builder镜像、执行编译和构建脚本等。
第4步,生成镜像。构建成功后将生成一个可供部署的应用容器镜像。平台将把此镜像推送到内部的镜像仓库组件Registry中。
第5步,更新ImageStream。镜像推送至内部的仓库后,平台将创建或更新应用的ImageStream的镜像信息,使之指向最新的镜像。
二、应用部署
第6步,触发镜像部署。当ImageStream的镜像信息更新后,将触发平台部署S2I构建生成的镜像。
第7步,实例化镜像部署。DeploymentConfig对象记录了部署的定义,平台将依据此配置实例化一次部署,生成一个Deploy对象跟踪当次部署的状态。
第8步,生成ReplicationController。平台部署将实例化一个ReplicationController,用以调度应用容器的部署。
第9步,部署容器。通过ReplicationController,OpenShift将Pod及应用容器部署到集群的计算节点中。
三、请求处理
第10步,用户访问。用户通过浏览器访问Route对象中定义的应用域名。
第11步,请求处理并返回。请求到Router组件后,Router根据Route定义的规则,找到请求所含域名相关联的Service的容器,并将请求转发给容器实例。容器实例除了请求后返回数据,还会通过Router将数据返回给调用的客户端。
四、应用更新
在应用更新时,平台将重复上述流程的第1步至第9步。平台将用下载更新后的代码构建应用,生成新的镜像,并将镜像部署至集群中。值得注意的是,OpenShit支持滚动更新。在第9步时,平台将通过滚动更新的方式,保证应用在新老实例交替时服务不间断。
部署结构
OpenShift集群:
- 所有服务组件都部署在阿里云上,即VPC网络的ECS机器上,分布在多个可用区
- 3个Master节点,3个etcd节点,1个Harbor节点,N个Node节点
- Node节点分布,根据业务类型打tag标签区分,分别为:
- Base集群,主要运行Router服务和Registry镜像仓库
- Inf集群,主要运行内部PyPI的Python内部源、Nexus服务(主要作为Maven的内部源)和Trace系统等
- Gateway集群,主要部署OpenResty的API网关服务,作为流量从公网域名进入集群的入口
- Service集群,主要部署公司的业务应用
- Bigdata集群,主要部署公司内部大数据服务
- 变更平台,通过调用OpenShift的API,来完成build镜像、通过Deployment的模板来更新容器,并记录当前Pod的代码版本。
- 回滚时选择代码版本对应的一个Deployment配置文件来进行重新部署(注意:Deployment是使用的img的对应hash值,启动参数主要通过ConfigMap、配置中心Apollo来管理)。
服务镜像自动化及部署模板
SourcetoImage(S2I),S2I是OpenShit的一个重要功能。容器镜像是容器云的应用交付格式。容器镜像中包含了应用及其所依赖的运行环境。通常的做法必须基于外部的基础镜像构建包含企业自身开发代码的应用。这个镜像的构建过程是必须的,要么由企业的IT人员手工完成,要么使用某种工具实现自动化。
作为一个面向应用的平台,OpenShift提供了S2I的流程,使得企业内容器的构建变得标准化和自动化,从而提高了软件从开发到上线的效率。
一个典型的S2I流程包含了以下几个步骤。
- 用户输入源代码仓库的地址。
- 用户选择S2I构建的基础镜像(又称为Builder镜像)。Builder镜像中包含了操作系统、编程语言、框架等应用所需的软件及配置。OpenShift默认提供了多种编程语言的Builder镜像,如Java、PHP、Ruby、Python、Perl等。用户也可以根据自身需求定制自己的Builder镜像,并发布到服务目录中供用户选用。
- 用户或系统触发S2I构建。OpenShift将实例化S2I构建执行器。
- S2I构建执行器将从用户指定的代码仓库下载源代码。
- S2I构建执行器实例化Builder镜像。代码将会被注入Builder镜像中。
- Builder镜像将根据预定义的逻辑执行源代码的编译、构建并完成部署。
- S2I构建执行器将完成操作的Builder镜像并生成新的Docker镜像。
- S2I构建执行器将新的镜像推送到OpenShift内部的镜像仓库。
- S2I构建执行器更新该次构建相关的ImageStream信息。
S2I构建完成后,根据用户定义的部署逻辑,OpenShift将把镜像实例化部署到集群中。
除了接受源代码仓库地址作为输入外,S2I还接受Dockerfile以及二进制文件作为构建的输入。甚至可以完全自定义构建逻辑来满足特殊的需求。
部署模板
通过自定义模板,可以创建我们自己应用发布时的快速部署模板。包括应用所需的多个Build Config、Deployment Config、Service及Route等对象。OpenShift的Template还有一个重要的特性就是参数化。用户可以在Template中定义参数,这些参数在用户部署模板时将显示在Web控制台的界面上,供用户输入。用户的输入最终以环境变量的方式传递到容器内部。一个OpenShift的Template在结构上主要分为三个组成部分:元信息、对象列表及参数列表。
服务访问拓扑
容器里的服务都是阿里云VPC的网络,旧服务都是部署在阿里云经典网络的ECS机器上,互相访问时经典网络SLB是一个问题。需要将原来经典网络的SLB换成VPC的SLB。
- 容器互访:通过Hostname+Port方式,后端是Service Ip
- 容器访问经典网络服务:将经典网络的SLB,替换成VPC的SLB
- 经典网络的服务访问容器:a、HTTP服务,通过内网域名;b、RPC服务,通过映射的Node+Port
- 外网访问容器里的服务:外网域名——>外网SLB——>API网关——>容器service的HOSTNAME——>Pod
踩过的坑
- 日志搜集:因为Pod来回漂移,我们采用了阿里云的NAS存储(NFS)作为PV;日志文件会被共享,并被抢占文件句柄,导致日志里有乱码;我们的处理方式是日志中间加一个hostname,例如:interface.paris-interface-service-c-44-bx52z.debug,日志收集时flume匹配interface.*.debug。
- 监控:OpenShift自身的监控是使用Hawkular+Cassandra+Heapster,只有容器的CPU、内存和网络的监控。Pod版本的一致性、events监控(包括imge的生命周期、Pod的生命周期、服务健康检查等)、PV的监控等,都需要通过API来获取并加入到自建的监控平台
- CronJob不太稳定,crash时间比较长的情况下,Job下一次执行时间延迟过久,导致不再执行。这种情况只能删除后重新部署Job。
- 版本的控制,Deployment需要通过配置里的image的hash值,找到对应的build(build信息里记录了代码版本信息,包括commit、commit message、更新人和提交时间等);回滚的时候要选择代码版本对应的build,然后再找到build对应的Deployment配置进行部署,这些都通过自建的变更平台来管理。
我们正在做的事情
- 将API网关替换成Kong,目前已经测试了大部分的功能,但Docker版本的稳定性比较差,QPS在很小的情况下也有很多5XX的错误。解决方案:在Kubernetes的Node节点上部署
- 由于现在对外业务发展比较快,计划通过模板、环境变量和配置中心来创建一整套的Applications,类似于SaaS服务。
- 打通QA,研发人员从提交代码转换到交付一个线上可用的image
OpenShift对容器化PaaS平台实践的借鉴意义
- S2I自动构建服务镜像,实现自动化的流程。
- 部署模板,根据某一类型服务进行快速部署deployment(例如Python的模板、Golang的模板等);在每一个版本的deployment配置中,img会使用镜像的hash值(例如:docker-registry.default.svc:5000/XXX/XXX@sha256:899007bXXXXXXXX95f561203cba);回滚时选择对应版本的deployment配置进行重新部署即可达到回滚的目的。
- Router服务使用haproxy(支持AB部署,及流量分配),Router根据Route定义的规则,找到请求所含域名相关联的Service的容器,并将请求转发给容器实例。容器实例除了请求后返回数据,还会通过Router将数据返回给调用的客户端。
- LDAP用户管理等多用户管理,通过clusterrole/clusterrolebinding(全局资源权限)、role/rolebinding、serviceaccount、oauthaccesstoken等来实现权限分配。
Q&A
Q:请问通过OpenShift怎么做高可用?
A:OpenShift的高可用是跟Kubernetes的高可用一致的,就是延用了Kubernetes的Service IP来做服务发现和负载均衡;另外,前面还有DNS服务,(例如:Hostname: service.abc-platform.svc,后端就是指向的Cluster IP)。
Q:image的版本管理怎么做?配置的版本管理怎么做?
A:OpenShift本身会创建一个内部的Registry,S2I会根据Build来更新image,image的版本是通过sha256的值对应Build的版本号(例如:Build版本#24对应registry.intra.XXXXX.com/abc/abc-platform@sha256:b41c8XXXXX)。
Q:OpenShift的网络方案性能方面有多少损耗?与Kubernetes的其他网络方案如Calico相比如何?
A:OpenShift的网络方案是选择的OVS,性能上肯定是不如Calico,但对于我们的服务足够了。目前跑了有1000+个常驻Pod,没有出现网络瓶颈。
Q:如果要做多机房部署,OpenShift能搞吗?
A:多机房,只要网络能通并比较稳定,是没有问题的。我们的部署方案就是在阿里云上的多个可用区部署的。而且,实际部署中也是鼓励多机房部署的,服务容灾要求一个服务要分布在多个可用区(或者机房)。
Q:你们平台性能怎么测试的,如何集成?
A:平台性能测试分两部分。一个是在集群内部不经过Nginx直接压测SVC,另外一个是在集群外部压测内网域名或者公网域名。
Q:我们之前用自己的镜像仓库,会报tls认证错误,不知道你们有没有遇到过?
A:我们自己创建的镜像仓库是用Harbor来建的,只是存储了内部服务的基础镜像。OpenShift集群内的镜像仓库有自己的认证,是通过Secrets管理对应权限的token(用户级别的权限是通过LDAP统一认证的)。S2I创建服务镜像的时候就是通过这个来获取权限的。还是比较稳定的,没有出现过tls的问题。
Q:生产环境的节点磁盘是怎么分区分配的?
A:生产环境的节点磁盘分为两类,一个是系统盘(40G),另一个是数据盘(100G);Docker的所有镜像、实例等存储都是放在数据盘,服务的日志是挂载的PV,PV是使用的阿里云的NAS存储。
Q:我看你们在集群访问前加了个API Gateway,用了OpenResty,这个能详细介绍下不?
A:可以简单理解为一个自建的Ingress,底层是Nginx+Lua实现的;我们已经在逐渐使用Kong来代替OpenResty了。Kong底层是Nginx+Lua+PostgreSQL,界面管理是使用的Konga。选择Kong和Konga的理由是:1、Kong的管理和插件比较方便,还支持自定义插件;2、Konga的界面更友好,管理、更新都比较方面。
Q:看到你们是3 Master高可用,请问Kubernetes–Master挂了一台,OpenShift如何恢复,etcd是否有做备份?
A:我们做过演练,Master挂一台或者两台,甚至三台全挂,也不会影响已经运行的服务。只要etcd没有问题,重启Master或者新增一台Master都可以快速恢复集群。etcd的备份是做的全量备份,上传到我们的备份存储中。
Q:内网域名是怎么跨VPC和经典网络的?
A:内网域名的DNSPod解析是解析到VPC网络的一台ECS机器上,通过Nginx来管理。经典网络的ECS服务集群可以在前面挂载一个VPC网络的SLB,Nginx的对应Server Name的Upstream设为这个VPC的SLB即可。
Q:监控和告警好像没有提到,感觉OC这块似乎缺失?
A:OpenShift本身有很多服务状态,image的Build、pull、push等状态,以及Pod的各种状态;另外还有强大events。我们是通过OpenShift的API来获取这些信息,同步到Open-Falcon上来处理报警信息的。
Q:日志统一生产、采集用了什么方式能介绍一下吗? A:日志是一个比较疑难的问题;我们的解决方案是,所有的日志都打到同一个NaS盘上,服务名来做该服务的日志路径。多个Pod打同一个日志的时候,会出现乱码。我们的解决方案是在日志中间加hostname,例如haadeers.melon-crm-b-9-nb9d5.log,melon-crm-b-9-nb9d5为Pod的hostname。日志收集,是几台ECS机器挂载改NAS盘,启动flume来收集。 Q:业务应用的自动化发布你们是怎么设计的,能否详细说说思路? A:我们是自己定义了S2I的流程。Build镜像统一在代码仓库里加一个Makefile,定义一个assemble的role,来做初始化(依赖包的安装、nodejs的Build等等,这里还是比较灵活的)。自动发布:我们是自定义了部署模板,分享的内容里有(只需要简单的几步就可以部署一套服务)。 以上内容根据2018年12月4日晚微信群分享内容整理。分享人徐义义,智融集团容器化PaaS平台负责人,从事云计算开发、设计6年(其中4年私有云,2年公有云<京东云>),目前负责公司内部PaaS平台的建设与应用的变更交付。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。