Spring Boot與Docker(三):構(gòu)建你的第一個(gè)微服務(wù)和相關(guān)容器以及容器的連接

本篇是《使用Spring Boot和Docker構(gòu)建微服務(wù)架構(gòu)》系列的第三篇,本篇我們將會(huì)準(zhǔn)備開(kāi)始構(gòu)建一個(gè)員工對(duì)象微服務(wù)。原文作者為3Pillar環(huán)球旗下美國(guó)Adbanced技術(shù)集團(tuán)的總監(jiān)Dan Greene,Dan有十八年的軟件設(shè)計(jì)和開(kāi)發(fā)經(jīng)驗(yàn),包括在電子商務(wù)、B2B集成、空間分析、SOA架構(gòu)、大數(shù)據(jù)以及云計(jì)算等領(lǐng)域的軟件產(chǎn)品架構(gòu)經(jīng)驗(yàn),他是AWS認(rèn)證解決方案架構(gòu)師,在3Pillar之前先后就職于Oracle、ChoicePoint和Booz Allen Hamilton。Dan畢業(yè)于喬治·華盛頓大學(xué),他也是一個(gè)父親、業(yè)余木工愛(ài)好者,還參加過(guò)包括國(guó)際障礙大賽這樣的障礙賽跑。本篇構(gòu)建微服務(wù)的步驟如下:建立一個(gè)新的Spring Boot工程
定義我們的員工對(duì)象
持久連接
公開(kāi)Web服務(wù)
定義一個(gè)Docker容器來(lái)運(yùn)行我們的微服務(wù),包括連接到我們?cè)诘诙袆?chuàng)建的Mongo容器
在稍早設(shè)置的Docker Machine中運(yùn)行我們的容器

建立我們的Spring Boot工程我們將在我們的工程根目錄下創(chuàng)建一個(gè)文件夾(生產(chǎn)環(huán)境中是在一個(gè)單獨(dú)的版本庫(kù)中)來(lái)承載我們的服務(wù),在這個(gè)文件夾中,我們將創(chuàng)建build.grade文件。Spring Boot的優(yōu)勢(shì)就是在于對(duì)于依賴(lài)定義非常純粹,如魔法般地帶來(lái)了大量的互操作性。我們的build.grade文件看起來(lái)如下:buildscript {repositories {jcenter()}dependencies { classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.2.0.RELEASE'}}apply plugin: 'spring-boot'repositories { jcenter()}dependencies {compile "org.springframework.boot:spring-boot-starter-actuator"compile "org.springframework.boot:spring-boot-starter-web"}
現(xiàn)在,正如我們提到的,我們將使用IDE,具體地說(shuō)就是Spring Tool Suite(STS),所以我們將增加對(duì)于Gradle的支持。首先,打開(kāi)STS,接著在打開(kāi)的Dashboard頁(yè)面上點(diǎn)擊“IDE Extensions”的鏈接:


在屏幕上選擇“Grade Support”,點(diǎn)擊“Install”,按照提示完成安裝,其中包括重啟STS:
468x127xmicroservice-part-3-pic-2.jpg.pagespeed_.ic_.K4Ui_72tTm_.jpg

重啟之后,選擇“Import project…”,接著選擇Gradle project(現(xiàn)在可用了),指向你的目錄,然后點(diǎn)擊“Build Model”——這將會(huì)用“Employee”來(lái)產(chǎn)生項(xiàng)目列表——選擇這個(gè)列表并且點(diǎn)擊“Finish”,這將會(huì)導(dǎo)入一個(gè)簡(jiǎn)單的build.grade到我們啟動(dòng)的工程。一旦工程被導(dǎo)入之后,第一個(gè)將是Spring Boot配置類(lèi),在這個(gè)場(chǎng)景中,我們將按照他們的服務(wù)來(lái)命名,所以在這種情況下配置類(lèi)將會(huì)命名為EmployeeBoot。Spring大量使用了注解和反射,所以最小的配置也是需要的(忽略導(dǎo)入):@Configuration@EnableAutoConfiguration@ComponentScanpublic class EmployeeBoot { public static void main(String[] args) { SpringApplication.run(EmployeeBoot.class); }}
我們的Employee類(lèi)接下來(lái),我們將使得我們的POJO類(lèi)來(lái)持有員工信息,我們目前保持最少的字段,有必要的話我們將增加:Employee.Class@Document(collection=”employees”)public class Employee {@Idprivate String id; private String email;private String fullName;private String managerEmail;// getters and setters omitted for brevity}
注意@Document這個(gè)注解——這會(huì)將這個(gè)對(duì)象連結(jié)為一個(gè)Mongo文檔,并為該Employee“文檔”在哪里存儲(chǔ)指定了集合名字。接下來(lái)我們將定義一個(gè)Spring持久類(lèi)來(lái)讀取這些Employee:EmployeeRepository.class:public interface EmployeeRepository extendsMongoRepository<Employee, String> {}
Spring框架的一個(gè)優(yōu)美之處就是在于所有你需要寫(xiě)的——比如擴(kuò)展自MongoRepository的接口甚至不需要手動(dòng)編寫(xiě)實(shí)現(xiàn)代碼。兩個(gè)通用的參數(shù)中第一個(gè)表示需要持久化的對(duì)象類(lèi)型(Employee),第二個(gè)表示唯一的標(biāo)識(shí)符類(lèi)型(String類(lèi)型)。Spring框架將會(huì)自動(dòng)提供所聲明的功能95%的實(shí)現(xiàn)。接下來(lái)的問(wèn)題就是:Spring如何知道數(shù)據(jù)庫(kù)的位置?Spring默認(rèn)情況下將會(huì)尋找localhost:27017,這顯然是不會(huì)工作的,所以我們需要直接設(shè)置位置新型。我們可以實(shí)現(xiàn)自己的Mongo模板Bean,但是幸運(yùn)的是Spring允許我們通過(guò)Java屬性表傳遞連接信息。我們可以定義一個(gè)屬性文件或者在命令行上傳遞進(jìn)來(lái)。我們選擇了后者因?yàn)楫?dāng)稍后構(gòu)建我們的容器時(shí)命令行方式非常方便。最后我們需要?jiǎng)?chuàng)建的是一個(gè)或者兩個(gè)Rest端點(diǎn)并確保它們可以工作。我們將構(gòu)建一個(gè)快速的Spring Controller,然后我們就可以測(cè)試了。EmployeeController.java@RestController@RequestMapping("/employee")public class EmployeeController {@AutowiredEmployeeRepository employeeRepository;@RequestMapping(method = RequestMethod.POST)public Employee create(@RequestBody Employee employee){ Employee result = employeeRepository.save(employee); return result;}@RequestMapping(method = RequestMethod.GET, value="/{employeeId}")public Employee get(@PathVariable String employeeId){ return employeeRepository.findOne(employeeId);}}
最開(kāi)始的@RestController和@RequestMapping這兩個(gè)類(lèi)級(jí)別的注解告訴Spring框架需要公開(kāi)這是一個(gè)接收J(rèn)SON的Rest服務(wù),并且公開(kāi)了URI路徑是/employee。@Autowired注解告訴Spring框架采用上面我們定義的Repository接口的自動(dòng)生成實(shí)現(xiàn)代碼并將其注入到這個(gè)Controller中。現(xiàn)在到了特定的操作——方法級(jí)別的@RequestMapping注解表明這個(gè)方法將會(huì)基于HTTP動(dòng)詞來(lái)使用(在本例中是POST和GET),另外對(duì)于GET操作,我們指明了一個(gè)URL路徑{employee},比如使用/employee/abcd1234來(lái)尋找一個(gè)員工并且返回該值。現(xiàn)在我們有了足夠多的準(zhǔn)備工作可以來(lái)測(cè)試了,第一點(diǎn),我們需要編譯和運(yùn)行我們的Spring Boot應(yīng)用,在Eclipse中有很多方法可以做到這一點(diǎn),但是我們將從命令行開(kāi)始,并以我們的方式工作。在你的Employee目錄中,敲入:gradle build
,這個(gè)命令將會(huì)編譯Spring Boot應(yīng)用到build/lib/Employee.jar,這個(gè)jar包包含了運(yùn)行這個(gè)應(yīng)用所需要的所有東西,包括一個(gè)嵌入式的Servlet容器(默認(rèn)情況下是Tomcat)。在我們運(yùn)行和測(cè)試這個(gè)應(yīng)用之前,我們需要稍作回顧——我們的Mongo服務(wù)又在哪里?觀察“docker ps”命令的輸出,我們記得虛擬機(jī)的32777端口映射到了Mongo容器的27017端口,虛擬機(jī)的IP地址是192.126.99.100。如前所述,我們可以通過(guò)傳遞一個(gè)環(huán)境變量屬性的方式來(lái)把連接屬性傳遞給Spring,所以運(yùn)行這個(gè)應(yīng)用的命令行如下:java -Dspring.data.mongodb.uri=mongodb://192.168.99.100:32777/micros -jar build/libs/Employee.jar
一旦應(yīng)用啟動(dòng)之后(應(yīng)該在1~4秒),你可以使用選項(xiàng)中的Rest工具來(lái)打開(kāi)Web服務(wù)。
456x171xmicroservice-part-3-pic-3.jpg.pagespeed_.ic_.wWMISBC68u_.jpg

不要忘了在HTTP頭部包含值為“application/json”的“Content-Type”,你應(yīng)該收到如下的響應(yīng)(id的值取決于你自己的情況):{"id": "55fb2f1930e07c6c844b02ff","email": "dan.greene@3pillarglobal.com","fullName": "Daniel Greene","managerEmail": null}
你可以通過(guò)如下的調(diào)用測(cè)試我們的GET方法:http://localhost:8080/employee/55fb2f1930e07c6c844b02ff
你應(yīng)該得到相同的文檔,萬(wàn)歲!我們的服務(wù)起作用了!將Boot應(yīng)用導(dǎo)入容器現(xiàn)在我們需要構(gòu)建我們的第一個(gè)容器來(lái)運(yùn)行我們的Employee微服務(wù)。我們的途徑是定義一個(gè)Dockerfile,這個(gè)文件將會(huì)定義如何生成一個(gè)鏡像并放入我們的精益求精、短小精悍的微服務(wù)中。讓我們閱讀這個(gè)文件并逐步解析(參考第三篇第三步請(qǐng)?zhí)竭@兒):FROM java:8VOLUME /tmpADD build/libs/Employee.jar app.jarEXPOSE 8080RUN bash -c 'touch /app.jar'ENTRYPOINT ["java","-Dspring.data.mongodb.uri=mongodb://mongodb/micros", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
我們從一個(gè)包含了安裝了Java 8的標(biāo)準(zhǔn)鏡像(鏡像名字為“Java”,標(biāo)簽為“8”)開(kāi)始構(gòu)建過(guò)程
我們接著定義了一個(gè)名為/tmp的卷
接著將本地文件系統(tǒng)的一個(gè)文件添加進(jìn)來(lái),并且重命名為“app.jar”,重命名不是必須的,只是一個(gè)可用的可選項(xiàng)
我們聲明想要公開(kāi)容器的8080端口
在容器內(nèi)運(yùn)行一個(gè)touch命令,這樣可以確保app.jar文件的修改日期
ENTRYPOINT命令定義了容器啟動(dòng)時(shí)需要運(yùn)行的內(nèi)容——我們運(yùn)行Java,設(shè)置我們的Spring Mongo屬性,還有快速的附加屬性來(lái)加速Tomcat啟動(dòng)時(shí)間,然后指向我們的jar包。

現(xiàn)在我們通過(guò)運(yùn)行如下命令構(gòu)建鏡像:docker build -t microservicedemo/employee .
我們可以敲入docker images
看到結(jié)果REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZEmicroservicedemo/employee latest 364ffd8162b9 15 minutes ago 846.6 MB
接下來(lái)的問(wèn)題就是“我們的服務(wù)容器如何與Mongo容器交互?”,為此,我們引入了容器的link機(jī)制。當(dāng)你運(yùn)行一個(gè)新的容器時(shí),你可以傳入一個(gè)可選的-link參數(shù)指定一個(gè)運(yùn)行中的容器的名字,這樣新的容器就可以與這個(gè)容器通訊了,所以我們的命令是:docker run -P -d --name employee --link mongodb microservicedemo/employee
我們啟動(dòng)了一個(gè)新的容器,公開(kāi)了端口(-P),以后臺(tái)方式運(yùn)行(-d),命名為employee(—name),接著將這個(gè)新的容器連接到了一個(gè)名為“mongodb”的容器(-link),連接過(guò)程如下:在employee容器的host文件添加一個(gè)條目指向MongoDB容器的運(yùn)行位置
在employee容器內(nèi)添加一些環(huán)境變量來(lái)協(xié)助其他必要的編程訪問(wèn),可以運(yùn)行如下命令查看: {{{docker exec employee bash -c 'env | grep MONGODB'}}}
允許容器通過(guò)公開(kāi)的端口來(lái)直接通訊,這樣就不需要擔(dān)心主機(jī)的部分映射了。如果你還記得上述的內(nèi)容,我們?cè)O(shè)置了Spring Mongo到MongoDB的URL作為主機(jī)名(mongodb://mongodb/micros),所以有了host文件條目和運(yùn)行在默認(rèn)端口的Mongo,Boot應(yīng)用容器可以連上數(shù)據(jù)庫(kù)了

在容器運(yùn)行時(shí)我們可以來(lái)執(zhí)行相同的Web服務(wù),只是這次是作為容器來(lái)運(yùn)行的(對(duì)于我來(lái)說(shuō),容器的8080端口會(huì)被映射到虛擬機(jī)的32772端口):


本篇我們已經(jīng)取得了很大的進(jìn)展,我們有了兩個(gè)容器可以工作并且可以互相通訊,接下來(lái)的第四篇我們將添加一些額外的服務(wù)/容器,可以觀察到構(gòu)建更新的進(jìn)度并與CI工具集成工作。原文鏈接:BUILDING A MICROSERVICE ARCHITECTURE WITH SPRING BOOT AND DOCKER, PART

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,786評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,986評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,204評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,964評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,354評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,554評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,106評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,918評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,093評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,342評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,755評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,009評(píng)論 1 289
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,839評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,107評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容