Spring Cloud

微服务概念

微服务组件示意图

image-20211019105136125

核心问题

  • 服务很多客户端怎么访问
  • 这么多服务如何通信
  • 如何治理
  • 服务崩溃怎么解决

注册中心

介绍

介你麻痹

学习顺序

image-20211019153453227

CAP原则

image-20211021110645846

A 可用性、C 一致性、P 分布式

  • Availability 可用性

  • Partition-Tolerance 分区容错性

  • Consistency 一致性

CP 效率低(牺牲可用性)

AP 牺牲一致性 (有脏数据)

CA 牺牲横向可扩容

对比

image-20211019154311484

Consul 注册中心

介绍

image-20211026224102258

调用方式

image-20211028012223931

特性

角色

  • client: 客户端,无状态,将HTTP和DNS接口请求转发给局域网内的服务端集群
  • server: 服务端,保存配置信息,高可用集群,每个配置数据中心的server数量推荐为3个或五个。

模式

  • dev

  • cluster client/server

    image-20211027233134980

工作原理

image-20211027003221980

安装consul

  • 从官网下载

  • 拷贝到 D:\Program Files\consul中

  • 创建 CONSUL_HOME 环境变量并且加入到PATH中

  • consul agent -dev -client=0.0.0.0

    [命令] [角色 ] [模式] [有权的访问者]

  • 查看localhost:8500

    如果localhost:8500 无法访问端口占用,可以找个linxu启动

    • linxu

      1
      2
      3
      sudo yum install -y yum-utils
      sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
      sudo yum -y install consul

Spring Cloud接入consul

  • 创建 一个spring cloud项目

  • 查看官网 https://spring.io/projects/spring-cloud-consul

  • 引入 pom

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    <version>3.0.4</version>
    </dependency>
  • yml配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    server:
    port: ${SERVER_PORT:17180}
    spring:
    application:
    name: consul-demo-service-product
    cloud:
    inetutils:
    ignoredInterfaces: ['VMware.*','ingress'] # 必须过滤掉VMware 因为会豁达86.1
    preferred-networks:
    - ${NET_DOMAIN:192.168/16} #必须只选择192网段的否则会选择一些虚拟机网卡
    consul:
    host: localhost
    port: 8500
    discovery:
    register: true
    instance-id: ${spring.application.name}-${spring.cloud.client.hostname}-${server.port} # 必须加入名字和端口否则ID会相同
    service-name: ${spring.application.name}
    prefer-ip-address: true
    # ip-address: ${spring.cloud.client.ip-address} #这里不能写会导致错误的IP
    management:
    endpoints:
    web:
    exposure:
    include: '*'
    endpoint:
    shutdown:
    enabled: true

    该死的国外资料真TM好

    源码在这:https://github.com/spring-cloud/spring-cloud-commons/blob/ca1a97a3a484910527b17e95ae2cc6e1c06722c6/spring-cloud-commons/src/main/java/org/springframework/cloud/commons/util/InetUtils.java#L76

  • 写一个Product服务 要有端口信息

  • 再写一个Order服务 并且调用自己ideProduct

  • 在Order中通过RestTemplet调用。

集群案例

环境准备表

服务器IP Consul类型 NODE节点
192.168.3.190 server server-01
192.168.3.191 server server-02
192.168.3.192 server server-03
192.168.3.148 clinet client-01

安装

1
2
3
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install consul

网络下载太忙就到官方下载 x86的zip包

  • zip安装
1
2
3
4
5
6
7
unzip consul_1.10.3_linux_amd64.zip -d /usr/local/consul
# 添加环境变量
vi /etc/profile
export CONSUL_HOME=/usr/consul
export PATH=$CONSUL_HOME:$PATH
# 测试
echo $PATH

启动集群

1
2
3
4
5
6
7
8
9
10
11
#关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
sed -i 's/enforcing/disabled/' /etc/selinux/config
setenforce 0
#启动服务
consul agent -server -bind=192.168.3.190 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/consul/data -node=server-01
#启动客户端
consul agent -bind=192.168.3.148 -client=0.0.0.0 -data-dir=D:\Example\consul\data -node=client-01
#关联集群 显示关联主节点 在clinet和所有服务器上执行
consul join 192.168.3.190

​ 参数含义:

  • -bootstrap-expect=3: 表示至少三个节点
  • -bind:表示绑定的ip
  • -server :表示以服务端启动
  • -ui:带有web界面
  • -data-dir:数据存放地址
  • -node:服务名

查看集群成员

1
2
3
4
5
6
C:\Users\dell> consul members
Node Address Status Type Build Protocol DC Segment
server-01 192.168.3.190:8301 alive server 1.10.3 2 dc1 <all>
server-02 192.168.3.191:8301 alive server 1.10.3 2 dc1 <all>
server-03 192.168.3.192:8301 alive server 1.10.3 2 dc1 <all>
client-01 192.168.3.148:8301 alive client 1.10.3 2 dc1 <default>

docker环境无部署consul

搭建docker私有仓库

创建私有仓库
  1. 创建密码

    1
    2
    mkdir auth
    docker run --entrypoint htpasswd httpd:2 -Bbn akachi TS8495877 > auth/htpasswd

    可能遇得到httpd:2下载不到的问题

    参考以下解决问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 1、阿里云docker加速器配置文件
    sudo mkdir -p /etc/docker

    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
    "registry-mirrors": ["https://s796m7v3.mirror.aliyuncs.com"]
    }
    EOF

    sudo systemctl daemon-reload

    sudo systemctl restart docker
  2. yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    services:
    registry:
    image: registry:2.7.1
    ports:
    - 5000:5000
    networks:
    - registry
    volumes:
    - ./data:/var/lib/registry
    - ./auth:/auth
    mem_limit: 256m
    restart: always
    environment:
    - "REGISTRY_AUTH=htpasswd"
    - "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm"
    - "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd"
    networks:
    registry:
  3. 登陆

    1
    docker login entry.akachi:5000

    报错:

    Error response from daemon: Get “https://192.168.3.140:5000/v2/": http: server gave HTTP response to HTTPS client

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    sudo mkdir -p /etc/docker

    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
    "registry-mirrors": ["https://s796m7v3.mirror.aliyuncs.com"],
    "insecure-registries": ["http://entry.akachi:5000"]
    }
    EOF

    sudo systemctl daemon-reload

    sudo systemctl restart docker
  4. 退出

    1
    docker logout entry.akachi:5000
  5. 考虑SSH的情况

    看文档这里没试

    创建ssh授权书

    1
    2
    mkdir -p certs
    openssl req -newkey rsa:4096 -nodes -sha256 -keyout certs/entry.akachi.key -x509 -days 3000 -out certs/entry.akachi.crt

    配置域名为entry.akachi

    在其他机器上使用DNS

    在DNS上使用hosts配置

  6. 测试仓库是不是可用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #下载
    docker pull ubuntu:16.04
    #改名
    docker tag ubuntu:16.04 entry.akachi:5000/my-ubuntu
    #上传
    docker push entry.akachi:5000/my-ubuntu
    #删除本地
    docker rmi entry.akachi:5000/my-ubuntu
    docker rmi ubuntu:16.04
    #下载
    docker pull entry.akachi:5000/my-ubuntu

    好测试成功你可以继续玩乐

准备资料
用k8s或者swarm的情境下不需要搭建consul
资料

看看人家的方案:https://segmentfault.com/a/1190000011009638

搭建无consul的微服务

  • DockerFile 在项目根目录上

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    FROM openjdk:11-jre-slim

    MAINTAINER akachi zsts@hotmail.com
    WORKDIR /ROOT
    COPY target/*.jar app.jar
    COPY src/main/resources/application*.* .
    #ENV PROFILES_ACTIVE pro
    EXPOSE 8080

    ENTRYPOINT ["java", "-jar", "app.jar"]
  • 打包命令

    1
    docker build -f DockerFile -t entry.akachi:5000/cloud-demo/product:1.0 .
  • 运行命令测试

    1
    2
    docker run -d -p 17180:17180 entry.akachi:5000/cloud-demo/product:1.0
    docker run -d -p 17280:17280 entry.akachi:5000/cloud-demo/order:1.0
  • pull

    1
    docker pull entry.akachi:5000/cloud-demo/product:1.0
  • 编写dcoker-compose.yml 在任何地方

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    version: "3.9"
    services:
    cloud-demo-order:
    image: entry.akachi:5000/cloud-demo/order:1.0
    deploy:
    mode: replicated
    replicas: 2
    placement:
    max_replicas_per_node: 1
    environment: vip
    PRODUCT_HOST: cloud-demo-product
    ports:
    - 17280:17280
    networks:
    - cloud-demo
    cloud-demo-product:
    image: entry.akachi:5000/cloud-demo/product:1.0
    deploy:
    mode: replicated
    replicas: 4
    placement:
    max_replicas_per_node: 2
    endpoint_mode: vip
    ports:
    - 17180:17180
    networks:
    - cloud-demo
    networks:
    cloud-demo:

Consul 配置中心

consul 特性

  • raft 算法
  • 服务发现
  • 健康检查
  • Key/Value 存储( 配置中心)
  • 多数据中心
  • 支持http和dns协议接口
  • 官方提供Web管理界面

安装

注册中心讲过了

1
2
3
4
5
6
7
unzip consul_1.10.3_linux_amd64.zip -d /usr/local/consul
# 添加环境变量 WINDOWS 也要添加环境变量
vi /etc/profile
export CONSUL_HOME=/usr/consul
export PATH=$CONSUL_HOME:$PATH
# 测试
echo $PATH

运行

1
2
consul agent -dev -client=0.0.0.0
#访问 localhost:8500 我在wsl中启动的

-dev 开发者模式

-client = 允许访问IP

创建资源文件夹

image-20211103154014562

初始化配置目录

  • 创建 config/productService-dev和config/oracleService-dev

初始化项目

  • product 和order 用consul 注册中心启动起来

项目中要导入的包介绍

  • spring-boot-starter-actuator 监控管理时需要
  • spring-cloud-starter-consul-discovery 用于发现服务-调用注册中心
  • spring-cloud-starter-consul-config spring-bootstrap文件导入需要系统级的权限在2020.* 版本禁用乐 如果需要我们需要引入包
  • spring-cloud-starter-consul-config 用于调用配置中心
  • spring-boot-starter-web springweb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>consul-demo</artifactId>
<groupId>org.akachi</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<groupId>org.akachi.consul-demo</groupId>
<artifactId>product</artifactId>

<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.4</spring-cloud.version>
<spring-boot.version>2.5.5</spring-boot.version>
<netflix-eureka-server.version>3.0.4</netflix-eureka-server.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.5.5</version>
</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>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

在resources 目录中创建bootstrap.yml

  • 参考cloud.spring-cloud

    内容基本与application.yml一致

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    server:
    port: ${SERVER_PORT:17180}
    spring:
    application:
    name: consul-demo-service-product
    profiles:
    active: dev # 指定环境,默认加载 default环境也就是无配置信息
    cloud:
    inetutils:
    ignoredInterfaces: [ 'VMware.*','ingress' ] # 必须过滤掉VMware 因为会豁达86.1
    preferred-networks:
    - ${NET_DOMAIN:192.168/16} #必须只选择192网段的否则会选择一些虚拟机网卡
    consul:
    host: ${CONSUL_HOST:localhost}
    port: 8500
    config: #使用consul配置中心
    enabled: true
    prefixes: [ "config" ] #路径
    default-context: productService
    profile-separator: '-' # 分隔符
    format: yaml
    data-key: appCconfig #文件名
    watch: #检查更新
    enabled: true
    delay: 1000
    discovery:
    register: true
    instance-id: ${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}} # 必须加入名字和端口否则ID会相同
    service-name: ${spring.application.name}
    prefer-ip-address: true
    # ip-address: ${spring.cloud.client.ip-address} #这里不能写会导致错误的IP
    management:
    endpoints:
    web:
    exposure:
    include: '*'
    endpoint:
    shutdown:
    enabled: true
  • 在consul上创建 appConfig

    1
    2
    3
    4
    5
    6
    name: order-service-dev
    mysql:
    host: localhost
    port: 3306
    username: root
    password: root
  • 在项目内用注解加载配置

    • @Value(“${name}”)

      加载单一配置项

    • @ConfigurationProperties(“mysql”)

      加载配置对象下的所有属性到Class

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      package org.akachi.eurekademo.product.config;

      import lombok.Data;
      import org.springframework.boot.context.properties.ConfigurationProperties;
      import org.springframework.cloud.context.config.annotation.RefreshScope;
      import org.springframework.stereotype.Component;

      /**
      * @Author akachi
      * @Email zsts@hotmail.com
      * @Date 2021/11/3 17:24
      */
      @Component
      @RefreshScope
      @ConfigurationProperties("mysql")
      @Data
      public class MySqlProperties {
      private String host;
      private Integer port;
      private String username;
      private String password;
      }
    • @RefreshScope 需要根据配置文件变化的类需要加入“刷新作用域”的注解

实际上我们可以只在启动配置中写入最少量的配置

  • bootstrap.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    spring:
    profiles:
    active: dev # 指定环境,默认加载 default环境也就是无配置信息
    cloud:
    consul:
    host: ${CONSUL_HOST:localhost}
    port: 8500
    config: #使用consul配置中心
    enabled: true
    prefixes: ["config"]#路径
    default-context: productService
    profile-separator: '-' # 分隔符
    format: yaml
    data-key: appConfig #文件名
    watch: #检查更新
    enabled: true
    delay: 1000
  • /config/orderProduct-dev/appConfig

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    name: product-dev
    mysql:
    username: root
    password: root
    port: 3306
    host: localhost
    server:
    port: ${SERVER_PORT:17180}
    spring:
    application:
    name: consul-demo-service-product
    profiles:
    active: dev # 指定环境,默认加载 default环境也就是无配置信息
    cloud:
    inetutils:
    ignoredInterfaces: [ 'VMware.*','ingress' ] # 必须过滤掉VMware 因为会豁达86.1
    preferred-networks:
    - ${NET_DOMAIN:192.168/16} #必须只选择192网段的否则会选择一些虚拟机网卡
    consul:
    host: ${CONSUL_HOST:localhost}
    port: 8500
    config: #使用consul配置中心
    enabled: true
    prefixes: ["config"]#路径
    default-context: productService
    profile-separator: '-' # 分隔符
    format: yaml
    data-key: appConfig #文件名
    watch: #检查更新
    enabled: true
    delay: 1000
    discovery:
    register: true
    instance-id: ${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}} #必须加入名字和端口否则ID会相同
    service-name: ${spring.application.name}
    prefer-ip-address: true
    # ip-address: ${spring.cloud.client.ip-address} #这里不能写会导致错误的IP
    management:
    endpoints:
    web:
    exposure:
    include: '*'
    endpoint:
    shutdown:
    enabled: true

运行后测试是否成功访问就可以了profiles.active

如果为空则没有-dev 直接为orderService 目录

备份和还原数据

1
2
3
4
5
#启动命令
consul agent -dev -client=0.0.0.0 -ui-data-dir=/home/akachi/consul/data
## 备份和还原
- consul snapshot save data/backup.snap
- consul snapshot restore data/backup.snap

dokcer环境部署全套 consul

问题1:

dockers环境弹性启动每个实例用的同一个yml所以很可能无法区分ID导致注册中心只知道一个实例

解决方案:

加入

$HOST_NAME

1
2
#!/bin/sh
export HOST_NAME=`hostname`

启动的时候加入一个环境变量$HOST_NAME

yml中加入环境变量

1
2
3
4
eureka.instance.hostname = ${HOST_NAME}
# 看你用什么注册中心了
consul.instance.hostname = ${HOST_NAME}

确保在yml的instanceId中有consul.instance.hostname的属性

问题2

consul 的k/v没有版本控制。通过git2consul加入版本控制

问题3

怎么在docker swarm 上搭建consul 集群

问题素材:

取得容器IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
docker run --detach --name consul --hostname consul-server-1 progrium/consul 
-server -bootstrap -ui-dir /ui

# Get container ip for further interactions
CONSUL_IP=$(docker inspect -f '{{ .NetworkSettings.IPAddress }}' consul)

# The container also runs a web UI at $CONSUL_IP:8500/ui

# 举个栗子 获得tomcatIP如下
docker inspect -f '{{ .NetworkSettings.Networks.tomcat01_default.IPAddress }}'

CONSUL_IP=$(docker inspect -f '{{ NetworkSettings.Networks.tomcat01_default.IPAddress }}' consul)
8eb571af2ac1

资源

搭建基于Docker Swarm 的 consul集群注册中心实战

准备

  • 下载consul

    • windows 下载

      https://www.consul.io/downloads

      https://releases.hashicorp.com/consul/1.12.2/consul_1.12.2_windows_386.zip

    • consul docker

      https://hub.docker.com/_/consul

      • 参考

        image-20220615160710853

      • 还有这个

        https://blog.csdn.net/liushengit/article/details/118693363

      融合两个内容我们编写出一个可以运行并自激活的consul-compose.yml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      version: '3.8'

      services:
      consul-server1:
      image: consul
      ports:
      - 8510:8500
      - 8310:8300
      - 8311:8301
      - 8312:8302
      - 8610:8600
      environment:
      - CONSUL_BIND_INTERFACE=eth0
      deploy:
      mode: global
      placement:
      constraints:
      - node.hostname == Docker-swarm-manager01
      command: >
      agent -server -ui
      -node=consul-server1
      -bootstrap-expect=3
      -client=0.0.0.0
      -retry-join=consul_consul-server2
      -retry-join=consul_consul-server3
      -retry-join=consul_consul-server4
      -data-dir=/consul/data
      -datacenter=dc1
      volumes:
      - /nfs/docker/volumes/consul/server1:/consul/data
      networks:
      consul-net:
      consul-server2:
      image: consul
      ports:
      - 8520:8500
      - 8320:8300
      - 8321:8301
      - 8322:8302
      - 8620:8600
      environment:
      - CONSUL_BIND_INTERFACE=eth0
      deploy:
      mode: global
      placement:
      constraints:
      - node.hostname == Docker-swarm-manager02
      command: >
      agent -server -ui
      -node=consul-server2
      -bootstrap-expect=3
      -client=0.0.0.0
      -retry-join=consul_consul-server1
      -retry-join=consul_consul-server3
      -retry-join=consul_consul-server4
      -data-dir=/consul/data
      -datacenter=dc1
      volumes:
      - /nfs/docker/volumes/consul/server2:/consul/data
      networks:
      consul-net:
      consul-server3:
      image: consul
      ports:
      - 8530:8500
      - 8330:8300
      - 8331:8301
      - 8332:8302
      - 8630:8600
      environment:
      - CONSUL_BIND_INTERFACE=eth0
      deploy:
      mode: global
      placement:
      constraints:
      - node.hostname == Docker-swarm-manager03
      command: >
      agent -server -ui
      -node=consul-server3
      -bootstrap-expect=3
      -client=0.0.0.0
      -retry-join=consul_consul-server1
      -retry-join=consul_consul-server2
      -retry-join=consul_consul-server4
      -data-dir=/consul/data
      -datacenter=dc1
      volumes:
      - /nfs/docker/volumes/consul/server3:/consul/data
      networks:
      consul-net:
      consul-server4:
      image: consul
      ports:
      - 8540:8500
      - 8340:8300
      - 8341:8301
      - 8342:8302
      - 8640:8600
      environment:
      - CONSUL_BIND_INTERFACE=eth0
      deploy:
      mode: global
      placement:
      constraints:
      - node.hostname == Docker-swarm-worker04
      command: >
      agent -server -ui
      -node=consul-server4
      -bootstrap-expect=3
      -client=0.0.0.0
      -retry-join=consul_consul-server1
      -retry-join=consul_consul-server2
      -retry-join=consul_consul-server3
      -data-dir=/consul/data
      -datacenter=dc1
      volumes:
      - /nfs/docker/volumes/consul/server4:/consul/data
      networks:
      consul-net:
      networks:
      consul-net:
      ipam:
      driver: default
      config:
      - subnet: "192.168.87.0/24"

image-20220617204819411

启动

  • 在 docker swarm上启动服务端

    • 首先在所有机器上(除非使用网络文件系统)创建相应的文件夹

      /nfs/docker/volumes/consul/server3

    • 执行docker stack deploy -c consul-compose.yml

创建项目

pom.xml

需要引入的包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>

YML及解读

基于consul搭建带openfegin的配置文件

这是client端口的,其他只会更加简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
server:
port: ${SERVER_PORT:19111}
spring:
application:
name: consul-demo-get
cloud:
inetutils:
preferred-networks: ${PREFERRED_NETWORKS:172\.(.*)}
consul:
host: ${CONSUL_HOST:localhost}
port: ${CONSUL_PORT:8500}
discovery:
prefer-ip-address: true
tags: version=1.0
instance-id: ${spring.application.name}:${spring.cloud.client.hostname}:${spring.cloud.client.ip-address}:${server.port}
healthCheckInterval: 15s
feign:
client:
config:
default:
connectTimeout: 3000
readTimeout: 3000
loggerLevel: basic
httpclient:
enabled: false
okhttp:
enabled: true
circuitbreaker:
enabled: true
alphanumeric-ids:
enabled: true
management:
endpoints:
web:
exposure:
include: "*"

circuitbreaker不工作的关键异常

必须引入包resilience4j

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-circuitbreaker-resilience4j -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
<version>2.1.3</version>
</dependency>
参考:

https://stackoverflow.com/questions/69524571/spring-cloud-openfeign-3-0-1-fallback-not-being-triggered

下次可以去:https://www.baeldung.com/ 上找例子

搭建client

创建两个client模式运行的consul,consul必须要能够相互连接的网络才可以使用。

1
2
3
4
5
6
7
8
9
# 安装consul consul.io去安装
# 创建 consul目录
mkdir consul
# 在四台机器上创建data目录
cd consul
mkdir data
#创建start.sh 并且写入一下内容
vi start.sh
consul agent -ui -node=client_wsl -client=0.0.0.0 -retry-join=192.168.2.50 -retry-join=192.168.2.51 -retry-join=192.168.2.52 -retry-join=192.168.2.53 -data-dir=/root/consul/data -datacenter=dc1 > consul_client.log &

搭建服务端之前的不能用

由于我们需要测试集群,而集群而端口被docker swarm 更改过所以需要重新搭建集群在8500上

  • 搭建四台服务器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 安装consul consul.io去安装
    # 创建 consul目录
    mkdir consul
    # 在四台机器上创建data目录
    cd consul
    mkdir data
    #创建start.sh 并且写入一下内容
    vi start.sh
    consul agent -server -ui -node=server1 -bootstrap-expect=3 -client=0.0.0.0 -bind=192.168.2.50 -retry-join=192.168.2.51 -retry-join=192.168.2.52 -retry-join=192.168.2.53 -data-dir=/root/consul/data -datacenter=dc1 > consul.log &
    consul agent -server -ui -node=server2 -bootstrap-expect=3 -client=0.0.0.0 -retry-join=192.168.2.50 -bind=192.168.2.51 -retry-join=192.168.2.52 -retry-join=192.168.2.53 -data-dir=/root/consul/data -datacenter=dc1 > consul.log &
    consul agent -server -ui -node=server4 -bootstrap-expect=3 -client=0.0.0.0 -retry-join=192.168.2.50 -retry-join=192.168.2.51 -bind=192.168.2.52 -retry-join=192.168.2.53 -data-dir=/root/consul/data -datacenter=dc1 > consul.log &
    consul agent -server -ui -node=server3 -bootstrap-expect=3 -client=0.0.0.0 -retry-join=192.168.2.50 -retry-join=192.168.2.51 -retry-join=192.168.2.52 -bind=192.168.2.53 -data-dir=/root/consul/data -datacenter=dc1 > consul.log &
    #./start.sh

创建docker

  • 编写dockerfile

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    FROM openjdk:11-jre-slim

    MAINTAINER akachi zsts@hotmail.com
    WORKDIR /ROOT
    COPY target/*SNAPSHOT.jar app.jar
    COPY src/main/resources/application*.properties .
    ENV PROFILES_ACTIVE dev
    EXPOSE 8080

    ENTRYPOINT ["java", "-jar", "app.jar"]
  • 构建

    docker build -t [server]:[port]/[path]/[name]:[tag] .

  • 上传

    docker push [allname]:[tag]

加入stack

  • 默认情况下调用docker stack deploy 只会更新用到的service,除非加入–prune 才会清理不存在的service

  • 编写一个demo-stack.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    version: "3.8"
    services:
    demo-get:
    image: 192.168.2.129:5000/clairvoyants/demo-get
    environment:
    - PROFILES_ACTIVE=dev
    - CONSUL_HOST=demo-get-consul
    ports:
    - 19111:19111
    depends_on:
    - demo-get-consu
    networks:
    consul-net:
    demo-get-consul:
    image: consul
    environment:
    - CONSUL_BIND_INTERFACE=eth0
    command: >
    agent -ui
    -node=demo-get-consul
    -client=0.0.0.0
    -retry-join=consul_consul-server1
    -retry-join=consul_consul-server2
    -retry-join=consul_consul-server3
    -retry-join=consul_consul-server4
    -data-dir=/consul/data
    networks:
    consul-net:
    demo-source:
    image: 192.168.2.129:5000/clairvoyants/demo-source
    environment:
    - PROFILES_ACTIVE=dev
    - CONSUL_HOST=demo-source-consul
    ports:
    - 19101:19101
    depends_on:
    - demo-source-consul
    networks:
    consul-net:
    demo-source-consul:
    image: consul
    environment:
    - CONSUL_BIND_INTERFACE=eth0
    command: >
    agent -ui
    -node=demo-source-consul
    -client=0.0.0.0
    -retry-join=consul_consul-server1
    -retry-join=consul_consul-server2
    -retry-join=consul_consul-server3
    -retry-join=consul_consul-server4
    -data-dir=/consul/data
    networks:
    consul-net:
    networks:
    consul-net:
    ipam:
    driver: default
    config:
    - subnet: "192.168.87.0/24"

    每个service都带有一个consul,为了方便,我还没搞明白怎么安装一个consul到JDK的docker中先这么用把。

  • 启动 docker

    docker stack deploy -c demo-compose.yml consul –with-registry-auth

    –with-registry-auth 必须加否则不会down image

编写getway