API网关Kong(三):功能梳理和插件使用

Wesley13
• 阅读 1023

作者: 李佶澳   转载请保留:原文地址   发布时间:2018-10-10 14:37:53 +0800

说明

这是API网关Kong的系列教程中的一篇,使用过程中遇到的问题和解决方法记录在API网关Kong的使用过程中遇到的问题以及解决方法

通过Nginx、OpenResty和Kong的基本概念与使用方法了解了Kong的工作原理,通过API网关Kong与Kubernetes的集成方法了解了与Kubernetes的集成方法。这里学习下Kong的插件,并尽可能压测一下感兴趣的插件。

因为计划将Kong与Kubernetes集成,因此下面使用的是部署在Kubernetes中的Kong,配置是通过Kubernetes的cRD设置的,参考API网关Kong与Kubernetes的集成方法

Kong-Ingress-Controller的版本是0.2.0,Kong的版本是0.14.1,是用下面的方式部署的:

./kubectl.sh create -f https://raw.githubusercontent.com/introclass/kubernetes-yamls/master/all-in-one/kong-all-in-one.yaml

Kong的Admin API

先了解下Kong的Admin API,后面的操作过程中,可以通过Kong的API查看数据变化。

GET /routers/                                #列出所有路由
GET /services/                               #列出所有服务
GET /consumers/                              #列出所有用户
GET /services/{service name or id}/routes    #列出服务关联的路由
GET /plugins/                                #列出所有的插件配置
GET /plugins/enabled                         #列出所有可以使用的插件
GET /plugins/schema/{plugin name}            #获得插件的配置模版
GET /certificates/                           #列出所有的证书
GET /snis/                                   #列出所有域名与证书的对应
GET /upstreams/                              #列出所有的upstream
GET /upstreams/{name or id}/health/          #查看upstream的健康状态
GET /upstreams/{name or id}/targets/all      #列出upstream中所有的target

例如:List Services

$ curl 192.168.33.12:32685/services 2>/dev/null |python -m json.tool
{
    "data": [
        {
            "connect_timeout": 60000,
            "created_at": 1539153249,
            "host": "demo-webshell.webshell.80",
            "id": "0df71804-3f99-4e00-af5c-0234eb155228",
            "name": "demo-webshell.webshell.80",
            "path": "/",
            "port": 80,
            "protocol": "http",
            "read_timeout": 60000,
            "retries": 5,
            "updated_at": 1539153249,
            "write_timeout": 60000
        },
       ...
    ],
    "next": null
}

列出所有可以使用的插件:

$ curl 192.168.33.12:32685/plugins/enabled 2>/dev/null |python -m json.tool
{
    "enabled_plugins": [
        "response-transformer",
        "oauth2",
        "acl",
        "correlation-id",
        "pre-function",
        "jwt",
        "cors",
        "ip-restriction",
        "basic-auth",
        "key-auth",
        "rate-limiting",
        "request-transformer",
        "http-log",
        "file-log",
        "hmac-auth",
        "ldap-auth",
        "datadog",
        "tcp-log",
        "zipkin",
        "post-function",
        "request-size-limiting",
        "bot-detection",
        "syslog",
        "loggly",
        "azure-functions",
        "udp-log",
        "response-ratelimiting",
        "aws-lambda",
        "statsd",
        "prometheus",
        "request-termination"
    ]
}

Kong定义的资源之间的关联关系

Route是请求的转发规则,按照Hostname和PATH,将请求转发给Service,Kubernetes的Ingress中每个path对应一个Route。

Services是多个Upstream的集合,是Route的转发目标。

Consumer是API的用户,里面记录用户的一些信息。

Plugin是插件,plugin可以是全局的,绑定到Service,绑定到Router,绑定到Consumer。

Certificate是https证书。

Sni是域名与Certificate的绑定,指定了一个域名对应的https证书。

Upstream是负载均衡策略。

Target是最终处理请求的Backend服务。

使用过程了解

先通过部署一个webshell应用和为它设置key-auth插件的过程,了解整个使用过程。

先了解下插件的作用范围和设置方法

Kong Add Plugin通过consumer_id、route_id、service_id限定插件的作用范围:

作用于所有的Service、Router、Consumer:       创建时不指定consumer_id、service_id、route_id
作用于所有的Service、Router和指定的Consumer: 创建时只指定consumer_id
作用于所有的Consumer和指定的Service:         创建时只指定service_id,有些插件还需要指定route_id
作用于所有的Consumer和指定的Router:          创建时只指定route_id,有些插件还需要指定service_id
作用于特定的Service、Router、Consumer:       创建时不指定consumer_id、service_id、route_id

没有绑定任何service、route、consumer的插件,称为global插件:

All plugins can be configured using the http://kong:8001/plugins/ endpoint. 
A plugin which is not associated to any Service, Route or Consumer (or API, if you are using an older version of Kong) is considered "global", 
and will be run on every request. Read the Plugin Reference and the Plugin Precedence sections for more information

在Kubernetes中部署目标应用和对应的Ingress

Kubernetes中部署的应用和Ingress是webshell-all-in-one.yaml

./kubectl.sh create -f https://raw.githubusercontent.com/introclass/kubernetes-yamls/master/all-in-one/webshell-all-in-one.yaml

Kong的数据平面用NodePort的方式暴露,端口是30939,下面随意选用的Node是192.168.33.12,所以请求地址都是192.168.33.12:30939

先验证下没有做任何配置时候的访问:

$ curl -H "Host: webshell.com" 192.168.33.12:30939
<html>
<head>
<meta content="text/html; charset=utf-8">
<title>WebShell</title>
</head>

<body>

<form method="post" accept-charset="utf-8">
    Command: <input type="text" name="command" width="40%" value="hostname">
    Params : <input type="text" name="params" width="80%" value="">
    <input type="submit" value="submit">
</form>
<pre>

webshell-cc785f4f8-p4bds

</pre>
</body>
</html>

可以访问。

创建KongConsumer,并设置该用户key-auth插件的key

创建名为websehll-user1的KongConsumer:

apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
  name: webshell-user1
  namespace: demo-webshell
username: user1
custom_id: demo-webshell-user1

从kubernetes中查看:

$ kubectl  -n demo-webshell get KongConsumer -o wide
NAME             AGE
webshell-user1   1m

从Kong中查看Consumer:

curl 192.168.33.12:32685/consumers

配置webshell-user1的key-auth的key,创建一个KongCredential,配置它关联到上面创建的KongConsumer,(consumerRef: webshell-user1):

apiVersion: configuration.konghq.com/v1
kind: KongCredential
metadata:
  namespace: demo-webshell
  name: credential-webshell-user1
consumerRef:  webshell-user1
type: key-auth
config:
  key: 62eb165c070a41d5c1b58d9d3d725ca1

从kubernetes查看:

$ kubectl -n demo-webshell get KongCredential -o wide
NAME                        AGE
credential-webshell-user1   2m

从Kong中查询Consumer的key-auth信息,ID是Kubernetes中KongConsumer的uid:

curl 192.168.33.12:32685/consumers/5433234c-d158-11e8-9da4-525400c042d5/key-auth/

这时候可以在kong-dashboard中看到名为user1的consumer,key为62eb165c070a41d5c1b58d9d3d725ca1

配置全局的key-auth插件

在kubernetes中创建下面的global插件:

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: global-plugin-key-auth
  namespace: kong
  labels:
    global: "true" # optional, please note the quotes around true
disabled: false  # optional
config:
plugin: key-auth

全局的插件不能重名。kong-ingress-controller(0.2.0)版本不关心全局插件所在的namespace,在任何一个namespace中都可以创建global plugin,实践中需要注意进行限制。

这时候直接访问Service,会提示缺少API key:

curl -H "Host: webshell.com" 192.168.33.12:30939
{"message":"No API key found in request"}

需要用下面的方式访问:

curl -H "Host: webshell.com" -H "apikey: 62eb165c070a41d5c1b58d9d3d725ca1" 192.168.33.12:30939

配置关联到Route的key-auth插件

Kong的Route对应Kubernetes的Ingress中的一个PATH。在Ingress中通过Kong Ingress Controller annotations绑定插件配置:

plugins.konghq.com: high-rate-limit, docs-site-cors

在demo-webshell空间中创建一个KongPlugin

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: plugin-key-auth-user1
  namespace: demo-webshell
#consumerRef: webshell-user1, 0.14.1存在一个Bug,这里设置Consumer后,会导致kong-ingress-controller更新失败
disabled: false  # optional
config:
  key_names: key
plugin: key-auth

Config中是key-auth插件的配置参数,前面的global plugin中没有设置config,使用的是默认配置。

key_names设置用来认证的key的名称,默认是apikey,这里修改成了key,后面访问的时候需要在header中添加的是key字段。

在同一个namespace的Ingress上添加annotations,指定使用刚创建的名为plugin-key-auth-user1的KongPlugin:

metadata:
  annotations:
    plugins.konghq.com: plugin-key-auth-user1

这时候在kong-dashboard中,可以看到新建了一个绑定到Router的key-auth插件。

直接访问,提示缺少key:

$ curl -H "Host: webshell.com" 192.168.33.12:30939
{"message":"No API key found in request"}%

用global插件的apikey,也提示缺少key:

$ curl -H "Host: webshell.com" -H "apikey: 62eb165c070a41d5c1b58d9d3d725ca1" 192.168.33.12:30939
{"message":"No API key found in request"}%

使用绑定的插件的中设置的key才可以:

curl -H "Host: webshell.com" -H "key: 62eb165c070a41d5c1b58d9d3d725ca1" 192.168.33.12:30939

由此可见绑定到Route的插件优先级高于global插件。

在kong中查看绑定到Route的plugin:

$ curl 192.168.33.12:32685/routes/8c81fdb6-4bff-4807-9e38-ab9c22c24a88/plugins
 "total":1,"data":[{"created_at":1539711481000,"config":{"key_names":["key"],"key_in_body":false,"anonymous":"","run_on_preflight":true,"hide_credentials":false},"id":"6d8c9e88-1211-4cfd-8410-c7d3a727f3e4","name":"key-auth","enabled":true,"route_id":"8c81fdb6-4bff-4807-9e38-ab9c22c24a88"}]}

配置关联到Service的key-auth插件

Service也通过Kong Ingress Controller annotations绑定插件,在名为webshell的Service中设置annotation:

kind: Service
metadata:
  annotations:
    plugins.konghq.com: plugin-key-auth-user1

这时候,在kong-dashboard中可以看到一个绑定到service的plugin。

尝试绑定到另一个key-auth插件,试验一下优先级。创建一个新的KongPlugin,key_names是key2

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: plugin-key-auth-user2
  namespace: demo-webshell
consumerRef: webshell-user1
disabled: false  # optional
config:
  key_names: key2
plugin: key-auth

然后修改service的annotations,绑定新建的KongPlugin,plugin-key-auth-user2:

kind: Service
metadata:
  annotations:
    plugins.konghq.com: plugin-key-auth-user2

使用Route的key能够通过验证:

curl -H "Host: webshell.com" -H "key: 62eb165c070a41d5c1b58d9d3d725ca1" 192.168.33.12:30939

使用Service的key2不行:

$ curl -H "Host: webshell.com" -H "key2: 62eb165c070a41d5c1b58d9d3d725ca1" 192.168.33.12:30939
{"message":"No API key found in request"}

将Route的key-auth停止后,用key2就可以访问了。

通过结果可以判断Route绑定的插件是优先于Service绑定的插件的,而Service绑定的插件又优于Global插件。

通过KongIngress增强配置

Ingress默认关联同一个namespace中同名的KongIngress。如果不想使用默认的关联,可以在annotation中用configuration.konghq.com指定同一个namespace中的另一个KongIngress。

下面创建一个与ingress同名的KongIngress

apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
  name: webshell-kong-ingress
  namespace: demo-webshell
upstream:
  hash_on: none
  hash_fallback: none
  healthchecks:
    active:
      concurrency: 10
      healthy:
        http_statuses:
        - 200
        - 302
        interval: 0
        successes: 0
      http_path: "/"
      timeout: 1
      unhealthy:
        http_failures: 0
        http_statuses:
        - 429
        interval: 0
        tcp_failures: 0
        timeouts: 0
    passive:
      healthy:
        http_statuses:
        - 200
        successes: 0
      unhealthy:
        http_failures: 0
        http_statuses:
        - 429
        - 503
        tcp_failures: 0
        timeouts: 0
    slots: 10
proxy:
  protocol: http
  path: /
  connect_timeout: 10000
  retries: 10
  read_timeout: 10000
  write_timeout: 10000
route:
  methods:
  - POST
  - GET
  regex_priority: 0
  strip_path: false
  preserve_host: true
  protocols:
  - http
  - https

可以在kong-dashboard中看到,KongIngress中的设置被应用到route、upstream、proxy中。

参考

  1. Nginx、OpenResty和Kong的基本概念与使用方法
  2. API网关Kong与Kubernetes的集成方法
  3. Kong的插件
  4. Kong的控制平面与数据平面
  5. Kong Admin API
  6. Kong Add Plugin
  7. Kong Ingress Controller annotations
  8. Kong key-auth Parameters
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这