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>