SpringBoot(十五):SpringBoot2.x集成eureka实现注高可用册中心,高可用的服务器提供者,以及消费者示例

本文代码请参考《https://github.com/478632418/springcloud-eureka-server-client/tree/master/mall》、《https://github.com/478632418/springboot-eureka

本章节主要包含SpringCloud终端服务器注册中心、服务提供者、服务器消费几个角色的项目创建示例。

我们这里选取Euerka作为服务注册发现框架,实际上能提供服务注册与发现的框架并不止它一个,但是业界内使用这个还比较广泛,但是有人说它从2.0之后Netflix就不在维护它了,但是依然有不少公司还坚持选了它,因为它到2.0就已经很稳定了。

Eureka注册中心简介

Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。

Eureka包含两个组件:Eureka Server和Eureka Client。

Eureka Server:提供服务注册服务,服务启动后,服务会在Eureka Server中进行注册,包括主机与端口号、服务版本号、通信协议等。这样Eureka Server中的服务注册表中将会存储所有可用的服务节点的信息,服务节点的信息可以在界面中直观的看到。

Eureka Server端支持集群模式部署,首尾相连形成一个闭环即可,集群中的不同服务注册中心通过异步模式互相复制各自的状态,这也意味着在给定的时间点每个实例中存储的所有服务的状态可能存在不一致的现象。

Eureka Client:主要处理服务的注册和发现。客户端服务通过注册和参数配置的方式,嵌入在客户端应用程序的代码中。在应用程序启动时,Eureka客户端向服务注册中心注册自身提供的服务,并周期性的发送心跳来更新它的服务租约。同时,它也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期性的刷新服务状态。

服务调用:

服务消费者在获取服务清单后,通过服务名可以获取具体提供服务的实例名和该实例的元数据信息。因为有这些服务实例的详细信息,所以客户端可以根据自己的需求决定具体调用哪个实例,在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。

服务提供者与服务消费者之间调用关系:

1)服务注册中心启动;

2)服务提供者在启动时,向注册中心注册自己提供的服务;

3)服务消费者在启动时,向注册中心订阅自己所需要的服务;

4)注册中心返回服务提供者地址给消费者;

5)服务消费者从提供者地址中调用消费者。

实际上在开发中过程中Eureka Server就是注册中心;Eureka Client就是服务提供者和消费者。

根项目创建:

SpringCloud是要基于SpringBoot的,因此在根项目导入了SpringBoot的parent引用。

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

根项目命名为mall,它包含了三个主要子模块(,config是配置中心的一个实现,放在下一篇文章中学习):

server(maven module):Eureka Server(服务注册中心)

provider(maven module):Eureka Client(服务提供者)+Actuator(服务器监控)

consumer(maven module):Eureka Client(服务器消费者)+Ribbon(负载均衡)+Actuator(服务器监控)

Eureka-Server

在上边新建的Maven Project下新建server项目(maven module). server project就是服务注册中心,这里讲会讲解采用分布式配置以及如何运行在docker container中。

1)修改server project的pom.xml

maven项目的名称为server,版本号为1.0.0

    <parent>
        <groupId>com.dx.mall</groupId>
        <artifactId>mall</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>com.mall</groupId>
    <artifactId>server</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    <name>server</name>
    <description>mall-server</description>

引入springboot-web引用,因为springcloud需要依赖于springboot,我们这里作为web项目因此引用springboot-web。

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-cloud.version>Finchley.SR2</spring-cloud.version>
        <docker.image.prefix>mall</docker.image.prefix>
        <java.version>1.8</java.version>
        <skipTests>true</skipTests>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

上边是springboot-web和eureka-server和dependencyManagement是必须的,然后引入docker-build maven插件,以来Dockerfile来实现生成image到docker。

    <!-- 
    使用maven插件的install执行时,会自动创建、更新images。
    使用时需要在根目录下包含Dockerfile文件,否则会抛出异常。
     -->
    <build>
        <finalName>server</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>dockerfile-maven-plugin</artifactId>
                <version>1.4.0</version>
                <executions>
                    <execution>
                        <id>build-image</id>
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <repository>${docker.image.prefix}/${project.build.finalName}</repository>
                    <tag>${version}</tag>
                    <buildArgs>
                        <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                    </buildArgs>
                </configuration>
            </plugin>
        </plugins>
    </build>

finalName中制定了打包的包名,上边plugins下包含两个maven plugin,第一个是spring-boot maven编译器,第二个就docker插件,构造docker image使用,需要在服务器端安装docker。

为了防止找不到包,引入maven仓库。

    <!-- 解决maven仓库找不到jar问题 -->
    <repositories>
        <repository>
            <id>spring-milestone-repo</id>
            <url>http://repo.spring.io/milestone/</url>
        </repository>
    </repositories>

2)application.yml文件配置

application.yml中配置内容如下:

spring:
  application:
    name: mall-server

eureka:
  #  关闭自我保护模式
  #  eureka.server.enable-self-preservation: false
  instance:
    prefer-ip-address: true
    lease-expiration-duration-in-seconds: 30
    lease-renewal-interval-in-seconds: 30
  client:
    registerWithEureka: false
    fetchRegistry: false
    healthcheck:
      enabled: true
    service-url:
      defaultZone: http://slave1:8761/eureka/,http://slave2:8762/eureka/,http://slave3:8763/eureka/
  server:
    enable-self-preservation: true
info:
  app:
    name: ${spring.application.name}
    description: Eureka 注册中心
    version: 1.0.0

---
spring:
  profiles:
    slave1
server:
  port: 8761
eureka:
  instance:
    hostname: slave1

---
spring:
  profiles:
    slave2
server:
  port: 8762
eureka:
  instance:
    hostname: slave2

---
spring:
  profiles:
    slave3
server:
  port: 8763
eureka:
  instance:
    hostname: slave3

这里相当于使用三个yml文件:application-slave1.yml,application-slave2.yml,application-slave3.yml(用法参考:https://docs.spring.io/spring-boot/docs/2.1.10.BUILD-SNAPSHOT/reference/html/howto-properties-and-configuration.html#howto-change-configuration-depending-on-the-environment)。只是配置方式不同罢了,这么做的目的是为了更方便在docker上部署分布式eureka-server。实际上就是使用docker-compose(docker重排功能)实现分布式部署。

其中info:下是actuator依赖配置为了在euerka-server ui中展示更有用详细信息,通过/info等地质访问到的信息。

其中eureka:client中展示的信息是是否注册自身等配置,service-url:defaultZone是用来eureka-server一起组成集群使用的,这个是必须配置的。

3)编写入口类(com.mall.server.ServerApplication):

package com.mall.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * 注册中心
 * 
 * @version 1.0.0
 */
@EnableEurekaServer
@SpringBootApplication
public class ServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }
}

其中@SpringBootApplicaiton是springboot项目中,制定项目启动入口注解;

其中@EnableEurekaServer是注解该project为Eureka-Server。

4)在server的根下创建Dockerfile

Dockerfile是docker maven plugin生成image时需要依赖的文件,否则无法正确生成image,Dockerfile中配置信息如下:

# 基于哪个镜像
FROM java:8
# 将本地文件夹挂载到当前容器
VOLUME /tmp
# 拷贝文件到容器,server.jar这里是maven打包后的名字
ADD ./target/server.jar app.jar
RUN bash -c 'touch /app.jar'
# 配置容器启动后执行的命令
ENTRYPOINT  ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

5)使用maven工具生成docker image

在eclipse中选中该server项目-》Run As-》Maven install进行项目编译:

[INFO] Scanning for projects...
[WARNING] 
[WARNING] Some problems were encountered while building the effective model for com.mall:server:jar:1.0.0
[WARNING] The expression ${version} is deprecated. Please use ${project.version} instead.
[WARNING] 
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING] 
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING] 
[INFO] 
[INFO] --------------------------< com.mall:server >---------------------------
[INFO] Building server 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ server ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ server ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ server ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ server ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ server ---
[INFO] Tests are skipped.
[INFO] 
[INFO] --- maven-jar-plugin:3.1.0:jar (default-jar) @ server ---
[INFO] Building jar: /Users/dz/work/springcloud-test/mall/server/target/server.jar
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.1.1.RELEASE:repackage (repackage) @ server ---
[INFO] Replacing main artifact with repackaged archive
[INFO] 
[INFO] --- dockerfile-maven-plugin:1.4.0:build (build-image) @ server ---
[INFO] Building Docker context /Users/dz/work/springcloud-test/mall/server
[INFO] 
[INFO] Image will be built as mall/server:1.0.0
[INFO] 
[INFO] Step 1/5 : FROM java:8
[INFO] 
[INFO] Pulling from library/java
[INFO] Image 5040bd298390: Pulling fs layer
...
[INFO] Image bb9cdec9c7f3: Extracting
[INFO] Image bb9cdec9c7f3: Pull complete
[INFO] Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d
[INFO] Status: Downloaded newer image for java:8
[INFO]  ---> d23bdf5b1b1b
[INFO] Step 2/5 : VOLUME /tmp
[INFO] 
[INFO]  ---> Running in 44f90f8f1fb1
[INFO] Removing intermediate container 44f90f8f1fb1
[INFO]  ---> 13d7c25e8287
[INFO] Step 3/5 : ADD ./target/server.jar app.jar
[INFO] 
[INFO]  ---> 54ecfa5e791d
[INFO] Step 4/5 : RUN bash -c 'touch /app.jar'
[INFO] 
[INFO]  ---> Running in bf2cbe1b90f7
[INFO] Removing intermediate container bf2cbe1b90f7
[INFO]  ---> 00c1f22288b9
[INFO] Step 5/5 : ENTRYPOINT  ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
[INFO] 
[INFO]  ---> Running in 0c28ddc6d2ce
[INFO] Removing intermediate container 0c28ddc6d2ce
[INFO]  ---> b195029b462d
[INFO] [Warning] One or more build-args [JAR_FILE] were not consumed
[INFO] Successfully built b195029b462d
[INFO] Successfully tagged mall/server:1.0.0
[INFO] 
[INFO] Detected build of image with id b195029b462d
[INFO] Building jar: /Users/dz/work/springcloud-test/mall/server/target/server-docker-info.jar
[INFO] Successfully built mall/server:1.0.0
[INFO] 
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ server ---
[INFO] Installing /Users/dz/work/springcloud-test/mall/server/target/server.jar to /opt/mvn_local_repo/com/mall/server/1.0.0/server-1.0.0.jar
[INFO] Installing /Users/dz/work/springcloud-test/mall/server/pom.xml to /opt/mvn_local_repo/com/mall/server/1.0.0/server-1.0.0.pom
[INFO] Installing /Users/dz/work/springcloud-test/mall/server/target/server-docker-info.jar to /opt/mvn_local_repo/com/mall/server/1.0.0/server-1.0.0-docker-info.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  11:12 min
[INFO] Finished at: 2019-09-23T11:27:43+08:00
[INFO] ------------------------------------------------------------------------

或者

通过mvn命令mvn package来生成images

dx:server $ mvn package -Ddockerfile.skip=false

mvn clean package -Ddockerfile.skip=false

此时查看Docker上的images列表如下:

dx:~ $ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mall/server         1.0.0               b195029b462d        2 hours ago         735MB
java                8                   d23bdf5b1b1b        2 years ago         643MB

6)在server项目根下创建docker-componse.yml重新编排文件

version: '3.5'
services:
  slave1:
    container_name: s1
    image: mall/server:1.0.0
    networks:
      - mall-server-net
    ports:
      - 8761:8761
    environment:
      - SPRING_PROFILES_ACTIVE=slave1

  slave2:
    container_name: s2
    image: mall/server:1.0.0
    networks:
      - mall-server-net
    ports:
      - 8762:8762
    environment:
      - SPRING_PROFILES_ACTIVE=slave2

  slave3:
    container_name: s3
    image: mall/server:1.0.0
    networks:
      - mall-server-net
    ports:
      - 8763:8763
    environment:
      - SPRING_PROFILES_ACTIVE=slave3

networks:
  mall-server-net:
    name: mall-server-net
    driver: bridge

重新编排的目的:使用images运行多个实例到container。

执行docker-compose重新编排。

dx:springcloud-test $ cd mall/
dx:mall $ ls
config        consumer    pom.xml        product        server        src
dx:mall $ cd server/
dx:server $ ls
Dockerfile        docker-compose.yml    pom.xml            src            target
dx:server $ docker-compose -f docker-compose.yml up -d
Creating network "mall-server-net" with driver "bridge"
Creating s1 ... done
Creating s2 ... done
Creating s3 ... done
dx:server $ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
e4b21fd1eb29        mall/server:1.0.0   "java -Djava.securit…"   6 seconds ago       Up 5 seconds        0.0.0.0:8761->8761/tcp   s1
9c798524acb1        mall/server:1.0.0   "java -Djava.securit…"   6 seconds ago       Up 5 seconds        0.0.0.0:8763->8763/tcp   s3
bd047426e71b        mall/server:1.0.0   "java -Djava.securit…"   6 seconds ago       Up 5 seconds        0.0.0.0:8762->8762/tcp   s2
dx:server $

此时访问:http://localhost:8761,http://localhost:8762,http://localhost:8763均可以访问到如下界面:

到这里就说明eureka server已经成功部署并运行。源代码参考:https://github.com/478632418/springcloud-eureka-server-client/tree/master/mall/server

Provider(Eureka-Client)

在maill(maven project)下新建product project(maven module) ,用来实现服务提供者功能。

1)修改server project的pom.xml

maven项目的名称为product,版本号为1.0.0,并引入eureka-client maven依赖。

    <parent>
        <groupId>com.dx.mall</groupId>
        <artifactId>mall</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>com.dx.mall.product</groupId>
    <artifactId>product</artifactId>
    <version>1.0.0</version>
    <name>product</name>
    <url>http://maven.apache.org</url>

引入springboot-web引用,因为springcloud需要依赖于springboot,我们这里作为web项目因此引用springboot-web。

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-cloud.version>Finchley.SR2</spring-cloud.version>
        <docker.image.prefix>mall</docker.image.prefix>
        <java.version>1.8</java.version>
        <skipTests>true</skipTests>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

上边是springboot-web和eureka-client和dependencyManagement是必须的,然后引入docker-build maven插件,用来Dockerfile来实现生成image到docker。

    <!-- 
    使用maven插件的install执行时,会自动创建、更新images。
    使用时需要在根目录下包含Dockerfile文件,否则会抛出异常。
     -->
    <build>
        <finalName>product</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>dockerfile-maven-plugin</artifactId>
                <version>1.4.0</version>
                <executions>
                    <execution>
                        <id>build-image</id>
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <repository>${docker.image.prefix}/${project.build.finalName}</repository>
                    <tag>${version}</tag>
                    <buildArgs>
                        <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                    </buildArgs>
                </configuration>
            </plugin>
        </plugins>
    </build>

finalName中制定了打包的包名,上边plugins下包含两个maven plugin,第一个是spring-boot maven编译器,第二个就docker插件,构造docker image使用,需要在服务器端安装docker。

为了防止找不到包,引入maven仓库。

    <!-- 解决maven仓库找不到jar问题 -->
    <repositories>
        <repository>
            <id>spring-milestone-repo</id>
            <url>http://repo.spring.io/milestone/</url>
        </repository>
    </repositories>

2)application.yml文件配置

application.yml中配置内容如下:

spring:
   application:
      name: spring-cloud-producer
      
eureka:
   client:
      service-url:
         defaultZone: http://slave1:8761/eureka/,http://slave2:8762/eureka/,http://slave3:8763/eureka/
   instance:
      preferIpAddress: true
      
info:
  app:
    name: ${spring.application.name}
    description: Spring-Cloud-Producer
    version: 1.0.0
    build.artifactId: $project.artifactId$
    build.version: $project.version$

---
spring:
  profiles:
    slave1
server:
  port: 7761
eureka:
  instance:
    hostname: slave1

---
spring:
  profiles:
    slave2
server:
  port: 7762
eureka:
  instance:
    hostname: slave2

---
spring:
  profiles:
    slave3
server:
  port: 7763
eureka:
  instance:
    hostname: slave3

这里相当于使用三个yml文件:application-slave1.yml,application-slave2.yml,application-slave3.yml。只是配置方式不同罢了,这么做的目的是为了更方便在docker上部署分布式eureka-client服务提供者。实际上就是使用docker-compose(docker重排功能)实现分布式部署。

其中info:下是actuator依赖配置为了在euerka-server ui中展示更有用详细信息,通过/info等地质访问到的信息。

其中eureka:client:service-url:defaultZone是用来eureka-client发现eureka-server使用的,这个是必须配置的。

3)编写入口类(org.product.App):

package org.product;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * Hello world!
 *
 */
@SpringBootApplication
@EnableEurekaClient
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

其中@SpringBootApplicaiton是springboot项目中,制定项目启动入口注解;

其中@EnableEurekaClient是注解该project为Eureka-Client。

4)编写服务提供(org.product.controller.DemoController)类

package org.product.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {
    @Value("${server.port}")
    String serverPort;

    @GetMapping("/getPortInfo")
    public String getPortInfo() {
        return "The port is "+serverPort;
    }

}

5)在product的根下创建Dockerfile

Dockerfile是docker maven plugin生成image时需要依赖的文件,否则无法正确生成image,Dockerfile中配置信息如下:

# 基于哪个镜像
FROM java:8
# 将本地文件夹挂载到当前容器
VOLUME /tmp
# 拷贝文件到容器,product.jar这里是maven打包后的名字
ADD ./target/product.jar product.jar
RUN bash -c 'touch /product.jar'
# 配置容器启动后执行的命令
ENTRYPOINT  ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/product.jar"]

6)使用maven工具生成docker image

在eclipse中选中该server项目-》Run As-》Maven install进行项目编译:

[INFO] Scanning for projects...
[WARNING] 
[WARNING] Some problems were encountered while building the effective model for com.dx.mall.product:product:jar:1.0.0
[WARNING] The expression ${version} is deprecated. Please use ${project.version} instead.
[WARNING] 
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING] 
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING] 
[INFO] 
[INFO] --------------------< com.dx.mall.product:product >---------------------
[INFO] Building product 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ product ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ product ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to /Users/dz/work/springcloud-test/mall/product/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ product ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/dz/work/springcloud-test/mall/product/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ product ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/dz/work/springcloud-test/mall/product/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ product ---
[INFO] Tests are skipped.
[INFO] 
[INFO] --- maven-jar-plugin:3.1.0:jar (default-jar) @ product ---
[INFO] Building jar: /Users/dz/work/springcloud-test/mall/product/target/product.jar
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.1.1.RELEASE:repackage (repackage) @ product ---
[INFO] Replacing main artifact with repackaged archive
[INFO] 
[INFO] --- dockerfile-maven-plugin:1.4.0:build (build-image) @ product ---
[INFO] Building Docker context /Users/dz/work/springcloud-test/mall/product
[INFO] 
[INFO] Image will be built as mall/product:1.0.0
[INFO] 
[INFO] Step 1/5 : FROM java:8
[INFO] 
[INFO] Pulling from library/java
[INFO] Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d
[INFO] Status: Image is up to date for java:8
[INFO]  ---> d23bdf5b1b1b
[INFO] Step 2/5 : VOLUME /tmp
[INFO] 
[INFO]  ---> Using cache
[INFO]  ---> 13d7c25e8287
[INFO] Step 3/5 : ADD ./target/product.jar product.jar
[INFO] 
[INFO]  ---> 7f918fde0731
[INFO] Step 4/5 : RUN bash -c 'touch /product.jar'
[INFO] 
[INFO]  ---> Running in 368ce696cbd6
[INFO] Removing intermediate container 368ce696cbd6
[INFO]  ---> 1fa85ed6c438
[INFO] Step 5/5 : ENTRYPOINT  ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/product.jar"]
[INFO] 
[INFO]  ---> Running in 5049235d2782
[INFO] Removing intermediate container 5049235d2782
[INFO]  ---> 614560332af7
[INFO] [Warning] One or more build-args [JAR_FILE] were not consumed
[INFO] Successfully built 614560332af7
[INFO] Successfully tagged mall/product:1.0.0
[INFO] 
[INFO] Detected build of image with id 614560332af7
[INFO] Building jar: /Users/dz/work/springcloud-test/mall/product/target/product-docker-info.jar
[INFO] Successfully built mall/product:1.0.0
[INFO] 
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ product ---
[INFO] Installing /Users/dz/work/springcloud-test/mall/product/target/product.jar to /opt/mvn_local_repo/com/dx/mall/product/product/1.0.0/product-1.0.0.jar
[INFO] Installing /Users/dz/work/springcloud-test/mall/product/pom.xml to /opt/mvn_local_repo/com/dx/mall/product/product/1.0.0/product-1.0.0.pom
[INFO] Installing /Users/dz/work/springcloud-test/mall/product/target/product-docker-info.jar to /opt/mvn_local_repo/com/dx/mall/product/product/1.0.0/product-1.0.0-docker-info.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  23.690 s
[INFO] Finished at: 2019-09-23T23:38:03+08:00
[INFO] ------------------------------------------------------------------------

或者进入provider项目根目录下,通过mvn命令mvn package来生成images

dx:provider $ mvn package -Ddockerfile.skip=false

mvn clean package -Ddockerfile.skip=false

此时查看Docker上的images列表如下:

dx:server $ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
mall/product        1.0.0               614560332af7        About a minute ago   724MB
mall/server         1.0.0               b195029b462d        12 hours ago         735MB
java                8                   d23bdf5b1b1b        2 years ago          643MB
dx:server $

出现上边信息说明已经成功生成了mall/product镜像。

6)在product项目根下创建docker-componse.yml重新编排文件

version: '3.5'
services:
  slave1:
    container_name: p1
    image: mall/product:1.0.0
    networks:
      - mall-server-net
    ports:
      - 7761:7761
    environment:
      - SPRING_PROFILES_ACTIVE=slave1

  slave2:
    container_name: p2
    image: mall/product:1.0.0
    networks:
      - mall-server-net
    ports:
      - 7762:7762
    environment:
      - SPRING_PROFILES_ACTIVE=slave2

  slave3:
    container_name: p3
    image: mall/product:1.0.0
    networks:
      - mall-server-net
    ports:
      - 7763:7763
    environment:
      - SPRING_PROFILES_ACTIVE=slave3

networks:
  mall-server-net:
    name: mall-server-net
    driver: bridge

注意:

1)生成该编排文件时,必须要networks和之前server的networks共用一个,否则会导致出现后边eureka-server和服务提供者(product)运行的容器的网段不在一起,进而导致网络无法被访问。

2)重新编排的目的:使用images运行多个实例到container。

执行docker-compose重新编排。

dx:server $ pwd
/Users/dz/work/springcloud-test/mall/server
dx:server $ cd ..
dx:mall $ cd product/
dx:product $ ls
Dockerfile        docker-compose.yml    pom.xml            src            target
dx:product $ docker-compose -f docker-compose.yml up -d
Creating p3 ... done
Creating p2 ... done
Creating p1 ... done
dx:product $ docker ps -a
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                    NAMES
ee3c8c4968eb        mall/product:1.0.0   "java -Djava.securit…"   7 seconds ago       Up 6 seconds        0.0.0.0:7762->7762/tcp   p2
893af08a6d8a        mall/product:1.0.0   "java -Djava.securit…"   7 seconds ago       Up 6 seconds        0.0.0.0:7763->7763/tcp   p3
02bea113a771        mall/product:1.0.0   "java -Djava.securit…"   7 seconds ago       Up 6 seconds        0.0.0.0:7761->7761/tcp   p1
e4b21fd1eb29        mall/server:1.0.0    "java -Djava.securit…"   10 hours ago        Up 10 hours         0.0.0.0:8761->8761/tcp   s1
9c798524acb1        mall/server:1.0.0    "java -Djava.securit…"   10 hours ago        Up 10 hours         0.0.0.0:8763->8763/tcp   s3
bd047426e71b        mall/server:1.0.0    "java -Djava.securit…"   10 hours ago        Up 10 hours         0.0.0.0:8762->8762/tcp   s2
dx:product $

此时访问:http://localhost:8761,http://localhost:8762,http://localhost:8763均可以访问到如下界面:

到这里就说明eureka provider已经成功部署并运行。

Consumer(Eureka-Client)

 在mall下新建consumer(maven module)项目,pom.xml版本名称修改:

1)修改server project的pom.xml

maven项目的名称为consumer,版本号为1.0.0,并引入eureka-client maven依赖。

    <parent>
        <groupId>com.dx.mall</groupId>
        <artifactId>mall</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>com.dx.mall.consumer</groupId>
    <artifactId>consumer</artifactId>
    <version>1.0.0</version>
    <name>consumer</name>
    <url>http://maven.apache.org</url>

引入springboot-web引用,因为springcloud需要依赖于springboot,我们这里作为web项目因此引用springboot-web。

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-cloud.version>Finchley.SR2</spring-cloud.version>
        <docker.image.prefix>mall</docker.image.prefix>
        <java.version>1.8</java.version>
        <skipTests>true</skipTests>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

上边是springboot-web和eureka-client和dependencyManagement是必须的,然后引入docker-build maven插件,用来Dockerfile来实现生成image到docker。

    <!-- 
    使用maven插件的install执行时,会自动创建、更新images。
    使用时需要在根目录下包含Dockerfile文件,否则会抛出异常。
     -->
    <build>
        <finalName>consumer</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>dockerfile-maven-plugin</artifactId>
                <version>1.4.0</version>
                <executions>
                    <execution>
                        <id>build-image</id>
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <repository>${docker.image.prefix}/${project.build.finalName}</repository>
                    <tag>${version}</tag>
                    <buildArgs>
                        <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                    </buildArgs>
                </configuration>
            </plugin>
        </plugins>
    </build>

finalName中制定了打包的包名,上边plugins下包含两个maven plugin,第一个是spring-boot maven编译器,第二个就docker插件,构造docker image使用,需要在服务器端安装docker。

为了防止找不到包,引入maven仓库。

    <!-- 解决maven仓库找不到jar问题 -->
    <repositories>
        <repository>
            <id>spring-milestone-repo</id>
            <url>http://repo.spring.io/milestone/</url>
        </repository>
    </repositories>

2)application.yml文件配置

application.yml中配置内容如下:

spring:
   application:
      name: spring-cloud-consumer
eureka:
   client:
      service-url:
         defaultZone: http://slave1:8761/eureka/,http://slave2:8762/eureka/,http://slave3:8763/eureka/
   instance:
      preferIpAddress: true
info:
   app:
      name: ${spring.application.name}
      description: Spring-Cloud-Consumer
      version: 1.0.0
      build.artifactId: $project.artifactId$
      build.version: $project.version$
#取消Ribbon使用Eureka
#ribbon:
#   eureka:
#      enabled: true
#配置Ribbon能访问 的微服务节点,多个节点用逗号隔开
#spring-cloud-consumer:
#    ribbon:
#       listOfServers: localhost:8001,localhost:8002

---
spring:
   profiles: slave1
server:
   port: 6761
management: 
  port: 54001
  health: 
    mail: 
      enabled: false 
eureka:
   instance:
      hostname: slave1

这里配置了一个application.yml的标签

3)编写入口类(org.consumer.App):

package org.consumer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
* Hello world!
*
*/
@SpringBootApplication
@EnableEurekaClient
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}

@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}

// 负载均衡策略
@Bean
public IRule myRule() {
return new RandomRule();
}
}
 

其中@SpringBootApplicaiton是springboot项目中,制定项目启动入口注解;

其中@EnableEurekaClient是注解该project为Eureka-Client。

4)编写服务提供(org.consumer.controller.DemoController)类

package org.consumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class RibbonController {

@Autowired
RestTemplate restTemplate;

@GetMapping("/getProviderInfo")
public String getProviderInfo() {
String result = this.restTemplate.getForObject("http://spring-cloud-producer/getPortInfo", String.class);
        return result;
}
}
 

注意:上边代码中访问provider的url(http://spring-cloud-producer/)其实是 provider项目中application.yml中的配置项spring.application.name配置的值。

5)在product的根下创建Dockerfile

Dockerfile是docker maven plugin生成image时需要依赖的文件,否则无法正确生成image,Dockerfile中配置信息如下:

# 基于哪个镜像
FROM java:8
# 将本地文件夹挂载到当前容器
VOLUME /tmp
# 拷贝文件到容器,consumer.jar这里是maven打包后的名字
ADD ./target/consumer.jar consumer.jar
RUN bash -c 'touch /consumer.jar'
# 配置容器启动后执行的命令
ENTRYPOINT  ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/consumer.jar"]

6)使用maven工具生成docker image

在eclipse中选中该consumer项目-》Run As-》Maven install进行项目编译就会通过mvn docker插件将生成images到本地docker上。

或者通过mvn命令也行:

进入consumer项目根目录下,通过mvn命令mvn package来生成images

dx:provider $ mvn package -Ddockerfile.skip=false

mvn clean package -Ddockerfile.skip=false

此时查看Docker上的images列表如下:

dx:server $ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
mall/product        1.0.0               614560332af7        About 1 hours ago    724MB
mall/server         1.0.0               b195029b462d        12 hours ago         735MB
mall/consumer 1.0.0 iudksjd95029 About a minute ago 733MB
java 8 d23bdf5b1b1b 2 years ago 643MB dx:server $

出现上边信息说明已经成功生成了mall/consumer镜像。

7)在consumer项目根下创建docker-componse.yml重新编排文件,文件内容如下:

version: '3.5'
services:
  slave1:
    container_name: c1
    image: mall/consumer:1.0.0
    networks:
      - mall-server-net
    ports:
      - 6761:6761
    environment:
      - SPRING_PROFILES_ACTIVE=slave1


networks:
  mall-server-net:
    name: mall-server-net
    driver: bridge

通过docker-compose构建container时,这里指定只启动一个cotainer实例。

执行docker-compose重新编排。

dx:server $ pwd
/Users/dz/work/springcloud-test/mall/server
dx:server $ cd ..
dx:mall $ cd consumer/
dx:consumer $ ls
Dockerfile        docker-compose.yml    pom.xml            src            target
dx:consumer $ docker-compose -f docker-compose.yml up -d
Creating c1 ... done
dx:consumer $ docker ps -a
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                    NAMES
ee3c8c4968eb        mall/product:1.0.0   "java -Djava.securit…"   1 hours ago         Up 1 hours          0.0.0.0:7762->7762/tcp   p2
893af08a6d8a        mall/product:1.0.0   "java -Djava.securit…"   1 hours ago         Up 1 hours          0.0.0.0:7763->7763/tcp   p3
02bea113a771        mall/product:1.0.0   "java -Djava.securit…"   1 hours ago         Up 1 hours          0.0.0.0:7761->7761/tcp   p1
e4b21fd1eb29        mall/server:1.0.0    "java -Djava.securit…"   10 hours ago        Up 10 hours         0.0.0.0:8761->8761/tcp   s1
9c798524acb1        mall/server:1.0.0    "java -Djava.securit…"   10 hours ago        Up 10 hours         0.0.0.0:8763->8763/tcp   s3
bd047426e71b        mall/server:1.0.0    "java -Djava.securit…"   10 hours ago        Up 10 hours         0.0.0.0:8762->8762/tcp   s2
ioweu2992333        mall/consumer:1.0.0  "java -Djava.securit…"   7 seconds ago       Up 6 seconds        0.0.0.0:6761->6761/tcp   c1
dx:consumer $

此时说明consumer容器已经启动,访问路径:http://slave1:6761/getProviderInfo

此时可能返回:The port is 7762

刷新后返回信息端口号会变化。

其他资源相同资源可参考:

1)《搜云技术团队-SpringCloud

2)《利用docker、docker-compose部署Eureka集群的完全详细步骤

3)《spring cloud---坏~牧羊人

原文地址:https://www.cnblogs.com/yy3b2007com/p/11556891.html