本篇紀錄在Mac將Spring Boot應用程式製作成docker image檔,並在本機的docker中運行。
也可參考「Docker build Spring Boot docker image」
範例環境:
- macOS High Sierra
- Docker
- Java 1.8
- Spring Boot 2.2.1.RELEASE
- Maven
- IntelliJ IDEA CE
本範例專案名稱為demo
,工作目錄在~/Documents/workspace/demo
。
在~/Documents
下新增一個mydocker
資料夾,此目錄為Dockerfile執行時的工作目錄(WORKDIR
)。
在Spring Boot預設配置檔src/main/resources/application.properties
設定應用程式目錄及port。所以在本機的應用程式路徑為http://localhost:8080/demo
。
#context path
server.servlet.context-path=/demo
#port
server.port=8080
在專案中建立一個Controller類別DemoController
如下。此類別僅是最後在docker運行Spring Boot的image時可以測試用。
DemoController
package com.abc.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@GetMapping("/")
public String hello() {
return "Hello Spring Boot with Docker";
}
}
在專案根目錄也就是~/Documents/workspace/demo/
新增一個名稱為Dockerfile
的檔案(不用副檔名),其是一個文字檔而已。
在Dockerfile
裡面設定以下內容為docker build image時會執行的指令。
Dockerfile
FROM openjdk:8-jdk-alpine
COPY ./target/*.jar /Documents/mydocker/demo.jar
WORKDIR /Documents/mydocker
RUN sh -c 'touch demo.jar'
ENTRYPOINT ["java","-jar","demo.jar"]
Dockerfile指令簡單說明:
FROM openjdk:8-jdk-alpine
:使用的base image。COPY ./target/*.jar /Documents/mydocker/demo.jar
:將build context,即所在目錄的target/*.jar
複製到container檔案目錄的/Documents/mydocker/demo.jar。WORKDIR /Documents/mydocker
:指定container的/Documents/mydocker
為Docker的命令執行目錄。RUN sh -c 'touch demo.jar'
:修改demo.jar
的時間戳記為目前時間。ENTRYPOINT ["java","-jar","demo.jar"]
:在container剛指定的WORKDIR
目錄執行java -jar demo.jar
。
然後用mvn clean install
將此Spring Boot打包為jar檔,本範例直接使用IntelliJ IDEA的Maven視窗工具,點兩下[install]即可。
建構成功後在專案的target
目錄下會產生jar檔,例如demo-0.0.1.SNAPSHOT.jar
。
接著就是把這個jar製作成docker image檔了。
把命令列所在目錄移到Dockerfile
的位置也就是~/Documents/workspace/demo
,
執行docker build -t demo-app .
指令來建立image。-t
後接的參數為image的名稱,所以製作的image名稱為demo-app
。
.
代表docker build時使用當下目錄的Dockerfile
。
~/Documents/workspace/demo$ docker build -t demo-app .
Sending build context to Docker daemon 19.5MB
Step 1/5 : FROM openjdk:8-jdk-alpine
8-jdk-alpine: Pulling from library/openjdk
e7c96db7181b: Pull complete
f910a506b6cb: Pull complete
c2274a1a0e27: Pull complete
Digest: sha256:94792824df2df33402f201713f932b58cb9de94a0cd524164a0f2283343547b3
Status: Downloaded newer image for openjdk:8-jdk-alpine
---> a3562aa0b991
Step 2/5 : COPY ./target/*.jar /Documents/mydocker/demo.jar
---> 96f62e91c5aa
Step 3/5 : WORKDIR /Documents/mydocker
---> Running in eaf63cde939c
Removing intermediate container eaf63cde939c
---> 9825b3aa91cf
Step 4/5 : RUN sh -c 'touch demo.jar'
---> Running in 3f23dc5f97ca
Removing intermediate container 3f23dc5f97ca
---> 4a271f8300a3
Step 5/5 : ENTRYPOINT ["java","-jar","demo.jar"]
---> Running in dfbdcbac56a5
Removing intermediate container dfbdcbac56a5
---> cc6a733eecd7
Successfully built cc6a733eecd7
image製作好後會存在本機的docker registry中。執行docker images
指令列出現存的images,可以看到剛剛製作好的demo-app
。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
demo-app latest cc6a733eecd7 3 minutes ago 143MB
openjdk 8-jdk-alpine a3562aa0b991 7 months ago 105MB
hello-world latest fce289e99eb9 11 months ago 1.84kB
輸入docker run -p 8080:8080 demo-app
讓demo-app
在docker中執行。
-p
參數用來綁定host的port及container的port。前面的8080
為本機的8080 port;後面的8080
為container的8080 port。
$ docker run -p 8080:8080 demo-app
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.1.RELEASE)
2019-12-17 07:08:33.894 INFO 1 --- [ main] com.abc.demo.DemoApplication : Starting DemoApplication v0.0.1-SNAPSHOT on f9bdf41d3e05 with PID 1 (/Documents/mydocker/demo.jar started by root in /Documents/mydocker)
2019-12-17 07:08:33.899 INFO 1 --- [ main] com.abc.demo.DemoApplication : No active profile set, falling back to default profiles: default
2019-12-17 07:08:35.347 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-12-17 07:08:35.370 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-12-17 07:08:35.370 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.27]
2019-12-17 07:08:35.464 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/demo] : Initializing Spring embedded WebApplicationContext
2019-12-17 07:08:35.464 INFO 1 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1452 ms
2019-12-17 07:08:35.809 INFO 1 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-12-17 07:08:36.070 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '/demo'
2019-12-17 07:08:36.075 INFO 1 --- [ main] com.abc.demo.DemoApplication : Started DemoApplication in 2.983 seconds (JVM running for 3.66)
2019-12-17 07:08:46.341 INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/demo] : Initializing Spring DispatcherServlet 'dispatcherServlet'
在本機的瀏覽器url位址輸入http://localhost:8080/demo/
可看到以下結果。
如要停止運行這個image先用docker ps
或docker container ls
列出運行中的docker container。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f9bdf41d3e05 demo-app "java -jar demo.jar" About an hour ago Up About an hour 0.0.0.0:8080->8080/tcp bold_heisenberg
然後輸入docker stop <container_id>
或docker stop <container_name>
停止運行。
$ docker stop f9bdf41d3e05
f9bdf41d3e05
作者已經移除這則留言。
回覆刪除是否有錯誤訊息?
回覆刪除您好,我按照步驟匯出,不過瀏覽網頁的時候是404,我其中有先遇到docker的db和docker image連不到的問題。後來嘗試綁定port有解決。不過瀏覽spring專案的網頁的時候還是404。我有上網查詢不過眾說紛紜。
回覆刪除首先我有一個疑問就是不是只有war才有辦法看到view的html/jsp的部分嗎?為什麼網上的教學都是jar的部分呢?還是其實jar也能看到view的部分。
另外,我搜尋關於404錯誤的時候,好像有看到說是因為匯出專案式war的關係,又或者是因為"targetPath必须为META-INF/resources"但這個設定在spring的properties時不是已經有設定了嗎@@!
謝謝前輩的幫忙
先回答你第二個問題,Spring Boot是否能看到view與打包成jar或war無關,兩者都可以看到view。Spring Boot的Maven預設打包為jar是因為內含embedded Tomcat容器,而會打包成war是有得時候必須部署到外部web server例如JBoss。
回覆刪除本範例使用maven install打包時預設是打包成jar並產出在專案下的/target目錄。
從你目前提供的資訊我仍無法判斷錯誤問題在哪,只能一步步來看:
1.請問你在執行docker build建立image時有成功嗎?
2.請問你用docker images查詢得到你建立的image檔嗎?
3.請問你執行docker run -p 8080:8080 <IMAGE> console有顯示Spring的啟動訊息嗎?
前輩您好:
回覆刪除您的問題這邊,我最後是用jar匯出,就是按照您的方式。
1. 有成功匯出。
2. 查詢得到image。
3. 啟動時有顯示成功啟動,但是一開始是顯示沒辦法連到資料庫。後來試了語法修改port有成功連上資料庫。
指令如下:
docker network create crm-mssql
docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Sa123456" -p 1433:1433 --name mssql --network crm-mssql -d mcr.microsoft.com/mssql/server:2019-latest
docker run --network crm-mssql --name crm-container -p 8080:8080 crm-app
那看來Spring Boot的image有啟動,那就和docker沒關係了。
回覆刪除所以你瀏覽器輸入http://localhost:8080/<context_path> 仍出現404是嗎?你可能要檢查一下你Spring Boot的controller的設定。
仔細看一下你的指令你運行docker時有使用自訂的docker network [crm-mssql],那麽連到docker container裡面的Spring Boot應該就不是用localhost,可能要用自訂docker network的IP位址。
回覆刪除