Spring cloud Gateway 服务网关 实战

news2024/12/26 10:50:24

Spring cloud Gateway 服务网关

    • 一、简介
      • 优点:
      • 特性:
      • 总结:
    • 二、核心概念
    • 三、路由规则
      • 1、Path
      • 2、Query
      • 3、Method
      • 4、Datetime
      • 5、RomoteAddr
      • 6、Header
    • 四、动态路由
      • 1、依赖
      • 2、配置
        • 动态获取URI
        • 服务名称转发
    • 五、过滤器
      • 1、网关过滤器 GatewayFilter
        • 局部
          • Path 过滤器
          • Parameter 参数过滤器
          • Status 状态过滤器
        • 全局
      • 2、全局过滤器 GlobalFilter
      • 3、自定义过滤器
          • 自定义网关过滤器
          • 自定义全局过滤器
    • 六、网关限流
      • 1、原因
      • 2、限流算法
        • 计算器算法
        • 漏桶算法(Leaky)
        • 令牌桶算法(Token)
      • 3、实例
        • URI 限流
        • 参数限流
        • IP 限流
    • 七、高可用网关
      • 1、项目结构
      • 2、配置文件
        • **parent 中的 pom.xml**
        • **nginx.conf**
        • **dockerFile**
        • **docker-compose.yml**
      • 3、docker 部署
        • **Maven 打包**
        • **docker部署**

一、简介

微服务中,客户端调用服务时,将服务分发到对应的微服务

优点:

zuul 使用阻塞式模型,一个请求一个线程,高并发压力大,已经停止维护。

gateway 使用非阻塞式响应模型,基于Netty使用webFlux,用于替代 Tomcat

  • 客户端无需多次请求不同的微服务,降低了客户端的复杂性
  • 解决跨域问题
  • 解决身份认证问题
  • 解决了项目迭代问题
  • 解决了一些协议的问题

特性:

  • 统一接入:

    为各种无线应用提供统一接入入口

    高性能、高并发、高可靠

    负载均衡、容灾切换(异地多活)

  • 流量监管

    服务降级

    熔断

    路由(异地多活中的应用)

  • 安全防护

    和安全部合作,IP 黑名单,URL 黑名单

    风控防刷,恶意攻击等

  • 协议适配

    前端系统(http、https)后端(RPC)

    长连接、短链接支持

    根据请求路由分配至相应的 SOA 服务并执行

总结:

  • 性能:API 高可用、负载均衡、容错机制
  • 安全:权限身份认证,流量清洗,黑名单,后端签名等
  • 日志:日志记录,一旦涉及分布式,全链路跟踪必不可少
  • 缓存:数据缓存
  • 监控:记录请求响应数据,API 耗时分析,性能监控
  • 限流:流量控制,错峰流控,可定义多种限流规则
  • 灰度:线上灰度部署,减小风险
  • 路由:动态路由

二、核心概念

  • 路由:是网关最基础的部分,由ID、目标URI、一组断言和一组过滤器组成,断言为真说明请求的 URI 和配置匹配
  • 断言:Java 8 中的断言函数,允许自定义匹配来自于 Http Request 中的任何信息
  • 过滤器:标准的 Spring Web Filter 对请求和响应进行处理

三、路由规则

1、Path

spring:
  cloud:
    # 路由规则
    gateway:
      routes:
        # 将 http://localhost:9000/product/** 路由至 http://localhost:7070/product/**
        - id: provider                  # 路由 ID,唯一
          uri: http://localhost:7070/   # 目标 URI,路由到微服务的地址
          predicates:                   # 断言(判断条件)
            - Path=/product/**          # 匹配对应的 URL 请求

2、Query

spring:
  cloud:
    # 路由规则
    gateway:
        # 将 http://localhost:9000/product/** 路由至 http://localhost:7070/product/**
        - id: order                     # 路由 ID,唯一
          uri: http://localhost:6060/   # 目标 URI,路由到微服务的地址
          predicates:                   # 断言(判断条件)
            - Query=name                # 匹配请求参数中包含 name 的请求
#            - Query=name, abc.          # 匹配请求参数中包含 name 且满足正则表达式 abc. 的请求
  • Query=name: 比如:http://localhost:9000/product/?name=123
  • Query=name,abc.: 比如:http://localhost:9000/product/?name=abc123

3、Method

spring:
  cloud:
    # 路由规则
    gateway:
      routes:
        # Method
        - id: provider                                            # 路由 ID,唯一
          uri: http://localhost:7070/                             # 目标 URI,路由到微服务的地址
          predicates:                                             # 断言(判断条件)
            - Method=GET                                          # 匹配 GET 请求

4、Datetime

spring:
  cloud:
    # 路由规则
    gateway:
      routes:
        # Datetime
        - id: provider                  # 路由 ID,唯一
          uri: http://localhost:7070/   # 目标 URI,路由到微服务的地址
          predicates:                   # 断言(判断条件)
          # 匹配中国上海 2022-06-27 16:00:00 后的时间
            - After=2022-06-27T16:00:00.000+08:00[Asia/Shanghai]

5、RomoteAddr

spring:
  cloud:
    # 路由规则
    gateway:
      routes:
        - id: provider                                            # 路由 ID,唯一
          uri: http://localhost:7070/                             # 目标 URI,路由到微服务的地址
          predicates:                                             # 断言(判断条件)
            # RemoteAddr
            - RemoteAddr=172.16.10.82/0                            # 匹配请求中地址是 172.16.10.82 的请求,/0为子网掩码

API: http://172.16.10.82:9000/product/list

6、Header

spring:
  cloud:
    # 路由规则
    gateway:
      routes:
        - id: provider                                            # 路由 ID,唯一
          uri: http://localhost:7070/                             # 目标 URI,路由到微服务的地址
          predicates:                                             # 断言(判断条件)
            # Header
            - Header=X-Request-Id, \d+                            # 匹配请求头中包含 X-Request-Id 并且其值匹配正则表达式 \d+ 的请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KS9fnrzD-1670555453107)(img/Gateway 路由规则 Header test.png)]

四、动态路由

1、依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

2、配置

动态获取URI

spring:
  cloud:
    # 路由规则
    gateway:
      routes:
        - id: provider                                            # 路由 ID,唯一
          uri: lb://provider                                      # 根据注册中心动态路由
#          uri: http://localhost:7070/                            # 目标 URI,路由到微服务的地址
          predicates:                                             # 断言(判断条件)
            # Path
            - Path=/product/**                                    # 匹配对应的 URL 请求

API:http://localhost:9000/product/list

服务名称转发

spring:
  cloud:
    # 路由规则
    gateway:
      discovery:
        locator:
          # 是否与服务发现组件进行结合,通过 serviceId 转发到具体服务
          enabled: true                      # 是否开启基于服务发现的路由规则
          lower-case-service-id: true        # 是否将服务名称转小写

API前要加服务名称服务名称: http://localhost:9000/provider/product/list

五、过滤器

1、网关过滤器 GatewayFilter

通过 spring.cloud.routes.filters 配置在具体路由下,只作用于当前路由或通过 spring.cloud.default-filters 配置在全局,作用在所有路由上

局部

Path 过滤器
spring:
  cloud:
    # 路由规则
    gateway:
      routes:
        - id: provider                                            # 路由 ID,唯一
          uri: lb://provider                                      # 根据注册中心动态路由
#          uri: http://localhost:7070/                            # 目标 URI,路由到微服务的地址
          predicates:                                             # 断言(判断条件)
            # Path
            - Path=/product/**,/gateway/**                        # 匹配对应的 URL 请求
          filters:
            # 将 /gateway/product/list 重写为 /product/list
            - RewritePath=/gateway(?<segment>/?.*),$\{segment}
            # 请求增加前缀 /list 变为 /product/list 
            - PrefixPath=/product
            # 分割前缀 /api/gateway/product/list 变为 /product/list 
            - StripPrefix=2
            
        - id: provider2                                           # 路由 ID,唯一
          uri: lb://provider                                      # 根据注册中心动态路由
          predicates:                                             # 断言(判断条件)
            # Path          设置参数 segment 
            - Path=/gateway/product/{segment}  
          filters:
            # 将 /gateway/product/list 重写为 /product/list
            - SetPath=/product/{segment}
Parameter 参数过滤器
spring:
  cloud:
    # 路由规则
    gateway:
      routes:
        - id: provider                                            # 路由 ID,唯一
          uri: lb://provider                                      # 根据注册中心动态路由
          predicates:                                             # 断言(判断条件)
            # Path
            - Path=/**                                            # 匹配对应的 URL 请求
          filters:
            # 在下游请求中添加 id = 1
            - AddRequestParameter=id,1
Status 状态过滤器
spring:
  cloud:
    # 路由规则
    gateway:
      routes:
        - id: provider                                            # 路由 ID,唯一
          uri: lb://provider                                      # 根据注册中心动态路由
          predicates:                                             # 断言(判断条件)
            # Path
            - Path=/product/**,/gateway/**                        # 匹配对应的 URL 请求
          filters:
            # 在任何情况下,响应状态码设置为888
            - SetStatus=888

全局

设置全局默认 filters

spring:
  application:
    name: gateway # 应用名称
  cloud:
      # 路由规则
    gateway:
      discovery:
        locator:
          # 是否与服务发现组件进行结合,通过 serviceId 转发到具体服务
          enabled: true                      # 是否开启基于服务发现的路由规则
          lower-case-service-id: true        # 是否将服务名称转小写
      default-filters:
        - PrefixPath=/product

2、全局过滤器 GlobalFilter

无需在配置文件中配置,作用在所有的路由上,最终通过 GatewayFilterAdapter 包装成 GatewayFilterChain 可识别的过滤器,它为请求业务以及路由的 URI 转换为真实业务请求地址的核心过滤器,不需要配置系统初始化时加载,并作用在每个路由上

3、自定义过滤器

自定义网关过滤器

CustomGatewayFilter:实现接口: GatewayFilter,Ordered

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * Date: 2022-06-28 星期二
 * Time: 13:56
 * Author: Dily_Su
 * Remark: 自定义网关协议
 */
public class CustomGatewayFilter implements GatewayFilter, Ordered {

    /**
     * 过滤器业务逻辑
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("自定义网关过滤器被执行");
        return chain.filter(exchange);
    }

    /**
     * 过滤器执行顺序,数值越小,优先级越高
     *
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

Configuration

import com.study.gateway.filter.CustomGatewayFilter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Date: 2022-06-28 星期二
 * Time: 14:00
 * Author: Dily_Su
 * Remark:
 */
@Configuration
public class GatewayRoutesConfiguration {
    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder) {
        return builder.routes().route("test1", r -> r
                        // 断言(判断条件)
                        .path("/product/**")
                        // 自定义网关过滤器
                        .filters(f -> f.filter(new CustomGatewayFilter()))
                        // 目标 URI 路由到服务器的地址
                        .uri("lb://provider"))
                .build();
    }
}
自定义全局过滤器

CustomGlobalFilter:实现接口: GatewayFilter,Ordered

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;

/**
 * Date: 2022-06-28 星期二
 * Time: 14:55
 * Author: Dily_Su
 * Remark: 自定义全局过滤器
 * 统一鉴权
 */
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {

    /**
     * 过滤器业务逻辑
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("自定义全局过滤器被执行");

        // 获取请求参数 
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        // 业务处理
        if (token == null){
            ServerHttpResponse response = exchange.getResponse();
            // 响应类型
            response.getHeaders().add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
            // 响应状态, 401 代表没权限
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            // 响应内容
            String message = "{\"message\":" + HttpStatus.UNAUTHORIZED.getReasonPhrase() + "\"}";
            DataBuffer buffer = response.bufferFactory().wrap(message.getBytes(StandardCharsets.UTF_8));
            // 请求结束
            return response.writeWith(Mono.just(buffer));
        }
        // 使用 token 进行身份验证
        System.out.println("验证通过");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

六、网关限流

顾名思义,限制流量,通过限流控制系统的QPS,从而保护系统

1、原因

  • 用户增长过快
  • 热点事件(如微博热搜)
  • 竞争对手爬虫
  • 恶意请求

2、限流算法

计算器算法

设置规定时间内请求数量

时间节点前后一起发送请求上限的请求,数量可能会超出,拖垮服务

资源浪费

漏桶算法(Leaky)

使用队列机制,请求进入网关不做限制,但是从网关访问下行服务时按规定速率请求

请求堆积,网关压力大,网关容易宕机

超出队列上限,可能导致请求丢失

微服务资源浪费

令牌桶算法(Token)

改进的漏桶算法,可以应对突发请求

1、网关恒定速率生成令牌放入令牌桶,桶满后丢弃令牌

2、请求到达后先获取令牌再做业务处理,没拿到令牌的请求丢弃

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tn0caniu-1670555453109)(img/Gateway 令牌桶算法.png)]

3、实例

通过 RequestRateLimiterGatewayFilterFactory 过滤工厂,使用Redis 和 lua 实现令牌桶

URI 限流

KeyResolverConfiguration

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

/**
 * Date: 2022-06-28 星期二
 * Time: 16:45
 * Author: Dily_Su
 * Remark:
 */
@Configuration
public class KeyResolverConfiguration {
    /**
     * 限流规则
     * URI 限流
     * @return
     */
    @Bean
    public KeyResolver pathKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
    }
}

application.yml

spring:
  application:
    name: gateway # 应用名称
  cloud:
      # 路由规则
    gateway:
      routes:
        - id: provider                                            # 路由 ID,唯一
          uri: lb://provider                                      # 根据注册中心动态路由
          predicates:                                             # 断言(判断条件)
            - Path=/product/**                                           # 匹配对应的 URL 请求,并追加到 URI 后
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1  # 令牌每秒填充数量
                redis-rate-limiter.burstCapacity: 2  # 令牌桶总容量
                key-resolver: "#{@pathKeyResolver}"  # 使用 SpEL 表达式按名称引用 bean

  redis:
    host: localhost               # redis 地址
    port: 6379                    # 端口
    database: 1                   # database

redis 中的 令牌会自动清理

参数限流

KeyResolverConfiguration

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

/**
 * Date: 2022-06-28 星期二
 * Time: 16:45
 * Author: Dily_Su
 * Remark: 限流规则
 * 下面 Bean 只能有一个
 */
@Configuration
public class KeyResolverConfiguration {
    /**
     * 参数 限流
     *
     * @return
     */
    @Bean
    public KeyResolver parameterKeyResolver() {
        return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("id")));
    }
}

application.yml

spring:
  application:
    name: gateway # 应用名称
  cloud:
      # 路由规则
    gateway:
      routes:
        - id: provider                                            # 路由 ID,唯一
          uri: lb://provider                                      # 根据注册中心动态路由
          predicates:                                             # 断言(判断条件)
            - Path=/product/**                                           # 匹配对应的 URL 请求,并追加到 URI 后
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1       # 令牌每秒填充数量
                redis-rate-limiter.burstCapacity: 2       # 令牌桶总容量
                key-resolver: "#{@parameterKeyResolver}"  # 使用 SpEL 表达式按名称引用 bean

  redis:
    host: localhost
    port: 6379
    database: 1

IP 限流

KeyResolverConfiguration

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

/**
 * Date: 2022-06-28 星期二
 * Time: 16:45
 * Author: Dily_Su
 * Remark: 限流规则
 * 下面 Bean 只能有一个
 */
@Configuration
public class KeyResolverConfiguration {
    /**
     * IP 限流
     *
     * @return
     */
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getRemoteAddress().getHostName()));
    }
}

application.yml

spring:
  application:
    name: gateway # 应用名称
  cloud:
      # 路由规则
    gateway:
      routes:
        - id: provider                                            # 路由 ID,唯一
          uri: lb://provider                                      # 根据注册中心动态路由
          predicates:                                             # 断言(判断条件)
            - Path=/product/**                                           # 匹配对应的 URL 请求,并追加到 URI 后
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1  # 令牌每秒填充数量
                redis-rate-limiter.burstCapacity: 2  # 令牌桶总容量
                key-resolver: "#{@ipKeyResolver}"    # 使用 SpEL 表达式按名称引用 bean

  redis:
    host: localhost
    port: 6379
    database: 1

七、高可用网关

nginx + 网关集群 + docker部署

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h6go9MHM-1670555453109)(img/nginx + 网关集群.png)]

1、项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-isdc5lu2-1670555453111)(img/高可用网关项目结构.png)]

2、配置文件

parent 中的 pom.xml

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.8</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.study</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <!-- 版本控制 -->
    <properties>
        <java.version>11</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-cloud.version>2021.0.3</spring-cloud.version>
        <packaging.type>jar</packaging.type>
        <lombok.version>1.18.24</lombok.version>
        <feign-httpClienr.version>10.7.4</feign-httpClienr.version>
        <ribbon.version>2.7.18</ribbon.version>
    </properties>

    <!-- maven 仓库 -->
    <repositories>
        <repository>
            <id>central</id>
            <name>Nexus aliyun</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>
    
    <!-- 依赖版本控制 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--        Feign 使用 httpClient -->
            <dependency>
                <groupId>io.github.openfeign</groupId>
                <artifactId>feign-httpclient</artifactId>
                <version>${feign-httpClienr.version}</version>
            </dependency>
            <!--        ribbon 点对点直连 和 局部负载均衡 不可用-->
            <dependency>
                <groupId>com.netflix.ribbon</groupId>
                <artifactId>ribbon-loadbalancer</artifactId>
                <version>${ribbon.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <!-- 项目打包配置 -->
    <!-- 不同的打包方式,使用不同的配置文件 -->
    <profiles>
        <profile>
            <id>docker</id>
            <properties>
                <activated.profile>docker</activated.profile>
                <!-- redis连接,更改 application-docker.yml 中的值 -->
                <redis.host>cloud-redis</redis.host>
                <redis.port>6379</redis.port>
            </properties>
            <build>
                <resources>
                    <resource>
                        <filtering>true</filtering>
                        <directory>src/main/resources</directory>
                    </resource>
                </resources>
            </build>
        </profile>
        <profile>
            <id>dev</id>
            <properties>
                <activated.profile>dev</activated.profile>
                <!-- redis连接,更改 application.yml 中的值 -->
                <redis.host>localhost</redis.host>
                <redis.port>6379</redis.port>
            </properties>
            <build>
                <resources>
                    <resource>
                        <filtering>true</filtering>
                        <directory>src/main/resources</directory>
                        <excludes>
                            <exclude>application-docker.*</exclude>
                        </excludes>
                    </resource>
                </resources>
            </build>
        </profile>
    </profiles>
</project>

nginx.conf

# nginx 配置文件:负载均衡默认为轮询
worker_processes 1;

events { worker_connections 1024; }

http {
    include    /etc/nginx/mime.types;
    sendfile   on;

    proxy_buffer_size   128k;
    proxy_buffers   4 256k;
    proxy_busy_buffers_size   256k;

    client_max_body_size   100m;

    # 网关集群
    upstream gateway {
        # docker 中 localhost 为 镜像容器名
        server gateway-01:9000;
        server gateway-02:9001;
    }

    server {
        listen 8080;

        location / {
            # 将所有请求指向 网关集群
            proxy_pass http://gateway;
        }
    }
}

dockerFile

# 每个微服务根目录下都要放置一个,用于将打包好的 jar 整理为 docker image
# jdk 版本不能低于自己编译时的版本,否则 docker 启动会报错
FROM openjdk:11.0.15-jre
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
WORKDIR /
ENTRYPOINT ["java","-jar","/app.jar"]

docker-compose.yml

version: "3.7"
services:
  redis:
    image: redis:latest  # 从 docker hub 中 pull 最新的 redis image
    container_name: cloud-redis # docker 中的容器名称
    ports:               # 对外映射的端口,占用容器内的 6379,本机的26379,不想对外暴漏时,可以省略
      - "26379:6379"
    networks:            # 容器内网关,用于容器内镜像互相调用
      - backend
    environment:         # 设置时区
      - TZ=Asia/Shanghai

  erurka-01:
    build: ./eureka01    # build 存在时,表示从该目录下获取镜像名称
    image: cloud/eureka01:latest # 镜像名称
    container_name: eureka-01 # 容器名称
    ports:
      - "28761:8761"
    networks:
      - backend
    environment:
      - TZ=Asia/Shanghai

  erurka-02:
    build: ./eureka02
    image: cloud/eureka02:latest
    container_name: eureka-02
    ports:
      - "28762:8762"
    networks:
      - backend
    environment:
      - TZ=Asia/Shanghai

  gateway-01:
    build: ./gateway01
    image: cloud/gateway01:latest
    container_name: gateway-01
    networks:
      - backend
    environment:
      - TZ=Asia/Shanghai

  gateway-02:
    build: ./gateway02
    image: cloud/gateway02:latest
    container_name: gateway-02
    networks:
      - backend
    environment:
      - TZ=Asia/Shanghai

  provider-01:
    build: ./provider01
    image: cloud/provider01:latest
    container_name: provider-01
    networks:
      - backend
    environment:
      - TZ=Asia/Shanghai

  provider-02:
    build: ./provider02
    image: cloud/provider02:latest
    container_name: provider-02
    networks:
      - backend
    environment:
      - TZ=Asia/Shanghai

  consumer-eureka:
    build: ./consumer-eureka
    image: cloud/consumer-eureka:latest
    container_name: consumer-eureka
    networks:
      - backend
    environment:
      - TZ=Asia/Shanghai

  consumer-eureka-feign:
    build: ./consumer-eureka-feign
    image: cloud/consumer-eureka-feign:latest
    container_name: consumer-eureka-feign
    networks:
      - backend
    environment:
      - TZ=Asia/Shanghai

  nginx:
    image: nginx
    container_name: cloud-demo-nginx
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    ports:
      - 28080:8080
    restart: unless-stopped
    networks:
      - backend

networks: # 该微服务项目在容器中的网关
  backend: 
    name: cloud-demo 

3、docker 部署

Maven 打包

# 清理 targer 文件,并按照 按照 docker 配置 打包
 mvn clean package -P docker -DskipTests

docker部署

# build image 并 生成容器,启动 image
docker compose up -d 		

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/75856.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Allegro如何给差分过孔添加禁布操作指导

Allegro如何给差分过孔添加禁布操作指导 Allegro支持给差分过孔添加禁布,让它避让周围的铜皮,具体操作如下 以下图两个过孔为例,需要做一个和via避让铜皮尺寸一样大的禁布 选择show element命令 Find选择Other segs 鼠标移动到铜皮避让圆形的地方 出现一个report,记住…

【并发编程】SemaphoreCountDownLatchCyclicBarrier

一、Semaphore Semaphore 通常又被称为信号量&#xff0c; 可以用来控制同时访问特定资源的线程数量&#xff0c;通过协调各个线程&#xff0c;以保证合理的使用资源。 1.简单的使用 1-1.控制线程的并发连接数 public static void main(String[] args) {// 只允许两个线程执…

中英翻译《动物看见了什么》

What animals see 动物看见了什么 一、Pre-reading activity 阅前思考 1.What animals do you like? 你喜欢什么动物&#xff1f; 2.Do you have any animals in your home? 你家里有动物吗&#xff1f; 3.Do you think most animals can see as well as we can? 你认为大多…

Windows下docker安装

安装 1.打开Hyper-V &#xff0c;在"启用或关闭Windows功能" 如果这里的Hyper-V平台灰色不能勾选 显示无法安装Hyper-v该固件中的虚拟化支持被禁用&#xff0c;则需要开启 开始方式&#xff1a; 重启电脑进入BIOSS界面 点击高级–>CPU设置 —> Intel virtu…

44. python的for循环嵌套

44. python的for循环嵌套 文章目录44. python的for循环嵌套1. 什么是嵌套2. for循环中嵌套有if条件判断语句2.1 先创建一个奇数序列2.2 判断一个数是否能被7整除2.3 将2部分代码合二为一3. for循环中嵌套有for循环1. 什么是嵌套 嵌套是指一个对象中包含另一个与它相似的对象。…

Python 中在两个字典中查找公共键

Python 中要在两个词典中查找公共键&#xff1a; 使用 dict.keys() 方法获取每个字典的键的视图对象。使用 & 符号获取常用键。使用 list() 类将结果转换为列表对象。 dict1 {name: jiyik, topic: Python, salary: 100} dict2 {name: alice, salary: 100, experience: …

R语言探索BRFSS数据可视化

设定 加载包 最近我们被客户要求撰写关于BRFSS数据的研究报告&#xff0c;包括一些图形和统计输出。在本实验中&#xff0c;我们将使用dplyr软件包探索数据&#xff0c;并使用ggplot2软件包对其进行可视化以进行数据可视化 library(ggplot2) library(dplyr) 载入资料 load…

初识Netty框架

总体概述 Netty作为一款网络通信框架&#xff0c;底层封装了NIO。我们在使用Netty时&#xff0c;无需再关注NIO细节。下图为Netty处理流程图&#xff1a; 应用程序中使用Netty作为网络通信框架后&#xff0c;会形成一条PipeLine链&#xff0c;PipeLine链上有一个一个的事件处…

buuctf10(异或注入中文字符绕过preg_match伪随机数漏洞seed)

目录 [WUSTCTF2020] 颜值成绩(异或注入) [Zer0pts2020]Can you guess it?(中文字符绕过preg_match) [FBCTF2019]RCEService(/bin/调用命令 || 回溯绕过preg_match) [GKCTF 2021]easycms(后台弱口令&任意文件下载) [GWCTF 2019]枯燥的抽奖(伪随机数漏洞seed) [MRCTF20…

msprofiler 性能调优命令行实战(口罩识别推理)

案例介绍 本案例使用口罩识别推理程序作为例子进行演示&#xff0c;硬件平台是华为昇腾310设备(Ascend 310)&#xff0c;该口罩识别使用目标检测中SSD模型&#xff0c;检测的结果有两个类别&#xff1a;戴口罩的脸、没带口罩的脸。成功执行推理程序后我们对其进行了推理调优&a…

连续7年领跑!在华为云桌面,藏了一盘数字办公的大棋

作者 | 曾响铃 文 | 响铃说 连续7年领跑&#xff01;在国内虚拟客户端计算软件市场&#xff0c;华为云再度占据行业第一的位置&#xff0c;力压Citrix、Microsoft和VMware等全球知名厂商。 所谓的虚拟客户端计算软件市场&#xff0c;简单来理解就是云桌面市场。伴随着数字办…

Oracle报错:ORA-28001:口令已失效

一、链接Oracle报错 &#xff1a;ORA-28001&#xff1a;口令已失效 解决办法 原因&#xff1a;Oracle11G创建用户时缺省密码过期限制是180天&#xff08;即6个月&#xff09;&#xff0c; 如果超过180天用户密码未做修改则该用户无法登录 解决方式&#xff1a; 方式一&#xf…

R语言可视化探索BRFSS数据并逻辑回归Logistic回归预测中风

第1部分&#xff1a;关于数据 行为风险因素监视系统&#xff08;BRFSS&#xff09;是美国的年度电话调查。最近我们被客户要求撰写关于BRFSS的研究报告&#xff0c;包括一些图形和统计输出。BRFSS旨在识别成年人口中的危险因素并报告新兴趋势。例如&#xff0c;询问受访者饮食…

Python 并发编程

一.Python 对并发编程的支持 多线程&#xff1a;threading&#xff0c;利用CPU和IO可同时执行的原理&#xff0c;让CPU不会干巴巴等待IO完成&#xff0c;而是切换到其他Task&#xff08;任务&#xff09;&#xff0c;进行多线程的执行。多进程&#xff1a;multiprocessing&…

微前端总结

微前端概述 微前端概念是从微服务概念扩展而来的&#xff0c;摒弃大型单体方式&#xff0c;将前端整体分解为小而简单的块&#xff0c;这些块可以独立开发、测试和部署&#xff0c;同时仍然聚合为一个产品出现在客户面前。可以理解微前端是一种将多个可独立交付的小型前端应用…

使用极限学习机进行股市预测(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 极限学习机&#xff08;Extreme Learning Machine,ELM&#xff09;作为前馈神经网络学习中一种全新的训练框架,在行为识别、情…

EPICS -- 使用asynPortDriver类编写示一个示例程序

本示例展示了如何使用asynPortDriver类编写一个EPICS端口驱动程序的示例。 这个驱动程序参数库中一个有5个参数&#xff0c;分别支持5个EPICS记录。 如下是具体步骤&#xff1a; 1&#xff09; 用makeBaseApp.pl脚本建立这个IOC应用程序的框架&#xff1a; [blctrlmain-mach…

IDEA中如何实现git的cherry-pick可视化操作?

目录 问题现象&#xff1a; 问题分析&#xff1a; 解决方法&#xff1a; 拓展&#xff1a;如何回退提交记录&#xff1f; 问题现象&#xff1a; 今天在学习了git的cherry-pick功能&#xff0c;于是引出了一个问题&#xff1a; IDEA中如何实现git的cherry-pick可视化操作&am…

【Docker学习教程系列】7-如何将本地的Docker镜像发布到阿里云

在上一篇中&#xff0c;我们使用docker commit 命令&#xff0c;创建了一个带有vim的Ubuntu镜像。那么怎么将这个镜像分享出去呢&#xff1f;本文就来讲解如何将本地的docker镜像发布到阿里云上。 本文主要内容&#xff1a; 1&#xff1a;本地镜像发布到阿里云流程 2&#xf…

Linux网络原理与编程(4)——第十四节 传输层协议

目录 前置知识 再谈端口号 几个函数 netstat telnet UDP报文 UDP协议端格式 UDP首部&#xff1a; UDP的特点 UDP的缓冲区 TCP报文详解 Tcp报头详解 传输层是在应用层的下面一层&#xff0c;我们在讲解传输层协议之前&#xff0c;先来说一说一些前置知识即命令函数等…