摘要:應用化極簡教程陳光劍基于的企業級應用開發最佳實踐前面的章節中,我們都是在環境中開發運行測試應用程序。關鍵字是分布式應用微服務容器虛擬化。通常,在企業項目實踐中,會實現一套應用部署發布的自動化運維平臺工具。
Spring Boot 應用 Docker 化
《Spring Boot 2.0極簡教程》(陳光劍)
—— 基于 Gradle + Kotlin的企業級應用開發最佳實踐
前面的章節中,我們都是在IDE環境中開發運行測試 Spring Boot 應用程序。在開發測試發布整個軟件生命周期的過程中,我們通常需要完成打包部署發布到日常、預發、線上機器運行等運維相關工作。
本章前半部分介紹 Spring Boot 應用的打包和部署,后半部分重點介紹如何使用 Docker 來構建部署運行 Spring Boot 應用。
首先,使用http://start.spring.io/ 創建一個打包方式為 war 的 Spring Boot Kotlin 應用,采用 Gradle 構建。點擊 Generate Project 等待創建完畢,下載 zip 包,導入 IDEA 中。可以看到,相比于項目打成jar 包方式,打成 war 包的項目中多了一個用于初始化Servlet的ServletInitializer類。代碼如下
class ServletInitializer : SpringBootServletInitializer() { override fun configure(application: SpringApplicationBuilder) : SpringApplicationBuilder { return application.sources(DemoPackageAndDeployApplication::class.java) } }
我們知道Spring Boot 默認集成了內嵌web容器(例如 Tomcat、Jetty 等),這個時候,Spring Boot 應用支持“一鍵啟動”,像一個普通Java程序一樣,從main函數入口開始啟動。現在,我們是將項目打包成war包,放到獨立的web容器中。
而如果我們這個 war 包中沒有配置Spring MVC 的 DispatcherServlet 的 web.xml 文件或者初始化 Servlet的類,那么這個 war 包就不會被 Tomcat識別啟動 。這個時候,我們需要告訴 Tomcat 這個 war 包的啟動入口。而SpringBootServletInitializer就是來完成這件事情的。
通過重寫configure (SpringApplicationBuilder) 方法,使用SpringApplicationBuilder 來配置應用程序的sources類。為了測試應用運行的效果,我們在DemoPackageAndDeployApplication.kt 中添加HelloWorld REST接口方便測試
@SpringBootApplication open class DemoPackageAndDeployApplication fun main(args: Array1.2 項目打包成可執行 jar) { runApplication (*args) } @RestController class HelloWorld { @GetMapping(value = ["", "/"]) fun hello(): Map { val result = mutableMapOf () result["msg"] = "Hello,World" result["time"] = Date() return result } }
在 IDEA 的右邊的 Gradle 工具欄中列出了 Gradle 構建項目的命令,如下圖
圖16-1 Gradle 構建項目的命令
我們可以直接點擊 bootJar 把項目打成 jar 包。當然,在運維部署腳本中通常使用命令行: gradle bootJar 。執行日志如下
17:44:21: Executing task "bootJar"... :compileKotlin UP-TO-DATE :compileJava NO-SOURCE :processResources UP-TO-DATE :classes UP-TO-DATE :bootJar UP-TO-DATE BUILD SUCCESSFUL in 1s 3 actionable tasks: 3 up-to-date 17:44:22: Task execution finished "bootJar".
執行完畢,我們可以在項目的build/libs 目錄下看到打好的 jar 包,如下圖所示
圖16-2 項目的build/libs 目錄下打好的 jar 包
然后,我們就可以直接使用 java –jar 命令執行該 jar 包了
$ java -jar build/libs/demo_package_and_deploy-0.0.1-SNAPSHOT.jar
此時,我們瀏覽器訪問 http://127.0.0.1:8080/ , 可以看到輸出
{ "msg": "Hello,World", "time": "2018-02-09T09:38:31.933+0000" }
不過,使用java –jar 命令行來啟動系統的這種方式
java -jar build/libs/demo_package_and_deploy-0.0.1-SNAPSHOT.jar
只要控制臺關閉,服務就不能訪問了。我們可以使用nohup 與 & 命令讓進程在后臺運行:
nohup java -jar build/libs/demo_package_and_deploy-0.0.1-SNAPSHOT.jar &
我們也可以在啟動的時候選擇讀取不同的配置文件。例如,在項目src/main/resources 目錄下面有不同環境下的配置文件。如下圖所示:
圖16-3 不同環境的屬性配置文件
其中,application-dev.properties中配置服務器端口號為9000:
server.port=9000
執行 bootJar重新打jar 包,執行下面的命令:
java -jar build/libs/demo_package_and_deploy-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
可以看到應用成功啟動,并監聽9000端口:
… o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 9000 (http) with context path "" 2018-02-09 18:18:47.336 INFO 69156 --- [ main] .e.s.d.DemoPackageAndDeployApplicationKt : Started DemoPackageAndDeployApplicationKt in 6.493 seconds (JVM running for 7.589)1.4 項目打包成 war 包
在上面創建的項目中,Gradle 構建配置文件 build.gradle 內容如下:
buildscript { … } … apply plugin: "war" … configurations { providedRuntime } dependencies { … providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") }
其中,apply plugin: "war" 是使用 war 插件來完成項目的打包工作。
直接使用 gradle bootWar,即可把項目打成 war包。然后,就可以像普通J2EE項目一樣部署到web容器。同樣的,war 包的路徑默認也是放在 build/libs 下面。
另外,如果下面這行代碼還在:
@SpringBootApplication open class DemoPackageAndDeployApplication fun main(args: Array) { runApplication (*args) }
項目打成的war包,依然支持java –jar 運行:
$ java -jar build/libs/demo_package_and_deploy-0.0.1-SNAPSHOT.war
這個 war 包很不錯,既可以直接扔到 Tomcat 容器中執行,也可以直接命令行啟動運行。
提示:項目打 war包的示例項目源代碼:https://github.com/EasySpring...
本節簡單介紹一些 Spring Boot 應用的生產運維的一些內容。
1.5.1 查看JVM參數的值使用命令:
ps -ef|grep java
拿到對于Java程序的pid (第2列):
501 69156 68678 0 6:18PM ttys002 0:21.59 /usr/bin/java -jar build/libs/demo_package_and_deploy-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
可以根據java自帶的jinfo命令:
jinfo -flags 69156
來查看jar 啟動后使用的是什么gc、新生代、老年代,分批的內存都是多少,示例如下:
$ jinfo -flags 69156 Attaching to process ID 69156, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.40-b25 Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:MaxNewSize=715653120 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=44564480 -XX:OldSize=89653248 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC
其中的參數簡單說明如表16-1所示。
表16-1 JVM參數
參數說明
-XX:CICompilerCount
最大的并行編譯數
-XX:InitialHeapSize 和 -XX:MaxHeapSize
指定JVM的初始堆內存和最大堆內存大小
-XX:MaxNewSize
JVM堆區域新生代內存的最大可分配大小
-XX:+UseParallelGC
垃圾回收使用Parallel收集器
我們可以在 Java 命令行中配置我們需要的JVM參數指標。
提示:更多關于 JVM 選項參數配置參考:http://www.oracle.com/technet... 。
1.5.2 應用重啟要想重啟應用,要首先找到該應用的 java進程,然后kill掉 java 進程。完成這個邏輯的shell 腳本如下:
kill -9 $(ps -ef|grep java|awk "{print $2}")
然后,再使用命令行重新啟動應用即可。
1.6 使用 Docker 構建部署運行Spring Boot應用本節介紹如何使用 Docker 來構建部署 Spring Boot 應用。
1.6.1 Docker 簡介Docker 是一個Go語言開發的開源的輕量級應用容器引擎,誕生與2013年。Docker的核心概念是:鏡像、容器、倉庫。關鍵字是: 分布式應用(distributed applications), 微服務( microservices), 容器( containers ), 虛擬化(docker virtualization)。
Docker容器“輕量級”的含義主要是跟傳統的虛擬機方式的對比而言。如下圖所示:
圖16-4 Docker “輕量級”容器VS.傳統的虛擬機方式
傳統的虛擬機技術是在硬件層面實現虛擬化,需要額外的虛擬機管理軟件跟虛擬機操作系統這層。而 Docker 是在操作系統層面上的虛擬化,直接使用的是本地操作系統資源,因此更加輕量級。
Docker 的主要目標是通過對應用組件的封裝、分發、部署、運行等生命周期的管理,做到“一次封裝,到處運行”。
Docker 是實現微服務( microservices )應用程序開發的理想選擇。開發、部署和回滾都將變成“一鍵操作”。傳統的在服務器上進行各種軟件包的安裝、環境配置、應用程序的打包部署、啟動進程等零散的運維操作——被更高層次的“抽象”,放到了一個“集裝箱”中,我們只是“開箱即用”。Docker把交付運行環境比作“海運”:OS如同一個貨輪,每一個在OS上運行的軟件都如同一個集裝箱,用戶可以通過標準化手段自由組裝運行環境,同時集裝箱的內容可以由用戶自定義,也可以由專業人員制造——這樣交付一個軟件,就是一系列標準化組件集的交付,如同樂高積木,用戶只需要選擇合適的積木組合,最后個標準化組件就是給用戶的應用程序。這就是基于docker的PaaS()產品的原型。
一個完整的Docker有以下幾個部分組成:
? DockerClient客戶端
? Docker Daemon守護進程
? Docker Image鏡像
? DockerContainer容器
? 在docker的網站上介紹了使用docker的典型場景:
? Automating the packaging and deployment of applications(應用打包部署自動化)
? Creation of lightweight, private PAAS environments(創建輕量、私有的PaaS環境)
? Automated testing and continuous integration/deployment(實現自動化測試和持續的集成/部署)
? Deploying and scaling web apps, databases and backend services(部署與擴展web app、數據庫和后端服務)
由于Docker 基于LXC的輕量級虛擬化的特點,相比 KVM 之類虛擬機而言,最明顯的特點就是啟動快,資源占用?。ㄝp量級)——這正是構建隔離的標準化的運行環境,輕量級的PaaS,構建自動化測試和持續集成環境,以及一切可以橫向擴展的應用等場景的最佳選擇。
提示:更多關于 Docker 的介紹參考: https://docs.docker.com 。Dockers Github 項目空間是:https://github.com/docker
本小節介紹如何搭建 Docker 環境。
安裝 Docker
去 docker 官網 https://docs.docker.com/install/ 下載對應的操作系統上的安裝包。安裝完畢,打開Docker運行,可以看到Mac 系統菜單欄上的顯示的 Docker 應用信息如下
圖16-5 Mac 系統菜單欄上的 Docker 圖標
想知道 docker 提供了哪些命令行操作嗎?執行docker help即可看到一個詳細的命令說明。例如,在命令行查看 Docker 版本信息:
$ docker version Client: Version: 17.12.0-ce API version: 1.35 Go version: go1.9.2 Git commit: c97c6d6 Built: Wed Dec 27 20:03:51 2017 OS/Arch: darwin/amd64 Server: Engine: Version: 17.12.0-ce API version: 1.35 (minimum version 1.12) Go version: go1.9.2 Git commit: c97c6d6 Built: Wed Dec 27 20:12:29 2017 OS/Arch: linux/amd64 Experimental: false
查看詳細的 docker 信息
$ docker info Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 1 Server Version: 17.12.0-ce …
從倉庫 pull Java 環境鏡像
使用sudo docker pull java命令從 Docker 官方倉庫獲取 Java 運行環境鏡像:
$ sudo docker pull java Password: Using default tag: latest latest: Pulling from library/java ... bb9cdec9c7f3: Pull complete Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d Status: Downloaded newer image for java:latest
下載完畢之后,可以通過docker images命令查看鏡像列表:
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE Java latest d23bdf5b1b1b 12 months ago 643MB
可以看到,本地鏡像中已經有了 java 運行環境。
1.7 Spring Boot 項目 Docker化實戰本節介紹如何把上面的 Spring Boot 項目 Docker 容器化。過程主要分為如下3步:
1)添加 docker構建插件。
2)配置Dockerfile文件創建自定義的鏡像。
3)構建Docker鏡像。
下面我們就來分別詳細介紹。
在 Gradle 項目構建配置文件build.gradle 中添加com.palantir.docker插件:
buildscript { ext { kotlinVersion = "1.2.20" springBootVersion = "2.0.0.RC1" } repositories { // gradle-docker plugin repo maven { url "https://plugins.gradle.org/m2/" } ... } dependencies { ... classpath("gradle.plugin.com.palantir.gradle.docker:gradle-docker:0.17.2") } } apply plugin: "com.palantir.docker" ... docker { name "${project.group}/${jar.baseName}" files jar.archivePath buildArgs(["JAR_FILE": "${jar.archiveName}"]) }
其中,buildArgs(["JAR_FILE": "${jar.archiveName}"]) 中配置的"JAR_FILE": "${jar.archiveName}" 是我們的 Spring Boot 項目打成 jar包的名稱,會傳遞到Dockerfile文件中使用(下一步驟中將會看到)。
提示:關于Docker 插件com.palantir.docker的介紹參考文檔: https://github.com/palantir/g...
這個插件發布在https://plugins.gradle.org/m2...,所以我們添加 maven 倉庫的依賴
repositories { // gradle-docker plugin repo maven { url "https://plugins.gradle.org/m2/" } ... }
gradle-docker提供的版本有:
https://plugins.gradle.org/m2...
Dockerfile文件放置在項目根目錄:
圖16-6 Dockerfile文件放置在項目根目錄
Dockerfile文件內容如下:
FROM java:latest VOLUME /tmp ARG JAR_FILE ADD ${JAR_FILE} app.jar ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
配置構建參數JAR_FILE,這里的JAR_FILE是在 build.gradle 中buildArgs中配置的
docker { name "${project.group}/${jar.baseName}" files jar.archivePath buildArgs(["JAR_FILE": "${jar.archiveName}"]) } ADD ${JAR_FILE} app.jar
將文件${JAR_FILE}拷貝到docker container的文件系統對應的路徑app.jar
ENTRYPOINT ["java", "-Djava.security.egd= file:/dev/./urandom", "-jar", "/app.jar"]
Docker container啟動時執行的命令。注意:一個Dockerfile中只能有一條ENTRYPOINT命令。如果多條,則只執行最后一條。
-Djava.security.egd=file:/dev/./urandom
配置 JRE 使用非阻塞的 Entropy Source。SecureRandom generateSeed 使用 /dev/random 生成種子。但是 /dev/random 是一個阻塞數字生成器,如果它沒有足夠的隨機數據提供,它就一直等,這迫使 JVM 等待。通過在 JVM 啟動參數中配置這么一行:-Djava.security.egd=file:/dev/./urandom 解決這個阻塞問題。
Dockerfile是一個文本格式的配置文件,我們可以使用Dockerfile文件快速創建自定義的鏡像。Dockerfile支持的豐富的運維指令。這些指令分為4部分:
? 基礎鏡像信息
? 維護者信息
? 鏡像操作指令
? 容器啟動時的執行指令
...
直接在命令行執行:
$ docker run -p 8080:9000 -t com.easy.springboot/demo_package_and_deploy
即可啟動我們構建發布在 Docker 鏡像倉庫中的Spring Boot 應用鏡像了。
1.7.6 端口映射我們的 Spring Boot 應用鏡像運行在 Docker容器沙箱環境中,端口號是9000,作為外部Host OS環境要訪問這個服務, 需要添加TCP端口映射:把本機8080端口映射到 Docker 容器端口9000,如下圖所示:
圖16-7 把本機8080端口映射到 Docker 容器端口9000
其中:
? -p 是將容器的端口9000映射到 docker 所在操作系統的端口8080;
? -t 是打開一個偽終端,以便后續可以進入查看控制臺 log。
使用 docker ps 命令查看運行中的容器:
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 36fbfaf05359 com.easy.springboot/demo_package_and_deploy "java -Djava.securit…" 25 minutes ago Up 25 minutes 0.0.0.0:8080->9000/tcp infallible_kare
……
然后,執行 push 命令即可:
$ docker push com.easy.springboot/demo_package_and_deploy
提示:本節項目源代碼:https://github.com/EasySpring...
1.8 本章小結本章簡單介紹了Spring Boot項目的打包、分環境運行、生產運維等操作。通常,在企業項目實踐中,會實現一套 Spring Boot應用部署發布的自動化運維平臺工具。本章還給出了一個完整的 Spring Boot項目 Docker 化的實戰案例。
經過前面的學習,相信您已經對如何使用基于 Kotlin 編程語言的 Spring Boot項目開發有了一個比較好的掌握。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/27280.html
摘要:應用化極簡教程陳光劍基于的企業級應用開發最佳實踐前面的章節中,我們都是在環境中開發運行測試應用程序。關鍵字是分布式應用微服務容器虛擬化。通常,在企業項目實踐中,會實現一套應用部署發布的自動化運維平臺工具。 Spring Boot 應用 Docker 化 《Spring Boot 2.0極簡教程》(陳光劍)—— 基于 Gradle + Kotlin的企業級應用開發最佳實踐 前面的章節中,...
摘要:是一門最近比較流行的靜態類型編程語言,而且和一樣同屬系。這個生成的構造函數是合成的,因此不能從或中直接調用,但可以使用反射調用。 showImg(https://segmentfault.com/img/remote/1460000012958496); Kotlin是一門最近比較流行的靜態類型編程語言,而且和Groovy、Scala一樣同屬Java系。Kotlin具有的很多靜態語言...
摘要:概述在我之前的應用監控實戰一文中,講述了如何利用版本來可視化地監控應用。接下來我們就來創建一個待監控的示例。 showImg(https://segmentfault.com/img/remote/1460000015671446); 概述 在我之前的 《Spring Boot應用監控實戰》 一文中,講述了如何利用 Spring Boot Admin 1.5.X 版本來可視化地監控 ...
摘要:創建工程將框架代碼包解壓后放到工作目錄。方便起見,本教程使用為例。添加創建一個,負責響應相關的業務請求。添加標注在中,對輸入參數進行校驗通常使用標注。在本教程,我們將實現的增和查的工作。創建用戶用戶名重啟并提交創建請求。 環境準備 系統:MacOS 開發:IntelliJ IDEA 語言:Java8 其它:Mysql、Redis 腳手架代碼 Spring提供了一個創建項目腳手架的官...
摘要:前提好幾周沒更新博客了,對不斷支持我博客的童鞋們說聲抱歉了。熟悉我的人都知道我寫博客的時間比較早,而且堅持的時間也比較久,一直到現在也是一直保持著更新狀態。 showImg(https://segmentfault.com/img/remote/1460000014076586?w=1920&h=1080); 前提 好幾周沒更新博客了,對不斷支持我博客的童鞋們說聲:抱歉了!。自己這段時...
閱讀 3738·2021-09-09 09:33
閱讀 3024·2019-08-30 15:56
閱讀 3017·2019-08-30 15:56
閱讀 3307·2019-08-30 15:55
閱讀 499·2019-08-30 15:53
閱讀 2179·2019-08-30 15:52
閱讀 662·2019-08-28 18:16
閱讀 2391·2019-08-26 13:51