Spring boot 與 Docker-compose構建微服務應用
Spring boot 與 Docker-compose構建微服務應用
前兩天看了一篇文章,講的是使用docker-compose將spring boot應用和mongodb應用一起構建,實現容器之間的相互通信,spring boot應用能夠直接將數據存儲到容器之中,但是那篇博客中在已有docker-compose.yml文件可以直接使用docker-compose進行build的時候,使用docker進行build,運行等等,并且其中各種過程并不詳細,感覺作者在這里沒有完全將docker-compose弄明白,因此我也寫一篇來介紹使用docker-compose實現管理兩個容器,并進行兩個容器之間通信。
docker compose
docker compose是從 fig 項目中而來, fig 可以說是 docker compose 前身,docker compose向下兼容fig,具體使用不再描述,有盡可能多的文章描述怎么安裝使用docker compose,但是在這里還是推薦閱讀官方的教程,以下就是:
若有不熟悉docker compose的可以閱讀以上教程。
spring boot需要的依賴
這個spring boot應用比較簡單,就是spring boot使用mongodb,將數據存儲在mongodb之中,其中操作mongodb的方法不是使用原生的mongodb提供的api,也不是使用spring boot提供的spring-data-mongodb來操作,而是使用morphia這一種mongodb orm框架來操作mongodb,使用morphia十分方便,具體用法在這里就不再詳述, google 一下有著足夠多的教程來教怎么使用morphia,以下就是個人的相關程序:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0 ;
<modelVersion>4.0.0</modelVersion>
<groupId>cn.com</groupId>
<artifactId>SpringBootMongoDocker</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring :: boot :: mongo :: docker</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>cn.com.Application</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mongodb.morphia</groupId>
<artifactId>morphia</artifactId>
<version>1.3.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>cn.com.Application</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>
repackage
</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project></code></pre>
在pom.xml中重要的依賴其實就是兩個,一個是:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
這個支撐我們使用spring boot提供的spring web,ioc等等模塊,另外一個就是我們需要的mongodb的orm框架morphia依賴:
<dependency>
<groupId>org.mongodb.morphia</groupId>
<artifactId>morphia</artifactId>
<version>1.3.0</version>
</dependency>
在這里我們并不需要單獨引入mongodb的驅動依賴,在引入morphia的時候,morphia會將mongodb的依賴一同引入進來。
spring boot程序
引入morphia后,mongo Bean的注入如下:
package cn.com.config;
import com.mongodb.Mongo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import javax.annotation.PreDestroy;
import java.net.UnknownHostException;
@Configuration
@ConditionalOnClass(Mongo.class)
@EnableConfigurationProperties(MongoProperties.class)
public class MongoAutoConfiguration {
@Autowired
private MongoProperties properties;
private Mongo mongo;
@Autowired
private Environment environment;
@PreDestroy
public void close() {
if (this.mongo != null) {
this.mongo.close();
}
}
@Bean
@ConditionalOnMissingBean
public Mongo mongo() throws UnknownHostException {
this.mongo = this.properties.createMongoClient(null, environment);
return this.mongo;
}
}</code></pre>
在這里,我們需要單獨的mongo bean的注入,這里為下文中的Morphia配置提供了一些依賴:
morphia的配置:
package cn.com.config;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.Morphia;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnClass(Mongo.class)
public class MorphiaFactory {
@Autowired
private Mongo mongo;
@Autowired
MongoProperties mongoProperties;
@Bean
public Datastore get() {
Morphia morphia = new Morphia();
return morphia.createDatastore((MongoClient) mongo,mongoProperties.getDatabase());
}
}</code></pre>
相當簡單,在此不作過多贅述。
其他程序模塊
在這里還需一個Application啟動類,一個controller,這些都是基本需要的,而且我也只是提供了一個十分簡單的功能,因此不再過多贅述,具體的可以到下面的源碼中去查看。
docker相關文件
使用docker-compose構建應用,需要以下幾個文件,當前應用的Dockerfile,docker-compose.yml,存儲容器的Dockerfile,但是在個人多次嘗試之后放棄了存儲鏡像的Dockerfile文件,直接將鏡像寫在docker-compose.yml之中,等會詳細講述:
當前應用的Dockerfile,因為在docker-compose.yml文件之中可以指定Dockerfile的名字,所以可以不一定完全Dockerfile命名,我在這里的命名為:
springapp.dockerfile:
FROM maven:3.3.3
ADD pom.xml /tmp/build/
RUN cd /tmp/build && mvn -q dependency:resolve
ADD src /tmp/build/src
#構建應用
RUN cd /tmp/build && mvn -q -DskipTests=true package \
#拷貝編譯結果到指定目錄
&& mv target/*.jar /app.jar \
#清理編譯痕跡
&& cd / && rm -rf /tmp/build
VOLUME /tmp
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]</code></pre>
以maven3.3為基礎鏡像,將當前程序打入鏡像之中后,進行相關的編譯打包,移出打出來的jar文件,然后執行這個文件,在這里相應的編譯打包過程中,其實也要下載相當多的jar,我再前面的幾篇的博文中曾經提到想要直接將本地的jar打進鏡像之中,但在這里試了許多次,一直是失敗的,應該是某個步驟出了一定的問題,在未來嘗試成功后,還是要單獨寫一篇博文來講下如何進行操作,在我找到的很多其他文章中,其實都講過怎么實現,但是在本機上實驗就是失敗的,十分沮喪。
在這里面另外一個相當重要的文件就是docker-compose.yml,其中內容如下:
version : '2'
services:
springappserver:
build:
context: .
dockerfile: springapp.dockerfile
ports:
- "8080:8080"
volumes:
- .:/vol/development
links:
- mongodb:mongodb
mongodb:
image: daocloud.io/library/mongo:latest
ports:
- "27017:27017"
</code></pre>
在其中我們定義了兩個鏡像,一個是spring boot應用,一個是mongodb,然后springboot應用可以和mongodb之間進行通信。
在以上這些全部完成之后,就可以運行我們的docker應用了。
運行
在當前spring boot應用的根目錄下執行 docker-compose up -d ,其中如果不清楚docker-compose用法的可以看上面我給出的教程,里面有詳細講述, docker-compose up -d 執行完之后,會進行一系列的拉取鏡像,完成鏡像的操作,具體不再展示出來,在經過一系列漫長的過程后(主要就是在下載jar),容器基本就運行起來了,使用 docker ps 觀察當前運行起來的容器,具體如下:

可以看到有兩個容器正處于運行之中,現在查看一下springboot這個容器的運行情況,使用 docker logs 來進行查看,如下:

可以看到springboot應用已經成功啟動起來。
在這里需要說明一下,為什么不需要檢查mongodb容器是否處于正常狀態,因為在我們再springboot應用中配置了mongodb后,并注入了bean,那么在springboot應用啟動的時候會去檢查mongodb是否可以正常連接上,如果springboot這里就拒絕連接了,在本身的配置文件沒有出錯的情況下,多半就是mongodb容器的運行不正常。
測試
我們在這里使用postman進行相應請求的發送,postman是chrome中的一款進行http操作的插件,進行http請求的發送十分方便,在這里也可以使用linux系統中的curl來進行操作,如果是使用curl的話,輸入以下即可:
curl -l -H "Content-type: application/json" -X POST -d '{ "username": "xiaxuan","mobile": "135xxxxxxxx","password": "123456"}' http://192.168.99.100:8080/add
使用postman的話,就是如下圖所示:

上半部分是請求參數,下半部分書返回結果,這個時候,已經得到spring boot應用的正常響應,說明運行一切正常,這個時候我們在連接上mongodb看看響應的數據是否已經保存進mongodb容器之中,如下圖所示:

可以看到mongodb之中有兩條記錄,mongodb容器之中也正常保存數據。
綜上
-
在使用docker-compose將多個容器之間關聯起來的時候,管理、運行便相當方便,啟動、關閉容器都可使用一條命令來完成,docker-compose因此也是docker徹底火起來的一個很大的原因之一。
-
在這里有多點需要改善,有一個點就是之前提過許多次的,spring boot應用的jar可以在本地打成jar之后直接打進鏡像之中,這樣運行起來就會十分迅速,不需要額外花費許多時間來下載jar。