如何開發(fā)容器化的Java程序

上一篇 / 目錄 / 下一篇

參考資料:https://github.com/docker/labs/tree/master/developer-tools/java/

如果讀者朋友閱讀了我之前的文章《Docker入門詳解》壁拉,那么大家應(yīng)該對Docker已經(jīng)有了一個基本的了解,也理解了容器化程序的概念,以及容器化為軟件行業(yè)特別是云計(jì)算領(lǐng)域的軟件行業(yè)帶來的便利性嘀粱。接下來浸遗,我將為大家介紹如何使用Docker來開發(fā)容器化的Java程序。

創(chuàng)建基于JDK 8的Docker鏡像

這里筆者將介紹如何創(chuàng)建基于JDK 8的Docker鏡像。首先使用下面的maven命令創(chuàng)建一個java項(xiàng)目帚湘。

mvn archetype:generate -DgroupId=org.examples.java -DartifactId=helloworld -DinteractiveMode=false

上述maven命令會在helloworld目錄中創(chuàng)建一個最簡單的java程序军洼。

我們使用mvn package來進(jìn)行編譯巩螃。

cd helloworld
mvn package

編譯成功后,會在target目錄下生成打包好的jar文件匕争。

接下來使用java命令來運(yùn)行這個程序避乏。

java -cp target\helloworld-1.0-SNAPSHOT.jar org.examples.java.App

讀者會看到該程序輸出一行字符串:

Hello World!

但是,如果想要讓這個程序在其他用戶的電腦上正常的運(yùn)行甘桑,用戶還需要在電腦上安裝一個JRE拍皮。假如是更加復(fù)雜的程序,可能還需要其他的依賴軟件支持才能正常工作跑杭。借助docker铆帽,則可以把這些依賴的軟件都打包到docker鏡像中,這樣用戶想使用這個軟件時德谅,只需要下載這個鏡像就可以運(yùn)行了爹橱,不再需要安裝其他的依賴軟件。

下面我們就把這個helloworld程序打包到docker鏡像中窄做。我們準(zhǔn)備讓java程序在基于JDK 8的環(huán)境下運(yùn)行愧驱,因此基礎(chǔ)鏡像需要包含JDK 8慰技。這里我們使用的基礎(chǔ)鏡像是openjdk:8。運(yùn)行下面的命令可以啟動一個openjdk:8的容器:

docker container run -it openjdk:8

-it 表示以交互模式啟動容器组砚,因此你會看到類似下面的輸出:

root@2e1c05978452:/#

這時可以在交互模式下輸入命令java -version來查看jdk 的版本信息:

openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)

輸入exit命令可以停止openjdk:8容器吻商。

如果我們以openjdk:8為基礎(chǔ)鏡像來創(chuàng)建一個新的鏡像,那么需要在之前的helloworld目錄糟红,即我們的java項(xiàng)目所在的目錄下創(chuàng)建一個文本文件手报,命名為Dockerfile。其內(nèi)容如下:

FROM openjdk:8
COPY target/helloworld-1.0-SNAPSHOT.jar /usr/src/helloworld-1.0-SNAPSHOT.jar
CMD java -cp /usr/src/helloworld-1.0-SNAPSHOT.jar org.examples.java.App

第一行改化,FROM openjdk:8 的作用是以openjdk:8作為基礎(chǔ)鏡像掩蛤。因此新創(chuàng)建的鏡像將包含openjdk:8的所有功能。

第二行陈肛,COPY target/helloworld-1.0-SNAPSHOT.jar /usr/src/helloworld-1.0-SNAPSHOT.jar揍鸟,它的作用是進(jìn)行一個文件拷貝【浜担拷貝哪個文件呢阳藻,就是我們使用mvn package命令編譯java程序后所生成的jar文件。具體來說谈撒,就是把當(dāng)前主機(jī)上的jar文件target/helloworld-1.0-SNAPSHOT.jar腥泥,拷貝到docker鏡像的目錄/usr/src/中。

第三行啃匿,CMD java -cp /usr/src/helloworld-1.0-SNAPSHOT.jar org.examples.java.App蛔外,作用是當(dāng)啟動一個容器來運(yùn)行鏡像時,執(zhí)行命令java -cp /usr/src/helloworld-1.0-SNAPSHOT.jar org.examples.java.App來啟動這個java程序溯乒。

有了Dockerfile夹厌,就可以使用下面的命令來創(chuàng)建鏡像了:

docker image build -t hello-java .

不要忘了上述命令末尾的小數(shù)點(diǎn),它表示當(dāng)前目錄裆悄,這樣docker就會在當(dāng)前目錄中查找Dockerfile文件矛纹,并根據(jù)Dockerfile的描述來創(chuàng)建鏡像。-t hello-java表示把新的鏡像命名為hello-java光稼。

上述命令會得到類似下面的輸出信息:

Sending build context to Docker daemon  50.69kB
Step 1/3 : FROM openjdk:8
 ---> 27da2af61908
Step 2/3 : COPY target/helloworld-1.0-SNAPSHOT.jar /usr/src/helloworld-1.0-SNAPSHOT.jar
 ---> cb30cc329413
Step 3/3 : CMD java -cp /usr/src/helloworld-1.0-SNAPSHOT.jar org.examples.java.App
 ---> Running in 9b85e8fbd443
Removing intermediate container 9b85e8fbd443
 ---> df751388fd1b
Successfully built df751388fd1b
Successfully tagged hello-java:latest

想要運(yùn)行這個鏡像也很簡單或南,只需要執(zhí)行下面的命令:

docker container run hello-java

容器運(yùn)行后會輸出字符串:

Hello World!

使用Docker Maven Plugin

maven不但可以編譯java程序,也可以用來創(chuàng)建docker鏡像艾君。利用docker-maven-plugin插件可以在編譯java程序的同時自動創(chuàng)建鏡像采够,這樣省去了創(chuàng)建Dockerfile并輸入docker命令行的步驟,顯得更加方便腻贰。

為此吁恍,需要修改java項(xiàng)目中的pom.xml文件扒秸,如下所示:

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.examples.java</groupId>
  <artifactId>helloworld</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>helloworld</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <profiles>
    <profile>
      <id>docker</id>
      <build>
        <plugins>
          <plugin>
            <groupId>io.fabric8</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>0.31.0</version>
            <configuration>
              <images>
                <image>
                  <name>hello-java</name>
                  <build>
                    <from>openjdk:8</from>
                    <assembly>
                      <descriptorRef>artifact</descriptorRef>
                    </assembly>
                    <cmd>java -cp maven/${project.name}-${project.version}.jar org.examples.java.App</cmd>
                  </build>
                  <run>
                    <wait>
                      <log>Hello World!</log>
                    </wait>
                  </run>
                </image>
              </images>
            </configuration>
            <executions>
              <execution>
                <id>docker:build</id>
                <phase>package</phase>
                <goals>
                  <goal>build</goal>
                </goals>
              </execution>
              <execution>
                <id>docker:start</id>
                <phase>install</phase>
                <goals>
                  <goal>run</goal>
                  <goal>logs</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>
</project>

關(guān)于maven-docker-plugin播演,截止筆者發(fā)布此博客時冀瓦,其最新的版本是0.31.0。讀者可以在maven repository網(wǎng)站上查詢這個plugin的發(fā)布版本號写烤。在插件的github主頁有更加詳細(xì)的使用說明翼闽。

在我們的示例中用到了這么幾個maven goals:

  • docker:build 編譯并創(chuàng)建docker鏡像。

要使這個maven goal 命令正常工作洲炊,需要在pom的<configuration>中添加<build>元素來定義如何創(chuàng)建docker鏡像感局。示例中定義的<build>元素如下:

<build>
    <from>openjdk:8</from>
    <assembly>
        <descriptorRef>artifact</descriptorRef>
    </assembly>
    <cmd>java -cp maven/${project.name}-${project.version}.jar org.examples.java.App</cmd>
</build>

<from>表示基礎(chǔ)鏡像為openjdk:8。<assembly>元素用來定義鏡像需要包含的文件暂衡,即我們需要把哪些文件拷貝到新創(chuàng)建的鏡像之中询微。一個簡單的配置就是使用<descriptorRef>artifact</descriptorRef>,這樣就可以把編譯后的jar文件拷貝到鏡像中狂巢。<cmd>元素用來定義容器運(yùn)行時執(zhí)行的命令行撑毛,本例執(zhí)行一個java命令來運(yùn)行我們的java程序。

  • docker:start 和 docker:run 創(chuàng)建并運(yùn)行docker容器唧领。

<configuration>中添加<run>元素藻雌,可以對容器的運(yùn)行方式進(jìn)行配置。示例中定義的<run>元素如下:

<run>
    <wait>
        <log>Hello World!</log>
    </wait>
</run>

這里的<wait>用來阻塞maven命令的執(zhí)行斩个,直到檢測到容器輸出日志"Hello World!"時胯杭,再恢復(fù)maven命令的執(zhí)行過程。

  • docker:logs 把容器輸出的日志打印到當(dāng)前的命令行窗口中受啥。

接下來做个,使用命令mvn -Pdocker package編譯java項(xiàng)目,并且創(chuàng)建docker鏡像滚局。這個命令會輸出類似下面的日志:

[INFO] Copying files to C:\Users\i062893\OneDrive\code\docker-workspace\docker-java\helloworld\target\docker\hello-java\build\maven
[INFO] Building tar: C:\Users\i062893\OneDrive\code\docker-workspace\docker-java\helloworld\target\docker\hello-java\tmp\docker-build.tar
[INFO] DOCKER> [hello-java:latest]: Created docker-build.tar in 155 milliseconds
[INFO] DOCKER> [hello-java:latest]: Built image sha256:cf28b
[INFO] DOCKER> [hello-java:latest]: Removed old image sha256:df751
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

注意這三行以"DOCKER>"開頭的日志了嗎叁温?這說明hello-java:latest鏡像已經(jīng)創(chuàng)建成功了。使用docker image ls來看一下本機(jī)的鏡像列表核畴。在列表中可以發(fā)現(xiàn)hello-java鏡像:

REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
hello-java                latest              cf28b4b83a26        2 minutes ago       488MB

我們也可以使用mvn -Pdocker install命令來編譯java項(xiàng)目膝但,創(chuàng)建鏡像,并啟動一個容器來運(yùn)行這個鏡像谤草。該命令輸出的日志類似下面這樣:

[INFO] --- docker-maven-plugin:0.31.0:run (docker:start) @ helloworld ---
[INFO] DOCKER> [hello-java:latest]: Start container f8deb08d2692
[INFO] DOCKER> Pattern 'Hello World!' matched for container f8deb08d2692
f8deb0> Hello World!
[INFO] DOCKER> [hello-java:latest]: Waited on log out 'Hello World!' 674 ms

讀者可以看到跟束,hello-java容器已經(jīng)啟動,并且輸出了字符串Hello World!丑孩。此時按下Ctrl + C可以停止這個容器冀宴。

至此,我們的容器化JAVA程序開發(fā)指南就告一段落了温学。在最后略贮,留給大家兩個思考題。

  1. 筆者介紹了兩種打包docker鏡像的方法,一種是使用Dockerfile逃延,另一種是使用maven插件maven-docker-plugin览妖。這兩種方法都會把新創(chuàng)建的鏡像保存在本機(jī)的鏡像倉庫中。但是怎樣才能把本機(jī)的鏡像發(fā)布出去揽祥,供其他用戶安裝和使用呢讽膏?

  2. 筆者創(chuàng)建了一個JAVA程序,并且將其打包到基于JDK 8的docker鏡像中了拄丰,這意味著我們的JAVA程序不能包含JDK 9及以上版本的新功能府树。那么如果想要使用JDK 12的新API和新的java語法,那該怎么做呢料按?

讀者朋友如果知道答案的話奄侠,歡迎大家在博客下方留言。筆者將在下一篇博客中為大家揭曉答案载矿。謝謝大家遭铺。

上一篇 / 目錄 / 下一篇

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恢准,隨后出現(xiàn)的幾起案子魂挂,更是在濱河造成了極大的恐慌,老刑警劉巖馁筐,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涂召,死亡現(xiàn)場離奇詭異,居然都是意外死亡敏沉,警方通過查閱死者的電腦和手機(jī)果正,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盟迟,“玉大人秋泳,你說我怎么就攤上這事≡懿ぃ” “怎么了迫皱?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辖众。 經(jīng)常有香客問我卓起,道長,這世上最難降的妖魔是什么凹炸? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任戏阅,我火速辦了婚禮,結(jié)果婚禮上啤它,老公的妹妹穿的比我還像新娘奕筐。我一直安慰自己舱痘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布离赫。 她就那樣靜靜地躺著芭逝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪笆怠。 梳的紋絲不亂的頭發(fā)上铝耻,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天誊爹,我揣著相機(jī)與錄音蹬刷,去河邊找鬼。 笑死频丘,一個胖子當(dāng)著我的面吹牛办成,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播搂漠,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼迂卢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了桐汤?” 一聲冷哼從身側(cè)響起而克,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎怔毛,沒想到半個月后员萍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拣度,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年碎绎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抗果。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡筋帖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冤馏,到底是詐尸還是另有隱情日麸,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布逮光,位于F島的核電站赘淮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏睦霎。R本人自食惡果不足惜梢卸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望副女。 院中可真熱鬧蛤高,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至恤批,卻和暖如春异吻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喜庞。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工诀浪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人延都。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓雷猪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親晰房。 傳聞我的和親對象是個殘疾皇子求摇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

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