Spring Boot目前流行的java web應用開發框架,相比傳統的spring開發,spring boot極大簡化了配置,而且遵照約定優於配置的原則即便0配置也能正常運行,這在spring中是不可思議的。spring boot應用程序能夠獨立運行,框架內嵌web容器,使得web應用程序能夠像本地程序同樣啓動和調試,十分的方便,這種設計方式也使得spring boot應用程序很是適合容器化進行大規模部署。生態方面,spring boot提供了很是豐富的組件,目前流行的java web框架基本都有spring boot版本,生態十分龐大,是目前java web開發最好的方案。java
Springboot應用程序有兩種運行方式python
兩種方式應用場景不同,各有優缺點git
經過maven插件spring-boot-maven-plugin
,在進行打包時,會動態生成jar的啓動類org.springframework.boot.loader.JarLauncher
,藉助該類對springboot應用程序進行啓動。web
以war包方式運行,經過maven插件spring-boot-maven-plugin
進行相關配置後,最終生成一個可運行在tomcat,weblogic等java web容器中的war包。spring
在實際的項目中,並無哪種方式是最好的,根據客戶不一樣的需求制定不一樣的部署方案,好比有些客戶比較看中管理功能,要求數據源和tomcat相關配置必須由管理員進行管理,那麼選擇war包方式,有些客戶但願藉助容器化進行大規模部署,那麼jar方式更適合。無論選擇哪一種方式,在部署時都會遇到下面的問題docker
spring.profiles.active
配置設置不一樣的環境,但一方面須要人爲修改配置文件,只要是人爲的就有可能出錯,另外一方面,客戶有時出於安全考慮不會提供生產環境配置信息,那麼這時候就沒法指定prifiles.active
。玩具
,隨處運行的jar包,缺乏統一管理,是達不到生產的要求,那麼若是從jar包到容器也是一個問題。早期碰到這些問題,都是人工解決,不只效率十分低下,部署一次都須要十幾分鍾,並且很容易出錯,一百次出錯一次算是機率低了,可是生產出錯一次都是重大事件,因此咱們也在思考如何經過自動化解決以上問題,如何將開發和部署分離,開發人員只關心開發,開發完提交代碼,打包和部署都是後臺透明的完成。如下就是咱們的解決方案。shell
spring boot打war包的步驟以下apache
pom.xml
中將打包方式改成war。<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"> ... <packaging>war</packaging> ... </project>
spring-boot-starter-tomcat
範圍爲provided
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency>
SpringBootServletInitializer
public class DemoApplication extends SpringBootServletInitializer{ @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(DemoApplication.class); } }
每打包一次都要修改pom.xml
和啓動類,打包完再修改回來,十分的繁瑣,由於,咱們提出如下整改方案tomcat
pom.xml
複製一個pom-war.xml
文件,將pom-war.xml
修改成war包配置shell腳本打包過程爲安全
pom-war.xml
文件進行打包。如下就是參考腳本
app-war.sh
#!/usr/bin/env bash v1=src/main/java/com/definesys/demo/DemoApplication.java v2=war/DemoApplication.java v3=war/DemoApplication-bak.java cp -rf $v2 $v1 mvn clean package -Dmaven.test.skip=true -f war-pom.xml #recovery cp -rf $v3 $v1
經過預先配置好pom文件和啓動類文件,開發人員只要運行app-war.sh
腳本無需修改任何文件便可生成war包。
以上方案pom文件和啓動類文件都須要預先準備好,未實現徹底的自動化,經過優化方案作到徹底自動化。
*Application.java
結尾的文件,做爲啓動類文件,讀取文件名獲取類名,經過字符串替換方式動態生成war包啓動類文件。這裏的多模塊指的是maven中的多模塊,項目工程中的代碼多模塊,一個項目按功能劃分模塊後,在建立工程時通常也按照功能層面上的模塊進行建立,這樣避免一個模塊代碼過於龐大,也利於任務的分工,但打包卻更麻煩了。
經過優化項目結構解決以上問題
start
項目。install
後再進入start項目進行打包,腳本參考以下mvn clean install cd start mvn clean package
目錄結構以下
. ├── pom.xml ├── role │ ├── pom.xml │ └── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ └── definesys │ │ │ └── demo │ │ │ └── controller │ │ │ └── RoleController.java │ │ └── resources ├── start │ ├── pom.xml │ ├── src │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ └── definesys │ │ │ │ └── demo │ │ │ │ └── DemoApplication.java │ │ │ └── resources │ │ │ └── application.properties └── user ├── pom.xml └── src └── main ├── java │ └── com │ └── definesys │ └── demo │ └── controller │ └── UserController.java └── resources
start pom.xml
<?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"> <parent> <artifactId>blog0915</artifactId> <groupId>com.definesys.demo</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>start</artifactId> <dependencies> <dependency> <groupId>com.definesys.demo</groupId> <artifactId>user</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.definesys.demo</groupId> <artifactId>role</artifactId> <version>1.0.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
父項目 pom.xml
<?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> <packaging>pom</packaging> <modules> <module>user</module> <module>role</module> <module>start</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> <relativePath/> </parent> <groupId>com.definesys.demo</groupId> <artifactId>blog0915</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>
子項目 pom.xml
<?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"> <parent> <artifactId>blog0915</artifactId> <groupId>com.definesys.demo</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>role</artifactId> <version>1.0.0</version> </project>
spring boot提供spring.profiles.active
指定配置文件,但生產環境有時候客戶出於安全考慮不提供配置信息給開發人員,而是預先將配置文件上傳到服務器指定路徑,程序須要在運行時去引用該配置文件,若是運行環境是kubernetes
,則會提供一個config map做爲配置文件,這時候就要求spring boot程序讀取外部配置文件。
這裏討論的是線上環境配置文件方案,本地調試參考子模塊打包相關內容,能夠將配置文件統一寫在start項目中。
jar運行能夠經過指定參數spring.config.location
引用外部文件,命令參考以下:
java -jar start-1.0-SNAPSHOT.jar --spring.config.location=/Users/asan/workspace/config
config
目錄存放properties配置文件
能夠經過配合spring.profiles.active
參數能夠指定目錄下配置文件,如:
java -jar start-1.0-SNAPSHOT.jar --spring.profiles.active=prod --spring.config.location=/Users/asan/workspace/config
則會讀取/Users/asan/workspace/config/appliction-prod.properties
文件做爲配置文件。
以tomcat
爲例,須要在tomcat啓動時指定-Dspring.config.location
參數,能夠設置服務器環境變量CATALINA_OPTS
達到目的。能夠編輯用戶 prifile文件
export CATALINA_OPTS=/Users/asan/workspace/config
一樣,也能夠經過-Dspring.profiles.active
指定配置文件名稱。
spring boot藉助容器化,能夠如虎添翼,發揮出更大的威力,也只有經過容器化,才能體會到spring boot開發的高效。經過以上的介紹,你能夠很順利的打好一個jar包或者war包,那麼能夠經過編寫dockerfile文件進行鏡像的構建。spring boot在構建鏡像時有兩個地方須要考慮
UTC
,比北京時間早8小時,須要指定鏡像時區。app-jar-dockerfile.Dockerfile
FROM openjdk:8-jdk-alpine MAINTAINER definesys.com VOLUME /tmp ADD start-1.0-SNAPSHOT.jar app.jar RUN echo "Asia/Shanghai" > /etc/timezone EXPOSE 8080 ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","--spring.config.location=/Users/asan/workspace/config","/app.jar"]
app-war.dockerfile.Dockerfile
FROM tomcat MAINTAINER definesys.com ENV CATALINA_OPTS -Dspring.config.location=file:/middleware/config/ ADD start-1.0-SNAPSHOT.war /usr/local/tomcat/webapps/app.jar RUN echo "Asia/Shanghai" > /etc/timezone EXPOSE 8080 EOF
早期咱們採用的是如下部署過程
每一次發佈都是一個新的鏡像,但這種方式有個問題就是如何保證前一個環境驗證沒問題,後一個環境就必定沒問題,由於兩個鏡像是不同的,雖然可能兩次構建都是基於同一版本代碼,但由於是從新構建,中間可能由於各類緣由,如maven包版本更新等,沒法保證兩次構建就是徹底同樣的鏡像。所以咱們優化了構建的流程,以下:
全部的環境都是用同一個鏡像,環境之間只有配置文件不一樣,文件經過configmap或者外部配置文件方式進行掛載,這樣保證了配置文件沒問題的前提下,每一個環境的程序必定是同樣的。
打包和部署在本地進行也是有問題的,本地jdk版本取決於我的電腦,甚至有黑客污染jdk致使編譯的class文件自帶後門,我的電腦環境也是隨着用戶不一樣操做可能改變,構建出來的包不能保證是穩定的包。所以須要一個遠程服務器用於打包和部署,可以實現從源碼到鏡像過程。jenkins是一個基於java開發的持續集成工具,經過配置插件和編寫腳本實現程序從代碼到製品再到線上運行的過程。jenkins在spring boot開發中主要完成了如下工做。
jenkins在構建鏡像時須要藉助docker工具,但jenkins自己也是有docker版本的,因此就面臨着docker in docker
的問題,這裏選擇的方案是用二進制文件安裝jenkin而非鏡像方式,雖然喪失了docker的便利性,但能夠簡化docker方案,下降集成的複雜度。