Spring boot 与 Docker-compose构建微服务应用
memr4964
8年前
<h2>Spring boot 与 Docker-compose构建微服务应用</h2> <p>前两天看了一篇文章,讲的是使用docker-compose将spring boot应用和mongodb应用一起构建,实现容器之间的相互通信,spring boot应用能够直接将数据存储到容器之中,但是那篇博客中在已有docker-compose.yml文件可以直接使用docker-compose进行build的时候,使用docker进行build,运行等等,并且其中各种过程并不详细,感觉作者在这里没有完全将docker-compose弄明白,因此我也写一篇来介绍使用docker-compose实现管理两个容器,并进行两个容器之间通信。</p> <h2>docker compose</h2> <p style="text-align:center"><img src="https://simg.open-open.com/show/acbb42a2add53ff86abbdce059c6293a.png"></p> <p>docker compose是从 <strong>fig</strong> 项目中而来, <strong>fig</strong> 可以说是 <strong>docker compose</strong> 前身,docker compose向下兼容fig,具体使用不再描述,有尽可能多的文章描述怎么安装使用docker compose,但是在这里还是推荐阅读官方的教程,以下就是:</p> <p>若有不熟悉docker compose的可以阅读以上教程。</p> <h2>spring boot需要的依赖</h2> <p>这个spring boot应用比较简单,就是spring boot使用mongodb,将数据存储在mongodb之中,其中操作mongodb的方法不是使用原生的mongodb提供的api,也不是使用spring boot提供的spring-data-mongodb来操作,而是使用morphia这一种mongodb orm框架来操作mongodb,使用morphia十分方便,具体用法在这里就不再详述, <strong>google</strong> 一下有着足够多的教程来教怎么使用morphia,以下就是个人的相关程序:</p> <p>pom.xml</p> <pre> <code class="language-java"><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> <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> <p>在pom.xml中重要的依赖其实就是两个,一个是:</p> <pre> <code class="language-java"><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency></code></pre> <p>这个支撑我们使用spring boot提供的spring web,ioc等等模块,另外一个就是我们需要的mongodb的orm框架morphia依赖:</p> <pre> <code class="language-java"><dependency> <groupId>org.mongodb.morphia</groupId> <artifactId>morphia</artifactId> <version>1.3.0</version> </dependency></code></pre> <p>在这里我们并不需要单独引入mongodb的驱动依赖,在引入morphia的时候,morphia会将mongodb的依赖一同引入进来。</p> <h2>spring boot程序</h2> <p>引入morphia后,mongo Bean的注入如下:</p> <pre> <code class="language-java">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> <p>在这里,我们需要单独的mongo bean的注入,这里为下文中的Morphia配置提供了一些依赖:</p> <p>morphia的配置:</p> <pre> <code class="language-java">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> <p>相当简单,在此不作过多赘述。</p> <h2>其他程序模块</h2> <p>在这里还需一个Application启动类,一个controller,这些都是基本需要的,而且我也只是提供了一个十分简单的功能,因此不再过多赘述,具体的可以到下面的源码中去查看。</p> <h2>docker相关文件</h2> <p>使用docker-compose构建应用,需要以下几个文件,当前应用的Dockerfile,docker-compose.yml,存储容器的Dockerfile,但是在个人多次尝试之后放弃了存储镜像的Dockerfile文件,直接将镜像写在docker-compose.yml之中,等会详细讲述:</p> <p>当前应用的Dockerfile,因为在docker-compose.yml文件之中可以指定Dockerfile的名字,所以可以不一定完全Dockerfile命名,我在这里的命名为:</p> <p>springapp.dockerfile:</p> <pre> <code class="language-java">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> <p>以maven3.3为基础镜像,将当前程序打入镜像之中后,进行相关的编译打包,移出打出来的jar文件,然后执行这个文件,在这里相应的编译打包过程中,其实也要下载相当多的jar,我再前面的几篇的博文中曾经提到想要直接将本地的jar打进镜像之中,但在这里试了许多次,一直是失败的,应该是某个步骤出了一定的问题,在未来尝试成功后,还是要单独写一篇博文来讲下如何进行操作,在我找到的很多其他文章中,其实都讲过怎么实现,但是在本机上实验就是失败的,十分沮丧。</p> <p>在这里面另外一个相当重要的文件就是docker-compose.yml,其中内容如下:</p> <pre> <code class="language-java">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> <p>在其中我们定义了两个镜像,一个是spring boot应用,一个是mongodb,然后springboot应用可以和mongodb之间进行通信。</p> <p>在以上这些全部完成之后,就可以运行我们的docker应用了。</p> <h2>运行</h2> <p>在当前spring boot应用的根目录下执行 <strong>docker-compose up -d</strong> ,其中如果不清楚docker-compose用法的可以看上面我给出的教程,里面有详细讲述, <strong>docker-compose up -d</strong> 执行完之后,会进行一系列的拉取镜像,完成镜像的操作,具体不再展示出来,在经过一系列漫长的过程后(主要就是在下载jar),容器基本就运行起来了,使用 <strong>docker ps</strong> 观察当前运行起来的容器,具体如下:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/00a28e97fee21f456a8209bd8bad9350.jpg"></p> <p>可以看到有两个容器正处于运行之中,现在查看一下springboot这个容器的运行情况,使用 <strong>docker logs</strong> 来进行查看,如下:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/078553bac1343fbd9c1b9d102f150035.jpg"></p> <p>可以看到springboot应用已经成功启动起来。</p> <p>在这里需要说明一下,为什么不需要检查mongodb容器是否处于正常状态,因为在我们再springboot应用中配置了mongodb后,并注入了bean,那么在springboot应用启动的时候会去检查mongodb是否可以正常连接上,如果springboot这里就拒绝连接了,在本身的配置文件没有出错的情况下,多半就是mongodb容器的运行不正常。</p> <h2>测试</h2> <p>我们在这里使用postman进行相应请求的发送,postman是chrome中的一款进行http操作的插件,进行http请求的发送十分方便,在这里也可以使用linux系统中的curl来进行操作,如果是使用curl的话,输入以下即可:</p> <pre> <code class="language-java">curl -l -H "Content-type: application/json" -X POST -d '{ "username": "xiaxuan","mobile": "135xxxxxxxx","password": "123456"}' http://192.168.99.100:8080/add</code></pre> <p>使用postman的话,就是如下图所示:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/cc3d6647d2063e97be7c97184b04b052.jpg"></p> <p>上半部分是请求参数,下半部分书返回结果,这个时候,已经得到spring boot应用的正常响应,说明运行一切正常,这个时候我们在连接上mongodb看看响应的数据是否已经保存进mongodb容器之中,如下图所示:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/a095036d46b6e0144ae7284c826a983c.jpg"></p> <p>可以看到mongodb之中有两条记录,mongodb容器之中也正常保存数据。</p> <h2>综上</h2> <ul> <li> <p>在使用docker-compose将多个容器之间关联起来的时候,管理、运行便相当方便,启动、关闭容器都可使用一条命令来完成,docker-compose因此也是docker彻底火起来的一个很大的原因之一。</p> </li> <li> <p>在这里有多点需要改善,有一个点就是之前提过许多次的,spring boot应用的jar可以在本地打成jar之后直接打进镜像之中,这样运行起来就会十分迅速,不需要额外花费许多时间来下载jar。</p> </li> </ul> <p> </p> <p> </p>