envoy流量治理

envoy流量治理(路由管理)

envoy通过路由实现流量治理

envoy内部流量处理过程

image-20231209123938103


http连接器

内置L4过滤器http连接管理器,将原始字节转为http应用层协议的数据

支持http/1.1、http2、websockets
关联的路由表可静态配置,也可以xds获取
内置重试插件,可用于配置重试行为,host predicates、priority predicates
内置支持302重定向,合并成新请求后发给新的路由匹配
支持适用于http连接及其组成流(constituent stream)的多种配置超时机制

  • 连接级别:空闲超时和排空超时(goaway)
  • 流级别:空闲超时,每路由相关的上游端点超时和每路由相关的grpc最大超时时间

基于自定义集群的动态转发代理

http协议相关的功能用http过滤器实现,过滤器大致分为:

编码器
解码器
编/解码

http route过滤器

route(envoy,router)是最常用的过滤器之一,基于路由表完成请求的转发或重定向等,可实现机制包括:

  • 域名映射虚拟主机
  • path路径匹配
  • 虚拟主机级别的tls重定向
  • envoy生成响应报文
  • 显式主机重写
  • 运行时参数做流量迁移
  • 基于http标头或路由做重试、超时
  • 权重或百分比跨集群流量分割
  • hash路由等

配置

image-20231209152431817

listeners:
  - name: listener_0        #侦听器名称
    address:          #侦听器监听地址
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:     #侦听器上的过滤链定义
    - filters:        #定义4层过滤器,7层包含在其中,因为7层基于4层
      - name: envoy.filters.network.http_connection_manager     #使用tcp 4层过滤器的http_connection_manager
        http_filters:             #指定http过滤器链
        - name: envoy.filters.http.router       #调用7层的路由过滤器
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
        typed_config:           #类型配置
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager    #使用http过滤器的v3版
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:           #静态路由配置,动态配置为rds
            name: local_route     #路由配置名称
            virtual_hosts:        #虚拟主机匹配,与ngx的server_name一样
            - name: web_service_1     #配置名,用于统计信息中显示
              domains: ["*"]          #匹配的域名
              routes:                 #路由的实际配置
              - name: str
                match: {}        #匹配内容
                route: {}
                redirect: {}
                direct_response: {}
              virtual_cluster: []

匹配路由过程:

检测http请求的host头部,或:authority,并与路由配置中定义的虚拟主机做匹配
在匹配到的虚拟主机中安顺序检查虚拟主机中的每个route条目的匹配条件,直到第一个匹配为止
若定义了虚拟集群。安顺序检查虚拟主机中每个虚拟集群,第一个匹配为止结束

匹配优先级

精确匹配->前缀匹配->后缀匹配->通配符

路由匹配方法

必须是prefix、path、safe_regex三种匹配条件之一

  • 区分字符大小写
  • 匹配指定的运行键值对,进行比率流量迁移
  • 基于标头的路由
  • 基于参数的路由
  • 仅匹配grpc流量
基于标头路由匹配

routes.match.headers

指定路由需要的额外标头
对路由配置中所有指定的标头检查匹配,路由中指定的所有标头都存在于请求中且值也相同,则匹配;若配置中未指定标头值,则只匹配标头

匹配条件必须为以下之一:

exact_match: str        #精确值匹配
safe_regex_match: str   #正则表达式匹配
range_match: str        #范围匹配,检查标头值是否在指定范围内
present_match: str      #标头存在性匹配
prefix_match: str       #值前缀匹配
suffix_match: str       #值后缀匹配
contains_match: str     #检测标头值是否包含字符串
string_match: str       #标头值是否匹配字符串
invert_match: false     #是否对匹配结果取反,不满足条件为真。默认false
基于查询参数路由匹配

route.match.query_parameters

根据url的参数匹配
查询参数匹配时,将请求的url中查询字符串视为以&符号分割的键值对元素列表。若存在指定查询参数,则所有参数都必须与url中的查询字符串匹配

匹配条件必须为以下之一:

  • value
  • safe_regex
  • string_match
  • present_match

路由目标

路由到指定集群
  • cluster 上游集群
  • cluster_header 请求标头中由cluster_header指定的上游集群
  • weighted_clusters 基于权重将请求路由到多个上游集群,进行流量分割,所有权重总计必须等于100
重定向

为请求响应301永久重定向
支持重定向行为:

  • 协议重定向: https_redirect、scheme_redirect二选一
  • 主机重定向: host_redirect
  • 端口重定向: port_redirect
  • 路径重定向: path_redirect
  • 路径前缀重定向: prefix_redirect
  • 正则表达式重定向: regex_rewrite
  • 重设响应码: response_code,默认301
  • strip_query: 是否在重定向期间删除url中的查询参数,默认false
直接响应请求

可直接响应状态码,并且指定响应正文

body响应正文中,可用3种方式指定:

  • filename:文件数据源
  • inline_bytes:字节码
  • inline_string:字符串

路由策略

基础路由配置

在match中简单配置prefix、path、regex匹配
对匹配的请求做重定向、直接响应、路由到目标集群

高级路由配置

结合runtime_fraction按比例切割流量
结合headers按指定的标头路由,如基于cookie的值路由到不同目标
结合query_parameters按参数路由

复杂路由

结合请求报文标头的cluster_header的值进行定向路由
weighted_clusters权重做流量分割
重试、超时、cors、限速等


高级流量管理

注意:在进行高级流量管理时,需要配合runtime api接口动态修改相关参数

灰度发布策略

基于请求内容发布

配置对应的请求内容规则,满足规则服务流量会路由到灰度版本

cookie实现
  • 完全匹配
  • 正则
自定义header
  • 完全匹配
  • 正则
自定义请求头
要求kv中,value支持完全匹配和正则匹配

基于流量比例发布

对灰度版本配置期望的流量权重,将服务流量以指定权重比率引流到灰度版本
所有版本的权重之和为100
这种灰度策略也成为AB测试

灰度实施

实施方法

基于负载均衡器

在流量入口处,根据权重按比例做流量分配,实现方法和功能较简单

基于k8s

根据新旧pod数量比例进行流量分配
不断滚动更新旧版本pod到新版本
访问入口是service或ingress

基于服务网格

envoy或istio
支持流量比例和请求内容分配
访问入口通常是单独部署的envoy gateway

实施过程

滚动更新

分批进行,先下线部分实例,更新后上线
先更新上线部分实例,后下线对一个比例的老版本实例进行更新

蓝绿部署

额外准备全量的新版本实例

AB测试

向用户随机显示页面的多个或多个变体版本,并用统计分析来确定哪个版本效果更好
可用于测试、比较、分析业务内容

流量迁移

将匹配到的流量,按比例分配到不同上游集群

配置

static_resources:
  ...
    routes:
    - match:
        prefix|path|safe_regex:
        runtime_fraction:     #额外匹配指定的运行时键值对。每次评估匹配路径时,它必须低于此字段指定的百分比,支持渐进式修改
          default_value:      #运行时键值对不可用时,则使用默认配置
            numerator: 0      #默认0分子
            denominator: HUNDRED     #指定分母,小于分子时,最终百分比为1.分母可固定使用:HUNDRED(100,默认)、TEN_THOUSADN(1W)、MILLION(百万)
          runtime_key: routing.traffic_shift.KEY    #指定要运行的运行时键,值需用户自定义
      route:
        cluster: app_v1             #接收默认流量
    - match:                 #匹配的内容必须完全和前面一致(因为是处理相同的流量),不用写runtime_fraction部分
        prefix|path|safe_regex:
      route:
        cluster: app_v2             #对应

修改方法

#"[]"为可选
curl -XPOST 'http://envoy_ip:admin_port/runtime_modify?自定义key=v1[&自定义key2=v2]'

流量分割

可实现类似流量迁移的功能,但不同点在于,不用再match中保持一致来匹配流量,可以放在集群来按比例分配

在路由中指定多个上游具有权重的集群,流量基于权重调度,类似流量迁移

配置

static_resources:
  ...
    routes:
    - match: {}
      route:
        weighted_clusters:           #权重,路由的目标集群有多个时,做权重比例
          cluster:            #与当前路由关联的1到多个集群
          - name: xx
            weight: 0         #权重取值为0到total_weight
            metadata_match: {}  #子集负载均衡器使用的端点元数据条件匹配。可选
          total_weight: 100     #总权重,默认100
          runtime_key_prefix:   #可选。用于设定键前缀,每个集群以:runtime_key_prefix+.+cluster[索引].name为键(其中cluster[索引].name可直接简写为name的名称),以运行时键值对的方式为每个集群提供权重,例此处前缀指定为route,集群名为app1,运行时key名为:route.app1

修改方法

#"[]"为可选
curl -XPOST 'ip:9901/runtime_modify?routing.traffic_split.虚拟主机名.路由集群1=0[&routing.traffic_split.虚拟主机名.路由集群2=100]'

流量镜像

流量镜像也叫流量复制、影子镜像。通常用于在生产环境测试,将生产流量镜像拷贝到测试集群或新版本集群,实现新版本接近真实环境的测试,旨在有效的降低新版本上线风险

无需等待影子集群返回响应

使用场景

  • 验证新版本
  • 测试
  • 隔离测试数据库,与数据处理相关的业务,可使用空的数据库存储加载测试测试,针对数据进行流量镜像,实现测试数据隔离

配置

static_resources:
  ...
    route:
      cluster|weighted_clusters:
      request_mirror_policies:
      - cluster:
        runtime_fraction:
          default_value:
            numerator: 0
            denominator: HUNDRED
          runtime_key: routing.request_mirror.KEY
        trace_sampied: {}     #是否跟踪采样,默认ture

说明:默认情况下,路由器会镜像所有请求,也可使用runtime_fraction参数配置转发的流量比例


混沌工程和故障注入

混沌工程

分布式系统天生还有大量的交互、依赖点、故障点层出不穷。很多故障时人力无法改变这种局面,需要做到的是在异常被触发之前尽可能多识别此类的系统脆弱环节、组件,进而有针对性的进行加固,避免故障发生。这就是混沌工程诞生的原因之一

混沌工程并不是简单的制造服务中断等故障,也不是全部都可以有建设性、高效的发现问题,此外还存在一些非故障类场景,如流量激增、资源竞争条件、拜占庭故障、非计划中的或非正常组合的消息处理等

作用

  • 对于架构师:验证系统架构的容错能力,如现在提倡的面向失败设计的系统
  • 对于开发和运维:提高故障的应急效率,实现故障告警、定位、恢复的有效和高效性
  • 对于测试:弥补传统测试方法留下的空白,混沌工程从系统的角度进行测试,降低故障复发率
  • 对于产品和设计:通过混沌事件,查看产品的表现,提升客户体验

场景

  • 模拟整个云服务区域或整个数据中心故障
  • 跨多实例删除部分kafak topic来重现生产环境发生过的问题
  • 挑选1个时间段、针对1部分流量对其设计的服务间调用注入一些特定的延时
  • 方法级别的混乱(运行时注入),让方法随机抛出各种异常
  • 在代码中插入一些指令可以允许在这些指令之前运行故障注入
  • 强制系统节点时间的时间不同步
  • 在驱动程序中执行模拟io错误的程序
  • 让某个es集群的cpu超负荷

故障注入

简称FIT,和故障测试在侧重点和工具集上有一些重叠,属于混沌工程的子集

混沌工程是发现新信息的实验过程,故障注入是对1个特定条件或变量的测试方法

故障注入应该只在业务刚上线时做稳定性测试使用,使用完后应该关闭

场景

  • cpu高负载
  • 磁盘高负载
  • 磁盘空间不足
  • kill直接停止应用,可能造成数据不一致
  • 网络恶化:随机改变一些包的数据,是数据内容不正确
  • 网络延迟:将包延迟在1个特定范围的时间
  • 网络丢包:狗仔1个tcp不会完全失败的丢包率
  • 网络黑洞:忽略某个ip的包
  • 外部服务不可达:将外部服务的域名指向本地会还地址或将外部服务端口的出栈数据包丢弃

故障注入过滤器

故障注入在envoy中实现上类似于重定向、重写、重试,通过修改http请求或响应内容实现

使用的7层http过滤器为:fault.injection,全称为:

envoy.filters.http.fault

可通过用户指定的错误代码注入延迟、请求终止来模拟出分阶段的不同故障情形。故障范围仅限于通过网络进行通信的应用程序可观察到的范围,不支持模拟本地主机上的cpu和磁盘故障

配置

    delay:              #注入延迟,延迟和请求中止至少有1个
      fixed_delay:      #持续时长,将请求转发到上游主机前添加固定延迟
      header_delay:     #基于http标头的指定控制故障延迟
      percentage:      #将注入延迟的操作、连接、请求的百分比。表示将错误注入到多大比例的请求中
    abort:              #注入请求中止
      http_status:      #中止http请求的状态码,http_status、grpc_status、header_status三者之间必须选一个
      grpc_status:      #中止grpc请求的状态码
      header_status:    #由http标头控制的中止
      percentage:       # #将注入延迟的操作、连接、请求的百分比
    upstream_cluster:       #过滤器关联的上游集群,只生效在这些目标集群
    headers:                #过滤器关联的请求头列表,各标头间为与关系
    downstream_nodes:       #要注入故障的下游主机列表,未指定时将匹配所有主机
    max_active_faults:      #在同1个书剑点所允许的最大活动故障数,默认为不限制,可用运行时参数:config_http_filters_fault_injection_runtime配置
    response_rate_limit:    #响应速率限制,可用运行时参数:fault.http.rate_limit.response_percent配置,此为单流或连接级别的限制
      fixed_limit:
        limit_kbps:         #固定速率,单位kiB/s
      header_limit:         #限制为http首部指定的速率
      percentage: {}        #
    delay_percent_runtime:
    abort_percent_runtime:
    delay_duration_runtime:
    max_active_faults_rumtime:
    response_rate_limit_percent_runtime:
    abort_grpc_status_runtime:
    disable_downstram_cluster_stats:

局部故障处理机制

重试、超时定义在路由,断路器定义在集群

retry

分布式环境中国对远程资源和服务的调用可能由于瞬态故障(短时间可自动恢复的故障)而失败,一般情况下重试机制可解决此类问题
常见有连接慢、超时、资源过量、暂时不可用

瞬态故障处理策略

  • 重试:对暂时性故障,反复请求
  • 延迟后重试:若故障是因为较常见的连接故障或繁忙引起,一般需要一些时间来纠正连接问题或清除挤积压的工作
  • 取消:对于非暂时性故障,反复重试也无效的情况下,取消操作报告异常即可

重试的注意事项

  • 重试策略需匹配应用程序的业务需求和故障的性质,非关键操作最好是快速失败而不是重试几次。对于交互式web应用程序,在较短延迟后进行少量重试,之后再对用户显示适当消息如“请稍后重试”;对于批处理程序,增加重试次数更合适,但重试次数自建的压制应该成倍增加
  • 大量请求后依旧失败,最好配置断路器并报告失败
  • 考虑操作幂等性,非幂等的应避免多次重试执行
  • 需为不同的异常配置不同的重试策略
  • 确保重试代码已针对各故障情况进行了全面测试,以检查他们是否不会严重影响应用程序性能

timeout

因某些故障导致不可用时,可能需要长时间才能恢复,这类故障重试、超时都没有意义,应该选择直接失败 。也就是超时过后直接失败

circuit breaker(断路器)

级联故障时,简单的超时策略可能导致对统一操作的许多并发请求被阻止,引起阻止的原因很可能包含内存不足、线程、数据库连接等问题,这些原因导致的故障最好立即使操作失败,并且仅在可能成功的情况下尝试调用服务器

级联故障:服务A、B、C,C故障后,B会堆积大量连接C的请求,导致B也挂掉,最后可能A也挂了


http请求重试

常见瞬态处理策略

  • 重试:适合暂时性、不常见类型故障
  • 延迟后重试:故障是由较常见的连接故障或繁忙故障引起,通常需要一些时间纠正连接问题,或清除积压工作,可以在适当等待后,重试
  • 取消:适合非暂时性故障,此类故障应报告异常

注意事项:

  • 需要根据业务程序、故障性质做
    • 对于交互式web应用,在较短的延迟后进行少量重试,再向用户显示适当的消息提示
    • 对于批处理程序,增加重试次数可能更合适,但重试次数间的延迟应成倍或指数级增加
  • 大量重试、超时后依旧失败,应立即报告失败,并配合断路器,一段时间后再尝试
  • 考虑幂等性,避免多次执行,产生意外的作用
  • 确保重试代码已针对各故障做了全面测试

重试策略

envoy支持在虚拟主机、路由级别配置特定请求标头的重试(路由级别高于虚拟主机级别)

包括重试次数和重试条件

重试条件

默认envoy不做任何重试

重试条件1(x-envoy-retry-on标头)
  • 5xx
  • gateway-error:网关错误,类似5xx,但只有502、503、504
  • connection-failure:在tcp级别与端点尽力连接失败时进行重试
  • retriable-4xx:上游服务器返回可重读的4xx响应码时进行重试
  • refused-stream:返回refused-stream错误码重置时进行重试
  • retriable-status-codes:上游服务器的响应码与重试策略或x-envoy-retriable-status-codes标头值中定义的响应码匹配时进行重试
  • reset:上游主机完全不响应时(disconnect、reset、read),envoy做重试
  • retriable-headers:上游服务器响应报文匹配重试策略或x-envoy-retriable-header-names标头中包含的任何标头,则envoy做重试
  • envoy-ratelimited:标头中存在x-envoy-ratelimited时进行重试
重试条件2(x-envoy-retry-grpc-on标头)
  • cancelled: grpc应答标头中状态码是cancelled时进行重试
  • deadline-exceeded: grpc应答标头中状态码是:deadline-exceeded时进行重试
  • internal: 状态码是internal重试
  • resource-cxhausted
  • unavailable
route:
  retry_policy:                #重试策略
    retry_on: 条件            #重试发生的条件,如网络故障、5xx类响应码,与标头x-envoy-retry-on、x-envoy-retry-grpc-on相同
    num_retries: 1            #重试次数,默认为1,与标头x-envoy-max-retries相同,但取2个配置之间的最大值
    per_try_timeout: 时间     #每次重试时与上游端点建立连接的超时时间
    retry_priority: 策略      #重试优先级策略,用于在各优先级之间分配负载
    retry_host_predicate:     #重试时使用的主机断言列表,各断言用于拒绝主机。在选择重试主机时将参考列表中的断言,若存在任何内容拒绝了该主机,则需要重新尝试选择其他主机
    retry_options_predicates:
    host_selection_retry_max_attempts:    #允许尝试重新选择主机的最大次数,默认为1
    retriable_status_codes:       #出了retry_on指定的条件外,用于触发重试icaozuo的http状态码列表
    retry_back_off: 25ms            #控制回退算法的参数,默认间隔25ms
    rate_limited_retry_back_off:    #定义控制重试回退策略的参数
    retriable_headers:              #触发重试的http响应标头列表,上游端点的响应报文与列表中任何标头匹配时将触发重试
    retriable_request_headers:      #必须在用于重试的请求报文中使用http标头列表

重试插件及相关配置

重试操作会触发重新选择目标主机

  • 重试期间选择主机与首次处理请求时选择主机的方式相同,选择行为由调度策略决定
  • 重试插件为用户提供了配置重试期间重新选择主机的方式

重试插件可配置的主机选择方式分为2类,他们可组合使用:

  • host predicates:用于拒绝重试选择1个主机的断言,任何主机匹配断言列表中的任何断言时将会被拒绝,并导致重试进行主机选择

    envoy.retry_host_predicates.previous_hosts #之前重试过的主机,不会再次调度到
    envoy.retry_host_predicates.omit_canary_hosts #拒绝任何标记为canary的主机,其标记配置在端点的元数据中

  • priority predicates:用于调整重试尝试选择优先级时,使用的优先级负载,此类断言只能指定1个

    envoy.retry_priority.previous_priorities #跟踪先前尝试的优先级,并根据此调整优先级负载以便在后续的重试尝试中将其他优先级作为目标


跨域资源共享CORS

跨域资源共享是http访问控制机制,使用额外的http标头告诉浏览器,运行在origin(domian)上的web应用,被允许谁来访问来自不同源服务器上的指定资源

cors可以在过滤器列表中定义,也可以在虚拟主机、路由中定义

当1个资源访问另一个资源时,服务器的域、协议、对岸卡不相同时,就会发起跨域http请求,如:

http://www.qq.com 请求 http://img.qq.com

cors过滤器支持的运行时

  • filter_enabled:在请求上启用过滤百分比,配合runtime_key可动态调整,默认100/100
  • shadow_enabled:影子模式下,请求过滤百分比,默认为0,用于评估请求的origin是否有效,但不强制任何策略

配置:

cors:
  allow_origin: []       #允许共享的资源列表,*为所有
  allow_origin_regex: []       #正则匹配
  allow_methods: str         #允许资源访问时的请求方法,对应:access-control-allow-methods标头
  allow_headers: str       #允许在请求资源时的请求标头,对应:access-control-allow-headers
  expose_headers: str       #浏览器可访问的http标头白名单,对应:access-control-expose-headers
  max_age: str        #请求缓存时间,对应:access-control-max-age
  allow_credentials: boolean       #是否允许服务调用方法使用凭证发起实际请求
  enabled: boolead      #是否启用cors,默认启用,新版本使用filter_enabled
  filter_enabled:     #是否启用cors过滤器,启用则需要定义请求百分比
    default_value:    #默认请求百分比:100/100
      numerator: 100
      denominator: HUNDRED
    runtime_key: str
  shadow_enabled:      #是否只在阴影模式下启用过滤器的请求的百分比,启用后将评估请求的来源,确定是否有效,但不强制执行任何策略,如果和filter_enabled一起使用,则filter_enabled优先
    default_value:      #默认请求百分比:100/100
      numerator: 100
      denominator: HUNDRED
    runtime_key: str

配置

  listeners:
  - name: listener_0        #侦听器名称
    address:          #侦听器监听地址
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:     #侦听器上的过滤链定义
    - filters:        #定义4层过滤器,7层包含在其中,因为7层基于4层
      - name: envoy.filters.network.http_connection_manager     #使用tcp 4层过滤器的http_connection_manager
        http_filters:             #指定http过滤器链
          - name: envoy.filters.http.router       #调用7层的路由过滤器
            typed_config:
             "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
          - name: envoy.filters.http.fault
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
              delay:              #注入延迟,延迟和请求中止至少有1个
                fixed_delay:      #持续时长,将请求转发到上游主机前添加固定延迟
                header_delay:     #基于http标头的指定控制故障延迟
                percentage:      #将注入延迟的操作、连接、请求的百分比。表示将错误注入到多大比例的请求中
              abort:              #注入请求中止
                http_status:      #中止http请求的状态码,http_status、grpc_status、header_status三者之间必须选一个
                grpc_status:      #中止grpc请求的状态码
                header_status:    #由http标头控制的中止
                percentage:       # #将注入延迟的操作、连接、请求的百分比
              upstream_cluster:       #过滤器关联的上游集群,只生效在这些目标集群
              headers:                #过滤器关联的请求头列表,各标头间为与关系
              downstream_nodes:       #要注入故障的下游主机列表,未指定时将匹配所有主机
              max_active_faults:      #在同1个书剑点所允许的最大活动故障数,默认为不限制,可用运行时参数:config_http_filters_fault_injection_runtime配置
              response_rate_limit:    #响应速率限制,可用运行时参数:fault.http.rate_limit.response_percent配置,此为单流或连接级别的限制
                fixed_limit:
                  limit_kbps:         #固定速率,单位kiB/s
                header_limit:         #限制为http首部指定的速率
                percentage:
              delay_percent_runtime:
              abort_percent_runtime:
              delay_duration_runtime:
              max_active_faults_rumtime:
              response_rate_limit_percent_runtime:
              abort_grpc_status_runtime:
              disable_downstram_cluster_stats:
        typed_config:           #类型配置
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager    #使用http过滤器的v3版
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:           #静态路由配置,动态配置为rds
            name: local_route     #路由配置名称
            virtual_hosts:        #虚拟主机匹配,与ngx的server_name一样
            - name: web_service_1     #配置名,用于统计信息中显示
              domains: ["*"]          #匹配的域名
              routes:                 #路由的实际配置
              - match:        #匹配内容
                  prefix: url                 #前缀匹配
                  safe_regex:
                    google_re2: {}      #使用谷歌正则
                    regex: 正则
                  path:                 #路径,精确匹配
                  headers:              #请求头
                  - name: X-canary
                    exact_match: "true"      #匹配字段的值
                  parameters:           #请求参数
                  runtime_fraction:     #额外匹配指定的运行时键值对。每次评估匹配路径时,它必须低于此字段指定的百分比,支持渐进式修改
                    default_value:      #运行时键值对不可用时,则使用默认配置
                      numerator: 0      #默认0分子
                      denominator: 分母     #指定分母,小于分子时,最终百分比为1.分母可固定使用:HUNDRED(默认)、TEN_THOUSADN、MILLION
                    runtime_key: routing.traffic_shift.KEY    #指定要运行的运行时键,值需用户自定义
                  exact_match: 值       #用于匹配首部的值
                  exact_match: str        #精确值匹配
                  safe_regex_match: str   #正则表达式匹配
                  range_match: str        #范围匹配,检查标头值是否在指定范围内
                  present_match: str      #标头存在性匹配
                  prefix_match: str       #值前缀匹配
                  suffix_match: str       #值后缀匹配
                  contains_match: str     #检测标头值是否包含字符串
                  string_match: str       #标头值是否匹配字符串
                  invert_match: false     #是否对匹配结果取反,不满足条件为真。默认false
                  query_parameters:     #匹配请求参数
                  - name: 'username'
                    value: 值
                    regex:
                    string_match:
                      exact: str
                      safe_regex: 正则
                      prefix: str
                      suffix: str
                      contains:
                      ignore_case: str      #忽略大小写
                    present_match:
                route:               #路由配置
                  cluster: local_cluster       #路由到指定集群
                  weighted_clusters:           #权重,路由的目标集群有多个时,做权重比例
                    cluster:            #与当前路由关联的1到多个集群
                    - name: xx
                      weight: 0         #权重取值为0到total_weight
                      metadata_match: {}  #子集负载均衡器使用的端点元数据条件匹配。可选
                    total_weight: 100     #总权重,默认100
                    runtime_key_prefix:   #可选。用于设定键前缀,每个集群以:runtime_key_prefix+.+cluster[索引].name为键,以运行时键值对的方式为每个集群提供权重
                  cluster_header:              #根据请求头中的cluster_header的值确定目标集群
                  cluster_not_found_response_code:
                  metadate_match:
                  timeout:                      #超时时间
                  idle_timeout:
                  retry_policy:                #重试策略
                    retry_on: 条件            #重试发生的条件,如网络故障、5xx类响应码,与标头x-envoy-retry-on、x-envoy-retry-grpc-on相同
                    num_retries: 1            #重试次数,默认为1,与标头x-envoy-max-retries相同,但取2个配置之间的最大值
                    per_try_timeout: 时间     #每次重试时与上游端点建立连接的超时时间
                    retry_priority:       #重试优先级策略,用于在各优先级之间分配负载
                      name: envoy.retry_priorities.previous_priorities
                      config:
                        update_frequency: 2
                    retry_host_predicate:     #重试时使用的主机断言列表,各断言用于拒绝主机。在选择重试主机时将参考列表中的断言,若存在任何内容拒绝了该主机,则需要重新尝试选择其他主机
                    - name: envoy.retry_host_predicates.previous_hosts

                    retry_options_predicates:
                    host_selection_retry_max_attempts:    #允许尝试重新选择主机的最大次数,默认为1
                    retriable_status_codes:       #出了retry_on指定的条件外,用于触发重试icaozuo的http状态码列表
                    retry_back_off: 25ms            #控制回退算法的参数,默认间隔25ms
                    rate_limited_retry_back_off:    #定义控制重试回退策略的参数
                    retriable_headers:              #触发重试的http响应标头列表,上游端点的响应报文与列表中任何标头匹配时将触发重试
                    retriable_request_headers:      #必须在用于重试的请求报文中使用http标头列表
                  request_mirror_policies:
                  - cluster:
                    runtime_fraction:
                      default_value:
                        numerator: 0
                        denominator: HUNDRED
                      runtime_key: routing.request_mirror.KEY
                    trace_sampied: {}       #是否对tranc span进行采样,默认true
                  priority:
                  include_vh_rate_limits:
                  rate_limits:                  #限速
                  cors: 跨域配置
                  prefix_rewrite:               #url重写
                  host_rewrite:                 #主机重写
                  auto_host_rewrite:
                  host_rewrite_literal:
                  host_rewrite_header:
                  host_rewrite_path_regex:
                  regex_rewrite: {}
                  max_grpc_timeout:
                  grpc_timeout_offset:
                  upgrade_configs:
                  internal_redirect_policy:
                  internal_redirect_action:
                  max_internal_redirects:
                  hedge_policy:
                  max_stream_duration:
                redirect:           #重定向
                  https_redirect: true
                  scheme_redirect:      #协议重定向
                  host_redirect:        #主机名重定向
                  port_redirect:        #端口重定向
                  path_redirect:        #路径重定向
                  prefix_redirect:      #url前缀重定向
                  regex_rewrite:
                  response_code:
                  strip_query: false
                direct_response:            #直接响应
                  status:                #响应码
                  body:                  #body
                    inline_string: "ok\n"
              require_tls:
              virtual_clusters:
              rate_limits:
              request_headers_to_add:
              request_headers_to_remove:
              response_headers_to_add:
              response_headers_to_remove:
              cors:
                allow_origin:           #允许共享的资源列表,*为所有
                allow_origin_regex:     #用正则允许资源访问
                allow_methods:          #允许的方法,内容对应access-control-allow-methods标头
                allow_headers:          #运行在请求资源时使用的标头,对应access-control-allow-headers标头
                expose_headers:         #浏览器可访问的标头白名单,对应access-control-expose-headers标头
                max_age:                  #缓存最大时间,对应access-control-max-age标头
                allow_credentials: 布尔值    #是否允许服务调用方式使用凭据发起实际请求
                enabled: 布尔值            #是否启用跨域,默认为启用,由filter_enab led取代
                filter_enabled: true      #启用跨域,需定义过滤器的请求百分比,默认100%
                  default_value:
                    numerator: 100
                    demominator: HUNDRED
                shadow_enabled: 布尔值       #是否只在阴影模式下启用过滤器的请求百分比,启用时,默认值为100/HUNDRED。并评估请求的来源以确定其是否有效,但不强制执行任何策略,若同时启用filter_enabled,则以filter_enabled优先
              typed_per_filter_config:
              include_request_attempt_count:
              include_attempt_count_in_response:
              retry_policy:
              hedge_policy:
              per_request_buffer_limit_bytes:
            vhds:
            internal_only_headers:
            response_headers_to_add:
            response_headers_to_remove:
            request_headers_to_add:
            request_headers_to_remove:
            most_specific_header_mutations_wins:
            validate_clusters:
            max_direct_response_body_size_bytes:

案例

例1:简单路由案例

1)front-envoy.yaml
admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: vh_001
              domains: ["ilinux.io", "*.ilinux.io", "ilinux.*"]
              routes:
              - match:
                  path: "/service/blue"
                route:
                  cluster: blue
              - match:
                  safe_regex: 
                    google_re2: {}
                    regex: "^/service/.*blue$"
                redirect:
                  path_redirect: "/service/blue"
              - match:
                  prefix: "/service/yellow"
                direct_response:
                  status: 200
                  body:
                    inline_string: "This page will be provided soon later.\n"
              - match:
                  prefix: "/"
                route:
                  cluster: red
            - name: vh_002
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: gray
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
             "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
  - name: blue
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    load_assignment:
      cluster_name: blue
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: blue
                port_value: 80

  - name: red
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    load_assignment:
      cluster_name: red
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: red
                port_value: 80

  - name: green
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    load_assignment:
      cluster_name: green
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: green
                port_value: 80

  - name: gray
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    load_assignment:
      cluster_name: gray
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: gray
                port_value: 80
2)docker-compose.yaml
version: '3'

services:
  front-envoy:
    image: envoyproxy/envoy-alpine:v1.20.0
    volumes:
      - ./front-envoy.yaml:/etc/envoy/envoy.yaml
    networks:
      envoymesh:
        ipv4_address: 172.31.50.10
    expose:
      # Expose ports 80 (for general traffic) and 9901 (for the admin server)
      - "80"
      - "9901"

  light_blue:
    image: ikubernetes/servicemesh-app:latest
    networks:
      envoymesh:
        aliases:
          - light_blue
          - blue
    environment:
      - SERVICE_NAME=light_blue
    expose:
      - "80"

  dark_blue:
    image: ikubernetes/servicemesh-app:latest
    networks:
      envoymesh:
        aliases:
          - dark_blue
          - blue
    environment:
      - SERVICE_NAME=dark_blue
    expose:
      - "80"

  light_green:
    image: ikubernetes/servicemesh-app:latest
    networks:
      envoymesh:
        aliases:
          - light_green
          - green
    environment:
      - SERVICE_NAME=light_green
    expose:
      - "80"

  dark_green:
    image: ikubernetes/servicemesh-app:latest
    networks:
      envoymesh:
        aliases:
          - dark_green
          - green
    environment:
      - SERVICE_NAME=dark_green
    expose:
      - "80"

  light_red:
    image: ikubernetes/servicemesh-app:latest
    networks:
      envoymesh:
        aliases:
          - light_red
          - red
    environment:
      - SERVICE_NAME=light_red
    expose:
      - "80"

  dark_red:
    image: ikubernetes/servicemesh-app:latest
    networks:
      envoymesh:
        aliases:
          - dark_red
          - red
    environment:
      - SERVICE_NAME=dark_red
    expose:
      - "80"

  gray:
    image: ikubernetes/servicemesh-app:latest
    networks:
      envoymesh:
        aliases:
          - gray
          - grey
    environment:
      - SERVICE_NAME=gray
    expose:
      - "80"

networks:
  envoymesh:
    driver: bridge
    ipam:
      config:
        - subnet: 172.31.50.0/24
3)测试
#能匹配路由,则返回对应内容
curl -H "host: www.ilinux.io" http://172.31.50.10/service/blue
curl -H "Host: www.ilinux.io" http://172.31.50.10/service/red

#匹配不了路由,则使用默认的
curl  http://172.31.50.10/service/red
curl -H "host: www.qq.com" http://172.31.50.10/service/blue

image-20231209160429086

例2:请求头、参数路由

简洁案例

...
  listeners:
    ...
    virtual_hosts:
    - name: xx
      domains:
      - '*'
      routes:
      - match:      #路由到金丝雀集群
          prefix: '/'
          headers:
          - name: X-Canary
            exact_match: "true"
        route:
          cluster: cluster2
      - match:
          prefix: '/'
          query_parameters:
          - name: 'username'
            string_match:
              prefix: "vip_"
        route:
          cluster: cluster1
      - match:
          prefix: '/'
        route:
          cluster: cluster3

例3:流量迁移

image-20231209164919910

1)front-envoy.yaml
admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}
       
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: demoapp
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                  runtime_fraction:
                    default_value:
                      numerator: 100
                      denominator: HUNDRED
                    runtime_key: routing.traffic_shift.demoapp
                route:
                  cluster: demoappv10
              - match:
                  prefix: "/"
                route:
                  cluster: demoappv11
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
             "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
  - name: demoappv10
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: demoappv10
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: demoappv10
                port_value: 80

  - name: demoappv11
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: demoappv11
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: demoappv11
                port_value: 80
2)docker-compose.yaml
version: '3'

services:
  front-envoy:
    image: envoyproxy/envoy-alpine:v1.20.0
    volumes:
      - ./front-envoy.yaml:/etc/envoy/envoy.yaml
    networks:
      envoymesh:
        ipv4_address: 172.31.55.10
    expose:
      # Expose ports 80 (for general traffic) and 9901 (for the admin server)
      - "80"
      - "9901"

  demoapp-v1.0-1:
    image: ikubernetes/demoapp:v1.0
    hostname: demoapp-v1.0-1
    networks:
      envoymesh:
        aliases:
          - demoappv10
    expose:
      - "80"      
      
  demoapp-v1.0-2:
    image: ikubernetes/demoapp:v1.0
    hostname: demoapp-v1.0-2
    networks:
      envoymesh:
        aliases:
          - demoappv10
    expose:
      - "80"  
      
  demoapp-v1.0-3:
    image: ikubernetes/demoapp:v1.0
    hostname: demoapp-v1.0-3
    networks:
      envoymesh:
        aliases:
          - demoappv10
    expose:
      - "80" 
      
  demoapp-v1.1-1:
    image: ikubernetes/demoapp:v1.1
    hostname: demoapp-v1.1-1
    networks:
      envoymesh:
        aliases:
          - demoappv11
    expose:
      - "80"      
      
  demoapp-v1.1-2:
    image: ikubernetes/demoapp:v1.1
    hostname: demoapp-v1.1-2
    networks:
      envoymesh:
        aliases:
          - demoappv11
    expose:
      - "80"  

networks:
  envoymesh:
    driver: bridge
    ipam:
      config:
        - subnet: 172.31.55.0/24
3)send-request.sh
#!/bin/bash
declare -i ver10=0
declare -i ver11=0

interval="0.2"

while true; do
	if curl -s http://$1/hostname | grep "demoapp-v1.0" &> /dev/null; then
		# $1 is the host address of the front-envoy.
		ver10=$[$ver10+1]
	else
		ver11=$[$ver11+1]
	fi
	echo "demoapp-v1.0:demoapp-v1.1 = $ver10:$ver11"
	sleep $interval
done
4)测试
#观察流量比例
sh send-request.sh 172.31.55.10

#动态修改流量比例为
curl -X POST http://172.31.55.10:9901/runtime_modify?routing.traffic_shift.demoapp=90

envoy在检测到第一个match时就会终止后续检测,因此numerator为100时,所有流量都留在第一个匹配

image-20231209165438978

由于配置了2个相同的匹配路由,然后通过运行时修改numerator的值,如第一次是100%,后续是90%,来放走10%的流量,第二个匹配就能接收10%的流量

image-20231209165538725

image-20231209165555288

例4:流量分割

image-20231209171430779

1)front-envoy.yaml

其余配置参考例3

admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}
       
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: demoapp
              domains: ["*"]
              routes:
              routes:
              - match:
                  prefix: "/"
                route:
                  weighted_clusters:
                    clusters:
                    - name: demoappv10
                      weight: 100
                    - name: demoappv11
                      weight: 0
                    total_weight: 100
                    runtime_key_prefix: routing.traffic_split.demoapp
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
             "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
  - name: demoappv10
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: demoappv10
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: demoappv10
                port_value: 80

  - name: demoappv11
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: demoappv11
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: demoappv11
                port_value: 80
2)测试
sh send-request.sh 172.31.57.10

curl -X POST '172.31.57.10:9901/runtime_modify?routing.traffic_split.demoapp.demoappv10=0&routing.traffic_split.demoapp.demoappv11=100'

初始权重app_v1为100,demoappv10集群承载所有的流量image-20231209171607356

后续通过运行时接口修改运行时配置,调整权重,demoappv11集群为100接收所有流量,v10就不再接收流量

image-20231209171845256

image-20231209171859754

例5:流量镜像

1)front-envoy.yaml

其余配置参考例3

admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}
       
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: demoapp
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: demoappv10
                  request_mirror_policies:
                  - cluster: demoappv11
                    runtime_fraction:
                      default_value:
                        numerator: 20
                        denominator: HUNDRED
                      runtime_key: routing.request_mirror.demoapp
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
             "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router

  clusters:
  - name: demoappv10
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: demoappv10
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: demoappv10
                port_value: 80

  - name: demoappv11
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: demoappv11
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: demoappv11
                port_value: 80
2)测试
sh send-request.sh 172.31.60.10

表面上只请求了v1.0集群,但实际上,也请求了v1.1集群

image-20231209173612549

image-20231209173645914

例6:故障注入(中断与延迟)

image-20231210142404758

1)front-envoy.yaml
admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}
       
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/service/blue"
                route:
                  cluster: blue_abort
              - match:
                  prefix: "/service/red"
                route:
                  cluster: red_delay
              - match:
                  prefix: "/service/green"
                route:
                  cluster: green
              - match:
                  prefix: "/service/colors"
                route:
                  cluster: mycluster
          http_filters:
          - name: envoy.filters.http.router

  clusters:
  - name: red_delay
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: red_delay
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: service_red
                port_value: 80

  - name: blue_abort
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: blue_abort
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: service_blue
                port_value: 80

  - name: green
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: green
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: service_green
                port_value: 80

  - name: mycluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: mycluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: colored
                port_value: 80
2)service-envoy.yaml
admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}
       
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: local_service
          http_filters:
          - name: envoy.filters.http.router

  clusters:
  - name: local_service
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: local_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 8080
3)service-envoy-fault-injection-abort.yaml
admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}
       
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: local_service
          http_filters:
          - name: envoy.filters.http.fault
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
              max_active_faults: 100
              abort:
                http_status: 503
                percentage:
                  numerator: 10
                  denominator: HUNDRED
          - name: envoy.filters.http.router
            typed_config: {}

  clusters:
  - name: local_service
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: local_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 8080
4)service-envoy-fault-injection-delay.yaml
admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}
       
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: local_service
          http_filters:
          - name: envoy.filters.http.fault
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
              max_active_faults: 100
              delay:
                fixed_delay: 10s
                percentage:
                  numerator: 10
                  denominator: HUNDRED
          - name: envoy.filters.http.router
            typed_config: {}

  clusters:
  - name: local_service
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: local_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 8080
5)docker-compose.yaml
version: '3.3'

services:
  envoy:
    image: envoyproxy/envoy-alpine:v1.20.0
    volumes:
    - ./front-envoy.yaml:/etc/envoy/envoy.yaml
    networks:
      envoymesh:
        ipv4_address: 172.31.62.10
        aliases:
        - front-proxy
    expose:
      # Expose ports 80 (for general traffic) and 9901 (for the admin server)
      - "80"
      - "9901"

  service_blue:
    image: ikubernetes/servicemesh-app:latest
    volumes:
      - ./service-envoy-fault-injection-abort.yaml:/etc/envoy/envoy.yaml
    networks:
      envoymesh:
        aliases:
          - service_blue
          - colored
    environment:
      - SERVICE_NAME=blue
    expose:
      - "80"

  service_green:
    image: ikubernetes/servicemesh-app:latest
    networks:
      envoymesh:
        aliases:
          - service_green
          - colored
    environment:
      - SERVICE_NAME=green
    expose:
      - "80"

  service_red:
    image: ikubernetes/servicemesh-app:latest
    volumes:
      - ./service-envoy-fault-injection-delay.yaml:/etc/envoy/envoy.yaml
    networks:
      envoymesh:
        aliases:
          - service_red
          - colored
    environment:
      - SERVICE_NAME=red
    expose:
      - "80"
    
networks:
  envoymesh:
    driver: bridge
    ipam:
      config:
        - subnet: 172.31.62.0/24
6)send-requests.sh
#!/bin/bash

if [ $# -ne 2 ]
then
    echo "USAGE: $0 <URL> <COUNT>"
    exit 1;
fi

URL=$1
COUNT=$2
c=1
#interval="0.2"

while [[ ${c} -le ${COUNT} ]];
do
  #echo "Sending GET request: ${URL}"
  curl -o /dev/null -w '%{http_code}\n' -s ${URL} &
  (( c++ ))
#  sleep $interval
done

wait
7)curl_format.txt
    time_namelookup:  %{time_namelookup}\n
       time_connect:  %{time_connect}\n
    time_appconnect:  %{time_appconnect}\n
   time_pretransfer:  %{time_pretransfer}\n
      time_redirect:  %{time_redirect}\n
 time_starttransfer:  %{time_starttransfer}\n
                    ----------\n
         time_total:  %{time_total}\n
8)测试
#查看响应时间
while :;do curl -w'@curl_format.txt' -o /dev/null -s 
172.31.62.10/service/red ;sleep .5;done

#查看响应码
while :;do curl -o /dev/null -w '%{http_code}' -s 172.31.62.10/service/blue ; echo;sleep .5;done

正常响应时间与延时故障时间
image-20231210143607722

正常响应码和中断故障响应码
image-20231210143844242

例7:故障注入(重试与超时)

image-20231210153200356

1)front-envoy.yaml

其余配置参考例6

admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}
       
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/service/blue"
                route:
                  cluster: blue_abort
                  retry_policy:
                    retry_on: "5xx"
                    num_retries: 3                  
              - match:
                  prefix: "/service/red"
                route:
                  cluster: red_delay
                  timeout: 1s
              - match:
                  prefix: "/service/green"
                route:
                  cluster: green
              - match:
                  prefix: "/service/colors"
                route:
                  cluster: mycluster
                  retry_policy:
                    retry_on: "5xx"
                    num_retries: 3                  
                  timeout: 1s
          http_filters:
          - name: envoy.filters.http.router 
            typed_config: {}

  clusters:
  - name: red_delay
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: red_delay
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: service_red
                port_value: 80

  - name: blue_abort
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: blue_abort
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: service_blue
                port_value: 80

  - name: green
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: green
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: service_green
                port_value: 80

  - name: mycluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: mycluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: colored
                port_value: 80
2)测试
#查看响应时间
while :;do curl -w'@curl_format.txt' -o /dev/null -s 172.31.65.10/service/red ;sleep .5;done

#查看响应码
while :;do curl -o /dev/null -w '%{http_code}' -s 172.31.62.10/service/blue ; echo;sleep .5;done

正常延时是10s,但由于配置超时,所有只用1s就返回
image-20231210161640310
加入重试后,对5xx系列做了3次重新请求
image-20231210162116105

例8:cors跨域配置

参考官方案例:https://github.com/envoyproxy/envoy/tree/main/examples/cors

参考文档:https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/cors.html

posted @ 2023-12-13 16:29  suyanhj  阅读(373)  评论(0)    收藏  举报