前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >给你的istio sidecar写一个自定义扩展程序

给你的istio sidecar写一个自定义扩展程序

作者头像
机械视角
发布2022-06-05 11:15:15
5620
发布2022-06-05 11:15:15
举报
文章被收录于专栏:TensorbytesTensorbytes

基于 lua 编写 istio 扩展包

我们知道 istio 支持 lua 和 wasm 两种扩展能力,lua 作为脚本语言,相信写过游戏或 nginx 插件的都了解他,这里以 Lua 为例子,介绍下 istio 的 sidecar 如何编写一个插件。

首先说下目标,我们希望编译一个只作用于带app=python-web-v1label的sidecar,将所有到他的流量请求都转发一份到istio-test-for-python-web.rcmd-tt.svc.cluster.local服务,使用EnvoyFilter进行扩展: 案例源代码

代码语言:javascript
复制
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: example-istio-lua
  namespace: rcmd-tt
spec:
  workloadSelector: # envoyfilter的作用域
    labels:
      app: python-web-v1
  configPatches:
    # 编写一个lua脚本在filter链上拦截处理处理连接请求
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND #"ANY", "SIDECAR_INBOUND", "SIDECAR_OUTBOUND", "GATEWAY"
      listener:
        portNumber: 80
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
            subFilter:
              name: "envoy.filters.http.router"
    patch:
      operation: INSERT_BEFORE
      value: # lua filter specification
       name: envoy.lua
       typed_config:
          "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
          inlineCode: |
            function envoy_on_request(request_handle)
              -- Make an HTTP call to an upstream host with the following headers, body, and timeout.
              local headers, body = request_handle:httpCall(
               "istio-plugin-example",
               {
                [":method"] = "GET",
                [":path"] = "/send-the-next-server",
                [":authority"] = "istio-test-for-python-web",
                [":host"] = "istio-test-for-python-web"
               },
              "",
              1000)
            end
            function envoy_on_response(response_handle)
              response_handle:headers():add("mytag", "hello-world-girl")
            end
  - applyTo: CLUSTER
    match:
      context: SIDECAR_OUTBOUND
    patch:
      operation: ADD
      value: # cluster specification
        name: "istio-plugin-example"
        type: STRICT_DNS
        connect_timeout: 0.5s
        lb_policy: ROUND_ROBIN
        load_assignment:
          cluster_name: istio-plugin-example
          endpoints:
          - lb_endpoints:
            - endpoint:
                address:
                  socket_address:
                    protocol: TCP
                    address: "istio-test-for-python-web.rcmd-tt.svc.cluster.local" # 自定义的一个下游服务
                    port_value: 80

首先,通过app: istio-test限制了下发的 istio-sidcar 服务。 发送一个请求给istio-test-for-python-web服务:

代码语言:javascript
复制
curl -vv http://python-web-v1.rcmd-tt.svc/
*   Trying 10.247.249.149:80...
* Connected to python-web-v1.rcmd-tt.svc (10.247.249.149) port 80 (#0)
> GET / HTTP/1.1
> Host: python-web-v1.rcmd-tt.svc
> User-Agent: curl/7.71.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< date: Tue, 31 May 2022 13:07:46 GMT
< server: istio-envoy
< content-length: 77
< content-type: application/json
< x-envoy-upstream-service-time: 1
< mytag: hello-world-girl
< x-envoy-decorator-operation: python-web-v1.rcmd-tt.svc.cluster.local:80/*

我们看python-web-v1istio-test-for-python-web服务的日志都可以看到请求日志。返回的response是python-web-v1的。

Lua Filter 说明

Lua 脚本方法说明:

  • envoy_on_request 函数在请求路径上被调用,
  • envoy_on_response 脚本则在响应路径上被调用。

每个函数都接收一个句柄,该句柄有不同的定义方法:

代码语言:javascript
复制
function envoy_on_request(request_handle)
end
function envoy_on_response(response_handle)
end

request_handle 和 response_handle 两个 handle 句柄。句柄方法:

headers()

代码语言:javascript
复制
headers = handle:headers()

返回一个头对象,返回流的头。只要它们还没有被发送到头链中的下一个过滤器,就可以被修改。例如,它们可以在一个 httpCall() 或者 body() 调用返回后被修改。如果头在任何其他情况下被修改,脚本将失败。

body()

代码语言:javascript
复制
body = handle:body()

返回一个缓存对象,返回流的正文。这个调用将造成 Envoy 退出脚本直到整个正文被缓存。注意,所有缓存必须遵从适当的流控策略。Envoy 将不会缓存比连接管理器允许的更多的数据。

log()

代码语言:javascript
复制
handle:logTrace(message)
handle:logDebug(message)
handle:logInfo(message)
handle:logWarn(message)
handle:logErr(message)
handle:logCritical(message)

打印一条消息。message 是被保存的字符串。

httpCall()

代码语言:javascript
复制
headers, body = handle:httpCall(cluster, headers, body, timeout)

一个 HTTP 调用,返回一个header和body。cluster 是一个字符串,映射为一个配置好的集群管理器。headers 一个要发送的键值对的表,header中的:method:path:authority 头必须被设置。body 是一个可选的要发送的正文数据的字符串。timeout 是一个整数,指定以微秒为单位的调用超时。

metadata()

代码语言:javascript
复制
metadata = handle:metadata()

返回当前条目元数据。元数据需要在过滤器名下指定,例如envoy.lua。

代码语言:javascript
复制
handle:streamInfo():dynamicMetadata()

可以用来存储和传递数据

respond()

代码语言:javascript
复制
handle:respond(headers, body)

立即响应,这个调用仅在请求流 request_handle 中合法。

Enovy Filter说明

EnvoyFilter
EnvoyFilter

Envoy 配置说明

在说明 envoy filter 之前,我们先来简单介绍下 envoy:

  • Listener(监听器):监听器是命名网地址(例如,端口、unix domain socket等),可以被下游客户端连接。Envoy 暴露一个或者多个监听器给下游主机连接。
  • Cluster(集群):集群是指 Envoy 连接到的逻辑上相同的一组上游主机。Envoy 通过服务发现来发现集群的成员。可以选择通过主动健康检查来确定集群成员的健康状态。Envoy 通过负载均衡策略决定将请求路由到哪个集群成员。
envoy架构.png
envoy架构.png

我们看一个标准的 envoy 静态配置文件:

代码语言:javascript
复制
static_resources:
  listeners: // 监听器
  - address:
      socket_address:
        address: 0.0.0.0
        port_value: 8000
    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
          codec_type: AUTO
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: service
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/service"
                route:
                  cluster: local_service
          http_filters:
          - name: envoy.filters.http.router
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
  clusters: // 集群
  - name: local_service
    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
admin:
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8081

每个监听器都可以配置多个 Filter Chains(过滤器链),监听器会根据 filter_chain_match 中的匹配条件将流量转交到对应的过滤器链,其中每一个过滤器链都由一个或多个Network filters(网络过滤器)组成。Listener filters(监听器过滤器),它会在过滤器链之前执行,用于操纵连接的元数据。

参考文献

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-05-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基于 lua 编写 istio 扩展包
    • Lua Filter 说明
    • Enovy Filter说明
      • Envoy 配置说明
      • 参考文献
      相关产品与服务
      负载均衡
      负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档