天啦嚕!看國外大神如何用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
推薦活動:
TAG:數人云 |