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 教程

若有不熟悉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" 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>

在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;  
    }  

}

在这里,我们需要单独的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());
    }  
}  

相当简单,在此不作过多赘述。


其他程序模块

在这里还需一个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"]

以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"

在其中我们定义了两个镜像,一个是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。

源码下载地址

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐