本文演示了一个在云或虚拟平台上,用于自动化部署和管理Docker Java微服务应用程序的解决方案。我们通过扩展现有项目Chris Richardson的示例——一个事件溯源(Event Sourcing)的基于微服务的资金转移程序。引入CQRS和Docker来自动构建和部署该项目。我们的项目包含有用于每个微服务的Dockerfiles文件,还将提供一个可在Web服务器上运行的整合前端,这个前端可以提供所用到的微服务。我们使用Nginx Web sever,在前端页面的默认目录/ usr / share / nginx / html /中编写JavaScript代码。前端将暴露出如下功能:
我们将创建的资金转移应用程序作为一个采用事件朔源架构,由CQRS和Docker组成的构建和部署微服务的示例。基于微服务的应用程序具有高可扩展性和高可用性,通过polyglot持久化、事件朔源(ES)和命令查询的责任分离(CQRS)实现。微服务应用程序由使用事件进行通信的松耦合组件组成。这些组件可以作为独立的服务进行部署,也可以作为单个应用程序进行打包以简化开发和测试。本文介绍的项目中,我们专注于自动化前一种方法 —— 即自动在Docker容器上运行单一服务。
我们的目标是在13个不同的云和虚拟化平台(包括vSphere,OpenStack,AWS,Rackspace,Microsoft Azure,Google Compute Engine,DigitalOcean,IBM SoftLayer等)上运行和管理此项目中的事件朔源Docker Java微服务应用程序模板。 我们建议您执行以下操作之一:
容纳企业级Java应用程序是一个巨大的挑战,主要是因为现有的应用程序组合框架无法解决复杂的依赖关系、外部集成关系以及添加服务实例之后(Post-Provision)的自动扩展流程等问题。此外,容器生存周期的短暂性也迫使开发人员在每次更新版本时,重新创建复杂的依赖关系和外部集成容器。
DCHQ(可用在托管版本或on-),通过高级应用程序组合框解决了这些挑战并简化了企业Java应用程序的集装箱化,该框架使用跨图像环境变量绑定扩展Docker Compose,可在请求时调用的可扩展BASH脚本插件时间或提供后,以及应用程序集群,以支持多个主机或区域的高可用性,并支持自动缩放。
一旦配置好了应用程序,用户就可以:
此外,即插即用的工作流程有助于基于Jenkins的持续交付(即将推出更多支持),使开发人员能够刷新正在运行应用程序的Java WAR文件,而不会干扰现有的依赖关系和集成。
在本作者的个人博客中,我们演示了跨越13层的多层基于Docker的应用程序堆栈中的更传统或典型的brownfield Java应用程序(如Names Directory,Pizza Shop和Movie Store应用程序)的端到端部署自动化不同的云和虚拟化平台。
在我们目前的项目中,我们将关注一个微服务架构,它不需要任何应用程序服务器。每个微服务都运行在一个非常轻量级的Java容器上。为了执行特定的任务(例如创建账户,查询账户或将资金从一个账户转移到另一个账户),构建了一个合并的前端,用于为每个连接的微服务创建REST API调用。微服务的一个主要优势(与典型的单一应用程序相比)是,这些模块化服务可以轻松替换和扩展,而无需更改其他微服务。从某种意义上说,这消除了单点故障,使开发人员更容易为整个项目做出贡献。
在这个项目中,我们将提供一个分步指南,用于在不同的云/虚拟基础架构上部署和管理这个Java应用程序。
我们需要执行以下每个步骤,我们将详细看到:
现在我们将详细介绍每个步骤:
为了单独运行微服务,您需要获取Event Store的凭据。
复制并粘贴EVENTUATE_API_KEY_ID和EVENTUATE_API_KEY_SECRET的值到Event Sourcing Docker Java微服务应用程序模板中。
Docker映像中使用的JAR文件是从该项目构建的。
所有的JAR文件都是在2015年12月27日建立的,并在此处嵌入Docker镜像。
在构建JAR文件之前,将CORSFilter.java复制到“event-sourcing-examples / java-spring / common-web / src / main / java / net / chrisrichardson / eventstore / javaexamples / banking / web / util”目录中。然后你可以执行
./gradlew assemble.
git clone https://github.com/cer/event-sourcing-examples.git
wget https://github.com/dchqinc/event-sourcing-microservices/raw/master/patch/CORSFilter.java -O /event-sourcing-examples/java-spring/common-web/src/main/java/net/chrisrichardson/eventstore/javaexamples/banking/web/util/CORSFilter.java
cd /event-sourcing-examples/java-spring
./gradlew assemble
该项目中的所有图像都已经构建并推送到DCHQ公共Docker Hub存储库供您参考。以下是将在应用程序模板中使用的自定义图像:
要构建图像并将它们推送到您自己的Docker Hub或Quay存储库中,可以使用DCHQ。以下是用于这些图像的四个GitHub项目:
一旦登录到DCHQ(托管的DCHQ.io或内部版本),您可以导航到Automate > Image Build,然后单击+按钮创建一个新的Dockerfile(Git / GitHub / BitBucket)图像版本。
提供所需的值如下:
一旦必填字段完成,请点击保存。
然后,您可以点击Play按钮来按需构建Docker镜像。
登录到DCHQ(托管的DCHQ.io或内部部署版本)后,用户可以导航到管理 > 应用程序/机器,然后单击+按钮创建一个新的Docker撰写模板。您可以参考此处创建Docker Compose应用程序模板的详细文档。
我们使用我们在前一步中构建的Docker镜像创建了一个应用程序模板。该模板包含以下组件:
在应用程序模板中,您会注意到Nginx容器正在请求时调用BASH脚本插件来配置容器。这个插件也可以在提供后执行。
这些插件可以通过导航到管理>插件来创建。一旦提供BASH脚本,DCHQ代理将在容器内执行该脚本。您可以指定在请求时间和提供后可覆盖的参数。以$符号开头的任何内容都被视为参数 - 例如,$ file_url可以是允许开发人员指定WAR文件的下载URL的参数。如果用户想要刷新正在运行的容器上的Java WAR文件,那么可以在请求时重写并在提供后进行此操作。
定义基于YAML的应用程序模板时,需要提供插件ID。例如,要调用Nginx的BASH脚本插件,我们将引用插件ID如下:
nginx:
image: dchq/nginx-microservices:latest
publish_all: true
mem_min: 50m
host: host1
plugins:
- !plugin
id: Gl5Hi
restart: true
lifecycle: on_create
arguments:
- ACCOUNT_CMD_IP={{accountscommandside | ip}}
- ACCOUNT_CMD_PORT={{accountscommandside | port_8080}}
- ACCOUNT_TRANSFER_IP={{transactionscommandside | ip}}
- ACCOUNT_TRANSFER_PORT={{transactionscommandside | port_8080}}
- ACCOUNT_QUERY_IP={{accountsqueryside | ip}}
- ACCOUNT_QUERY_PORT={{accountsqueryside | port_8080}}
在这个例子中,Nginx正在调用一个BASH脚本插件,动态地(或在请求时)在/usr/share/nginx/html/js/app.js文件中注入微服务容器IP和端口号。插件ID是Gl5Hi。
插件中的生命周期参数允许您指定执行插件的确切阶段或事件。如果没有指定生命周期,那么默认情况下,插件将被执行on_create。您可以参考此处设置Docker服务发现的详细文档。以下是支持的生命周期阶段:
您会注意到cluster_size参数允许您指定要启动的容器数量(具有相同的应用程序依赖性)。
该主机参数允许你指定你想使用容器部署主机。如果您在创建群集时选择了Weave作为网络层,确保跨不同主机(或区域)的应用程序服务器群集的高可用性,同时允许您遵守关联性规则以确保数据库运行在一个单独的主机上。以下是主机参数支持的值:
另外,用户可以通过引用另一个图像的环境变量来创建跨图像环境变量绑定。在这种情况下,我们做了几个绑定 - 包括ACCOUNT_CMD_IP = {{accountscommandside | ip}} - 帐户创建微服务容器IP在请求时动态解析,并用于确保Nginx可以与此微服务建立连接。
以下是支持的环境变量值列表:
nginx:
image: dchq/nginx-microservices:latest
publish_all: true
mem_min: 50m
host: host1
plugins:
- !plugin
id: Gl5Hi
restart: true
lifecycle: on_create
arguments:
- ACCOUNT_CMD_IP={{accountscommandside | ip}}
- ACCOUNT_CMD_PORT={{accountscommandside | port_8080}}
- ACCOUNT_TRANSFER_IP={{transactionscommandside | ip}}
- ACCOUNT_TRANSFER_PORT={{transactionscommandside | port_8080}}
- ACCOUNT_QUERY_IP={{accountsqueryside | ip}}
- ACCOUNT_QUERY_PORT={{accountsqueryside | port_8080}}
accountscommandside:
image: dchq/accounts-command-side-service
mem_min: 300m
cluster_size: 1
host: host1
publish_all: true
environment:
- EVENTUATE_API_KEY_ID=<paste-your-key-here>
- EVENTUATE_API_KEY_SECRET=<paste-your-key-here>
transactionscommandside:
image: dchq/transactions-command-side-service
mem_min: 300m
cluster_size: 1
host: host1
publish_all: true
environment:
- EVENTUATE_API_KEY_ID=<paste-your-key-here>
- EVENTUATE_API_KEY_SECRET=<paste-your-key-here>
accountsqueryside:
image: dchq/accounts-query-side-service
mem_min: 300m
cluster_size: 1
host: host1
publish_all: true
environment:
- EVENTUATE_API_KEY_ID=<paste-your-key-here>
- EVENTUATE_API_KEY_SECRET=<paste-your-key-here>
- SPRING_DATA_MONGODB_URI=mongodb://{{mongodb | container_private_ip}}/mydb
mongodb:
image: mongo:3.0.4
host: host1
一旦保存了应用程序,您就可以注册一个云提供商,在12个不同的云终端上自动执行配置和自动扩展,包括VMware vSphere,OpenStack,CloudStack,亚马逊网络服务,Rackspace,Microsoft Azure,DigitalOcean,IBM SoftLayer,谷歌计算引擎等。
要为Rackspace注册云提供商(例如),请导航至管理 > 云提供商和回购站,然后单击+按钮选择Rackspace。需要提供Rackspace API密钥 - 可以从Rackspace Cloud控制面板的帐户设置部分检索。
然后,您可以使用自动缩放策略创建群集,以自动启动新的云服务器。这可以通过导航到“ 管理” >“ 群集”页面,然后单击“ +”按钮完成。您可以选择一个基于容量的放置策略,然后选择Weave作为网络层,以便在集群内的多个主机之间实现安全,密码保护的跨容器通信。该自动缩放策略,例如,可以虚拟机(或云服务器)的最大数量设置为10。
现在,您可以通过基于UI的工作流程或通过定义可从自助服务库请求的简单的基于YAML的Machine Compose模板,在新创建的群集上配置多个Cloud Server。
基于UI的工作流程 - 您可以通过导航到“ 管理” >“ 机器”然后单击“ +”按钮选择“ Rackspace”来请求Rackspace云服务器。选择Cloud Provider后,请选择所需的区域,大小和图像。默认情况下,Rackspace Cloud Servers会打开端口以适应端口要求(例如Docker的32000-59000,Weave的6783和RabbitMQ的5672)。然后选择一个群集并指定云服务器的数量。
基于YAML的机器撰写模板 - 您可以先导航到管理 > 应用/机器,然后选择机器撰写,然后为Rackspace创建一个机器撰写模板。
这是用于请求4GB云服务器的模板。
Medium:
region: IAD
description: Rackspace small instance
instanceType: general1-4
image: IAD/5ed162cc-b4eb-4371-b24a-a0ae73376c73
count: 1
Machine Compose模板支持的参数汇总如下:
一旦保存了机器撰写模板,您可以从自助服务库请求本机。您可以单击Customize(自定义),然后选择用于配置这些Rackspace Cloud Server 的Cloud Provider和Cluster。
一旦配置了Cloud Server,您就可以在新的云服务器上部署基于Docker的多层Java应用程序。这可以通过导航到自助服务库,然后单击自定义来请求多层应用程序来完成。
选择一个环境标签(如DEV或QE)和您创建的Rackspace Cluster,然后单击运行。
命令提示符图标应位于Live Apps页面上容器名称旁边。这允许用户通过代理消息队列使用安全通信协议进入容器。租户管理员可以定义白名单,以确保用户不会对正在运行的容器进行任何有害更改。
例如,对于Nginx容器,我们使用命令提示符来确保app.js文件包含Docker Java微服务的正确IP和端口。
在此屏幕截图中,浏览器内终端用于在Nginx容器中显示/usr/share/nginx/html/js/app.js的内容。我们可以看到,使用DCHQ的插件框架将Docker Java微服务的IP和端口正确注入到此文件中。
一旦应用程序启动并运行,我们的开发人员将监视正在运行的容器的CPU,内存和I / O,以便在这些度量标准超出预定义阈值时收到警报。这在执行功能和负载测试时特别有用。
您可以执行历史监视分析,然后将问题关联到容器更新或构建部署。这可以通过点击统计,并选择一个自定义的日期范围来查看历史上的CPU,内存和I / O。
“不可变”容器模型是一种常见的最佳实践,它通过重建包含应用程序代码的Docker镜像并在每次应用程序更新时启用新容器来完成。DCHQ提供了自动构建功能,允许开发人员从Dockerfiles或包含Dockerfiles的私有GitHub项目自动创建Docker镜像。然后将这些图像推送到Docker Private Registry,Docker Hub或Quay上的已注册私人或公共存储库之一。
您可以使用从Docker注册表中推送的最新映像启动的新容器自动“替换”正在运行的容器。这可以按需执行,也可以在Docker注册表中检测到新图像时自动完成。要用一个包含最新JAR文件的新包替换Docker Java微服务容器,用户只需单击Actions菜单并选择Replace。然后,用户可以输入将从其启动新容器的映像名称,以用相同的应用程序依赖关系替换已运行的容器。或者,用户可以指定此容器替换的触发器 - 可以基于简单的CRON表达式(即预定义的计划)或基于Docker注册表上的最新映像推送。
许多开发人员可能希望使用最新的Java JAR文件更新正在运行的容器。为此,DCHQ允许开发人员与Jenkins建立持续交付工作流程。这可以通过单击正在运行的应用程序的操作菜单,然后选择连续传送来完成。您可以选择一个Jenkins实例,该实例已经在DCHQ中注册,Jenkins上的实际工作将生成最新的JAR文件,然后选择一个BASH脚本插件来抓取该构建并将其部署到正在运行的应用程序服务器上。保存此策略后,任何时候触发构建,DCHQ都会从Jenkins获取最新的WAR文件,并将其部署到正在运行的应用程序服务器上。
因此,开发人员将始终在DEV / TEST环境中的运行容器上部署最新的JAR。
容纳企业Java应用程序是一个挑战,主要是因为现有的应用程序组合框架无法解决复杂的依赖关系,服务发现或后置自动扩展工作流程。
DCHQ以托管和本地版本的形式提供,解决了所有这些挑战,并通过高级应用程序组合框架简化了企业Java应用程序的集装箱化,该框架有助于实现跨图像环境变量绑定,可在不同生活中调用的可扩展BASH脚本插件应用程序部署的循环阶段以及跨多个主机或区域提供高可用性的应用程序集群,并支持自动扩展。
免费注册在http://DCHQ.io或下载DCHQ内部部署以访问外的箱多层Java应用程序模板中包含监控应用程序生命周期管理功能,集装箱更新,规模沿着输入/输出和持续交付。