當前位置:
首頁 > 最新 > 天啦嚕!看國外大神如何用Docker+Jenkins&CI/CD打造微服務架構?

天啦嚕!看國外大神如何用Docker+Jenkins&CI/CD打造微服務架構?

導讀:

Docker、微服務、持續交付是目前編程領域中最受歡迎的話題。在由幾十個相互通信的微服務組成的環境中,特別重要的是測試、構建和部署過程的自動化。Docker是一種極好的微服務解決方案,因為它可以創建和運行獨立的容器和服務。將Docker容器連接在一起,它們之間能夠通信,確保所有的工具和微服務都在同一台機器上運行。

1

今天,將介紹如何使用流行的軟體自動化工具:Jenkins,創建一個基本的持續交付管道,用於示例微服務。

微服務樣本

在討論本文主題之前,首先介紹一些用於微服務創建的架構和工具。此示例包含兩個微服務,它們彼此通信(account、customer)、發現伺服器(Eureka)和API網關(Zuul)。使用Spring Boot和Spring Cloud框架實現的。源代碼可以在GitHub上找到。Spring Cloud支持微服務服務發現和網關,只需要在maven項目配置文件(pom.xml)中定義正確的依賴關係。

下圖說明了所採用的解決方案架構。客戶、帳戶REST API服務、發現伺服器和網關都在獨立的Docker容器中運行。網關是微服務系統的入口。它與所有其他服務交互。將代理請求到所選的微服務在發現服務中搜索其地址。在存在多個帳戶或客戶微服務實例的情況下,該請求是用Ribbon和Feign客戶端進行負載平衡的。

帳戶和客戶服務在啟動後自己註冊到發現伺服器中。它們之間也有交互的可能——例如,如果想找到並返回所有客戶的帳戶細節。

一般來說,Spring框架對微服務提供了全面的支持,包括諸如Ribbon、Hystrix和Eureka等所有的Netflix OSS工具。本文描述了如何實現服務發現、分散式跟蹤、負載平衡、日誌跟蹤ID propagation,以及使用這些解決方案的微服務 API 網關。

Dockerfiles

示例源代碼中的每個服務都有一個Dockerfile和Docker映像構建定義。這是很簡單的。這裡是帳戶服務的Dockerfile。我們使用OpenJDK作為基本映像。將目標中的JAR文件添加到映像中,然後使用java -jar命令運行。服務在埠2222上運行,該埠暴露在外面。

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構建定義非常相似。

account-service

spring-boot-maven-plugin

1.5.2.RELEASE

pl.piomin.microservices.account.Application

true

repackage

(向下向右滑動)

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:$"

app.push()

}

}

stage ("Run") {

docker.image("localhost:5000/discovery-service:$").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:$"

app.push()

}

}

stage ("Run") {

docker.image("localhost:5000/account-service:$").run("-p 2222:2222 -h account --name account --link discovery")

}

stage ("Final") {

build job: "customer-service-pipeline", wait: false

}

}

}

類似的管道也為客戶和網關服務定義。它們在每個微服務的主項目目錄中作為Jenkinsfile可用。在pipeline執行過程中構建的每個鏡像都被推到本地Docker註冊表。在主機上啟用本地註冊表,需要拉取和運行Docker註冊表鏡像,並在拉取時使用該註冊中心地址作為鏡像名稱前綴。本地註冊表暴露在默認的5000埠上。本地註冊表顯示在其默認的5000埠上。 可以通過調用其REST API(例如http://localhost:5000 / v2 / _catalog)將推送的鏡像列表顯示到本地註冊表中。

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,那麼可以使用這種類型的服務。模型服務是模型應該存在的地方。邊界通常是在聚合或實體層面進行,具體取決於域的複雜性。

2. Denormalizer服務

除了分散式系統之外,Denormalizer正是關係資料庫所做的事情。它們將多個規範化的輸入源合併到一個可讀的數據結構中,客戶端可以使用這些數據結構。

例如,假設一個電商應用。當庫存水平增加或減少,或在庫存中可用時,應用程序應該知道它。

想像一下,如果你是應用工程師,他們使用的是與MongoDB類似的東西——他們只是從外部系統獲得了實時的庫存,而無需編寫一行代碼。這也適用於RethinkDB和GraphQL訂閱!

如果團隊需要在Kafka中為大數據提供數據,只需添加一個Kafka的denormalizer服務。

3.網關服務

網關服務非常類似於Denormalizers。但是,它不是連接到資料庫,而是與API連接。

後來,又增加了一項服務,監聽相同的事件,並通過建立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

推薦活動:


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 數人云 的精彩文章:

細數20年間開源帶給世界的那些改變,及5大開源趨勢預測

TAG:數人云 |