關(guān)于SpringBoot微服務(wù)發(fā)布與部署的三種方式
SpringBoot 微服務(wù)部署流程
基于 SpringBoot 的微服務(wù)開發(fā)完成之后,現(xiàn)在到了把它們發(fā)布并部署到相應(yīng)的環(huán)境去運(yùn)行的時(shí)候了。
SpringBoot 框架只提供了一套基于可執(zhí)行 jar 包(executable jar)格式的標(biāo)準(zhǔn)發(fā)布形式,但并沒有對(duì)部署做過多的界定,而且為了簡(jiǎn)化可執(zhí)行 jar 包的生成,SpringBoot 提供了相應(yīng)的 Maven 項(xiàng)目插件:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!-- 其他插件定義 --> </plugins> </build>
然后只要我們運(yùn)行 mvn package,當(dāng)前 SpringBoot 項(xiàng)目就會(huì)被打包成一個(gè)包含了其所有項(xiàng)目依賴以及該項(xiàng)目本身的可執(zhí)行 jar 包,通過 scp 或者 rsync 等方式將這個(gè)可執(zhí)行 jar 包部署到目標(biāo)環(huán)境的服務(wù)器之后,就可以通過 java-jar your-project.jar 啟動(dòng) SpringBoot 應(yīng)用了。
整個(gè)流程看起來(lái)很簡(jiǎn)單,也很符合大部分開發(fā)人員的認(rèn)知,但是,相對(duì)于一套較為嚴(yán)謹(jǐn)?shù)能浖桓读鞒虂?lái)說(shuō),以上流程則難免過于粗糙了。
軟件的發(fā)布和部署可以有多種不同的形式,這更多由軟件項(xiàng)目的屬性決定,比如:
- 這個(gè)項(xiàng)目使用的是什么語(yǔ)言?
- 這個(gè)項(xiàng)目屬于類庫(kù)項(xiàng)目還是可獨(dú)立運(yùn)行的項(xiàng)目?
- 這個(gè)項(xiàng)目是面向什么平臺(tái)和環(huán)境的項(xiàng)目?
此外,我們希望使用什么樣的形式進(jìn)行軟件的交付,這里則涉及生態(tài)管理以及技術(shù)選型的喜好等因素,所以,為了降低講解的復(fù)雜度,我們還是先將發(fā)布和部署分開來(lái)說(shuō)吧。
首先,大家應(yīng)該都知道,發(fā)布并不等于部署,這是兩個(gè)階段的事情,如圖 1 所示。
圖 1 發(fā)布與部署示意圖
發(fā)布一般是將項(xiàng)目以指定的格式打包成某種可直接交付的形式,然后放置到預(yù)先指定的交付地點(diǎn)。
比如對(duì)于 Java 類庫(kù)(Java Library)來(lái)說(shuō),我們一般將其打包成 jar 包,然后 mvn deploy 到公司內(nèi)部的 Maven 倉(cāng)庫(kù)中(Maven Repository),像 Nexus Repository Manager 或者 JFrog Artifactory 以及 Apache Archiva。
而對(duì)于可獨(dú)立運(yùn)行的程序,比如 SpringBoot 微服務(wù)或者一般的 Java Standalone 程序,我們既可以將它們打包成 RPM、DEB 等面向特定目標(biāo)系統(tǒng)的發(fā)布形式,也可以將它們制作成一個(gè)個(gè)的 docker images,然后將制作完成的發(fā)布成品存儲(chǔ)到相應(yīng)的倉(cāng)庫(kù)中(Repository)去。
部署一般緊接著發(fā)布完成之后進(jìn)行,它的主要職能就是將已經(jīng)發(fā)布好的成品從倉(cāng)庫(kù)中拿出來(lái),然后分發(fā)到目標(biāo)環(huán)境的指定資源池(比如物理機(jī)結(jié)點(diǎn),虛擬機(jī)結(jié)點(diǎn),docker 宿主機(jī)等),并最終啟動(dòng)服務(wù)。
軟件成品分發(fā)的手段和工具可以有很多種,從最常見的 scp、rsync,到 Chef、Puppet,進(jìn)而再到最新的 saltstack、ansible 等,一般根據(jù)團(tuán)隊(duì)對(duì)這些工具的把控力度和喜好進(jìn)行選型。
下面我們就幾種典型的發(fā)布和部署形式跟大家一起探索相應(yīng)的實(shí)踐。
spring-boot-starter 的發(fā)布與部署方式
spring-boot-starter(s)屬于 Java 類庫(kù)性質(zhì)的組件,只被其他可獨(dú)立運(yùn)行的程序依賴使用,自身不可獨(dú)立運(yùn)行,對(duì)于這種性質(zhì)的軟件實(shí)體,我們一般將其發(fā)布到公司內(nèi)部的軟件倉(cāng)庫(kù)或者以開源形式發(fā)布到 Maven 的中央倉(cāng)庫(kù)(Maven Central Repository)。
下面我們就以 spring-boot-starter-metrics 為例,向大家展示如何將類似 spring-boot-starter-metrics 這樣的 Java 類庫(kù)發(fā)布到自己公司內(nèi)部搭建的 Nexus 服務(wù)器上。
首先,你要有一套已經(jīng)搭建完成并運(yùn)行的 Nexus 服務(wù)器,然后我們需要對(duì) spring-boot-starter-metrics 的 pom.xml 附加一點(diǎn)兒發(fā)布相關(guān)的內(nèi)容:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.keevol</groupId> <artifactId>spring-boot-starter-metrics</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>spring-boot-starter-metrics</name> <description>auto configuration module for dropwizard metrics</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.0.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <distributionManagement> <repository> <id>deployment</id> <name>internal repository for releases</name> <url>http://{內(nèi)部nexus服務(wù)器地址}/nexus/content/repositories/ releases/</url> </repository> <snapshotRepository> <id>deployment</id> <name>internal repository for snapshots</name> <url>http://{內(nèi)部nexus服務(wù)器地址}/nexus/content/repositories/ snapshots/</url> </snapshotRepository> </distributionManagement> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> <metrics.version>3.1.2</metrics.version> </properties> <!--其他配置 --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>io.dropwizard.metrics</groupId> <artifactId>metrics-core</artifactId> <version>${metrics.version}</version> </dependency> <dependency> <groupId>io.dropwizard.metrics</groupId> <artifactId>metrics-annotation</artifactId> <version>${metrics.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.7</version> </dependency> </dependencies> </project>
主要關(guān)注我們添加的 distributionManagement 相關(guān)內(nèi)容,用于將我們的當(dāng)前項(xiàng)目與內(nèi)部的 Nexus 服務(wù)器進(jìn)行關(guān)聯(lián),這樣,就可以將當(dāng)前項(xiàng)目不同階段的成品(比如 SNAPSHOT 版本或者 RELEASE 版本)發(fā)布到特定的倉(cāng)庫(kù)路徑下。
但是,只是在項(xiàng)目的 pom.xml 中添加 distributionManagement 相關(guān)內(nèi)容還不夠,對(duì)發(fā)布服務(wù)器的安全管控等敏感信息不能與 pom.xml 一同公開,所以,還需要在 ~/.m2/settings.xml 配置文件中添加 Nexus 服務(wù)器訪問和認(rèn)證信息:
<server> <id>deployment</id> <username>deployment</username> <password>********</password> </server>
因?yàn)槲覀兦懊?distributionManagement 定義的 repository 和 snapshotRepository 的 id 都是 deployment,所以,這里的 server 的 id 也是匹配性地指定為 deployment,至于 username 和 password,則完全是我們內(nèi)部的 nexus 服務(wù)器對(duì)應(yīng)的安全認(rèn)證用的用戶名和密碼啦。
將內(nèi)部 Nexus 服務(wù)器的認(rèn)證信息放到 maven 的 settings.xml 中并非什么好的實(shí)踐,純粹是為了便利性而犧牲安全性,二者之間需要根據(jù)情況做出權(quán)衡,如果對(duì)安全性要求比較高的公司或者組織,最好將這些認(rèn)證信息移除,并只在管控的范圍內(nèi)使用。
比如將這些認(rèn)證信息回收到發(fā)布和部署平臺(tái)這一可控的小范圍環(huán)境中,而所有開發(fā)人員使用的 settings.xml 屬于“消毒”后無(wú)安全認(rèn)證等敏感信息的版本。
當(dāng) pom.xml 中的 distributionManagement 以及 settings.xml 中對(duì)應(yīng)的 server 設(shè)定都準(zhǔn)備好之后,我們就可以直接 mvn deploy 將 spring-boot-starter-metrics 或者類似的 Java Library 項(xiàng)目發(fā)布到內(nèi)部 Nexus 倉(cāng)庫(kù)了。
對(duì)于 Java 類庫(kù)類型的項(xiàng)目來(lái)說(shuō),并無(wú)明確的部署過程,如果說(shuō)有,也是存在于可獨(dú)立運(yùn)行項(xiàng)目的開發(fā)過程中,比如使用 lib 目錄或者結(jié)合 Ant“部署”為項(xiàng)目的依賴,或者直接享受 maven、gradle、sbt 等編譯工具提供的“透明”的依賴部署過程。
基于RPM的發(fā)布與部署方式
部署的目標(biāo)服務(wù)器從硬件到系統(tǒng)軟件,一般情況下都應(yīng)該是盡量相同,這與軟件的標(biāo)準(zhǔn)化目的相同,一個(gè)是可以減少應(yīng)對(duì)不同類型實(shí)體的復(fù)雜度,另一個(gè)就是標(biāo)準(zhǔn)化硬件和軟件之后,就可以通過工具批量化以“邊際成本遞減”近乎為 0 的做法來(lái)提升效率,減少成本。
所以,對(duì)于大部分互聯(lián)網(wǎng)公司來(lái)說(shuō),在硬件標(biāo)準(zhǔn)化的基礎(chǔ)上,還會(huì)使操作系統(tǒng)盡量統(tǒng)一,比如大多數(shù)都是使用穩(wěn)定性和可靠性經(jīng)過長(zhǎng)期驗(yàn)證過的 Red Hat CentOS 系統(tǒng),而 CentOS 本身經(jīng)過長(zhǎng)期的沉淀也有一套自己的系統(tǒng)管理工具,比如像 YUM 或者 RPM 這樣的系統(tǒng)包依賴管理器(Debian/Ubuntu 等 Linux 發(fā)行版也有對(duì)應(yīng)的 deb 形式的包管理器)。
像 RPM 這樣的包管理器對(duì)系統(tǒng)軟件包的依賴和配置提供了很好的支持,如果我們的微服務(wù)等可獨(dú)立執(zhí)行實(shí)體要部署到像 CentOS 這樣的目標(biāo)環(huán)境中,使用 RPM 完成微服務(wù)的發(fā)布和部署,對(duì)于運(yùn)維人員來(lái)說(shuō)幾乎就是無(wú)縫銜接的。
而且,對(duì)于 SpringBoot 微服務(wù)來(lái)說(shuō),單單一個(gè)可執(zhí)行的 jar 包實(shí)際上是遠(yuǎn)遠(yuǎn)無(wú)法達(dá)到發(fā)布和部署要求的,如果只是發(fā)布一個(gè)可執(zhí)行的 jar 包,那就意味著在部署階段,運(yùn)維要做更多的事情來(lái)彌補(bǔ)某些缺失,比如:
- 啟動(dòng)參數(shù)是否調(diào)整?
- 配置文件是否修改?
- 安裝部署結(jié)構(gòu)如何規(guī)范?
- 資源的對(duì)接和映射要不要做?
但是,如果我們能夠?qū)⒄麄€(gè)軟件交付體系標(biāo)準(zhǔn)化和規(guī)范化,然后通過 RPM 這樣的發(fā)布形式將這些標(biāo)注和規(guī)范固化到發(fā)布包中,那么,整個(gè)部署過程就可以簡(jiǎn)化為一條命令,這其實(shí)也是使用 RPM 這種系統(tǒng)原生包管理工具完成交付部署的好處:自動(dòng)化的 orcherstration,減少不必要的人工干預(yù)中間環(huán)節(jié)。
使用 RPM 發(fā)布 SpringBoot 微服務(wù),我們簡(jiǎn)單將這一個(gè)過程劃分為幾步,如圖 2 所示。
圖 2 使用 RPM 交付的 SpringBoot 微服務(wù)發(fā)布流程圖
首先,我們需要有一個(gè)特定的編譯和項(xiàng)目構(gòu)建環(huán)境,可以不管這個(gè)編譯和項(xiàng)目構(gòu)建環(huán)境是搭建在本地(比如你的開發(fā)機(jī)上),還是搭建在特定的一臺(tái)服務(wù)器上,但這個(gè)編譯和項(xiàng)目構(gòu)建環(huán)境需要安裝 rpmbuild,用來(lái)構(gòu)建 rpm 包。
其次,我們不推薦 RPM 編譯和構(gòu)建的過程使用某些定義在項(xiàng)目編譯腳本中的插件來(lái)完成,這樣會(huì)讓一些通用的邏輯散落在所有需要發(fā)布的項(xiàng)目中而不好治理。所以,我們建議使用一個(gè)外部化的獨(dú)立的編譯服務(wù)器完成整個(gè) SpringBoot 微服務(wù)的 RPM 發(fā)布和部署。
SpringBoot 微服務(wù)的 rpmbuild 腳本構(gòu)建過程主要分幾個(gè)主要步驟(如圖 2 中 1 所標(biāo)注):
1)調(diào)用標(biāo)準(zhǔn)的 mvn package 完成可執(zhí)行 jar 包的打包。
2)根據(jù)軟件交付規(guī)范,構(gòu)建標(biāo)準(zhǔn)發(fā)布格式的 rpm 包,如下所示:
- 使用 bin 目錄存放根據(jù)腳本模板以及環(huán)境變量生成的啟停腳本。
- 使用 config 目錄(SpringBoot 默認(rèn)文件系統(tǒng)中的配置目錄名)或者 conf 目錄存放特定的配置文件。
- 使用 docs 目錄存放文檔。
- 使用 agents 目錄存放某些 javaagent。
- ……
3)在標(biāo)準(zhǔn)發(fā)布格式的基礎(chǔ)上,生成從標(biāo)準(zhǔn)發(fā)布格式到具體目標(biāo)環(huán)境的映射。
比如原來(lái)應(yīng)用的日志是默認(rèn)打印到當(dāng)前項(xiàng)目部署目錄,而根據(jù)要求,我們希望打印到 /var/logs/{projectId}/ 或者其他服務(wù)器磁盤容量分配更大的分區(qū),這個(gè)時(shí)候,可以在 rpmbuild 過程中指定安裝類似的安裝規(guī)則。
下面是一個(gè)簡(jiǎn)化的 SpringBoot 微服務(wù)的 rpmbuild 腳本定義:
Summary: metrics autoconfigure module for spring boot applicationName: spring-boot-starter-metricsVersion: {version}Release: 1Copyright: ...Group: Applications/ProductivitySource: ...URL: ...Distribution: Vendor: KEEp eVOLution, Inc.Packager: Darren <afoo@keevol.com>%description%prep%buildgit clone .... # 檢出代碼到本地cd {project folder}mvn package ...%install%clean%files/{install_location}/{projectId}/bin/start.sh/{install_location} /{projectId}/bin/stop.sh/{install_location}/{projectId}/agents/jolokia-jvm-1.3.1-agent.jar...%attr(755, user, group) /{install_location}/{projectId}/agents/jolokia-jvm-1.3.1-agent.jar...%doc%changelog
然后需要調(diào)用 rpmbuild 的 spec 定義完成最終 rpm 包的構(gòu)建:
rpmbuild -bb {projectId}.spec#
然后 scp or sftp 生成的 rpm 包到指定的 rpm 倉(cāng)庫(kù) 我們可以像上面那樣直接執(zhí)行 rpmbuild 命令完成最終的 rpm 包構(gòu)建,也可以將這些邏輯納入編譯構(gòu)建腳本并部署到像 Jenkins 這樣現(xiàn)成的持續(xù)集成服務(wù)器上,總之,執(zhí)行完成后,打包好的 rpm 就發(fā)布到目標(biāo)環(huán)境對(duì)應(yīng)的 rpm 倉(cāng)庫(kù)了。
rpm 包發(fā)布到 rpm 倉(cāng)庫(kù)之后,就可以執(zhí)行部署,比如通過 Salt 或者 ansible 在目標(biāo)環(huán)境執(zhí)行 rpm 或者 yum 命令,但具體的部署行為可能因?yàn)椴煌_發(fā)者的習(xí)慣和理念而有所不同。
有的開發(fā)者喜歡將不同目標(biāo)環(huán)境的配置都一股腦地打包到發(fā)布包中,然后通過配置文件的命名和啟動(dòng)程序時(shí)單獨(dú)指定一個(gè)環(huán)境變量來(lái)決定如何啟用哪一個(gè)配置文件,對(duì)于這種做法,只需要打一個(gè) rpm 包,同時(shí)也只需要搭建一個(gè)內(nèi)部的 rpm 倉(cāng)庫(kù),部署的時(shí)候,則需要運(yùn)維人員根據(jù)具體的操作環(huán)境傳遞相應(yīng)的環(huán)境變量來(lái)啟停程序。
有的開發(fā)者則認(rèn)為,一個(gè)軟件實(shí)體發(fā)布的時(shí)候就應(yīng)該是針對(duì)目標(biāo)環(huán)境“裝配”完備的,rpm 包中的各項(xiàng)配置都是針對(duì)特定目標(biāo)環(huán)境配置好的,只要將 rpm 包部署到目標(biāo)環(huán)境,就可以直接啟動(dòng),啟停完全無(wú)差別操作,唯一的差別是,rpm 包分別是根據(jù)目標(biāo)環(huán)境發(fā)布和部署到不同的 rpm 倉(cāng)庫(kù)的,如圖 3 所示。
圖 3 “根據(jù)不同交付目標(biāo)環(huán)境,設(shè)置不同RPM倉(cāng)庫(kù)作為交付地點(diǎn)”示意圖
以上兩種策略并無(wú)優(yōu)劣之分,但卻有各自適合的場(chǎng)景:
1)在團(tuán)隊(duì)小,以人為本的時(shí)候,前者更適合,原因在于,整個(gè)軟件交付鏈路更多是通過開發(fā)人員來(lái)協(xié)調(diào)和完成的。所以,開發(fā)、測(cè)試、運(yùn)維一把抓,即使是不同環(huán)境的配置文件,也都是為了開發(fā)人員方便,直接放到了項(xiàng)目目錄下一起管理和修改。
當(dāng)?shù)搅司€上,開發(fā)人員同時(shí)擔(dān)當(dāng)運(yùn)維人員的角色,啟停程序的可控性也很高,所以,可以在熟知自身程序的前提下,很好地完成整個(gè)鏈路的工作。
2)隨著團(tuán)隊(duì)規(guī)模的擴(kuò)張,職能更加明確,交付鏈路要承擔(dān)的關(guān)注點(diǎn)也更多的時(shí)候,為了保證整個(gè)軟件的交付質(zhì)量,需要引入規(guī)范化的流程來(lái)關(guān)聯(lián)和約束整個(gè)鏈路上各個(gè)環(huán)節(jié)和團(tuán)隊(duì)之間的工作。
這個(gè)時(shí)候,開發(fā)人員的職責(zé)范圍將縮小到明確的范圍,測(cè)試團(tuán)隊(duì)、安全團(tuán)隊(duì)、應(yīng)用運(yùn)維團(tuán)隊(duì)等也將加入并根據(jù)流程各司其職,每個(gè)團(tuán)隊(duì)之間的工作需要橫向關(guān)聯(lián)的同時(shí),又需要垂直隔離。
這個(gè)時(shí)候,我們就需要從交付的源頭一直到發(fā)布和部署,根據(jù)環(huán)境進(jìn)行隔離,每個(gè)人即使只關(guān)注自己負(fù)責(zé)的事情,也可以讓整個(gè)軟件交付鏈路很好地工作,這考慮的是規(guī)范和流程對(duì)整體粒度上的把控和支撐。
對(duì)于小團(tuán)隊(duì)來(lái)說(shuō),微服務(wù)并不是什么太好的選擇,高內(nèi)聚的應(yīng)用開發(fā)和部署單元,對(duì)整個(gè)交付鏈路的要求沒那么高,也不需要更多自動(dòng)化和平臺(tái)化層面的投入和支持。
而一旦你選擇了微服務(wù)的軟件交付策略,數(shù)量龐大的微服務(wù)治理將耗費(fèi)更多資源在支撐整個(gè)交付鏈路的自動(dòng)化和平臺(tái)化建設(shè)層面。否則,如此數(shù)量上的差異化的實(shí)體管理,單純還靠人工拼苦勞是“撈不著好果子吃的”。
所以,我們要標(biāo)準(zhǔn)化和規(guī)范化微服務(wù)的開發(fā)、交付、部署以及運(yùn)維,從而收斂整條鏈路的治理復(fù)雜度,以近乎無(wú)差別的方式,完成各個(gè)環(huán)節(jié)上的工作。這個(gè)時(shí)候,規(guī)范、流程、平臺(tái)是核心,對(duì)人的要求則適當(dāng)降低。
說(shuō)了這么多,其實(shí)就一點(diǎn),如果團(tuán)隊(duì)要轉(zhuǎn)向微服務(wù)的交付策略,那么,標(biāo)準(zhǔn)化、單一化的微服務(wù)發(fā)布和部署行為是大家努力的方向,雖然我們?cè)谡f(shuō)基于 RPM 這種特定的微服務(wù)發(fā)布和部署形式,但并不意味著我們只應(yīng)該關(guān)注這一點(diǎn)或者這單一環(huán)節(jié),只有系統(tǒng)的從整體的微服務(wù)交付鏈路和體系層面考慮,才能夠在各個(gè)單一環(huán)節(jié)落地的時(shí)候選擇合適的方案。
基于 RPM 的發(fā)布與部署方式就說(shuō)這么多,希望對(duì)大家有所啟發(fā)。
基于 Docker 的發(fā)布與部署方式
隨著資源虛擬化技術(shù)的持續(xù)精進(jìn),一種基于容器(container)的方式開始風(fēng)行,Docker 就屬于當(dāng)下這個(gè)風(fēng)口上最耀眼的明星,而且,很多微服務(wù)相關(guān)的文章也是言必提 Docker,好像沒有 Docker 的微服務(wù)就不是正宗的微服務(wù)了,所以,我們自然也要適當(dāng)提及一下如何結(jié)合 Docker 發(fā)布和部署我們的 SpringBoot 微服務(wù)。
我們知道,RPM 包的構(gòu)建是使用系統(tǒng)的 rpmbuild 工具完成的,該工具需要一個(gè)構(gòu)建描述文件,即 .spec 文件,rpmbuild 工具讀取 .spec 構(gòu)建描述文件之后,根據(jù)構(gòu)建描述文件生成一個(gè) rpm 包,然后我們就可以把 rpm 包發(fā)布到相應(yīng)的 RPM 倉(cāng)庫(kù)(RPM Repository)。
使用 Docker 其實(shí)也是類似的過程,如圖 4 所示。
圖 4 基于Docker的SpringBoot微服務(wù)發(fā)布流程圖
我們需要提供一個(gè) Dockerfile 用于描述 Docker 發(fā)布成品的構(gòu)建過程,這類似于 rpmbuild 需要的 .spec 文件。
在編寫好要使用的 Dockerfile 之后,我們使用 docker build 命令讀取 Dockerfile 開始構(gòu)建一個(gè) Docker 的 image,docker build 完成 rpmbuild 類似的功能,Docker 的 image 則類似于 rpm 包,即 Docker 的軟件發(fā)布成品。
有了 docker image 之后,我們就可以將其發(fā)布到一個(gè) Docker 的 image registry,這里的 image registry 就類似于 RPM 倉(cāng)庫(kù)(RPM Repository),而將 docker image 發(fā)布到 image registry 的過程,可以通過 docker push 完成。
所以,假設(shè)要以 Docker 的形式發(fā)布我們的匯率查詢 SpringBoot 微服務(wù),首先需要編寫一個(gè)對(duì)應(yīng)的 Dockerfile 來(lái)構(gòu)建相應(yīng)的 docker image:
FROM java:8MAINTAINER AFOO <afoo@afoo.me>LABEL groupId=...LABEL artifactId=...LABEL version=...LABEL ...USER deployerEXPOSE 8080ENV {key}={value}...VOLUME ...RUN mkdir /{group}/{projectId}/configRUN mkdir /{group}/{projectId}/agentRUN mkdir /{group}/{projectId}/docsRUN mkdir /{group}/{projectId}/libCOPY target/docker-springboot-chapter4-0.0.1-SNAPSHOT.jar /{group}/{projectId}/lib/docker-springboot-chapter4-0.0.1-SNAPSHOT.jarCOPY conf/application.properties /{group}/{projectId}/config/application.propertiesCOPY agent/jolokia-jvm-1.3.3-agent.jar /{group}/{projectId}/jolokia-jvm-1.3.3-agent.jar...ENTRYPOINT ["java", "...", "-jar", "lib/docker-springboot-chapter4-0.0.1-SNAPSHOT.jar"]
之后,我們就可以使用這個(gè) dockerfile 來(lái)進(jìn)行構(gòu)建并發(fā)布了:
$ docker build . -t "{groupId}/{artifactId}:{version}
$ docker push 基于 Docker 的微服務(wù)部署與 RPM 類似,都是從發(fā)布倉(cāng)庫(kù)中拉取發(fā)布的成品,并在目標(biāo)環(huán)境安裝部署,一般情況下我們也同樣是使用 Salt 或者 Ansible 之類的工具執(zhí)行如下類似的命令完成基于 Docker 的微服務(wù)的部署:
$ ansible {cluster} -m shell -a "cd /microservices/{groupId}/{artifactId}; docker pull"
為了簡(jiǎn)化基于 Docker 的發(fā)布和部署流程,實(shí)際上,以上演示的只是單人單微服務(wù)項(xiàng)目的方法,在講究集團(tuán)軍作戰(zhàn)的微服務(wù)場(chǎng)景下,我們希望的是能夠快速、批量且標(biāo)準(zhǔn)化的形式完成數(shù)量巨大的微服務(wù)發(fā)布和部署。
這就要求不能只盯著單一項(xiàng)目?jī)?nèi)部去思考如何實(shí)現(xiàn)發(fā)布和部署,而應(yīng)該將視線從單一項(xiàng)目?jī)?nèi)部抽取出來(lái),以更高的視角來(lái)審視如何快速地完成批量微服務(wù)的發(fā)布和部署。
筆者建議的一個(gè)思路是適當(dāng)?shù)厝趸?Docker 屬性,將發(fā)布和部署邏輯外部化到發(fā)布腳本中。
外部化后的發(fā)布腳本將集中協(xié)調(diào) Docker 基礎(chǔ)設(shè)施,要發(fā)布的微服務(wù)上下文信息以及其他中間步驟,將微服務(wù)項(xiàng)目與 Docker 掛鉤的唯一紐帶也僅僅是一個(gè)模板化、標(biāo)注化后的 Dockerfile,整個(gè)過程如圖 5 所示。
圖 5 外部化的基于Docker的SpringBoot微服務(wù)發(fā)布腳步邏輯流程圖
如此一來(lái),對(duì)于所有希望以 Docker 形式發(fā)布的標(biāo)準(zhǔn)化的微服務(wù)來(lái)說(shuō),一套發(fā)布腳本即可完成所有微服務(wù)的發(fā)布和部署,而不需要每一個(gè)微服務(wù)自己去編寫 Dockerfile 甚至發(fā)布腳本。
上面的 Docker 實(shí)踐并非 Docker 社區(qū)建議的最佳實(shí)踐方式,這里更多只是為了簡(jiǎn)化說(shuō)明和對(duì)比,Docker 背后是一套更為龐大完備的體系,比如 Docker 容器的注冊(cè)和發(fā)現(xiàn),容器的編排及調(diào)度等功能和系統(tǒng),限于篇幅和內(nèi)容定位,這里不再贅述。
總的來(lái)說(shuō),其實(shí)基于 Docker 的微服務(wù)發(fā)布和部署與其他形式從本質(zhì)上來(lái)說(shuō)沒有太大差別,唯一的差別只是各自方案特定的實(shí)現(xiàn)不同而已。
大部分人選擇和認(rèn)同 Docker 方案,更多是從系統(tǒng)資源利用率以及 Docker 對(duì)整個(gè)軟件交付鏈路的支撐體系比較完備這些角度考慮的,而微服務(wù)自身的很多特點(diǎn)以及需求(比如隔離、輕量),恰好與 Docker 能提供的相互吻合,或許這就是二者經(jīng)常被“相提并論”的原因。
不過,對(duì)于 Java 應(yīng)用和微服務(wù)來(lái)說(shuō),Docker 能給予的好處可能沒有想象的那么多。
到此這篇關(guān)于關(guān)于SpringBoot微服務(wù)發(fā)布與部署的三種方式的文章就介紹到這了,更多相關(guān)SpringBoot微服務(wù)發(fā)布與部署內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中ArrayList具體實(shí)現(xiàn)之簡(jiǎn)單的洗牌算法
這篇文章主要給大家介紹了Java中ArrayList具體實(shí)現(xiàn)之簡(jiǎn)單的洗牌算法,文中通過代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-12-12詳解Spring Cloud Finchley版中Consul多實(shí)例注冊(cè)的問題處理
這篇文章主要介紹了詳解Spring Cloud Finchley版中Consul多實(shí)例注冊(cè)的問題處理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2018-08-08Sleuth(Micrometer)+ZipKin分布式鏈路問題小結(jié)
在微服務(wù)架構(gòu)中,分布式鏈路追蹤技術(shù)成為了解決系統(tǒng)復(fù)雜調(diào)用問題的關(guān)鍵,本文介紹了其他鏈路追蹤方案,如Cat、Pinpoint和Skywalking,展示了分布式鏈路追蹤技術(shù)的多樣化,感興趣的朋友一起看看吧2024-10-10Java判斷一個(gè)時(shí)間是否在當(dāng)前時(shí)間區(qū)間代碼示例
這篇文章主要給大家介紹了關(guān)于使用Java判斷一個(gè)時(shí)間是否在當(dāng)前時(shí)間區(qū)間的相關(guān)資料,在日常開發(fā)中我們經(jīng)常會(huì)涉及到時(shí)間的大小比較或者是判斷某個(gè)時(shí)間是否在某個(gè)時(shí)間段內(nèi),需要的朋友可以參考下2023-07-07