标签归档:Kong中文文档

微服务 API 网关 Kong 插件开发 – 插件配置

原文地址:https://docs.konghq.com/1.1.x/plugin-development/plugin-configuration/(不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

简介

大多数情况下,您的插件可以配置为满足您的所有用户需求。当插件被执行的时候,您的插件的配置存储在Kong的数据存储区中,以检索它并将其传递给handler.lua方法。

配置由Kong中的Lua表组成,我们称之为 schema。它包含用户在通过Admin API启用插件时将设置的键/值属性。Kong为您提供了一种验证用户插件配置的方法。

当用户向Admin API发出请求以启用或更新给定Service,Route和/或Consumer上的插件时,将根据您的架构schema插件的配置。

例如,用户执行以下请求:

$ curl -X POST http://kong:8001/services/<service-name-or-id>/plugins/ \
    -d "name=my-custom-plugin" \
    -d "config.foo=bar"

如果配置对象的所有config都根据您的模式有效,则API将返回201 Created,并且插件将与其配置一起存储在数据库中(在这种情况下为{foo =“bar”})。如果配置无效,Admin API将返回400 Bad Request和相应的错误消息。

模块

kong.plugins.<plugin_name>.schema

schema.lua规范

此模块将返回一个Lua表,其中包含将定义用户以后如何配置插件的属性的属性。 可用的属性是:

属性名称 Lua type 默认值 描述
no_consumer Boolen false 如果为true,则无法将此插件应用于特定的Consumer。此插件必须仅应用于服务和路由。例如:身份验证插件。
fields Table {} 你插件的schema,可用属性及其规则的键/值表。
self_check Function nil 如果要在接受插件配置之前执行任何自定义验证,则要实现的功能。

self_check函数必须按如下方式实现:

-- @param `schema` 描述插件配置的架构(规则)的表。
-- @param `config` 当前插件配置的键/值表。
-- @param `dao` DAO的一个实例 (查看 DAO 章节).
-- @param `is_updating` 一个布尔值,指示是否在更新的上下文中执行此检查。
-- @return `valid` 一个布尔值,指示插件的配置是否有效。
-- @return `error` 一个 DAO 错误 (查看 DAO 章节)

以下是一个可能的schema.lua文件的示例:

return {
  no_consumer = true, -- 此插件仅适用于服务或路由,
  fields = {
    -- 在此处描述您的插件配置架构。
  },
  self_check = function(schema, plugin_t, dao, is_updating)
    -- 执行任何自定义验证
    return true
  end
}

描述您的配置schema

schema.lua文件的fields自选描述了插件配置的schema。它是一个灵活的键/值表,其中每个键都是插件的有效配置属性,每个键都是一个描述该属性规则的表。例如:

 fields = {
    some_string = {type = "string", required = true},
    some_boolean = {type = "boolean", default = false},
    some_array = {type = "array", enum = {"GET", "POST", "PUT", "DELETE"}}
  }

以下是属性的规则列表:

规则 LUA TYPE(S) 可使用的值 描述
type string “id”, “number”, “boolean”, “string”, 
“table”, “array”, “url”, “timestamp”
验证属性的类型。
required boolean 默认值:false。
如果为true,则该属性必须存在于配置中。
unique boolean 默认值:false。
如果为true,则该值必须是唯一的(请参阅下面的注释)。
default any 如果未在配置中指定该属性,则将该属性设置为给定值。
immutable boolean 默认值:false。
如果为true,则在创建插件配置后将不允许更新该属性。
enum table 属性的可接受值列表。不接受此列表中未包含的任何值。
regex string 用于验证属性值的正则表达式。
schema table 如果属性的类型是table,则定义用于验证这些子属性的模式。
func function 用于对属性执行任何自定义验证的函数。请参阅后面的示例,了解其参数和返回值。
  • type:将转换从请求参数中检索的值。如果类型不是本机Lua类型之一,则会对其执行自定义验证:
    • id:必须是string
    • timestamp:必须是nember
    • uri:必须是有效的URL
    • array:必须是整数索引表(相当于Lua中的数组)。在Admin API中,可以通过在请求的正文中使用不同值的属性键的多次来发送这样的数组,或者通过单个body参数以逗号分隔。
  • unique:此属性对插件配置没有意义,但在插件需要在数据存储区中存储自定义实体时使用。
  • schema:如果您需要对嵌套属性进行深化验证,则此字段允许您创建嵌套模式。模式验证是递归的。任何级别的嵌套都是有效的,但请记住,这会影响插件的可用性。
  • 附加到配置对象但schema中不存在的任何属性也将使所述配置无效。

例子

key-auth插件的schema.lua文件定义了API密钥的可接受参数名称的默认列表,以及默认设置为false的布尔值:

-- schema.lua
return {
  no_consumer = true,
  fields = {
    key_names = {type = "array", required = true, default = {"apikey"}},
    hide_credentials = {type = "boolean", default = false}
  }
}

于是,当在handler.lua中实现插件的access()函数并且用户使用默认值启用插件时,您可以如下:

-- handler.lua
local BasePlugin = require "kong.plugins.base_plugin"
local CustomHandler = BasePlugin:extend()

function CustomHandler:new()
  CustomHandler.super.new(self, "my-custom-plugin")
end

function CustomHandler:access(config)
  CustomHandler.super.access(self)

  kong.log.inspect(config.key_names)        -- {"apikey"}
  kong.log.inspect(config.hide_credentials) -- false
end

return CustomHandler

请注意,上面的示例使用插件开发工具包(PDK)kong.log.inspect函数将这些值打印到Kong日志中。

一个更复杂的示例,可用于最终日志记录插件:

-- schema.lua

local function server_port(given_value, given_config)
  -- 自定义验证
  if given_value > 65534 then
    return false, "port value too high"
  end

  -- 如果环境是“开发”,8080将是默认端口
  if given_config.environment == "development" then
    return true, nil, {port = 8080}
  end
end

return {
  fields = {
    environment = {type = "string", required = true, enum = {"production", "development"}}
    server = {
      type = "table",
      schema = {
        fields = {
          host = {type = "url", default = "http://example.com"},
          port = {type = "number", func = server_port, default = 80}
        }
      }
    }
  }
}

这样的配置将允许用户将配置发布到您的插件,如下所示:

curl -X POST http://kong:8001/services/<service-name-or-id>/plugins \
    -d "name=my-custom-plugin" \
    -d "config.environment=development" \
    -d "config.server.host=http://localhost"

以下内容将在handler.lua中提供:

-- handler.lua
local BasePlugin = require "kong.plugins.base_plugin"
local CustomHandler = BasePlugin:extend()

function CustomHandler:new()
  CustomHandler.super.new(self, "my-custom-plugin")
end

function CustomHandler:access(config)
  CustomHandler.super.access(self)

  kong.log.inspect(config.environment) -- "development"
  kong.log.inspect(config.server.host) -- "http://localhost"
  kong.log.inspect(config.server.port) -- 8080
end

return CustomHandler

您还可以在Key-Auth插件源代码中查看schema的真实示例。

微服务 API 网关 Kong 插件开发 – 文件结构

原文地址:https://docs.konghq.com/1.1.x/plugin-development/file-structure/ (不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

本章假定你已经会使用Lua语言

介绍

将您的插件视为一组Lua模块。本章中描述的每个文件都被视为一个单独的模块。如果他们的名字遵循这个约定,Kong将检测并加载你的插件的模块:

kong.plugins.<plugin_name>.<module_name>

您的模块当然需要通过package.path变量访问,可以通过lua_package_path配置属性调整您的需求。但是,安装插件的首选方法是通过LuaRocks,它与Kong本身集成。有关LuaRocks安装的插件的更多信息,请参阅本指南后面的内容。

为了让Kong意识到必须查找插件的模块,你必须将它添加到配置文件中的plugins属性中,这是一个以逗号分隔的列表。例如

plugins = bundled,my-custom-plugin # 你的插件名称

或者,如果您不想加载任何自带的插件:

plugins = my-custom-plugin  # 你的插件名称

现在,Kong将尝试从以下命名空间加载几个Lua模块:

kong.plugins.my-custom-plugin.<module_name>

其中一些模块是必需的(例如handler.lua),有些是可选的,并且允许插件实现一些额外的功能(例如api.lua以扩展Admin API)。现在让我们准确描述您可以实现的模块以及它们的用途。

基本插件模块

在最基本的形式中,插件包含两个必需的模块:

simple-plugin
├── handler.lua
└── schema.lua
  • 每个函数将在请求的生命周期中的所需时刻运行。
  • 由用户。此模块保存该配置的模式并在其上定义规则,以便用户只能输入有效的配置值。

高级插件模块

有些插件可能需要与Kong更深入地集成:在数据库中拥有自己的表,在Admin API中公开端点等等……每个插件都可以通过向插件添加新模块来完成。如果它实现了所有可选模块,那么插件的结构如下:

complete-plugin
├── api.lua
├── daos.lua
├── handler.lua
├── migrations
│   ├── cassandra.lua
│   └── postgres.lua
└── schema.lua

以下是要实施的可能模块的完整列表以及其目的的简要说明。 本指南将详细介绍,让您掌握其中的每一个文件。

模块文件名称 是否必须 描述
api.lua No 定义Admin API中可用的端点列表,以与插件处理的实体自定义实体进行交互。
daos.lua No 定义DAO(数据库访问对象)列表,这些DAO是插件所需并存储在数据存储区中的自定义实体的抽象。
handler.lua Yes 一个接口的实现。每个函数都由Kong在请求的生命周期中的所需时刻运行。
migrations/xxxx.lua No 给定数据存储的相应迁移。只有当您的插件必须在数据库中存储自定义实体并通过daos.lua定义的其中一个DAO与它们进行交互时,才需要进行迁移。
schema.lua Yes 保存插件配置的架构,以便用户只能输入有效的配置值。

Key-Auth 插件是具有此文件结构的插件的示例。 有关详细信息,请参阅其源代码

微服务 API 网关 Kong 插件开发 – 安装/卸载插件

原文地址:https://docs.konghq.com/1.1.x/plugin-development/entities-cache/ (不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

介绍

Kong的自定义插件由Lua源文件组成,这些源文件需要位于每个Kong节点的文件系统中。本指南将为您提供逐步说明,使Kong节点了解您的自定义插件。这些步骤应该应用于Kong集群中的每个节点,以确保每个节点上都有自定义插件。

打包源

您可以使用常规打包策略(例如tar),也可以使用LuaRocks包管理器为您执行此操作。我们推荐使用LuaRocks,因为它在使用其中一个官方分发包时与Kong一起安装。

使用LuaRocks时,您必须创建一个rockspec文件,用来指定包的内容。有关示例,请参阅Kong插件模板,有关该格式的更多信息,请参阅有关rockspecs的LuaRocks文档

使用以下命令打包你的rock(来自插件仓库):

# install it locally (based on the `.rockspec` in the current directory)
$ luarocks make

# 打包已安装的rock
$ luarocks pack <plugin-name> <version>

假设你的插件rockspec的名字为kong-plugin-myPlugin-0.1.0-1.rockspec,上面就会变成:

$ luarocks pack kong-plugin-myPlugin 0.1.0-1

LuaRocks pack命令现在已经创建了一个.rock文件(这只是一个包含安装rock所需内容的zip文件)。

如果您不使用或不能使用LuaRocks,则使用tar将插件所包含的.lua文件打包到.tar.gz存档中。 如果目标系统上有LuaRocks,也可以包含.rockspec文件。

该插件的内容应该接近以下内容:

$ tree <plugin-name>
<plugin-name>
├── INSTALL.txt
├── README.md
├── kong
│   └── plugins
│       └── <plugin-name>
│           ├── handler.lua
│           └── schema.lua
└── <plugin-name>-<version>.rockspec

安装插件

要使Kong节点能够使用自定义插件,必须在主机的文件系统上安装自定义插件的Lua源。有多种方法:通过LuaRocks,或手动。 选择一个,然后跳转到第3部分。

  1. 来自新建的’rock’的LuaRocks。
    .rock文件是一个自包含的软件包,可以在本地安装,也可以从远程服务器安装。
    如果您的系统中安装了luarocks实用程序(如果使用其中一个官方安装包,可能就是这种情况),您可以在LuaRocks树(LuaRocks安装Lua模块的目录)中安装“rock”。
    它可以通过以下方式安装:

     $ luarocks install <rock-filename>
    

    文件名可以是本地名称,或任何支持的方法。
    例如:http://myrepository.lan/rocks/myplugin-0.1.0-1.all.rock

  2. 从源档案中通过LuaRocks安装。 如果您的系统中安装了luarocks实用程序(如果使用其中一个官方安装包,可能就是这种情况),您可以在LuaRocks树(LuaRocks安装Lua模块的目录)中安装Lua源代码。
    您可以通过将当前目录更改为提取的存档来实现,其中rockspec文件是:

     $ cd <plugin-name>
    

    然后运行以下命令:

     $ luarocks make
    

    这将在系统的LuaRocks树中的kong/plugins/<plugin-name>中安装Lua源代码,其中所有的Kong源都已存在。

  3. 手动
    安装插件源的一种更保守的方法是避免“污染”LuaRocks树,而是将Kong指向包含它们的目录。
    这是通过调整Kong配置的lua_package_path属性来完成的。如果你熟悉它,那么这个属性是Lua VM的LUA_PATH变量的别名。
    这些属性包含以分号分隔的目录列表,用于搜索Lua源。它应该在您的Kong配置文件中设置如下:

     lua_package_path = /<path-to-plugin-location>/?.lua;
    

    继续:
    4./<path-to-plugin-location>是包含提取的存档的目录的路径。它应该是归档中kong目录的位置。
    5.?是一个占位符,将被kong.plugins替换。<plugin-name>当Kong将尝试加载你的插件。
    6.;;“默认Lua路径”的占位符。不要改变它。
    例如:
    插件位于文件系统上,使处理程序文件为:

     /usr/local/custom/kong/plugins/<something>/handler.lua
    

    kong目录的位置是:/usr/local/custom,因此正确的路径设置将是:

     lua_package_path = /usr/local/custom/?.lua;;
    

    多个插件:

    如果您希望以这种方式安装两个或更多自定义插件,可以将变量设置为:

      lua_package_path = /path/to/plugin1/?.lua;/path/to/plugin2/?.lua;;
    
     7.`;`是目录之间的分隔符。
     8.`;;`仍然意味着“默认的Lua路径”。
    

    注意:您还可以通过其等效的环境变量KONG_LUA_PACKAGE_PATH设置此属性。

提醒:无论您使用哪种方法来安装插件的源,您仍必须为Kong群集中的每个节点执行此操作。

加载插件

您现在必须将自定义插件的名称添加到Kong配置中的插件列表中(在每个Kong节点上):

plugins = bundled,<plugin-name>

或者,如果您不想包含默认捆绑的插件:

plugins = <plugin-name>

或者

plugins = plugin1,plugin2

注意:您还可以通过其等效的环境变量KONG_PLUGINS来设置此属性。 提醒:不要忘记更新Kong群集中每个节点的plugins指令。 提醒:插件重启后会生效:

kong restart

但是,如果你想在kong永不停止时应用插件,你可以使用:

kong prepare
kong reload

验证加载插件

你现在应该能够毫无问题地启动Kong。 请参阅自定义插件有关如何在服务,路由或消费者实体上启用/配置插件的说明。

为确保您的插件由Kong加载,您可以使用调试日志级别启动Kong:

log_level = debug

或者

KONG_LOG_LEVEL=debug

然后,您应该看到正在加载的每个插件的以下日志:

[debug] Loading plugin <plugin-name>

删除插件

完全删除插件有三个步骤。

  1. 从您的Kong Service或Route配置中删除插件。确保它不再适用于全局,也不适用于任何服务,路由或使用者。对于整个Kong集群,只需执行一次,不需要重新启动/重新加载。此步骤本身将使插件不再使用。但它仍然可用,仍然可以重新应用插件。
  2. plugins指令中删除插件(在每个Kong节点上)。确保在执行此操作之前已完成步骤1。在此步骤之后,任何人都无法将插件重新应用于任何Kong Service,Route,Consumer甚至全局。此步骤需要重新启动/重新加载Kong节点才能生效。
  3. 要彻底删除插件,请从每个Kong节点中删除与插件相关的文件。在删除文件之前,请确保已完成步骤2,包括重新启动/重新加载Kong。如果你使用LuaRocks来安装插件,你可以使用luarocks remove <plugin-name>来删除它。

分发插件

这样做的首选方法是使用LuaRocks,Lua模块的包管理器。它称这些模块为“rocks”。 您的模块不必存在于Kong存储库中,但如果您希望维护Kong设置,则可能就是这样。

通过在rockspec文件中定义模块(及其最终依赖项),您可以通过LuaRocks在您的平台上安装这些模块。

您也可以在LuaRocks上传模块并将其提供给所有人!

有关示例,请参阅Kong插件模板,有关该格式的更多信息,请参阅有关rockspecs的LuaRocks文档

故障排除

由于以下几个原因,配置错误的自定义插件可能无法启动:

  • “plugin is in use but not enabled” -> 您从另一个节点配置了一个自定义插件,并且该插件配置在数据库中,但您尝试启动的当前节点在其plugins指令中没有它。要解决此问题,请将插件的名称添加到节点的plugins指令中。
  • “plugin is enabled but not installed” -> 插件的名称出现在plugins指令中,但是Kong无法从文件系统加载handler.lua源文件。要解决此问题,请确保正确设置lua_package_path指令以加载此插件的Lua源。
  • “no configuration schema found for plugin” -> 插件已在plugins指令中安装,但是Kong无法从文件系统加载schema.lua源文件。要解决此问题,请确保schema.lua文件与插件的handler.lua文件一起存在。

微服务 API 网关 Kong 插件开发 – 缓存自定义实体

原文地址:https://docs.konghq.com/1.1.x/plugin-development/entities-cache/ (不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

介绍

您的插件可能需要经常访问每个请求 和/或 响应的自定义实体(在前一章中可见)。通常,加载它们一次并将它们缓存在内存中会显着提高性能,同时确保数据存储区不会因负载增加而受到压力。

考虑一个api-key身份验证插件,需要在每个请求上验证api-key,从而在每个请求中从数据存储区加载自定义凭据对象。当客户端提供api-key以及请求时,通常你会查询数据存储区以检查该密钥是否存在,然后,阻止请求或检索 Consumer ID以识别用户,这将在每个请求上发生,并且效率非常低:

  • 查询数据存储会增加每个请求的延迟,使请求处理速度变慢。
  • 数据存储区也会受到负载增加,可能崩溃或减速的影响,这反过来会影响每个Kong节点。

为避免每次都查询数据存储区,我们可以在节点上缓存内存中的自定义实体,这样频繁的实体查找不会每次都触发数据存储区查询(仅限第一次),而是在内存中查询,从数据存储区查询它(特别是在高负载下)更快更可靠。

Modules

kong.plugins.<plugin_name>.daos

缓存自定义实体

一旦定义了自定义实体,就可以使用插件开发工具包提供的 kong.cache 模块将它们缓存在代码中的内存中:

local cache = kong.cache

有两级缓存:

  1. L1:Lua内存缓存 – nginx worker的本地缓存这可以包含任何类型的Lua值。
  2. L2:共享内存缓存(SHM) – nginx节点的本地缓存,但在所有工作者之间共享。这只能保存标量值,因此需要(反)序列化。

从数据库中提取数据时,它将存储在两个缓存中。现在,如果同一个工作进程再次请求数据,它将从Lua内存缓存中检索以前反序列化的数据。如果同一Nginx节点中的另一个工作程序请求该数据,它将在SHM中找到数据,对其进行反序列化(并将其存储在自己的Lua内存缓存中),然后将其返回。

该模块公开以下功能:

FUNCTION NAME DESCRIPTION
value, err = cache:get(key, opts?, cb, ...) 从缓存中检索值。如果缓存没有值(未命中),在保护模式下调用cbcb必须返回一个(并且只有一个)将被缓存的值。它可能会抛出错误,因为这些错误会被Kong捕获并正确记录在ngx.ERR级别。 此函数会缓存否定结果(nil)。因此,在检查错误时必须依赖其第二个参数err
ttl, err, value = cache:probe(key) 检查是否缓存了值。如果是,则返回其剩余的TTL。它没有,返回零。

缓存的值也可以是负缓存。第三个返回值是被缓存的值本身。 | | cache:invalidate_local(key)| 从节点缓存中移除一个值。 | |cache:invalidate(key) | 从节点的缓存中删除一个值,并将删除事件传播到集群中的所有其他节点。 | | cache:purge() | 从节点缓存中删除所有值。 |

回到我们的身份验证插件示例,要查找具有特定api-key的凭据,我们将编写类似于:

-- access.lua

local function load_entity_key(api_key)
  -- 重要: 回调是在锁中执行的,因此我们不能在这里终止请求,我们必须始终返回。
  local apikeys, err = kong.dao.apikeys:find_all({key = api_key}) -- Lookup in the datastore
  if err then
    error(err) -- 被kong.cache捕获并记录
  end

  if not apikeys then
    return nil -- 没有找到 (cached for `neg_ttl`)
  end

  -- 假设键是唯一的,我们总是只有一个值…
  return apikeys[1] -- cache the credential (cached for `ttl`)
end

-- 从请求querystring检索apikey
local querystring = kong.request.get_query()
local apikey = querystring.apikey

-- 我们使用缓存。首先检查apikey是否已经存在
-- 存储在内存缓存中的键值为:“apikeys”。. .apikey
-- 如果不是,则查找数据存储并返回凭据对象。
-- 内部缓存。get将把值保存在内存中,然后返回凭据。
local credential, err = kong.cache:get("apikeys." .. apikey, nil,
                                       load_entity_key, apikey)
if err then
  return kong.response.exit(500, "Unexpected error: " .. err)
end

if not credential then
  -- 缓存和数据存储中没有凭据
  return kong.response.exit(403, "Invalid authentication credentials")
end

-- 如果凭据存在且有效,则设置上游标头
kong.service.request.set_header("X-API-Key", credential.apikey)

注意,在上面的示例中,我们使用插件开发工具包中的各种组件与请求、缓存模块交互,甚至从插件生成响应。
现在,有了上面的机制,一旦使用者使用API键发出请求,缓存就会被认为是热的,随后的请求不会导致数据库查询。 在Key-Auth插件处理程序中,缓存用于多个位置。让我们来看看官方插件是如何使用缓存的。

更新或者删除一个缓存实体

每次在数据存储中更新或删除缓存的自定义实体(即使用Admin API)时,都会在数据存储中的数据与缓存在Kong节点内存中的数据之间产生不一致。为了避免这种不一致,我们需要从内存存储中删除缓存的实体,并强制Kong从数据存储中再次请求它。我们将此过程称为缓存失效。

缓存失效

如果希望缓存的实体在CRUD操作时失效,而不是等待它们到达TTL,则必须执行以下步骤。对于大多数实体,这个过程都可以自动化,但是手动订阅一些CRUD事件可能需要使一些具有更复杂关系的实体失效。

自动缓存失效

如果依赖于实体模式的cache_key属性,则可以为实体提供开箱即用的缓存失效。例如,在下面的模式中:

local SCHEMA = {
  primary_key = { "id" },
  table = "keyauth_credentials",
  cache_key = { "key" }, -- 此实体的缓存键
  fields = {
    id = { type = "id" },
    created_at = { type = "timestamp", immutable = true },
    consumer_id = { type = "id", required = true, foreign = "consumers:id"},
    key = { type = "string", required = false, unique = true }
  }
}

return { keyauth_credentials = SCHEMA }

我们可以看到,我们将这个API key实体的缓存键声明为它的key属性。这里使用key是因为它有一个唯一的约束。因此,添加到cache_key的属性应该产生唯一的组合,这样就不会有两个实体产生相同的缓存键。
添加此值允许您在该实体的DAO上使用以下函数:

cache_key = kong.db.<dao>:cache_key(arg1, arg2, arg3, ...)

其中参数必须是模式的cache_key属性中指定的属性,按照指定的顺序,然后,此函数计算确保唯一的字符串值cache_key
例如,如果我们要生成API密钥的cache_key:

local cache_key = kong.db.keyauth_credentials:cache_key("abcd")

这将为API密钥“abcd”(从查询的一个参数中检索)生成一个cache_key,我们可以使用它来从缓存中检索密钥(如果缓存是未命中,则从数据库中获取):

local apikey = kong.request.get_query().apikey
local cache_key = kong.db.keyauth_credentials:cache_key(apikey)

local credential, err = kong.cache:get(cache_key, nil, load_entity_key, apikey)
if err then
  return kong.response.exit(500, "Unexpected error: " .. err)
end

-- do something with the credential

如果cache_key是这样生成的并且在实体的模式中指定,则缓存失效将是一个自动过程:影响此API密钥的每个CRUD操作都将使make生成受影响的cache_key,并将其广播到群集上的所有其他节点,以便他们可以从缓存中逐出该特定值,并在下一个请求中从数据存储区中获取新值。

当父实体正在接收CRUD操作时(例如,拥有此API密钥的消费者,根据我们的模式的consumer_id属性),Kong为父实体和子实体执行缓存失效机制。

注意:请注意Kong提供的负面缓存。在上面的示例中,如果给定密钥的数据存储区中没有API密钥,则缓存模块将存储未命中,就像它是命中一样。这意味着Kong也会传播“创建”事件(使用此给定密钥创建API密钥的事件),以便存储未命中的所有节点都可以驱逐它,并从数据存储中正确地获取新创建的API密钥。

请参阅群集指南以确保为此类失效事件正确配置了群集。

手动缓存失效

在某些情况下,实体架构的cache_key属性不够灵活,并且必须手动使其缓存无效。原因可能是插件没有通过传统的foreign =“parent_entity:parent_attribute”语法定义与另一个实体的关系,或者因为它没有使用来自其DAO的cache_key方法,或者甚至因为它以某种方式滥用缓存机制。

在这些情况下,您可以手动将自己的订户设置为Kong正在收听的相同失效频道,并执行您自己的自定义失效工作。

要监听Kong内部的失效通道,请在插件的init_worker处理程序中实现以下内容:

function MyCustomHandler:init_worker()
  -- listen to all CRUD operations made on Consumers
  kong.worker_events.register(function(data)

  end, "crud", "consumers")

  -- or, listen to a specific CRUD operation only
  kong.worker_events.register(function(data)
    kong.log.inspect(data.operation)  -- "update"
    kong.log.inspect(data.old_entity) -- old entity table (only for "update")
    kong.log.inspect(data.entity)     -- new entity table
    kong.log.inspect(data.schema)     -- entity's schema
  end, "crud", "consumers:update")
end

一旦上述侦听器适用于所需的实体,您就可以根据需要对插件已缓存的任何实体执行手动失效。 例如:

kong.worker_events.register(function(data)
  if data.operation == "delete" then
    local cache_key = data.entity.id
    kong.cache:invalidate("prefix:" .. cache_key)
  end
end, "crud", "consumers")

扩展Admin API

您可能已经知道,Admin API是Kong用户与Kong通信以设置其API和插件的地方。他们可能还需要能够与您为插件实现的自定义实体进行交互(例如,创建和删除API密钥)。这样做的方法是扩展Admin API,我们将在下一章详细介绍:扩展Admin API

微服务 API 网关 Kong 插件开发 – 实现自定义逻辑

简介

Kong插件允许您在 request/response 的生命周期中的几个入口点注入自定义逻辑(使用 Lua 语言),因为它由Kong代理。为此,必须实现base_plugin.lua 接口的一个或多个方法。这些方法将在命名空间下的模块中实现:kong.plugins。<plugin_name> .handler

Module

kong.plugins.<plugin_name>.handler

可用的请求上下文

插件接口允许您覆盖handler.lua文件中的以下任何方法,以在Kong的执行生命周期的各个入口点实现自定义逻辑:

函数名 LUA-NGINX-MODULE Context 描述
:init_worker() init_worker_by_lua 在每个 Nginx 工作进程启动时执行
:certificate() ssl_certificate_by_lua 在SSL握手阶段的SSL证书服务阶段执行
:rewrite() rewrite_by_lua 从客户端接收作为重写阶段处理程序的每个请求执行。在这个阶段,无论是API还是消费者都没有被识别,因此这个处理器只在插件被配置为全局插件时执行
:access() access_by_lua 为客户的每一个请求而执行,并在它被代理到上游服务之前执行
:header_filter() header_filter_by_lua 从上游服务接收到所有响应头字节时执行
:body_filter() body_filter_by_lua 从上游服务接收的响应体的每个块时执行。由于响应流回客户端,它可以超过缓冲区大小,因此,如果响应较大,该方法可以被多次调用
:log() log_by_lua 当最后一个响应字节已经发送到客户端时执行

所有这些函数都使用一个参数,该参数由Kong在调用时给出:插件的配置。此参数是Lua表,并包含用户根据插件的架构(在schema.lua模块中描述)定义的值。有关插件模式的更多信息将在下一章中介绍。

handler.lua规范

handler.lua文件必须返回一个表,该表实现了您希望执行的函数。为简洁起见,这里有一个注释示例模块,它实现了所有可用的方法:

-- 扩展基本插件处理程序是可选的,因为Lua中没有真正的接口概念,
-- 但是基本插件处理程序的方法可以从子实现中调用,
-- 并将在“error.log”中打印日志(其中打印所有日志)。
local BasePlugin = require "kong.plugins.base_plugin"
local CustomHandler = BasePlugin:extend()

-- 你的插件处理程序的构造函数。
-- 如果要扩展基本插件处理程序,它的唯一作用就是用名称实例化自己。
-- 该名称是您的插件名称,因为它将打印在日志中
function CustomHandler:new()
  CustomHandler.super.new(self, "my-custom-plugin")
end

function CustomHandler:init_worker()
  -- 最终,执行父实现
  -- (将记录您的插件正在进入此上下文)
  CustomHandler.super.init_worker(self)

  -- 在此实现任何自定义逻辑
end

function CustomHandler:certificate(config)
  -- 最终,执行父实现
  -- (将记录您的插件正在进入此上下文)
  CustomHandler.super.certificate(self)

  -- Implement any custom logic here
end

function CustomHandler:rewrite(config)
  -- Eventually, execute the parent implementation
  -- (will log that your plugin is entering this context)
  CustomHandler.super.rewrite(self)

  -- Implement any custom logic here
end

function CustomHandler:access(config)
  -- Eventually, execute the parent implementation
  -- (will log that your plugin is entering this context)
  CustomHandler.super.access(self)

  -- Implement any custom logic here
end

function CustomHandler:header_filter(config)
  -- Eventually, execute the parent implementation
  -- (will log that your plugin is entering this context)
  CustomHandler.super.header_filter(self)

  -- Implement any custom logic here
end

function CustomHandler:body_filter(config)
  -- Eventually, execute the parent implementation
  -- (will log that your plugin is entering this context)
  CustomHandler.super.body_filter(self)

  -- Implement any custom logic here
end

function CustomHandler:log(config)
  -- Eventually, execute the parent implementation
  -- (will log that your plugin is entering this context)
  CustomHandler.super.log(self)

  -- Implement any custom logic here
end

-- 该模块需要返回创建的表
-- 让Kong 可以执行这些功能。
return CustomHandler

当然,插件本身的逻辑可以抽象到另一个模块中,并从处理程序模块调用。许多现有的插件在逻辑冗长时已经选择了这种模式,但它是完全可选的:

local BasePlugin = require "kong.plugins.base_plugin"

-- 实际的逻辑是在这些模块中实现的
local access = require "kong.plugins.my-custom-plugin.access"
local body_filter = require "kong.plugins.my-custom-plugin.body_filter"

local CustomHandler = BasePlugin:extend()

function CustomHandler:new()
  CustomHandler.super.new(self, "my-custom-plugin")
end

function CustomHandler:access(config)
  CustomHandler.super.access(self)

  -- 从“access”中加载的模块执行任何函数,
  -- 例如,`execute()`并将插件的配置传递给它。
  access.execute(config)
end

function CustomHandler:body_filter(config)
  CustomHandler.super.body_filter(self)

  -- Execute any function from the module loaded in `body_filter`,
  -- for example, `execute()` and passing it the plugin's configuration.
  body_filter.execute(config)
end

return CustomHandler

有关实际处理程序代码的示例,请参阅Key-Auth插件的源代码

插件开发套件

在这些阶段中实现的逻辑很可能必须与请求/响应对象或核心组件交互(例如访问缓存、数据库……)。Kong提供了一个插件开发套件(简称PSK),一组Lua函数和变量,插件可以使用这些Lua函数和变量来执行各种网关操作,确保它们与将来的Kong版本向前兼容。

当您试图实现一些需要与Kong交互的逻辑时(例如检索请求头、从插件生成响应、记录一些错误或调试信息……),您应该参考插件开发工具包

插件执行顺序

一些插件可能依赖于其他插件的执行来执行一些操作。例如,依赖于消费者身份的插件必须在身份验证插件之后运行。考虑到这一点,Kong定义了插件执行之间的优先级,以确保顺序得到遵守。

你的插件的优先级可以通过一个属性来配置,在返回的handler table 中一个数字:

CustomHandler.PRIORITY = 10

优先级越高,相对于其他插件的阶段(如:access()、:log()等),插件的阶段执行得越快。 已有捆绑插件的当前执行顺序为:

插件 优先级
pre-function +inf
zipkin 100000
ip-restriction 3000
bot-detection 2500
cors 25000
jwt 1005
oauth2 1004
key-auth 1003
ldap-auth 1002
basic-auth 1001
hmac-auth 1000
request-size-limiting 951
acl 950
rate-limiting 901
response-ratelimiting 900
request-transformer 801
response-transformer 800
aws-lambda 750
azure-functions 749
prometheus 13
http-log 12
statsd 11
datadog 10
file-log 9
udp-log 8
tcp-log 7
loggly 6
syslog 4
galileo 3
request-termination 2
correlation-id 1
post-function -1000

微服务 API 网关 Kong 插件开发 – 访问数据存储区

原文地址:https://docs.konghq.com/1.1.x/plugin-development/access-the-datastore/ (不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

简介

Kong通过我们称为“DAOs”的类与模型层交互。本章将详细介绍与数据存储交互的可用API。Kong支持两个主数据存储:Cassandra 3.x.xPostgreSQL 9.5+

kong.db

Kong 的所有实例表示为:

  • 描述实体在数据存储区中与哪个表相关的模式,对其字段的约束,如外键,非空约束等…此schema是插件配置章节中描述的表。
  • DAO类的一个实例映射到当前正在使用的数据库(Cassandra或PostgreSQL)。此类的方法使用模式并公开方法来插入,更新,查找和删除该类型的实体。

Kong的核心实体是:Services, Routes, Consumers 和 Plugins。所有这些都可以作为数据访问对象(DAO)通过kong.db全局单例访问:

-- Core DAOs
local services_dao = kong.db.services
local routes_dao = kong.db.routes
local consumers_dao = kong.db.consumers
local plugins_dao = kong.dao.plugins

来自Kong的核心实体和插件中的自定义实体都可以通过kong.db.*

The DAO Lua API

DAO类负责在数据存储区中的给定表上执行的操作,通常映射到Kong的实体。所有底层支持的数据库(目前是Cassandra和PostgreSQL)都遵循相同的接口,从而使DAO与所有这些兼容。 例如,插入服务和插件非常简单:

local inserted_service, err = kong.db.services:insert({
  name = "mockbin",
  url = "http://mockbin.org",
})

local inserted_plugin, err = kong.db.plugins:insert({
  name = "key-auth",
  service_id = { id = inserted_service.id },
})

有关在插件中使用的DAO的实际示例,请参阅 Key-Auth plugin 的源代码

微服务 API 网关 Kong 插件开发 – 存储自定义实体

原文地址:https://docs.konghq.com/1.1.x/plugin-development/custom-entities/ (不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

介绍

虽然不是所有插件都需要它,但是您的插件可能需要在数据库中存储比配置更多的东西。在这种情况下,Kong在其主要数据存储之上提供了一个抽象,允许您存储自定义实体。

前一章节访问数据存储区所述。Kong通过我们称之为“DAOs”的类与模型层交互,并且可以在通常被称为“DAO Factory”的单例上使用。本章将解释如何为您自己的实体提供一个抽象体。

Modules

kong.plugins.<plugin_name>.daos
kong.plugins.<plugin_name>.migrations.init
kong.plugins.<plugin_name>.migrations.000_base
kong.plugins.<plugin_name>.migrations.001_xxx
kong.plugins.<plugin_name>.migrations.002_yyy

创建migrations文件夹

一旦定义了model,您必须创建将由Kong执行的migration modules,创建将存储您的实体记录的表。迁移文件包含一系列迁移,并返回它们。
如果您的插件旨在支持Cassandra和PostgreSQL,那么必须编写两个migrations。
如果您的插件还没有migrations文件夹,你应该添加一个<plugin_name>/migrations文件夹。如果里面没有init.lua文件,你应该创建一个。这是引导插件所有迁移的地方。
migrations/init.lua文件的初始版本将指向单个迁移。
在这种情况下,我们称之为000_base

-- `migrations/init.lua`
return {
  "000_base",
}

这意味着<plugin_name>/migrations/000_base.lua中将包含一个包含初始迁移的文件。
我们将在一分钟内看到这是如何完成的。

迁移文件的语法

虽然Kong的核心迁移支持PostgreSQL和Cassandra,但自定义插件可以选择支持它们或只支持一个。

迁移文件是一个Lua文件,它返回一个具有以下结构的表:

-- `<plugin_name>/migrations/000_base.lua`
return {
  postgresql = {
    up = [[
      CREATE INDEX IF NOT EXISTS "routes_name_idx" ON "routes" ("name");
    ]],
    teardown = function(connector, helpers)
      assert(connector:connect_migrations())
      assert(connector:query('DROP TABLE IF EXISTS "schema_migrations" CASCADE;'))
    end,
  },

  cassandra = {
    up = [[
      CREATE INDEX IF NOT EXISTS routes_name_idx ON routes(name);
    ]],
    teardown = function(connector, helpers)
      assert(connector:connect_migrations())
      assert(connector:query("DROP TABLE IF EXISTS schema_migrations"))
    end,
  }
}

如果插件仅支持PostgreSQL或Cassandra,则只需要这个策略的一部分。每个策略部分都有两个部分,upteardown

  • up是一个可选的原始SQL / CQL语句字符串。当执行ong migrations up时,将执行这些语句。
  • teardown是一个可选的Lua函数,它接受一个connector参数。此类连接器可以调用查询方法来执行SQL/CQL查询。删除是由kong migrations finish触发。

建议在up部分上完成所有非破坏性操作,例如创建新表和添加新记录。而在进行破坏性操作(例如删除数据,更改行类型,插入新数据)时候在teardown部分。

在这两种情况下,建议编写所有SQL/CQL语句,以使它们尽可能重入。DROP TABLE IF EXISTS代替DROP TABLECREATE INDEX IF NOT EXIST代替CREATE INDEX等等。如果迁移由于某种原因而失败,则预计解决问题的第一次尝试将只是重新运行迁移。

虽然PostgreSQL没有,但Cassandra不支持诸如“NOT NULL”,“UNIQUE”或“FOREIGN KEY”之类的约束,但是,当您定义模型的模式时,Kong会为您提供此类功能。请记住,这个模式对于PostgreSQL和Cassandra都是相同的,因此,您可能会为使用Cassandra的模式权衡纯SQL模式。

重要:如果您的schema使用unique约束,那么Kong将为Cassandra强制执行它,但对于PostgreSQL,您必须在迁移中设置此约束。

从DAO Factory检索您的自定义DAO

要使DAO Factory加载自定义DAO,您需要定义实体的架构(就像描述插件配置的模式一样)。此模式包含更多值,因为它必须描述实体在数据存储区中与哪个表相关,对其字段的约束(如外键,非空约束等)。

此模式将在名为的模块中定义:

"kong.plugins.<plugin_name>.daos"

一旦该模块返回您的实体模式,并假设您的插件由Kong加载(请参阅kong.conf中的plugins属性),DAO Factory将使用它来实例化DAO对象。

以下是如何定义用于在其数据库中存储API密钥的模式的示例:

-- daos.lua
local SCHEMA = {
  primary_key = {"id"},
  table = "keyauth_credentials", -- 数据库中的表
  fields = {
    id = {type = "id", dao_insert_value = true}, -- DAO本身要插入的值(想想序列号和这里所需的唯一性)
    created_at = {type = "timestamp", immutable = true, dao_insert_value = true}, -- DAO本身也有所涉及
    consumer_id = {type = "id", required = true, foreign = "consumers:id"}, -- Consumer's id 的外键
    key = {type = "string", required = false, unique = true} --  唯一 API key
  }
}

return {keyauth_credentials = SCHEMA} -- 这个插件只产生一个自定义DAO, 名为 `keyauth_credentials`

由于您的插件可能必须处理多个自定义DAO(在您要存储多个实体的情况下),此模块必须返回一个键/值表,其中键是DAO Factory中可用的自定义DAO的名称。

您将注意到架构定义中的一些新属性(与schema.lua文件进行比较)

属性名 LUA TYPE 描述
primary_key Integer indexed table 每个部分column family的主键的数组,它还支持复合键,即使所有Kong实体当前都使用简单ID来管理Admin API的可用性。如果主键是组合键,则只包含分区键的组成部分。
fields.*.dao_insert_value Boolean 如果为true,则指定此字段由DAO(在base_dao实现中)自动填充,具体取决于其类型。id类型的属性将是生成的uuid,时间戳是具有第二精度的时间戳。
fields.*.queryable Boolean 如果为true,则指定Cassandra在指定column上维护索引。允许查询由该column过滤的column family 。
fields.*.foreign String 指定此column是另一个实体列的外键。格式为:dao_name:column_name,这使得Cassandra不支持外键。当父行将被删除时,Kong还将删除包含父列值的行。

您的DAO现在将由DAO Factory加载并作为其属性之一提供。因为DAO工厂是由插件开发工具包的kong global(参见kong)公开的。dao,可以这样检索:

local key_credential, err = kong.dao.key_credentials:insert({
  consumer_id = consumer.id,
  key = "abcd"
})

可以从DAO Factory访问的DAO名称(keyauth_credentials),取决于您在daos.lua的返回表中导出DAO的键。

您可以在Key-Auth daos.lua文件中看到此示例。

缓存自定义实体

有时每个request/response都需要自定义实体,每次都会在数据存储区上触发查询。这样效率非常低,因为查询数据存储会增加延迟并降低request/response速度。并且由此导致的数据存储区负载增加可能会影响数据存储区性能本身,进而影响其他Kong节点。

当每个请求/响应都需要自定义实体时,最好通过利用Kong提供的内存缓存API将其缓存在内存中。

下一章将重点介绍如何缓存自定义实体,并在数据存储区中更改时使它们失效:缓存自定义实体。

微服务 API 网关 Kong 单元测试中文文档

原文链接: https://docs.konghq.com/1.0.x/plugin-development/tests/ (如有翻译的不准确或错误之处,欢迎留言指出)
集成测试:https://docs.konghq.com/1.0.x/plugin-development/tests/#write-integration-tests

介绍

如果你认真对待你写的插件,你可能想为它编写一些测试。Lua的单元测试很简单,并且可以使用许多测试框架。但是,您可能还想编写集成测试。Kong可以再次为您提供支援。

编写集成测试

Kong的首选测试框架是busted,它与resty-cli解释器一起运行,但如果您愿意,可以自由使用另一个。在Kong存储库中,可以在bin/busted找到 busted 的可执行文件。

Kong为您提供了一个帮助程序,可以在测试套件中从Lua启动和停止它:spec.helpers。此助手还提供了在运行测试之前在数据存储区中插入fixtures的方法,以及删除,以及各种其他helper。

如果您在自己的存储库中编写插件,则需要复制以下文件,直到Kong测试框架发布:

  • bin/busted: 与resty-cli解释器一起运行的 busted 的可执行文件
  • spec/helpers.lua:Kong的helper函数 可以从busted中 启动/关闭kong
  • spec/kong_tests.conf:使用helpers模块运行的Kong实例的配置文件

假设您的LUA_PATH中有spec.helpers模块,您可以使用以下Lua代码来启动和停止Kong:

local helpers = require "spec.helpers"

for _, strategy in helpers.each_strategy() do
  describe("my plugin", function()

    local bp = helpers.get_db_utils(strategy)

    setup(function()
      local service = bp.services:insert {
        name = "test-service",
        host = "httpbin.org"
      }

      bp.routes:insert({
        hosts = { "test.com" },
        service = { id = service.id }
      })

      -- start Kong with your testing Kong configuration (defined in "spec.helpers")
      assert(helpers.start_kong( { plugins = "bundled,my-plugin" }))

      admin_client = helpers.admin_client()
    end)

    teardown(function()
      if admin_client then
        admin_client:close()
      endhttps://github.com/Kong/kong/tree/master/spec/03-plugins/09-key-auth

      helpers.stop_kong()
    end)

    before_each(function()
      proxy_client = helpers.proxy_client()
    end)

    after_each(function()
      if proxy_client then
        proxy_client:close()
      end
    end)

    describe("thing", function()
      it("should do thing", function()
        -- send requests through Kong
        local res = proxy_client:get("/get", {
          headers = {
            ["Host"] = "test.com"
          }
        })

        local body = assert.res_status(200, res)

        -- body is a string containing the response
      end)
    end)
  end)
end

提醒:通过test Kong配置文件,Kong运行在代理监听端口9000(HTTP),9443 (HTTPS)和端口9001上的Admin API。

如果想看一下真实的例子,可以来这里看一看 Key-Auth plugin specs

微服务 API 网关 Kong 命令行中文文档

原文链接: https://docs.konghq.com/1.0.x/cli/
(如有翻译的不准确或错误之处,欢迎留言指出)

介绍

提供的CLI(命令行界面Command Line Interface)允许启动,停止和管理Kong实例。CLI可以管理本地节点(如在当前计算机上)。

如果您还没有使用,我们建议您阅读配置参考

通用标志参数

所有命令都将一组特殊的可选标志作为参数:

  • --help:打印此命令的帮助信息
  • --v:启用详细模式
  • --vv:启用调试模式(很多输出)

可用命令

kong check

Usage: kong check <conf>

检查给定Kong配置文件的有效性。

<conf> (default /etc/kong/kong.conf) 配置文件

kong health

Usage: kong health [OPTIONS]

验证Kong 的服务组件是否正常运行

Options:
 -p,--prefix      (可选参数) Kong运行位置的前缀

kong migrations

Usage: kong migrations COMMAND [OPTIONS]

管理数据库迁移。

可用的命令如下:
  bootstrap                         引导数据库并运行全部迁移(初始化)。

  up                                运行新迁移。

  finish                            完成正在等待中的迁移命令,在执行`up`后。

  list                              列出已执行的迁移。

  reset                             重置数据库。

Options(可选):
 -y,--yes                           假设提示“yes”,并运行非交互模式

 -q,--quiet                         忽略所有输出

 -f,--force                         依旧执行迁移,即使数据库报告已经执行过了。

 --db-timeout     (default 60)      超时时间,以秒为单位,所有数据库操作通用(包括Cassandra的schema consensus)。

 --lock-timeout   (default 60)      超时时间,以秒为单位, 节点等待领导节点迁移完成。

 -c,--conf        (optional string) 配置文件。

kong prepare

此命令用来准备Kong前缀文件夹及其子文件夹和文件。

Usage: kong prepare [OPTIONS]

在配置的前缀目录中准备Kong前缀。这个命令可以用于从nginx二进制文件启动Kong而不使用`kong start`命令。

Example usage:
  kong migrations up
  kong prepare -p /usr/local/kong -c kong.conf
  nginx -p /usr/local/kong -c /usr/local/kong/nginx.conf

Options:
  -c,--conf       (optional string) 配置文件
  -p,--prefix     (optional string) 覆盖前缀目录
  --nginx-conf    (optional string) 自定义Nginx配置模板

kong quit

Usage: kong quit [OPTIONS]

优雅地退出一个正在运行的Kong节点(Nginx和其他节点)在给定的前缀目录中配置的服务。

此命令将会向Nginx发送SIGQUIT信号,表示全部请求将在关闭之前完成处理。
如果达到超时延迟,则该节点将被强制执行停止(SIGTERM)

Options:
 -p,--prefix      (optional string) kong正在运行的前缀
 -t,--timeout     (default 10) 强制停止前的超时

kong reload

Usage: kong reload [OPTIONS]

重新加载Kong节点(并启动其他已配置的服务)在给定的前缀目录中。

此命令将HUP信号发送到Nginx,它将生成workers(告知account配置变更),当他们处理完成当前的请求后就停止旧的。

Options:
  -c,--conf       (optional string) 配置文件
  -p,--prefix     (optional string) 覆盖前缀目录
  --nginx-conf    (optional string) 自定义Nginx配置模板

kong restart

Usage: kong restart [OPTIONS]

重新启动Kong节点(以及其他配置的服务,如Serf)在给定的前缀目录中。

这个命令相当于同时执行`kong stop`和`kong start`。

Options:
 -c,--conf        (optional string)   配置文件
 -p,--prefix      (optional string)   Kong运行的前缀
 --nginx-conf     (optional string)   自定义Nginx配置模板
 --run-migrations (optional boolean)  可选地在DB上运行迁移
 --db-timeout     (default 60)
 --lock-timeout   (default 60)

kong start

Usage: kong start [OPTIONS]

在配置中启动Kong(Nginx和其他配置的服务)。

Options:
 -c,--conf        (optional string)   配置文件。

 -p,--prefix      (optional string)   覆盖前缀目录。

 --nginx-conf     (optional string)   自定义Nginx配置模板。

 --run-migrations (optional boolean)  在开始之前运行迁移。

 --db-timeout     (default 60)      超时时间,以秒为单位,所有数据库操作通用(包括Cassandra的schema consensus)。

 --lock-timeout   (default 60)      超时时间,以秒为单位, 节点等待领导节点迁移完成。

kong stop

Usage: kong stop [OPTIONS]

停止给定的正在运行的Kong节点(Nginx和其他已配置的服务)在指定的前缀目录。

此命令将SIGTERM信号发送到Nginx。

Options:
 -p,--prefix      (optional string) Kong运行的前缀

kong version

Usage: kong version [OPTIONS]

打印kong的版本。
使用-a选项,将打印所有底层依赖项的版本。

Options:
 -a,--all         获取所有依赖项的版本

微服务 API 网关 Kong File Log 插件中文文档

原文链接: https://docs.konghq.com/hub/kong-inc/file-log
(如有翻译的不准确或错误之处,欢迎留言指出)

将请求和响应数据写入磁盘上的日志文件中。不建议在生产中使用此插件,在生产环境下,最好使用另一个日志插件,例如syslog。由于系统限制,此插件使用阻塞文件i/o,将会损害性能,因此是Kong安装的反面模式。
注意:此插件的功能与0.10.2之前的Kong版本捆绑在一起,与此处记录的不同。 有关详细信息,请参阅CHANGELOG

配置

在服务上启用插件

通过发出以下请求在服务上配置此插件:

$ curl -X POST http://kong:8001/services/{service}/plugins \
    --data "name=file-log"  \
    --data "config.path=/tmp/file.log"

service:此插件配置将绑定的服务的ID或名称。

在路由上启用插件

Route上配置此插件:

$ curl -X POST http://kong:8001/routes/{route_id}/plugins \
    --data "name=file-log"  \
    --data "config.path=/tmp/file.log"

route_id:此插件配置将绑定的路由的ID。

在Consumer上启用插件

您可以使用 http://localhost:8001/plugins 端点在特定的Consumers上启用此插件:

$ curl -X POST http://kong:8001/plugins \
    --data "name=file-log" \
    --data "consumer_id={consumer_id}"  \
    --data "config.path=/tmp/file.log"

其中,consumer_id是我们想要与此插件关联的消费者的ID。您可以组合consumer_idservice_id。在同一个请求中,进一步缩小插件的范围。

全局插件

可以使用http://kong:8001/plugins/ 配置所有插件。与任何服务,路由或消费者(或API,如果您使用旧版本的Kong)无关的插件被视为“全局”,并将在每个请求上运行。有关更多信息,请阅读插件参考插件优先级部分。

参数

以下是可在此插件配置中使用的所有参数的列表:

参数名称 默认值 描述
name 要使用的插件的名称,在本例中为file-log
service_id 此插件将关联的服务的ID。
route_id 此插件将关联的路由的ID。
enabled true 是否将应用此插件。
consumer_id 此插件将定位的绑定的id。
config.path 输出日志文件的文件路径。
如果该文件尚不存在,该插件将创建该文件。
确保Kong对此文件具有写入权限。
config.reopen false 在kong0.10.2引入。确定是否关闭日志文件并在每个请求时重新打开。 如果文件未重新打开,并且已被删除/循环,则插件将继续写入过时的文件描述符,从而丢失信息。

日志格式

每个请求将分别记录在由新行\n分隔的JSON对象中,格式如下:

{
    "request": {
        "method": "GET",
        "uri": "/get",
        "url": "http://httpbin.org:8000/get",
        "size": "75",
        "querystring": {},
        "headers": {
            "accept": "*/*",
            "host": "httpbin.org",
            "user-agent": "curl/7.37.1"
        }
    },
    "upstream_uri": "/",
    "response": {
        "status": 200,
        "size": "434",
        "headers": {
            "Content-Length": "197",
            "via": "kong/0.3.0",
            "Connection": "close",
            "access-control-allow-credentials": "true",
            "Content-Type": "application/json",
            "server": "nginx",
            "access-control-allow-origin": "*"
        }
    },
    "tries": [
        {
            "state": "next",
            "code": 502,
            "ip": "127.0.0.1",
            "port": 8000
        },
        {
            "ip": "127.0.0.1",
            "port": 8000
        }
    ],
    "authenticated_entity": {
        "consumer_id": "80f74eef-31b8-45d5-c525-ae532297ea8e",
        "id": "eaa330c0-4cff-47f5-c79e-b2e4f355207e"
    },
    "route": {
        "created_at": 1521555129,
        "hosts": null,
        "id": "75818c5f-202d-4b82-a553-6a46e7c9a19e",
        "methods": null,
        "paths": [
            "/example-path"
        ],
        "preserve_host": false,
        "protocols": [
            "http",
            "https"
        ],
        "regex_priority": 0,
        "service": {
            "id": "0590139e-7481-466c-bcdf-929adcaaf804"
        },
        "strip_path": true,
        "updated_at": 1521555129
    },
    "service": {
        "connect_timeout": 60000,
        "created_at": 1521554518,
        "host": "example.com",cuowu
        "id": "0590139e-7481-466c-bcdf-929adcaaf804",
        "name": "myservice",
        "path": "/",
        "port": 80,
        "protocol": "http",
        "read_timeout": 60000,
        "retries": 5,
        "updated_at": 1521554518,
        "write_timeout": 60000
    },
    "workspaces": [
        {
            "id":"b7cac81a-05dc-41f5-b6dc-b87e29b6c3a3",
            "name": "default"
        }
    ],
    "consumer": {
        "username": "demo",
        "created_at": 1491847011000,
        "id": "35b03bfc-7a5b-4a23-a594-aa350c585fa8"
    },
    "latencies": {
        "proxy": 1430,
        "kong": 9,
        "request": 1921
    },
    "client_ip": "127.0.0.1",
    "started_at": 1433209822425
}

关于上述JSON对象的一些注意事项:

  • request 包含有关客户端发送的请求的属性
  • response 包含有关发送到客户端的响应的属性
  • tries 包含负载均衡器为此请求进行的(重新)尝试(成功和失败)列表
  • route 包含有关所请求的特定路线的Kong属性
  • service 包含与所请求的路线相关联的服务的Kong属性
  • authenticated_entity 包含有关经过身份验证的凭据的Kong属性(如果已启用身份验证插件)
  • workspaces 包含与请求的路由关联的工作空间的Kong属性。仅限Kong Enterprise版本> = 0.34
  • consumer 包含经过身份验证的使用者(如果已启用身份验证插件)
  • latencies 包含一些有关延迟的数据:
    • proxy 是最终服务处理请求所花费的时间
    • kong 是运行所有插件所需的内部Kong延迟
    • request 是从客户端读取的第一个字节之间以及最后一个字节发送到客户端之间经过的时间。用于检测慢速客户端。
  • client_ip 包含原始客户端IP地址
  • started_at 包含开始处理请求的UTC时间戳。

Kong执行错误

此日志记录插件仅记录HTTP请求和响应数据。 如果您正在寻找Kong进程错误文件(这是nginx错误文件),那么您可以在以下路径找到它:{prefix}/logs/error.log

微服务 API 网关 Kong 1.0.0 升级指南

原文地址:https://docs.konghq.com/1.0.x/upgrading/#2-deprecation-notices (不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

注意:以下是1.0.x的升级指南。 如果您要升级到Kong的早期版本,请阅读Kong repo中的UPGRADE.md文件。

本指南将告知您在升级时应了解的重大更改,并指导您完成正确的步骤,以便在不同的升级方案中获得不需要停止服务的迁移。

升级到 1.0.0

此版本(1.0.0) 是Kong的主要版本,包括许多新功能以及重大变化。
这个版本中引入了新的插件架构格式,Admin API 终端的更改,数据库迁移,Nginx配置更改以及已删除的配置属性。
在此版本中,将删除 API 及其相关的Admin API 终端。
本节将重点介绍在升级之前需要注意的重大更改,并将介绍建议的升级路径。我们建议您查阅完整的1.0.0更新日志,以获取更改和新功能的完整列表。

1.突破性修改

依赖

  • 所需的OpenResty版本是1.13.6.2,但是对于完整的功能集,包括具有相互TLS的流路由和服务网格功能,您需要Kong的openresty-patches
  • 所需的最低OpenSSL版本为1.1.1。如果您手动构建,请确保使用相同的OpenSSL版本编译所有依赖项(包括LuaRocks模块)。如果您从我们的某个分发包中安装Kong,则不会受此更改的影响。

配置

  • 删除了custom_plugins 指令(自0.14.0起不推荐使用)。请改用plugin,您不仅可以使用插件来启用自定义插件,还可以禁用自带的捆绑插件。
  • cassandra_lb_policy的默认值从Round Robin更改为Request Round Robin
  • Kong为其流路由生成了一个新的模板文件nginx-kong-stream.conf,该文件包含在其顶级Nginx配置文件的stream块中。如果您使用自定义Nginx配置并希望使用流路由,则可以使用kong prepare生成此文件。
  • Nginx配置文件已更改,这意味着如果使用自定义模板,则需要更新它:
diff --git a/kong/templates/nginx_kong.lua b/kong/templates/nginx_kong.lua
index d4e416bc..8f268ffd 100644
--- a/kong/templates/nginx_kong.lua
+++ b/kong/templates/nginx_kong.lua
@@ -66,7 +66,9 @@ upstream kong_upstream {
     balancer_by_lua_block {
         Kong.balancer()
     }
+> if upstream_keepalive > 0 then
     keepalive $;
+> end
 }

 server {
@@ -85,7 +87,7 @@ server {
 > if proxy_ssl_enabled then
     ssl_certificate $;
     ssl_certificate_key $;
-    ssl_protocols TLSv1.1 TLSv1.2;
+    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
     ssl_certificate_by_lua_block {
         Kong.ssl_certificate()
     }
@@ -200,7 +202,7 @@ server {
 > if admin_ssl_enabled then
     ssl_certificate $;
     ssl_certificate_key $;
-    ssl_protocols TLSv1.1 TLSv1.2;
+    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;

     ssl_session_cache shared:SSL:10m;
     ssl_session_timeout 10m;

核心

  • 将删除API实体和相关概念,例如/apis终端。自0.13.0起,这些已被弃用。而是使用Routes配置终端,Services以配置上游服务。
  • 删除旧的DAO实现(kong.dao),其中包括旧的模式验证库。这对插件开发人员有影响,如下所示。
    • 转换为新DAO实现的最后剩余实体是Plugins,Upstreams和Targets。这会对下面列出的Admin API产生影响。

插件

kong 1.0.0标志着插件开发套件(PDK)1.0.0版的推出。与版本0.14相比,PDK没有进行重大更改,但现在可以删除一些可能由自定义插件使用的较旧的非PDK功能。

  • 插件现在使用新DAO实现引入的新模式格式,用于插件模式(在schema.lua中)和自定义DAO实体(daos.lua)。为了简化插件的转换,1.0中的插件加载器包含了一个为schema.lua的自动转换器,对于许多插件来说应该足够了(在1.0.0rc1中,我们的自带捆绑插件使用了自动转换器;它们们现在使用的是新格式)。
    • 如果您在schema.lua中使用旧格式的插件无法加载,请检查自动转换器生成的消息的错误日志。如果无法自动转换字段,则可以通过向格式的字段表转换添加new_type条目来逐步转换模式文件。例如,请参阅1.0.0rc1中的key-auth架构new_type注释被Kong 0.x忽略。
    • 如果您的自定义插件使用自定义DAO对象(如果它包含daos.lua文件),则需要将其转换为新格式。代码也需要相应调整,用kong.db代替singletons.daokong.dao的使用(注意,这个模块暴露了与旧DAO实现不同的API)。
  • 现已删除了在0.14.0中由PDK替换其功能的ome Kong模块:
    • kong.tools.ip:改为用PDK中的kong.ip
    • kong.tools.public:由PDK的各种功能取代。
    • kong.tools.responses:由PDK中的kong.response.exit取代。您可能还使用kong.log.err来记录内部服务器错误。
  • kong.api.crud_helpers模块已被删除。如果需要自定义自动生成的终端,请使用kong.api.endpoints

Admin API

  • 删除API实体后,将删除/apis终端;因此,接受api_id的其他终端不再这样做。请改用Routes和Services。
  • 现在,所有实体终端都使用新的Admin API实现。这意味着他们的请求和响应现在使用相同的语法,该语法已在终端(例如/routes/services)中使用。
    • 所有端点现在使用相同的语法将其他实体作为/routes引用(例如,“service”:{“id”:“...”}而不是“service_id”:“...”),包括请求和响应。
      • 此更改会影响/plugins以及特定于插件的终端。
    • 数组类型的值不再指定为以逗号分隔的列表。必须将其指定为JSON数组或使用新Admin API实现的url-formencoded数组表示法支持的各种格式(a[1]=x&a[2]=y, a[]=x&a[]=y, a=x&a=y
      • 此更改会影响/upstreams终端的属性。
    • 更新终端的错误响应使用新的标准化格式。
    • 由于被移动到新的Admin API实现,支持PUT的所有终端都使用适当的语义。
    • 有关更多详细信息,请参阅Admin API参考

2.弃用通知

此版本中没有弃用通知。

3.建议的升级路径

初步检查

如果您的群集运行的版本低于0.14,则需要先升级到0.14.1。不支持从0.14之前的群集直接升级到Kong 1.0。如果您仍然使用已弃用的API实体来配置终端和上游服务(通过/apis),而不是使用路由Routes(通过’/routes’)和服务Service(通过/services),现在是时候这样做了。如果您在数据存储区中使用/apis配置了任何实体,则kong 1.0将拒绝运行迁移。创建等效的路由和服务并删除您的API。请注意,Kong不会自动执行此操作,因为为每个API创建一对路由和服务这样天真的操作将错过路由和服务带来的改进点;路由和服务的理想映射取决于您的微服务架构。

如果您使用除与Kong自带捆绑的插件以外的其他插件,请确保在升级之前它们与Kong 1.0兼容。有关插件兼容性的信息,请参阅上面有关插件的部分。

从0.14开始逐步迁移

Kong 1.0引入了一个新的,改进的迁移框架。它支持无停机,蓝/绿迁移模型,可从0.14.x升级。完整迁移现在分为两个步骤,这两个步骤通过命令kong migrations upkong migrations finish完成。

对于从0.14群集到1.0群集的无停机时间迁移,我们建议采用以下一系列步骤:

  • 第一步:下载1.0,并将其配置为指向与0.14群集相同的数据存储。执行kong migrations up
  • 第二步:现在,0.14和1.0节点都可以在同一数据存储上同时运行。开始配置1.0节点,但是先不要使用其Admin API。更好的操作是向0.14节点发出Admin API请求。
  • 第三步:逐渐将流量从0.14节点转移到1.0集群中。监控您的流量,确保一切顺利。
  • 第四步:当您的流量完全迁移到1.0群集时,停用0.14节点。
  • 第五步:从1.0集群中,运行:kong migrations finish。从现在开始,将无法再启动指向同一数据存储区的0.14个节点。仅在您确信迁移成功时才运行此命令。从现在开始,您可以安全地向1.0节点发出Admin API请求。

在任何一步,您都可以运行kong migrations list来获取迁移状态的报告。它将列出是否缺少迁移,如果有待处理的迁移(已经在kong迁移步骤中启动,之后需要在kong迁移完成步骤中完成)或者是否有新的迁移可用。流程的状态代码也会相应更改:

  • 0 - 迁移是最新的
  • 1 - 检查迁移状态失败(例如数据库已关闭)
  • 3 - 数据库需要引导:你应该运行kong migrations bootstrap来安装在新的数据存储上。
  • 4 - 有待处理的迁移:一旦您的旧群集被解除,您应该运行kong迁移完成(上面的步骤5)。
  • 5 - 有新的迁移:您应该开始迁移序列(从上面的步骤1开始)。

从1.0 Release Candidates迁移

该过程与上面列出的0.14升级过程相同,但在第1步中,您应该运行kong migrations --force。

补丁版本的升级路径

同一次要版本的Kong的当前或未来补丁版本之间的升级没有迁移(例如1.0.0到1.0.1,1.0.1到1.0.4等)。

假设Kong已在您的系统上运行,请从任何可用的安装方法获取最新版本并继续安装它,覆盖以前的安装。

如果您计划对配置进行修改,那么这是一个好时机。然后,运行迁移以升级数据库模式

$ kong migrations up [-c configuration_file]

如果命令成功,并且没有运行迁移(没有输出),那么您只需要重新加载Kong

$ kong reload [-c configuration_file]

提醒:kong reload利用ngnix的reload来无缝启动一个新的worker。在那些旧worker被终止之前接管旧的worker。通过这种方式,Kong将通过新配置提供新请求,而不会丢弃现有的服务连接。

在新数据存储上安装1.0

为了在新的数据存储上安装,Kong 1.0引入了kong migrations bootstrap命令。可以运行以下命令从新数据存储区准备新的1.0集群:

$ kong migrations bootstrap [-c config]
$ kong start [-c config]

微服务 API 网关 Kong CORS 插件中文文档

原文地址:https://docs.konghq.com/hub/kong-inc/cors/ (不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

通过启用此插件,轻松将跨源资源共享(CORS)添加到 Service, Route 。

配置

在 Service 上启用插件

通过发出以下请求在 Service 上配置此插件:

$ curl -X POST http://kong:8001/services/{service}/plugins \
    --data "name=cors"  \
    --data "config.origins=http://mockbin.com" \
    --data "config.methods=GET, POST" \
    --data "config.headers=Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Auth-Token" \
    --data "config.exposed_headers=X-Auth-Token" \
    --data "config.credentials=true" \
    --data "config.max_age=3600"
  • service:此插件配置将绑定的服务的ID或名称。

在 Route 上启用插件

通过发出以下请求在 Route 上配置此插件:

$ curl -X POST http://kong:8001/routes/{route_id}/plugins \
    --data "name=cors"  \
    --data "config.origins=http://mockbin.com" \
    --data "config.methods=GET, POST" \
    --data "config.headers=Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Auth-Token" \
    --data "config.exposed_headers=X-Auth-Token" \
    --data "config.credentials=true" \
    --data "config.max_age=3600"

全局插件

可以使用http://kong:8001/plugins/ 配置所有插件。与任何Service, Route 或者 Consumer(或API,如果您使用旧版本的Kong)无关的插件被视为“全局”,并将在每个请求上运行。有关更多信息,请阅读插件参考插件优先级部分。

参数

以下是可在此插件配置中使用的所有参数的列表:

参数名称 默认值 描述
name 要使用的插件的名称,在本例中为cors
service_id 此插件将绑定的 Service 的ID。
route_id 此插件将绑定的 Route 的ID。
enabled true 是否将应用此插件。
config.origins 
optional
Access-Control-Allow-Origin标头的允许域,用逗号分割,如果想允许所有,就使用*。接受的值可以是flat strings 或PCRE正则表达式。 
注意:在Kong 0.10.x之前,此参数是config.origin(请注意s的更改),并且只接受单个值或*特殊值。
config.methods 
optional
GET, HEAD, PUT, PATCH,POST Access-Control-Allow-Methods header的值,使用逗号分隔的字符串(例如GETPOST)。
config.headers 
optional
Access-Control-Request-Headers请求header的值 Access-Control-Allow-Headers header的值,使用逗号分割(例如OriginAuthorization)。
config.exposed_headers 
optional
Access-Control-Expose-Headers header 的值,使用逗号分割(例如OriginAuthorization),如果未指定,则不会开放自定义header。
config.credentials 
optional
false 用于确定是否应使用true作为值发送Access-Control-Allow-Credentialsheader。
config.max_age 
optional
指示可以缓存预检请求的结果的时间长度(以秒为单位)。
config.preflight_continue
optional
false 一个布尔值,指示插件将OPTIONS预检请求代理到上游服务。

相关问题

以下是此插件的已知问题或限制的列表。

CORS限制

如果客户端是浏览器,则由于CORS规范的限制导致此插件存在已知问题,该限制不允许在预检OPTIONS请求中指定自定义header。
由于此限制,此插件仅适用于已使用路径设置配置的路由,并且对于使用自定义DNS(hosts属性)解析的路由不起作用。
要了解如何为Route配置路径,请阅读代理参考