天啦噜!看国外大神如何用Docker+Jenkins&CI/CD打造微服务架构?
Posted 优云数智
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了天啦噜!看国外大神如何用Docker+Jenkins&CI/CD打造微服务架构?相关的知识,希望对你有一定的参考价值。
导读:
Docker、微服务、持续交付是目前编程领域中最受欢迎的话题。在由几十个相互通信的微服务组成的环境中,特别重要的是测试、构建和部署过程的自动化。Docker是一种极好的微服务解决方案,因为它可以创建和运行独立的容器和服务。将Docker容器连接在一起,它们之间能够通信,确保所有的工具和微服务都在同一台机器上运行。
1
今天,将介绍如何使用流行的软件自动化工具:Jenkins,创建一个基本的持续交付管道,用于示例微服务。
微服务样本
在讨论本文主题之前,首先介绍一些用于微服务创建的架构和工具。此示例包含两个微服务,它们彼此通信(account、customer)、发现服务器(Eureka)和API网关(Zuul)。使用Spring Boot和Spring Cloud框架实现的。源代码可以在GitHub上找到。Spring Cloud支持微服务服务发现和网关,只需要在maven项目配置文件(pom.xml)中定义正确的依赖关系。
帐户和客户服务在启动后自己注册到发现服务器中。它们之间也有交互的可能——例如,如果想找到并返回所有客户的帐户细节。
一般来说,Spring框架对微服务提供了全面的支持,包括诸如Ribbon、Hystrix和Eureka等所有的Netflix OSS工具。本文描述了如何实现服务发现、分布式跟踪、负载平衡、日志跟踪ID propagation,以及使用这些解决方案的微服务 API 网关。
Dockerfiles
示例源代码中的每个服务都有一个Dockerfile和Docker映像构建定义。这是很简单的。这里是帐户服务的Dockerfile。我们使用OpenJDK作为基本映像。将目标中的JAR文件添加到映像中,然后使用java -jar命令运行。服务在端口2222上运行,该端口暴露在外面。
MAINTAINER Piotr Minkowski <piotr.minkowski@gmail.com>
ADD target/account-service.jar account-service.jar
ENTRYPOINT ["java", "-jar", "/account-service.jar"]
EXPOSE 2222
(向右滑动)
我们还必须在JAR清单中设置主类。在模块pom.xml中使用spring-boot-maven-plugin实现。碎片在下面可见。我们还设置了build finalName来从目标JAR文件中删除版本号。对于所有其他微服务,Dockerfile和Maven构建定义非常相似。
<build>
<finalName>account-service</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.2.RELEASE</version>
<configuration>
<mainClass>pl.piomin.microservices.account.Application</mainClass>
<addResources>true</addResources>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
(向下向右滑动)
Jenkins Pipelines
使用Pipeline Plugin为微服务构建持续交付。除了在Jenkins中设置的标准插件外,还需要CloudBees的Docker Pipeline Plugin。这里定义了四条管道,如下图所示。
这是用Groovy语言编写的用于发现服务的管道定义。有五个执行阶段。在Checkout阶段,为项目的远程Git存储库进行更改。然后,使用MVN clean install命令构建项目,并从pom.xml读取Maven版本。在镜像阶段,从发现服务Dockerfile中构建Docker镜像,然后将该镜像推送到本地注册表。在第4步中,运行构建的镜像,默认端口是公开的,主机名对linked docker容器可见。最后,帐户管道开始时没有等待选项,这意味着源管道已经完成,并且不必等待帐户管道执行结束。
node {
withMaven(maven:'maven') {
stage('Checkout') {
git url: 'https://github.com/piomin/sample-spring-microservices.git', credentialsId: 'github-piomin', branch: 'master'
}
stage('Build') {
sh 'mvn clean install'
def pom = readMavenPom file:'pom.xml'
print pom.version
env.version = pom.version
}
stage('Image') {
dir ('discovery-service') {
def app = docker.build "localhost:5000/discovery-service:${env.version}"
app.push()
}
}
stage ('Run') {
docker.image("localhost:5000/discovery-service:${env.version}").run('-p 8761:8761 -h discovery --name discovery')
}
stage ('Final') {
build job: 'account-service-pipeline', wait: false
}
}
}
(向下向右滑动)
帐户管道非常类似。主要的区别是在第四个阶段,帐户服务容器与发现容器相关联。我们需要将这些容器链接起来,因为account服务在发现服务器中注册,并且必须能够使用主机名连接。
node {
withMaven(maven:'maven') {
stage('Checkout') {
git url: 'https://github.com/piomin/sample-spring-microservices.git', credentialsId: 'github-piomin', branch: 'master'
}
stage('Build') {
sh 'mvn clean install'
def pom = readMavenPom file:'pom.xml'
print pom.version
env.version = pom.version
}
stage('Image') {
dir ('account-service') {
def app = docker.build "localhost:5000/account-service:${env.version}"
app.push()
}
}
stage ('Run') {
docker.image("localhost:5000/account-service:${env.version}").run('-p 2222:2222 -h account --name account --link discovery')
}
stage ('Final') {
build job: 'customer-service-pipeline', wait: false
}
}
}
docker run -d --name registry -p 5000:5000 registry
测试
应该启动“发现-服务”管道的构建。这条管道不仅将为发现服务运行构建,而且还将在最后调用下一个管道构建(account-service-pipeline)。
同样的规则被配置为account-service-pipeline,它是调用服务管道和客户服务管道(callgateway-service-pipeline)。
因此,在所有管道完成之后,可以通过调用docker ps命令来检查运行docker容器的列表。你应该已经看到了五个容器:本地注册表和四个微服务。
还可以通过运行命令docker logs(例如dockerlogs帐户)来检查每个容器的日志。 如果一切正常,您应该可以调用服务,如http://localhost:2222/accounts or via the Zuul gateway http://localhost:8765/account/account.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fa3b9e408bb4 localhost:5000/gateway-service:1.0-SNAPSHOT "java -jar /gatewa..." About an hour ago Up About an hour 0.0.0.0:8765->8765/tcp gateway
cc9e2b44fe44 localhost:5000/customer-service:1.0-SNAPSHOT "java -jar /custom..." About an hour ago Up About an hour 0.0.0.0:3333->3333/tcp customer
49657f4531de localhost:5000/account-service:1.0-SNAPSHOT "java -jar /accoun..." About an hour ago Up About an hour 0.0.0.0:2222->2222/tcp account
fe07b8dfe96c localhost:5000/discovery-service:1.0-SNAPSHOT "java -jar /discov..." About an hour ago Up About an hour 0.0.0.0:8761->8761/tcp discovery
f9a7691ddbba registry "/entrypoint.sh /e..." About an hour ago Up About an hour 0.0.0.0:5000->5000/tcp registry
小结
上面介绍了使用Docker和Jenkins进行微服务持续交付的基本示例。你可以很容易地发现提出的解决方案的局限性。例如,我们已经将Docker容器连接在一起,以便在它们之间进行通信,或者所有的工具和微服务都在同一台机器上运行。
对于更高级的示例,可以使用运行在不同机器或Docker容器上的Jenkins slaves,例如用于编排和集群的Kubernetes工具,或者用于模拟多台Docker机器的Docker-in-Docker容器。
2
学习5种微服务模式成为更出色的工程师
对于很多工程师来说,进入微服务领域是很困难的。99%的服务属于五类之一,通过这种方式划分责任考虑如何通过管道服务一起管理特性,就像在Unixshell脚本中一样。
所有的微服务有什么共同之处,域驱动设计之父Eric Evans将其定义为:“(服务)可以消费和生成消息。”
考虑到这一点,对于每个服务模式,会讨论产生或使用消息的类型。
这些消息可以再分为两类:事件和命令。
开始之前,因为上下文很重要,我首先从Matt Walters那里听说了这些微服务模式,它是libraryservicebus的创建者。Servicebus是一个名为NServiceBus的流行.Net库的节点改编,由Udi Dahan创建和推广。
通过Servicebus,可以轻松编写发送和监听命令,并使用AMQP作为通用语言发布和订阅事件,使用JSON有效负载。这意味着其他编程语言可以轻松实现相同的接口,并能够无缝地参与由多种语言编写的部件组成的系统。
不再赘述,5个微服务模式。
1.模型服务(Model Services)
如果想到MVC,那么可以使用这种类型的服务。模型服务是模型应该存在的地方。边界通常是在聚合或实体层面进行,具体取决于域的复杂性。
模型服务使用与上下文相关的消息。例如,如果有一个库存服务,与消耗相关的命令消息将是inventory.product.create或inventory.product.increaseStock。作为响应,你希望生成一些事件消息,以便系统的其余部分能够了解模型是如何变化的,并响应这些更改。本例中生成的事件消息将是inventory.product.created和inventory.product.stockLevelIncreased。
2. Denormalizer服务
除了分布式系统之外,Denormalizer正是关系数据库所做的事情。它们将多个规范化的输入源合并到一个可读的数据结构中,客户端可以使用这些数据结构。
例如,假设一个电商应用。当库存水平增加或减少,或在库存中可用时,应用程序应该知道它。
想象一下,如果你是应用工程师,他们使用的是与MongoDB类似的东西——他们只是从外部系统获得了实时的库存,而无需编写一行代码。这也适用于RethinkDB和GraphQL订阅!
如果团队需要在Kafka中为大数据提供数据,只需添加一个Kafka的denormalizer服务。
3.网关服务
网关服务非常类似于Denormalizers。但是,它不是连接到数据库,而是与API连接。
最近在和一个叫LiftIgniter的推荐引擎合作,库存需要同步。该服务订阅inventory.product.updated 和inventory.product.added 事件,并将格式化数据发布到适当的端点。
后来,又增加了一项服务,监听相同的事件,并通过建立Magento网关服务,保持更新库存的水平。
4.Ingestor服务
到目前为止,我们讨论的都是通过系统传播的数据,或者在模型服务中创建的数据。但是,经常需要将外部数据输入到系统中。从概念上讲,来自外部源的数据需要被输入到系统其它部分所讲的通用语言中。
Ingestor服务通常只会产生信息。这些服务通常包括通过HTTP接收API POST,或者运行CRON作业,并在一个时间间隔内抓取。获取或接收的数据随后使用通用语言(AMQP w/ JSON)发布到系统中。
5.适配器服务
适配器服务是更少见,但值得一提。与网关服务类似,适配器使用消息,使用该数据来调用系统上的库。这个例子是使用ImageMagick这样的图形处理工具。ImageMagick是一个强大的工具,但是没有Node.js绑定。适配器服务通过执行子进程来解决这个问题,然后以系统的通用语言生成消息。
API服务
API服务应该保持轻量级。如果您正在将一大堆业务逻辑构建到API中,那么正在构建一个庞然大物。 它比我们用“n层”架构看到的应用程序和服务器的组合稍好一些,但最终导致臭名昭著的“大泥球”。
要实现这一点,可以使用上面的 Denormalizer 服务,将数据的查询效率视图映射到API读取的数据库中。这就产生了一个单向的数据流。
Unidirectional Systems
使用上述模式可以让企业在单向工作流中使用不可变事件。如果你已经进入应用程序开发,肯定熟悉Redux如何改变了状态管理的游戏。有一个存储在组件树下的状态可以轻松地解释操作如何影响状态,因为它们是所有发生在集中位置的简单的不可变事实。
如果遵循上述模式,将使用更复杂的称为命令查询责任隔离(Command Query Responsibility Segregation ,CQRS)的方法。命令是由模型服务消费的,而事件的生成则是由Denormalizer或网关服务所消耗的。然后对读模型进行查询。
因为使用的是不可变消息,这使得事件采购成为构建模型服务的完美模式。值得一提的是Matt Walters的另一个创造,一个名为[sourced]的微观框架,与servicebus完美协调,可以轻松添加事件采购功能来消费服务的事件,并持久存储到数据库中。
原文链接:
1、Microservices With Continuous DeliveryUsing Docker and Jenkins
https://dzone.com/articles/microservices-continuous-delivery-with-docker-and
2、Learningthese 5 microservice patterns will make you a better engineer
https://hackernoon.com/learning-these-5-microservice-patterns-will-make-you-a-better-engineer-52fc779c470a
推荐活动:
数人云联合ServiceComb、ServiceMesh社区举办的 Building Microservice Meetup系列活动第2站--3月31日,北京站开始报名啦!本期主题为《微服务,从架构到发布》依旧大咖汇集,点击最下方的“阅读原文”快来报名~
相关阅读:
添加小数微信:xiaoshu062
备注公司、姓名、职位
小数将拉您进入相应技术群
以上是关于天啦噜!看国外大神如何用Docker+Jenkins&CI/CD打造微服务架构?的主要内容,如果未能解决你的问题,请参考以下文章