数人云上海&深圳两地“容器之Mesos/K8S/Swarm三国演义”的嘉宾精彩实录第一弹来啦。今天是广发银行数据中心的运维老兵沈伟康关于传统运维与容器适配的全方位分享,万字长文倾情奉上~java
沈伟康,广发银行数据中心程序员
运维中年人,经历传统运维,建设自动化运维,尝试云计算运维web
你们好!我是广发银行的沈伟康,从传统行业出身,如今还在传统行业的坑里,今天分享的内容是在传统运维会遇到的各类想作可是不必定能作,又不得不去作的事情。算法
不管是传统运维仍是自动化运维, CMDB是一个很重要的核心。若是Docker没有本身的CMDB,也会有不少用起来不自在的地方。数据库
从环境这方面来谈一下CMDB对Docker的做用。若是全部事物都能标准化,那事情都会很简单、很便利,这是一个很好的理想,但在现实里尤为传统行业想把标准化进行推广,实现起来有必定的难度。编程
它会面临一个问题:差别化。差别化多了之后,Docker就会有各类各样的镜像,不一样应用之间会有不一样的镜像。即使是同一个应用,不一样的月度版本下都有不一样的镜像,好比升级了某一个库,镜像也是不同的,这时候应该怎么作呢?这时按正常逻辑,会给它作自定义。若是要自定义Docker的一个镜像,能够经过DockerFile来作。服务器
如今各大厂商的产品里面几乎都有一个WebUI的界面让用户去选择一些内容,能够自主编程一个DockerFile。若是只是单纯地把里面一些FROM、ADD参数直接加到页面上去选的话,至少要有必定的适配过程。网络
因此借鉴你们惯用的传统运维思路,并配有一个与之前传统CMDB对接的点,广发银行有以下几个作法:架构
第一,操做系统。对着DockerFile的FROM,让它在列表里选择这个应用要跑在什么样的OS里面,包括它的版本等。app
第二,经常使用软件。在下拉框选完以后是一个ADD,例如选了JAVA,要在Docker运行环境里面给它环境变量,容器里要找到JAVA相关的命令。Tomcat或者其它软件,都会有一些环境变量。因此在经常使用软件这块,如今打包的大部分是Tomcat或者JAVA类软件,把一些特定要使用的环境变量,根据这个页面选完以后,用ADD添加软件包的同时,用ENV把它设到环境变量中。
第三,需求包上传,对于差别化来讲很重要。例如这个项目组的应用依赖某个Python版本,另外一个项目组又依赖另外一个版本的Python,又如OS自带的一些so库,它到下个月度版本的时候又要依赖不一样的版本,可是不想把这么多版本都作成不一样的镜像提供不一样的服务市场,就会有一个需求包上传,这个包里把项目组应用需求的除了经常使用软件跟OS基本的套件以外的其余库或者软件打包,好比Python的安装包,RPM包,还有一些应用自身的东西,如启动的时候须要加载的证书之类都打包在这个包里。
第四,执行安装。这个包打完以后,为它定义一个执行安装过程的入口,即一个安装脚本,约定的时候让它将安装脚本放在压缩包的第一个目录下。这个包就至关于有了setup.sh的一个入口,这个入口让应用去定义安装什么、如何安装以及安装顺序。
第五,映射端口。对应DockerFile的EXPOSE,应用、服务或者容器启动完以后,会对外暴露哪一些端口。
第六,存储使用。存储路径选择对应VOLUMN,若是IO要求比较高就不用容器内部的AUFS,若是要求持久化就用外挂路径,若是宿主机之间共享就须要放到一些分布式存储或者NAS这种共享存储里面。
第七,启动运行。等价于CMD,让项目组在一个页面设置完以后,把它放到与传统CMDB对接的一个Docker专属的CMDB里。
这个CMDB主要的内容总结有三部分:环境需求配置,配置文件管理,应用运行配置。应用运行配置是项目组在一个页面作完配置后,运行和编译的时候就不用再填参数了,全部不一样的项目都在这里一次性设置好。
管理的纬度,配置是一个应用加一个项目标识。这个项目标识能够理解成是按月度或者是按照本身喜欢的命名的规则,如海外版本和国内版本。但对于广发来讲,用得比较多的是月度的标识,例如一个应用有ABC环境,分别对应几月份版本。
这里把镜像分红三类:第一类,基础环境镜像,上面只有OS还有一些依赖库的安装,一个运行的中间件。它会有一个命名规则, “应用名+项目标识”,好比“ABC_”,而后“201701”,就是2017年1月份版本,“base”表示镜像的tag是base,表示这是它的一个基础环境镜像。
第二类是应用版本镜像,在第一个基础环境镜像上加了编译后的目标码,不带环境差别的配置文件。这时命名规则是“应用名+项目标识”,tag变成了目标码的时间戳,在持续集成整条线下有一个惟一的标识,就是时间戳。固然,你们也会有其它各类各样的惟一标识选择。
第三种叫应用运行镜像,它是上面应用版本镜像再加上环境配置文件。开发环境有它本身的数据库,各类不一样的环境都会有本身的数据库配置,这个配置是不同的。若是说抽象成配置中心的话,它能够管理,但仍是用配置文件。命名规则是“应用名+项目标识”,再加“目标码时间戳”和“环境”。环境包括DEV开发环境、TEST测试环境以及PROD生产环境。最后是“配置文件时间戳”,一个项目组在项目初始的时候定义的配置文件内容有四个配置项,过了一段时间可能变成五个配置项,因此仍是一个时间戳,即配置文件的时间戳,以此去标识一个完整的运行镜像。
与传统的过程项目相比,广发的过程主要是搭建一个应用的OS环境,安装相应的中间件,而后部署相关的应用目标码。用Jenkins去持续集成出它整个应用版本镜像。整个过程就是应用版本镜像,加上测试的环境配置,它就变成测试环境的应用运行镜像,加上生产的配置就变成生产环境的应用运行镜像。
为何作配置文件而不作配置中心?推广配置中心的话,应用要改不少内容。传统应用里面不少配置都是写在配置文件里面的。若是要把配置文件改为从一个库里面读出来,举例开发环境,它的IP要有一个配套的插件从数据库里面把配置抽取出来,取代它本来的配置文件,才能在环境里面作它的开发;或者也能够作一个相似Eclipse插件去作这个事情,但配套的东西仍是要不少。若是为了上Docker要去推进这个事,它会变得很现实:第一,时间长;第二,阻力大。
另一个方法就是环境变量。相对数据库形式的配置中心来讲,环境变量稍微简单了一点,可是它要求项目组有一我的去抽离出配置文件里面各项的配置,而后转变成环境变量,再告诉项目组 “本来的DBURL配置”,代码里面须要变成System.getEnv()来获取DBURL,而再也不用getProperty读出来。
因此广发使用了一个配置文件包。这个配置文件包是一个tar,不会限制它有一个很严肃的名字,可是它的目录格式规则有一个限制的规则,它的第一个目录是最终访问的子URL,也就是TOMCAT的webapps下看到的目录。而后将全部的配置,假设最下面示例,应用有三个配置文件,要求它严格按照相对路径,把最终的相对路径打包好,打包成一个tar。
它按照war包的相对路径将配置文件打包成一个tar。而后把这个tar上传到不一样的环境目录,例如它有三个阶段,一个是开发,一个是测试,一个是生产,那它就会有三个目录,这三个目录由不一样的运维人员编辑,开发环境的原则上不用改,由于原本就是从开发来的;测试环境要由测试环境的运维同窗,把那些DBURL、数据库用户等配置按实际状况修改,生产环境也相似。
以后用一个最简单的DockerFile,即FROM应用版本镜像,再ADD,将配置文件到指定路径,假设是Tomcat就是webapps目录下,由于ADD会自动解压,自动地把它覆盖成一个真正的相应测试环境的运行镜像、测试环境的运行镜像、生产环境的运行镜像。项目组只要找一我的把这些配置文件抽出来就能够了。好久之前咱们已经谢绝全部把配置硬解到代码里面去,因此这种场景不适合。在JAVA里面直接写一个环境的数据库连接上面,可是它应该适用于把配置全部都抽离出一个文件里面或者说某个文件里面。
这是广发银行持续集总的框架。代码用Git,有一个目标码库,以及配置库。虽然上了Docker,可是没有舍去传统的环境。WAR包是持续集成编译一次后的war包,存起来并开放给传统部署的同事下载使用。配置库是刚才提到的存配置文件的地方。测试镜像库是独立的,它们之间的同步是经过脚本去自动同步的,即export出来的镜像,一个pull,一个push。
开发人员写代码,写完代码以后提交,提交完会由Jenkins自动下载回来编译。在这个过程当中有一个FindBugs来作的代码审查。而后编译生成一个war包,这个war包到这一阶段理论上与正常持续集成过程或者是人工编译后的war包同样。这时若是须要传统部署,能够经过FTP把war包下载回来,投产直接使用。
若是要用Docker,这个war包会加上它的第一个镜像:应用基础环境镜像,生成它的一个应用版本镜像;应用版本镜像生成完以后,加上测试环境的配置文件,它就会变成测试环境的运行镜像;这个测试环境的镜像只要运行起来,就会变成一个测试环境;测试环境是由测试员测试的,或者由一个自动化的工具作自动化测试。
测试环境的运行到生产上来讲也是一样一个过程,广发还有一个准生产环境,整个过程也都是相似的,准生产环境是与测试环境共用的。生产环境也是由版本镜像加上配置文件。全部从应用版本镜像生成运行镜像的过程都是能够不断迭代自动化的,运行的时候就会在环境里面跑起来。
在传统运维里若是拿到一个虚拟机,它有固定的IP或者DNS域名,想对它作什么就能够进去作,能够查看数据或者性能,尤为是在查性能问题的时候要看OS里面的资源使用状况,还有一些应用的状态,包括OS的状态。而这些东西到了Docker里面,就会变得有不少的阻力。
若是Docker容器里出了性能问题的话,要如何查?若是按照传统的观念,要SSH到容器里面去作,例如说有一个应用,Tomcat到了90%,那是否必定要在生产环境要保留这个环境,让应用开发的人去查?仍是直接毁掉它,从新起一个或者两个,业务量就不受任何影响,这种事情因人而异。
另外一个方法,能够把这些简单的交互分红两类,一是查看类型的需求,尝试经过外挂目录,由于假设要查看生成的javacore、heapdump文件等,之前作法是在OS里面使用kill-3生成heapdump文件,但若是把这些生成heapdump的动做归结为第三点操做类的话,是否是能够直接在宿主机上放一个agent,要对哪一个容器作heapdump至关于让用户在页面上直接选一个生成heapdump或者一个动做,而后由agent经过EXEC命令跑到容器里面去作,尽可能禁止用户直接跟容器进行交互。固然也有比较粗暴的,好比WebSSH。
应用更新的概念是服务没有中断。人们常说的滚动升级,在不少产品里面都实现了。可是实现的层面或许是这样的:假设有五个容器,滚动升级是按批的,第一批升级两个,升级完以后毁掉旧容器,用新的两个容器去换掉旧的两个容器,隔一段时间再升级后面的三个。这种按批升级会有一个须要关注的地方——容器销毁的时机。
常见的云平台调度算法里,容器状态OK的时候,调度平台会把本来的容器替换掉,但这个时候容器状态OK并不等于服务可用,由于容器里的Tomcat端口起来以后,它就会说这个容器是已经OK了,可是Tomcat起来以后的服务加载这个过程,快的话能够几秒,慢的话例如一个很庞大没有作任何微服务化改造的应用,就会是一分钟。但这一分钟之间,新的容器已经替换掉旧容器,那么这一分钟就悲剧了。因此服务加载的时间不可以忽略。容器销毁的时机是要大于容器状态OK的时间加上应用自启动的时间,在容器的调度上至少要用户每一个项目组加上服务要起的时间,要十秒就填十秒,十秒钟以后再按照按批滚动升级的过程去作。
如今传统运维里面一个应用可不可用,尤为是在银行里可不可用影响是很大的,因此广发银行在运维体系里有不少应用对外暴露的一些服务接口,而后经过自动化的监控工具去监控它的可用性。从这个角度来讲,调度器能够与传统监控对接,经过调用传统运维的内容获取到一个服务状态可用的时候才去执行五个升级两个,再升级三个这个动做。
第二要关注流量转移,在服务启动完以后,经过负载均衡自动去设置权重把新的流量转移到新的容器里面。由于有一个容器销毁的时机,因此这个容器也不会销毁,可是不要把新请求转给它。在传统行业,若是新容器或者服务好了、旧容器就立刻关掉的话,应用的架构不必定可以支持。在生产上尤为是在银行,例如在转帐的时候有一个交易流程,在一个容器里面规定要一、二、三、四、5步发生,并非第一步作完放到一个地方,而后由其余任何一我的去调第二步均可以。若是把一、二、三、四、5都串到一个容器里面,作到第三步的时候旧容器服务被停了,又没有对外的转帐接口去把钱转到别人那里去,后果就很严重,因此流量转移工做包括销毁的时间是要慎重的。
在不少厂商那里都会听到灰度发布,可是大部分都只是说没有中断。这个中断是否是真的没有中断,有待考究。广发会强调另一个A/B TEST。若是经过负载均衡去设置,举一个简单的例子,经过F5或者其它LVS负载均衡去设置来源IP来选择新版本仍是旧版本是没问题的。可是来源IP是能够欺骗的,像之前Pokemon go出来的时候,人不在国外,可是搞一个国外的IP也能够上。因此在应用能够接受的状况下,灰度发布应该由应用的人去作,例如每个帐号生成了惟一的ID,由ID决定他们是用新版本仍是用旧版本。尽可能不要用负载均衡来作灰度发布。
如今弹性扩容至少会讲到两点:一个是业务时间点,好比九点到十点这个业务时间点,能够把容器从十个变成二十个;另外一个是经过监控策略来自动化弹性扩容。扩其实很简单,从十个变成二十个没什么问题。可是扩完以后要缩回来,好比要应对某一个节日“双11”,找一个特定的时间点给它加OS,可是加完OS以后缩回来须要一个停机时间窗口,或者先从F5上Disable而后回收。
可是到了容器,若是听任调度器自动回收、自动缩容,是否真的可取?和刚才提到的销毁时间同样,是否要与传统的监控、服务可用的平台作一个对接后再缩?若是能够作到才是真正可以缩的,而不是如今页面上选择五个缩成三个,它就真的缩了两个,至少咱们在生产当中是不敢这样作的。
均衡资源。假设传统运维里,把Docker的宿主机交给传统运维的监控平台去监控,但这时监控平台判断这台宿主机已经CPU使用率90%了, Docker调度器与传统运维的监控平台作对接的时候,为了避免影响应用服务是否须要把容器给迁走,是所有迁走仍是把CPU消耗高的迁走,或者把启动时间最长的迁走?做为一个程序员永远都不敢说本身写的程序跑了一段时间以后会不会比刚刚跑起来的时候更稳定。这种策略在生产实践是很关键的,须要一个博弈的过程。如今不少厂商自身支持各类各样的弹性,可是弹性缩是否真的可以支持而不会有业务影响,是有待考究的。
目前来讲,没有任何一个厂商说“只要用个人平台,包括把个人平台堆积到传统运维以后,能够作到想缩就缩,不会让用户帐户丢了钱”,不用让业务员去作一个回滚的操做。在传统运维里面,若是应用开发的项目组能够按照各类各样优雅关闭的特性去写应用,没问题。但毕竟业务程序是由人写的,人是不可控的。
在传统的应用容器化运行后,会有一个归档和查看日志的问题。目前项目组把它改为标准输出,再由自动的一个收集平台,例如广发银行如今是用数人云的一个logagent去自动收logstash的,而后存储到ES里面,由Kibana去展现。若是要对接传统运维,也可让项目组把应用的目录放到一个外挂的文件。传统的监控里面有一个外挂支持在某一个路径下监测全部的配置文件,因此只要把它放到一个外挂的共享存储或者分布式存储,而后再把这个外挂路径做为一个对接的入口到传统的日志管理平台里面就能够了。
另外一种是之前作CloudFoundry时,他们会强调应用要把全部的日志做为流写入到这个平台里面,例如FLUME。若是只是简单粗暴地把应用的日志写进去,会有时间乱序的问题,固然这个问题是能够解决的,但若是A容器实例跟B容器实例都是属于同一个应用,就会有这里来了一句以后,那里下一句话又来了的状况。要截取某一个加密的日志,须要开发人员配合在日志里面加各类各样的标识,例如如今要查询某一个业务量的日志,要根据业务量的代码去查,查完以后它可以抽取出来在同一个容器里面的那一段日志,那如何作到在同一个容器?无疑在写日志的时候,也须要把容器的标识放在日志里面。
若是作实时,用syslog就能够。若是只是日志收集,ELK也是能够知足的。为了减小应用改造,单应用日志时就重定向到标准输出。若是是多个日志,如今考虑的方案是把它放到一个外挂目录,再由专门的容器去收上送,而不会经过其它的agent。外挂目录也是能够对接传统的应用日志监控平台,传统运维里面能够有一个监控平台去监控这个日志的增量更新里面有没有应用关注的关键字,若是有这个关键字的话,就会发短信提醒说应用出现了什么异常。
在传统行业里面要对接传统监控必定是必然的。对接的过程能够分红几个纬度,一是Docker与平台自身的监控,能够经过接口去对接、上送数据。另外一个是宿主机的监控,宿主机是一个物理OS,传统监控里面如何折腾这个OS已是很标准或者很天然的动做。
容器监控,能够尝试cadvisor或者其它在业界应用比较多的东西。应用监控比较难,传统运维会关注应用CPU和内存使用率,以及数据源的链接词,或者一些线程数,当达到某一个值后,就进行告警。而到了容器里面,要把它抽离出来。举一个例子,它能够把Tomcat里面的Apache公布的那一堆指标经过Tomcat的接口给暴露出来。暴露到哪里,是须要额外去定制化、去收集容器里面的Tomcat,因此对不一样的工具要作一个对接的过程。
在容器化的网络里,除了一些对外暴露的端口, Docker DB就不用说了。可是在应用的端口里面,假设是HaProxy, HAProxy的端口可用不表示相应容器的服务是可用的,能够尝试直接在监控HaProxy这些端口服务的同时直接让应用暴露服务可用性的一个接口,直接监个应用接口的返回码到底是200或是非200就能够了。
应用改造只列了四点,并不表示应用改造只有四点,而是努力让应用只作这四点,只关注这四点就能够了。
第一是节点差别化,在环境里假设有三台应用服务器,其中一台应用服务器作了一些其它两台应用服务器没有的事情。这种状况在广发或者金融行业里都是比较多的。到了Docker以后,就尽可能不要作这种事情。
第二是持久化,在广发的环境里面,举一个数据,OS里面的外挂存储不多少于500G的。一个OS若是要作动态扩缩,里面的存储越少越好,由于不须要让它作其它事情。若是要把一个文件持久化,是由于IO的性能问题须要把它外挂,仍是日志不属于容器销毁而持久化?或是这个容器在A宿主机跑起来,下一次在B宿主机跑起来,都要读写一样一份东西,那么就搬到NFSDATA的一个文件里面,选NAS data做为一个volume,配置文件配上那个路径。
在内存数据里面,建议作一个剥离,好比剥离到REDIS,可是若是在有统一的应用开发框架状况下要把一些东西剥离出来,只要有框架内的应用去改造就能够。若是不是的话,能够采用一些自然比较支持这种转换的,例如把数据放到Redis,有一些框架直接支持改一下配置就能够,另外一些框架则是不行的。
第三是可变性。之前传统运维会把上游IP抓下来,下发到下游。但容器的OS环境变量是可变的, IP地址获取方式,变成从环境变量获取。Hostname是不建议使用的,之前看到把Hostname做为一个标准传到日志里面或者直接用来起日志共享目录的一个名字,到云里面跑得久越读不懂,至少IP的名字都读不懂,由于没有一我的去干预它的Hostname。
第四是易处理,快速启动,优雅关闭。以微服务化改造来讲,可以作到易处理,即随时启动的时间不会超过几秒,随时均可以关闭,若是应用上Docker而且要跑得很好的话,那必定要去考虑这方面的事情。
分享就到这里,谢谢你们。