本文获得codingthearchitecture.com授权翻译发表,转载需要注明来自公众号EAWorld。
作者:Simon Brown
译者:月满西楼
原题:Paas for Java developers
全文7600字,阅读约需要20分钟
简介
我从事软件开发工作已有20多年,在此期间,我参与了各种不同的环境下,各类软件系统的搭建工作,其中大部分系统都以Java和web技术为核心,当然其他技术也有所接触。同时,我也有幸参与了从开始到交付的整个软件开发过程。不过在基础设施这一块,我没有参与太多。另外,我也创建过一些服务器,但大多数生产基础设施的构建都是由基础设施团队完成的。我认为这很常见。提供生产级基础设施是一项专门的任务;需要了解安装、配置和强化操作系统、数据库、负载平衡器、防火墙等方面的知识。坦率来讲,这都不是我特别感兴趣的,尤其身在软件行业,我们都需要不断地去学习新知识、新技能,新技术的更新换代实在太快。
记得三年前,我在匈牙利布达佩斯的Craft Conference上,曾就我的一个名为Structurizr的创新应用程序和与会者进行了多次探讨。这个程序的初期演示是在Rackspace的Ubuntu上运行的,但牵扯到了一系列基础设施和操作上的问题,这些问题的解决不在我的能力范围内。会中我收到的一个建议是, 我可以去关注一下Pivotal Web Services这个 PaaS云服务。我确实也在泽西运营一些当地学校的编程俱乐部时接触过这个服务,但没有考虑过它是否能承载我自己的应用程序。
1、Pivotal Web Services
与Cloud Foundry
Pivotal Web Services是一个基于Cloud Foundry的商业服务,提供“平台即服务”(PaaS)。从本质上讲,Cloud Foundry通过API提供了一个应用程序部署平台,可以将部署在公有云、私有云或是数据中心服务器上的底层基础结构抽象出来。
假设你正要在Apache Tomcat Web服务器上构建一个Java web应用程序。那么,在其能在网络上运行之前,你需要在某处提供服务器,安装Java和Apache Tomcat Web服务器。你还需要强化服务器、配置SSL、定期应用补丁等,如果你还想通过使用两个实例来提高恢复能力,那还需要启动第二个服务器,重复前面的步骤,并配置这两个服务器,来支持例如负载平衡器。
当然,你还可以,也可能会,使用Vagrant, Chef, Puppet, Docker等这些自动化配置和部署工具来自动化大部分的操作步骤。
当Cloud Foundry命令行界面安装完成之后,如果我们想部署一个Java .WAR 或.JAR文件,只需要简单地运行一个“cf push”命令,就可以将它部署到Pivotal Web Services 这个PaaS云服务上。仅此而已! 我还可以使用“cf scale”命令来请求Pivotal Web Services来纵向扩展应用程序,例如添加更多的RAM,或把应用程序横向扩展,例如添加更多实例。
如果需要更新应用程序,则要用到另一个“cf push”命令。但这么做会中止当前实例的运行,并将其替换为新版本,因此会有一些服务停止时间。然而,Cloud Foundry PaaS云平台使得通过命令行接口来进行蓝绿部署变得非常容易。如此一来,Java开发人员就可以不具备底层基础设施专业知识的前提下,也在几分钟内建立一个“零停机时间(zero-downtime)”(即服务不会停止)的连续交付通道。
2、基础设施上层的应用程序
正如Joshua McKenty在最近的一个关于思科云的播客中所讲的,Pivotal Web Services和Cloud Foundry为开发者提供了一个更高的抽象层。软件开发人员的职责是处理应用程序,而不是基础设施或容器。
目前,业内关于Docker容器的讨论很火热。我认为Docker是一项了不起的技术。但是,软件开发人员更多的还是要专注于处理应用程序,而不是去关注容器技术或基础设施。我认为关注Docker技术是对大多数软件开发人员本职工作的干扰,对此,我会在另一篇博客里进行阐述。
3、供应商锁定(Vendor Lock-in)
在上文中,我介绍了平台即服务(PaaS),并讨论了如何使用Pivotal Web Services PaaS云服务和Cloud Foundry PaaS云平台来实现应用程序的快捷部署,且无需担心任何底层基础设施的问题。 一个比较常见的误区是,大家总觉得使用Cloud Foundry PaaS云平台(以及Pivotal Web Services PaaS云服务或其他项目)会导致供应商锁定(Vendor Lock-in),从而不能轻易转换云服务提供商。
回过头来再看Structurizr,它是用于可视化和文件记录软件架构的一组工具,系统图示如下:
总而言之,经过身份验证的用户使用Structurizr Client函数库(Java 和.NET)可创建和上传软件架构模型,并通过web查看这些模型的内容。Structurizr使用SendGrid这个电子邮件服务平台发送电子邮件,所有支付处理都是由Taxamo和 Braintree支付工具服务一起完成的。这里也用到了其他一些云服务(例如CloudFlare、Pingdom和Papertrail),但在图表中没有显示。
从一个(C4模型)容器角度来看,Structurizr如下图所示(图表中忽略了外部服务,因为它们与此次讨论无关):
从本质上讲, Structurizr由一个运行在web浏览器(服务于HTML、CSS和JavaScript)的客户端应用程序组成,而服务器端包含一个Java web应用程序服务https://structurizr.com,和另一个Java应用程序服务https://api.structurizr.com,再加上一些数据存储(MySQL数据库管理系统, Redis缓存和Amazon S3云存储服务)。这两个Java web应用程序都运行在Pivotal Web Services这个PaaS云服务上。
这两个Java web应用程序都基于Spring MVC框架,并按照“twelve-factor methodology”中所说明的一系列原则实现的。实际上,从技术角度来看,这两个程序都只是设计在云平台上运行的典型Java web应用程序。两个程序都是无状态的,不会向本地文件系统写入重要信息。
4、供应商锁定(Vendor Lock-in)
和迁移成本
接下来让我们来谈谈供应商锁定(Vendor Lock-in),正如Sam Newman说的那样,“不要一提到供应商锁定(Vendor Lock-in),就自然想到迁移成本”。 Structurizr的所有开发都是在Mac上使用IntelliJ IDEA完成的,而Vagrant虚拟机运行环境管理工具则被用来运行本地的MySQL数据库系统和Redis缓存拷贝。在代码库中,没有任何东西与Cloud Foundry PaaS云平台有关,我也没有在本地运行Cloud Foundry相关的内容。Java应用程序是部署到本地运行的Apache Tomcat实例的标准Java EE.WAR文件。
推送(Push) Structurizr“Web应用程序”(使用“cf push”命令)会导致Web应用程序被部署到Pivotal Web Services 上,并且可以在https://struct-web.cfapps.io的URL中使用。想要把这个web应用程序迁移到另一个云服务提供商的话,以下是我需要进行的一些操作。
1.首先我需要找到另一个支持Java 8,Apache Tomcat 8.x服务器的PaaS云服务,或者构建自己的服务器。另外,Java虚拟机(JVM)还要求安装"Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files",这是因为web应用程序在存储数据时使用了一些强度更高的加密算法。
2. 考虑到web应用程序多个实例在运行(显然,Pivotal Web Services PaaS云服务在单一的URL后进行处理),我需要对这个设置进行镜像。
3. Structurizr.com域的域名服务器(DNS)正由CloudFlare管理,为映射新的部署位置,一些别名(即CNAME)记录需要更改。
就是这么简单。虽说部署脚本需要更改,但不需要对代码进行任何变动。Pivotal Web Services 这个PaaS云服务确实提供了一些基于Cloud Foundry PaaS云平台的附加功能,比如它们的数据仪表板,这对监控和管理很很方便,但这些并不是应用程序的关键组成部分。总之,我并遇到没有任何供应商锁定的问题(Vendor Lock-in),而且迁移成本很低。毕竟,我的Java web应用程序很普通,并不依赖于Cloud Foundry PaaS云平台。
至此,你可能会想,“等等,那数据存储呢?”,这是另一个话题。接下来,我将分享在Pivotal Web Services PaaS云服务中可用的市场服务(Marketplace Service),以及为什么我不做推荐。
5、应用市场服务
(Marketplace Service)
从这部分开始,我想说,我个人确实喜欢且推荐Pivotal Web Services PaaS云服务和Cloud Foundry PaaS云平台来作为部署Java应用程序的方法, 它们能显著简化部署流程,并带来出色的性能表现。我在Pivotal Web Services PaaS云服务上运行Structurizr已经三年多了,几乎没在核心平台上发现有什么问题。但应用市场服务(Marketplace Service)则另当别论。
除了提供一个用于运行代码的部署平台之外,大多数像Pivotal Web Services、Heroku、AzurePaaS云服务这类的平台还会提供“应用市场服务(Marketplace Service)”集合。本质上,这些是附加服务,可以让用户方便地访问数据库、信息传递提供程序、监视工具等,在我写这篇文章时,Pivotal Web Services PaaS云服务应用市场(Marketplace)包含很多当下比较流行的技术; 比如MySQL、 PostgreSQL、 Redis、 Memcached、MongoDB、RabbitMQ等。
6、MySQL 即服务
假设你正构建一个Java web应用程序,并希望将数据存储在MySQL数据管理系统中。你可以有几种处理方法:一种是在Amazon AWS之类的平台上构建你自己的数据库服务器。当然,这要求你有能力来实现,前文中我曾用很大篇幅来阐述利用PaaS平台构建个性化基础设施的优点,但这种DIY方法不一定适用于每个人。
另一种选择是找到一个“数据库即服务(DaaS)”的提供商,由它来为你创建和运行MySQL服务器。ClearDB就是一个例子,你可以在Pivotal Web Services PaaS云服务应用市场(Marketplace)上找到它。你只需通过应用市场(Marketplace)订阅一个免费的ClearDB,并将其连接到数据库,从而来构建你的解决方案。就是这么简单,MySQL数据库在操作方面大都都需要维护;包括备份和复制。
当Java应用程序连接到ClearDB时,同样也有几种选择。一是常规做法,将数据库端点URL、用户名和密码放在配置中。也以用Cloud Foundry命令行接口来发出一个“cf bind”命令,将ClearDB数据库实例绑定应用程序实例,并使用云平台的自动重新配置功能来进行操作。
如果您构建的是一个基于spring框架的应用程序,且已经配置了MySQL数据源(一些注意事项),那么Cloud Foundry PaaS云平台将自动地重新配置数据源,指向已绑定到应用程序的MySQL数据库。这项功能一经使用,你一定会觉得体验非常不错,因为又少了一件需要你担心的事。这还意味着,即使后续更改了URL、用户名和密码,你也不需要自己去更新。
几年来我都是这么操作的,在Structurizr changelog上你会发现版本号都快过1000了。每个版本号都代表一个在Pivotal Web Services上的独立(自动)部署。在我运行的这些大量部署中,大多数都部署成功了,偶尔,我也会收到一些因为服务(比如ClearDB)不能绑定到应用程序实例的失败提示。
不过这都是些暂时性的错误,只需要重新启动部署就能修复它们。但遇到其他错误提示时,我不得不承认我实在没有办法解决它。PaaS的一个大问题就在于,一旦出错,管理者就会陷入困境,因为无法访问到底层的基础设施。好在这类错误出现频度很低,现实中没有让我真正担心过,但还是挺烦人的。
更闹心的是我发现了一个Structurizr和UTF-8字符编码的小bug。当用户注册帐户时,记录会被保存在MySQL里,用户会收到一封“请验证您的电子邮件地址”的电子邮件。一旦注册者的名字中包含了UTF-8字符,尽管第一封电子邮件不会有什么问题,但后续就会出错。这个问题出在MySQL无法正确地存储UTF-8字符上。
我在dev环境中重演了这个问题,可以通过向JDBC URL添加一个字符编码参数来修复。不过,推送这个补丁到实时环境也存在问题,因为Cloud Foundry又会自动重新配置我的数据源URL。简单处理是不启用自动重新配置,这很容易通过Java构建包来实现禁用,也不需要将MySQL数据库实例绑定到Java应用程序。基于以上操作,现在我仍然会通过应用市场来使用ClearDB,但在配置中我会指定连接细节。
我所遇到的有关ClearDB的最后一个问题是在今年早些时候,当时我经常在日志中看到错误消息,提示已经超过了能连接的最大数量。不同的ClearDB计划会提供不同级别的性能和连接数量。我认为应用市场提供的ClearDB数据库是面向多租户(Multi-tenant)的,它会设置一个连接限制来确保所有客户的服务质量。这可以理解,但我不明白为什么我会超过可使用数量,因为我清楚地知道我运行的应用实例数量,而且也清楚每个应用实例所限定的连接数量范围。
于是,我在Apache基准测试中运行了一些负载测试,结果我无法得知打开连接的数量,从而无法判断它们是否超过了连接池中所配置的最大限额。我再三查看ClearDB的数据指示仪表板,按说它可以显示打开连接的数量,但我的应用程序却无法连接,仪表板上只显示了几个实时连接。
回到供应商锁定和迁移成本这个话题,将应用程序从ClearDB迁移到另一个MySQL供应商的成本很低,特别是不使用Cloud Foundry的自动重新配置机制之后。因此,我可以导出数据,并在Amazon RDS上创建一个MySQL数据库。每个月在不需要支付很多费用的前提下,我就可以有个运行在多个可用性区域的MySQL数据库,在rest中使用加密的数据,并且我确信JDBC连接是通过SSL进行的(因为这就是我配置它的方式)。
7、电子邮件传送即服务
我早期使用的另一个应用市场服务是SendGrid,它提供“电子邮件传送即服务(E-mail delivery as a service)”。同样的,运行一个“cf bind”命令就可以将SendGrid服务绑定到应用程序。
但在这种情况下,不会有自动重新配置,因为SendGrid公开了一个web API。这就提出了一个问题,即在哪里找到API凭据。应用市场服务一个很好的特性是,只需要一个单点登录的操作,就能通过关键Web服务 UI来访问服务数据仪表板(例如ClearDB仪表板、SendGrid仪表板等),在服务仪表板上的某个位置找到服务凭证。
在获取SendGrid的密码后,我将它硬编码到一个配置文件中,并将其推送到应用程序中。出乎我意料的是,程序尝试连接SendGrid后提示了身份验证失败,因为密码错误。于是我再次访问了仪表板,发现密码已经不一样了,我不知道造成这样的结果是否是因为运行了一个“cf bind”命令而导致SendGrid凭证被更改。
我没有意识到服务凭证是在运行中的JVM的 VCAP_SERVICES 环境变量中设置的,凭证应该从那里提取。这只是一个带有JSON content 的常规环境变量。获取它并解析所需的凭证,或是使用GitHub上众多代码示例或函数库(library)就可以完成此操作。从开发的角度来看,我现在对这个VCAP的数据有小小的依赖,我需要确保我的本地Apache Tomcat实例以相同的方式进行配置,并在启动时使用VCAP_SERVICES环境变量。
一段时间之后,SendGrid已经将其Web API升级到了v3版 ,其中也包括了Java函数库的新版本。 所以我也进行了升级,但却导致了API调用的失败。在登录到SendGrid数据仪表板之后,我注意到现在可以通过API密钥进行连接。简而言之,我放弃了VCAP的可调用数据,配置了SendGrid客户端,用使用API密钥的方法来调用API,这些也被我添加到了部署配置中。
8、其他服务
我还使用过一段时间的Pivotal SSL Service,用来上传SSL证书。当它与Cloud Foundry路由器同时工作,就可以通过一个有效的SSL证书为指定域名提供流量服务。在使用过程中我也遇到一些问题,比如会导致运行停止。Java程序在cfapps.io域里还能正常工作,但structurizr.com域则不行。
此后,我又换成了CloudFlare专用的SSL证书服务,每月花费5美元。我确实尝试过免费的SSL证书服务,但一部分用户还是反馈了通过Structurizr's web API上传软件架构模型时,发现了一些“SSL握手”方面的问题。
曾经我也结合 Spring Session一起,用了免费的Redis缓存服务,将其作为存储HTTP session信息的一种方式。不过,我很快就消耗完了免费的额度,同时发现通过Redis Labs直接切换到Redis Cloud计划性价比会更高些。
9、无市场服务的PaaS
使用与PaaS产品相配套的应用市场服务(Marketplace Service)肯定有一些好处。你只需要选择订阅一项附加服务,就可以开始使用了,既快又便捷。而且所有的服务都可以在同一个市场里进行购买和管理,这点也很棒。在使用Cloud Foundry PaaS云平台时,我就通过VCAP_SERVICES进行配置;这样所有的服务都在一起。
如果你刚开始使用PaaS,我想你肯定会考虑与其配套的那些应用市场服务。虽然大家具体情况会有所不同,但我还是不推荐用这些应用市场服务来从事生产活动。正如我在本文开头所说,我使用Pivotal Web Services PaaS的核心功能差不多有三年,这期间系统一直都比较稳定。我所遇到的那些不稳定的情况,都和应用市场服务有关。这些市场服务很可能导致你无法获知一些具体情况,比如在特定情况下,服务实际能带来什么样的运行结果,以及服务具体在哪里运行。
ClearDB数据库计划其实也有暗示,免费计划(Spark DB)是“完美适用于概念验证和初级开发”,而每月100美元的"Shock DB"计划则“专为高性能应用而设计”。这些计划没有在ClearDB网站上列出,因此很难判断它们是多租户服务 还是单一租户服务。考虑到需要进行网络登录,应用市场服务创建的一些访问密码看起来也相当简短(比如8个字符)。
考虑到以上种种情况,我更倾向于直接注册一个服务,并以常用的方式来进行集成,我不认为采用应用市场服务利大于弊。如果哪一天我需要从PaaS项目中移走。我还将进一步降低迁移成本。总的来说,Structurizr目前的现场部署方案图如下所示:
Java应用程序托管在Pivotal Web Services PaaS云服务上,其他所有组件都在外部运行,但它仍然在亚马逊(Amazon)的us-east-1 AWS区域。这应该有助于解决另一个常见的,大家都认为需要在PaaS环境中运行所有内容的误区,但其实没什么能阻止你在PaaS上运行Java应用程序,并让它们连接到你自己构建的数据库服务器。如此一来,你可以自由使用你选择的技术,不管它是否在应用市场(Marketplace)上可用。当然,你还需要考虑适配性、性能和安全性。
以上是我对应用市场服务(Marketplace Service)经验的总结。接下来,我将更多地讨论构建/部署脚本,以及通过Cloud Foundry PaaS云平台实现零停机时间(zero-downtime)、蓝绿部署方面的内容。
本文的前几部分已经从多个不同的角度对Cloud Foundry PaaS云平台作了介绍; 包括high-level概念、供应商锁定(vendor lock-in) 和Pivotal Web Services PaaS云服务应用市场服务(Marketplace Service)。接下来,我们将讨论Cloud Foundry PaaS云平台如何实现“零停机时间(zero-downtime)”部署,并让这个操作变得更为简易。
10、蓝绿部署
先简要介绍下这个主题,假设有个Java web应用程序在某处运行。将该应用程序升级到新版本的一个简单方法是先暂停程序,然后更新相关的部署构件(例如.JAR 或 .WAR文件),再重启。一些web应用程序服务器也会为应用程序的热部署(hot swapping) 提供支持,但原理都一样。
尽管这个方法是可行的,但在这个过程中,用户就会有一段时间无法使用服务。多年来,技术人员也构想了许多技术方案来处理这个问题,业界最流行的就是蓝绿部署,在这种部署方案里,会有一个物理或是虚拟的路由器,将流量从应用程序的一个运行实例切换到另一个。这听起来很先进,但如果你使用Cloud Foundry,任何规模的开发团队都可以轻松地进行蓝绿部署。
在本文的前面部分我也提到过,Structurizr是由两个java/spring web应用程序组成;一个服务于HTML、CSS和JavaScript的“Web应用程序”和一个允许客户获取或放置软件架构的工作区的“API应用程序”。构建和部署过程由Amazon EC2服务器上运行的TeamCity触发,等待提交到git存储库,这整个过程都是完全自动化的。总而言之,蓝绿部署的构建和部署过程遵循以下几个步骤:
-
处理好依赖关系(dependencies)
-
初始化构建目录、新增版本号等
-
编译生产和测试代码
-
运行单元/类(unit/class)测试
-
运行集成/组件测试
-
创建部署构件(例如.WAR文件)
-
将API应用程序推送至Pivotal Web Services
-
在API应用程序上运行e2e/系统测试
-
将Web应用程序推送至Pivotal Web Services
-
在Web应用程序上运行e2e/系统测试
-
激活API应用程序
-
激活Web应用程序
-
生成并发布新的软件架构图和文档
11、推送应用程序至
Pivotal Web Services
假设构建和测试的过程都顺利, 那么这个过程中,每个API和Web应用程序都会被推送至Pivotal Web Services PaaS云服务。构建服务器上安装了Cloud Foundry命令行接口,构建脚本只需使用“cf push”命令来推送(Push).WAR文件。为便于应用程序的推送(Push),我们使用“--no-start”标记(flag),但不启动它,这样就可以通过“cf env”命令来设置像配置这样的应用程序环境变量。设置完配置后,在实际启动应用程序之前,使用“cf scale”命令还可以设置所需的实例和RAM数量。此时,应用程序还在运行,但是只能通过包含版本号的临时URL进行访问(例如“https://structurizrweb - 123. cfapps.io”)。
在应用程序运行的同时,构建脚本可以运行一系列端到端测试,比如“冒烟测试(smoke test)” 和系统测试并行的混合测试,以验证新版本的应用程序是否按预期运行。这些测试包括一些像登录、获取/安装软件架构模型等场景。
12、激活新版本
如果成功通过了端到端测试,接下来就是激活这些程序的新版本。这需要使用Cloud Foundry命令行接口,将实时URL映射到应用程序的新版本("cf map-route"),然后将其从旧版本中删除(“cf-unmap-路由”)。这个过程使用了Cloud Foundry路由器,它可以实现对访问当前运行程序的URL的配置。 如果这一切都成功了,那么应用程序的前一个版本就会被删除。整个构建过程只需要不到10分钟。如果你感兴趣,这里还有一些关于如何进行蓝绿部署的内容。
将实时URL切换到应用程序新版本的这个过程,是允许“零停机时间(zero-downtime)”部署的。这里要提醒大家的是,切换到新版本后,任何只驻留在旧版程序内存空间中的信息都会丢失。例如,如果HTTP 会话(session)状态只存储在内存中,那么一旦用户在请求被导入到新的Apache Tomcat实例时,就会被迫退出。 处理这个问题有包括会话(session)复制在内的多种方法, 但Structurizr使用Spring session+Redis技术,将HTTP会话信息存储在Apache Tomcat服务器实例之外,以便在部署过程中保留会话信息,从而解决了会话共享问题。
如此一来……仅仅是使用Cloud Foundry命令行接口,我们就简单高效地完成了一个“零停机时间(zero-downtime)”部署过程。
原文地址:
http://www.codingthearchitecture.com/2017/09/27/paas_for_java_developers_part_1.html
http://www.codingthearchitecture.com/2017/09/28/paas_for_java_developers_part_2.html
http://www.codingthearchitecture.com/2017/09/29/paas_for_java_developers_part_3.html
http://www.codingthearchitecture.com/2017/10/10/paas_for_java_developers_part_4.html
(编者注:原文分为四部分,此文为全部内容的整合。)
作者简介:
Simon Brown,全球知名软件架构独立咨询师、讲师,专注于软件架构研究,他是C4软件架构模型的创建者,也是Structurizr的创始人。
关于EAWorld:微服务,DevOps,数据治理,移动架构原创技术分享,长按二维码关注