VS Code开发Spring Boot + Cloud示例(五)服务注册和发现示例(Docker + Consul)

运行环境:
Windows 10 专业版
Docker for Windows 18.06.0-ce(安装方法参见win10环境下安装Docker

主要参考文章《springcloud(十三):Eureka 2.X 停止开发,但注册中心还有更多选择:Consul 使用详解

1 我对Consul的理解

Consul是什么,为什么用Consul,请大家看上面提到的Consul使用详解或百度。这里列出一些我试出来或理解的一些东西。

  1. datacenter(数据中心):提供了多数据中心功能,可以把注册和发现服务根据地域、组织、系统划分开,组建不同的数据中心,访问本地数据中心的server可以发现别的数据中心的service。
  2. server节点:主要提供注册服务,多个节点可以组成集群,集群中注册的所有service各节点都能访问。
  3. client节点:主要提供发现服务,server一般是3、5各组成集群,而client则没限制。
  4. service(服务生产者):可以在一个server节点上注册多个同名service来实现负载均衡,也可以把一个service注册到多个server节点上来防止因某个server节点挂了而找不到注册在它下面的service。
  5. consumer(服务消费者):想调用service的微服务都是服务消费者。

2 用docker运行consul集群

2.1 下载consul镜像

docker pull consul
docker images

下载consul镜像
这里写图片描述

2.2 创建数据中心dc1

注意:带”$(“这种命令的操作必须在PowerShell下执行。

docker run -d -h node1 --name node1 -p 8501:8500 consul agent -server -bootstrap-expect=3 -client 0.0.0.0 -ui
$JOIN_IP="$(docker inspect -f '{{.NetworkSettings.IPAddress}}' node1)"
docker run -d -h node2 --name node2 -p 8502:8500 consul agent -server -join $JOIN_IP -client 0.0.0.0 -ui
docker run -d -h node3 --name node3 -p 8503:8500 consul agent -server -join $JOIN_IP -client 0.0.0.0 -ui
docker run -d -h node4 --name node4 -p 8504:8500 consul agent -server -join $JOIN_IP -client 0.0.0.0 -ui
docker run -d -h node5 --name node5 -p 8505:8500 consul agent -server -join $JOIN_IP -client 0.0.0.0 -ui
docker run -d -h node6 --name node6 -p 8506:8500 consul agent -join $JOIN_IP -client 0.0.0.0 -ui
docker exec node1 consul members

这里写图片描述
-d:在后台运行
-h:容器的主机名(也就是consul节点的名字)
–name:容器名称(可以指定名字删除容器)
-p:把容器内的端口映射到宿主机(我们可以把每个节点的端口都映射出来)
-server:作为server节点(node6没加这参数就是client节点)
-bootstrap-expect=3:至少3个server节点才算正常的集群
-client 0.0.0.0:表示接受任何客户端连接
-ui:能访问web管理页面(-p和-client也必须设好)
JOIN_IP:把node1的ip地址设为变量(cmd不支持,必须PowerShell)
-join $JOIN_IP:把节点加入到某个IP,组成集群(新的节点只要加到已有集群中任何一个IP都行)
docker exec node1 consul members:运行node1(随便哪个)的consul members命令,查看集群情况

2.3 创建dc2

docker run -d -h node21 --name node21 -p 8521:8500 consul agent -server -bootstrap-expect=3 -client 0.0.0.0 -ui -datacenter=dc2
$JOIN_IP="$(docker inspect -f '{{.NetworkSettings.IPAddress}}' node21)"
docker run -d -h node22 --name node22 consul agent -server -datacenter=dc2 -join $JOIN_IP
docker run -d -h node23 --name node23 consul agent -server -datacenter=dc2 -join $JOIN_IP
docker run -d -h node24 --name node24 consul agent -datacenter=dc2 -join $JOIN_IP
docker exec node21 consul members

这里写图片描述
-datacenter=dc2:当前节点的数据中心设为dc2(默认是dc1)
后面3个节点都加入node21组成了集群(必须同数据中心才能组成集群)

2.4 数据中心建立关联

docker exec node1 consul join -wan $JOIN_IP
docker exec node1 consul members -wan

这里写图片描述
node1:数据中心dc1任一节点
JOIN_IP:数据中心dc2任一节点的IP
join -wan:两个数据中心建立关联
members -wan:查看广域网集群情况(两个数据中心的server节点组成了广域网集群)

2.5 用web查看consul

http://localhost:8501/ui/dc2/services

8501可以是前面映射出来的任一个ip,能看到同样的效果,说明集群创建成功了。
这里写图片描述
这里写图片描述
这里写图片描述

2.6 删除docker容器

如果容器创建失败或不想要了,可以删除某个或全部容器。

docker stop node1
docker rm node1
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

3 服务注册和发现

3.1 创建子项目

  1. 关闭VS Code文件夹
  2. 用《创建Spring Boot示例项目》的方法创建空项目,保存到spring-cloud-demo\discovery-consul-server文件夹,并打开discovery-consul-server,VS Code会自动创建项目相关文件。创建好后的目录结构如下图:
    这里写图片描述
  3. 修改相关文件
    .project中修改项目名称discovery-consul-server
    DemoApplication.java改名为ConsulServerApplication.java
    application.properties改名为application.yml
    DemoApplicationTests.java改名为ConsulServerApplicationTests.java
    这里写图片描述
  4. 关闭文件夹
  5. 用同样的方式创建discovery-consul-client子项目

3.2完善代码

  1. 用VS Code打开spring-cloud-demo文件夹。
  2. 自动刷新项目时如果发现不正常,可能是缓存问题,可以删除C:\Users\hugo\AppData\Roaming\Code\CachedData下的东西后重新打开文件夹。
  3. 增加相关类文件
    server的HelloController.java
    client的CallHelloController.java、ServiceController.java
    这里写图片描述
    这里写图片描述
  4. 修改setting,包含子项目
    include ‘discovery-consul-server’
    include ‘discovery-consul-client’
    这里写图片描述
  5. 修改build.gradle
    主项目build.gradle增加springCloudVersion = ‘Finchley.RELEASE’
    这里写图片描述
    server和client子项目build.gradle去掉通用配置,增加个性化配置(两个文件一模一样)
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-actuator')
    compile('org.springframework.cloud:spring-cloud-starter')
    compile('org.springframework.cloud:spring-cloud-starter-consul-discovery')
} 

6.完善server代码
ConsulServerApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient //表示支持服务发现
public class ConsulServerApplication {

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

application.yml

spring:
    cloud:
        consul:
            host: 127.0.0.1
            port: 8502
            discovery:
                instance-id: consul-server1
                serviceName: consul-server
                hostname: 192.168.3.115
    application:
        name: spring-cloud-consul-server
server:
    port: 8511

consul:server因为已经映射出来,所以就是本机IP(别的电脑想连你的consul就要用你的局域网IP)
consul:port因为都映射出来了,所以可以是8501-8506、8521任一个端口(指定哪个就注册在哪个节点下面)
instance-id本服务的id,同名服务这个id要不同才好区分
serviceName服务名称,服务消费者靠这个找到服务
hostname告诉consul本服务的IP
server:port指定并告诉consul本服务的端口

7.完善client代码
ConsulClientApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ConsulClientApplication {

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

CallHelloController.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class CallHelloController {

    @Autowired
    private LoadBalancerClient loadBalancer;

    @RequestMapping("/call")
    public String call() {
        ServiceInstance serviceInstance = loadBalancer.choose("consul-server");
        System.out.println("服务地址:" + serviceInstance.getUri());
        System.out.println("服务名称:" + serviceInstance.getServiceId());

        String callServiceResult = new RestTemplate().getForObject(serviceInstance.getUri().toString() + "/hello", String.class);
        System.out.println(callServiceResult);
        return callServiceResult;
    }

}

ServiceController.java

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServiceController {

    @Autowired
    private LoadBalancerClient loadBalancer;
    @Autowired
    private DiscoveryClient discoveryClient;

   /**
     * 获取所有服务
     */
    @RequestMapping("/services")
    public Object services() {
        return discoveryClient.getInstances("consul-server");
    }

    /**
     * 从所有服务中选择一个服务(轮询)
     */
    @RequestMapping("/discover")
    public Object discover() {
        return loadBalancer.choose("consul-server").getUri().toString();
    }
}

application.yml

spring:
    cloud:
        consul:
            host: 127.0.0.1
            port: 8503
            discovery:
                register: false

    application:
        name: spring-cloud-consul-client
server:
    port: 8601

register: false表示不注册到consul

3.3 调试

  1. 生成调试配置

    删除launch.json后按F5重新生成,删除多余的配置
    这里写图片描述

  2. 运行server
    这里写图片描述
    访问http://localhost:8501 能看到服务已注册
    这里写图片描述

  3. 运行client
    这里写图片描述
    访问http://localhost:8601/discover
    http://localhost:8601/services
    http://localhost:8601/call
    能正常显示说明服务发现成功
    这里写图片描述
    这里写图片描述
    这里写图片描述

猜你喜欢

转载自blog.csdn.net/hugowang/article/details/82218882