美文网首页kubernetes
自定义kong plugin在k8s中的使用

自定义kong plugin在k8s中的使用

作者: lodestar | 来源:发表于2020-08-13 09:44 被阅读0次

    背景:在小程序上线审核时间段内,如果后端代码直接上线到线上,如果后端不兼容上个版本的接口,可能会导致前端某些接口请求失败。不断的兼容接口,会导致代码混乱,如果是大版本的迭代,有时候也很难去兼容。在审核期间,新版本接口走灰度服务器,老接口还是走线上服务器。审核通过后,小程序和接口同时提交上线,那边就不存在什么问题了。

    灰度服务总体架构


    Kong 灰度服务.png

    kong plugin gray服务

    plugins路径
    /usr/local/share/lua/5.1/kong/plugins/gray
    ├── client_redis.lua
    ├── handler.lua
    └── schema.lua
    

    handler.lua

    local BasePlugin = require "kong.plugins.base_plugin"
    local utils = require "kong.tools.utils"
    local client_redis = require "kong.plugins.gray.client_redis"
    local xml = require "pl.xml"
    
    local function get_redis_conf(conf)
      local redis_conf = {
        ["ip"] = conf.redis_host,
        ["port"] = conf.redis_port,
        ["passwd"] = conf.redis_password,
        ["timeout"]=conf.redis_timeout,
        ['database']=conf.redis_database}
      return redis_conf
    end
    
    local GrayHandler = BasePlugin:extend()
    
    GrayHandler.PRIORITY = 2000
    
    function GrayHandler:new()
      GrayHandler.super.new(self, "gray")
    end
    
    function GrayHandler:access(conf)
      GrayHandler.super.access(self)
      -- 获取版本号
      local method = kong.request.get_method()
      kong.log("method=" .. method)
      local version
      if method == "GET" then
         version = kong.request.get_query_arg("v")
      elseif method == "POST" then
         local body, err, mimetype = kong.request.get_body()
         if body ~= nil then
           version = body.v
         end
      else
        return
      end
      kong.log("version type=" .. type(version))
      if version == nil then
        return
      end
    
      local host = kong.request.get_host()
      --kong.log("host=" .. host)
      local arr = utils.split(host, ".")
      local prefix_host = arr[1]
      local key = "gray:"..prefix_host
      kong.log("host=" .. host .."\tkey=" .. key)
      --kong.log("host=" .. conf.redis_host.."\tport=" .. conf.redis_port.."\tpasswd=" .. conf.redis_password.."\ttimeout=" .. conf.redis_timeout.."\tdatabase="..conf.redis_database)
    
      local redis_conf = get_redis_conf(conf)
      --kong.log("timeout=" .. redis_conf['timeout'])
      --local robj = client_redis:new()
      local conn = client_redis:connection(redis_conf)
      local gray_version,err = conn:get(key)
      --kong.log("gray_version type=" .. type(gray_version))
      if gray_version == ngx.null then
        return
      end
      local log_str = "key=" .. key .. "\tversion=" .. version .. "\tgray_version=" .. gray_version
      kong.log(log_str)
    
      if version ~= nil and gray_version ~= ngx.null and gray_version == version then
        local upstream = conf.upstream
        kong.log(" into set upstream=" .. upstream)
        local ok, err = kong.service.set_upstream(upstream)
        if not ok then
          kong.log.err(err)
        end
      end
    
    end
    
    return GrayHandler
    

    schema.lua

    local typedefs = require "kong.db.schema.typedefs"
    return {
      name = "gray",
      fields = {
        { consumer = typedefs.no_consumer },
        { protocols = typedefs.protocols_http },
        { config={
           type = "record",
           fields = {
             { redis_host = { type = "string", required = true },},
             { redis_port = { type = "number", default = 6379 },},
             { redis_password = { type = "string", required = true},},
             { redis_database = { type = "number", default = 0},},
             { redis_timeout = { type = "number", default = 1000},},
             { upstream = { type = "string", required = true},},
           }
          }
        }
      }
    }
    

    client_redis.lua

    local redis = require "resty.redis"
    local _M = {}
        function _M:new()
          local o = {}
          setmetatable(o, self)
          self.__index = self;
          return o
        end
    
        function _M:connection(config)
            --kong.log("into redis")
            --kong.log("redis:ip=" .. config['ip']  .. "\tport=" .. config['port'])
            --kong.log("redis:ip=" .. config['ip']  .. "\tport=" .. config['port'] .. "\ttimeout=" .. config['timeout'])
            local red = redis:new()
            red:set_timeout(config['timeout'])
    
            local ok, err = red:connect(config['ip'],config['port'])
            if not ok then
                ngx.log(ngx.ERR, 'failed to connection redis',err)
                return nil
            end
    
            local ok, err = red:auth(config['passwd'])
            if not ok then
                red:close()
                ngx.log(ngx.ERR, 'Auth not pass')
                return nil
            end
            red:select(config['database'])
            return red
        end
    
    return _M
    

    将代码添加到configmap

    kubectl create configmap kong-plugin-gray-cm --from-file=/usr/local/share/lua/5.1/kong/plugins/gray
    

    gray.yaml

    apiVersion: configuration.konghq.com/v1
    kind: KongPlugin
    metadata:
      name: kong-plugin-gray
      labels:
        global: "false"
    config:
      redis_host: "172.16.1.1"
      redis_port: 6379
      redis_password: "xxxxxxx"
      redis_database: 0
      redis_timeout: 1000
      upstream: "k8s-gray-mobile.default.80.svc"
    plugin: gray
    

    创建KongPluin

    kubectl apply -f gray.yaml
    

    ingress中注解,需要使用kong-plugin-gray插件

    ingress:
      enabled: true
      annotations:
        konghq.com/plugins: "kong-plugin-gray"
    

    至此,整个灰度服务流程已完成。

    相关文章

      网友评论

        本文标题:自定义kong plugin在k8s中的使用

        本文链接:https://www.haomeiwen.com/subject/nztmdktx.html