1. 程式人生 > >API閘道器Kong(三):功能梳理和外掛使用-基本使用過程

API閘道器Kong(三):功能梳理和外掛使用-基本使用過程

作者: 李佶澳   轉載請保留:原文地址   釋出時間: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