首先,以Java项目为例,部署方式有很多,我总结如下:
Tomcat等:所有文件放在war包中部署
WAS/Weblogic:通常外挂lib,每次只更新项目自身代码(ear包或war包)
JBOSS/EAP:不同于其他Web Container,JBOSS自创了VFS
Executable Fat Jar(自带Web Container):
所谓Fat Jar就是所有打包在一个jar中,涉及 jar:jar:file:/path 问题, 需要hack,一些特殊项目可能无法这样做(spring-boot-maven-plugin是一个常用主流强大的Fat Jar工具,然而Github上还是有一堆的issues)【从某种角度来看,JBOSS的VFS(参见官方文档)就是为了解决类似这些资源访问问题而设计的重量级解决方案】
Executable Jar(自带Web Container)+ 外挂其他文件:
为了弥补Fat Jar的不足,引入外挂文件,一方面解决特殊问题,另一方面易于局部更新
Docker镜像(自带Web Container):
只需要将应用的包放到指定目录即可。【显然,这是比上面所有方案更重量级的方案,直接套一个终极外壳,比JBOSS套一个VFS还要强得多】
我的分析如下:
从打包和部署的角度来说,Fat Jar很臃肿(所有项目文件打包在一起),动辄50M以上甚至100多M。我以前长期使用WAS/Weblogic,一般把公共的jar lib分类,然后项目直接加载即可,应用包更轻量(实际上我们频繁上线,但是基础lib几乎不怎么更新,lib更新的次数占总上线次数的5%不到)。
Fat jar更新不方便,假设我想更新一个lib包(xx-util.jar)或者js、html文件,那就得重新打Fat Jar包,同理Docker镜像也是如此。
回过头来,我们先不看技术方案,先来想清楚我们的诉求:
(以下不分顺序)
部署方便(主要考虑全自动化部署的场景)
部署灵活(易于配置和局部更新,容易备份和回滚)
首先,大前提,针对DevOps自运维团队,不考虑交给运维部门这种低级的运维方式。
项目和服务器完全自主可控,只需要考虑的是怎么高效和安全。根据我多年文件维护的经验,建议将文件分类:冷热和大小。将经常更新的文件集中在一起(zip、war、jar包中),每次整体更新,而不经常更新的文件(第三方库、依赖文件)只做同步更新(增删改)。
针对一般Java项目,第三方依赖包,放置在外部,配置文件,放置在外部,其他文件打包在一起。每次更新时,先各个部分分别对比,如无更新,则跳过这部分。对比之前,先拉一个文件清单,是对比清单而不直接对比文件。
简单实现方式,就是写一个脚本,自动获取两边各部分的清单,自动对比出要更新的文件列表,然后tar归档一个更新包、一个备份包,然后更新所有文件,更新有三种:新增、替换、删除,还原时反过来:删除、替换、新增。
外加一点,大量而细小(2k~2w个,平均每个10KB以内)的文件打包成一个大文件维护——虽然通常的项目都不存在这种情况,但可能有一些奇葩,例如NodeJS的node_modules依赖,可能有这种文件(轻松上2万)。为了提高效率,可以特殊处理。一种方案,在拉清单对比之前,先将node_modules下面的文件夹各自归档(用相同工具和算法)。这样处理之后,项目的文件数可能就从2万变成了2千,在对比和维护时就简单了许多。另外,需要吐槽一句,NPM的设计简直就是垃圾,可以学习一下Maven,设置本地仓库(local repo)且将公共的依赖库打包(zip、jar)并分类/分版本集中管理,然后项目中用到哪些库就引用(软引用、符号链接)就行了,根本不需要每个项目单独维护一份文件,而且文件还是零散的、没有归档压缩的,这导致所有前端项目的依赖文件成千上万甚至十万,即便是SSD硬盘,要处理这么多小文件,也很累。
另外,文件的备份和存取,可以单独写一个管理系统,后端对接分布式对象存储。例如备份和获取:
curl 172.168.12.2/api/backup -F file=@/tmp/a9d8/zoa-main.tar curl 172.168.12.2/api/getfile -X POST -d "name=zoa-main.tar&version=v20170210s01"
备份逻辑系统会自动处理,当然curl的时候也可以传参数去控制。这样一来,其实一个脚本就可以完全实现自动化,而且部署非常灵活。当然,整个部署过程,也可以由智能运维系统自动控制,操作人输入参数、点一下按钮就行了,也可以提前准备好,定时自动执行。
再回到前面说的Java项目问题,显然,我赞成Tomcat + 文件夹部署,或者Fat jar+外挂文件,对自动化来说,两者没什么区别,所以我优先选择Tomcat + 文件夹部署方式。
有的人可能会说,全量包部署更好,全量包部署更简单一些,不需要这么麻烦的对比和备份。而且全量包主要的缺点是体积较大,但是100多MB也不算大,内网传输很快的。至于方便些、安全性,都是差不多的,都需要靠规章和自动化系统去保障。
我的回答是,没错,其实两者差别不大,但即便如此,我还是不建议使用全量包。说全量包部署更简单,那是基于传统手工运维的思路,对自动化运维来说,只能说初期实现要费一番精力,后面其实都是自动化的,都是点一下按钮就执行,简单程度是一样。体积较大,虽然100多MB算不上什么,但是系统多了,而且备份次数多了,节省的时间和空间还是很可观的。安全性上,全量包和增量包,都有可能出错,但是增量包出错一般只是局部影响,而全量包出错可能影响很多部分。
Docker部署专题
前面说了,Docker部署很有特点,一是因为Docker镜像自带操作系统,二是因为Docker独特的文件系统、镜像分层,可以复用文件。所以,使用Docker部署,有很大的优化空间。
根据上述指导思想,需要考虑文件冷热和大小因素,重点考虑上述“Tomcat + 文件夹部署,或者Fat jar+外挂文件”的方式部署项目(而非全量包)。将不经常变动的文件封装在基础层中,例如
COPY target/base-lib/ /app/lib/
然后再拷贝 易变动 的部分:
COPY target/app-lib/ /app/lib/
COPY target/*.jar /app/