Kong

简介

  1. Kong是一个可扩展的开源API层(也称为API网关或API中间件),是一个在Nginx运行的Lua应用程序,由lua-nginx-module实现。
  1. Kong核心基于OpenResty构建,实现了请求/响应的Lua处理化
  2. Kong插件拦截请求/响应,如果接触过Java Servlet,等价于拦截器,实现请求/响应的AOP处理
  3. Kong Restful 管理API提供了API/API消费者/插件的管理
  4. 数据中心用于存储Kong集群节点信息、API、消费者、插件等信息,目前提供了PostgreSQLCassandra支持,如果需要高可用建议使用Cassandra
  5. Kong集群中的节点通过gossip协议自动发现其他节点,当通过一个Kong节点的管理API进行一些变更时也会通知其他节点。每个Kong节点的配置信息是会缓存的,如插件,那么当在某一个Kong节点修改了插件配置时,需要通知其他节点配置的变更
  1. 特性
  1. 可扩展: 通过简单地添加更多的机器,可以轻松地平行扩展,这意味着您的平台可以在一个较低负载的情况下处理任何请求。
  2. 模块化: 可以通过添加新的插件进行扩展,这些插件可以通过RESTful Admin API轻松配置。
  3. 在任何基础架构上运行: Kong可以在任何地方都能运行。您可以在云或内部部署环境中部署Kong,包括单个或多个数据中心设置,以及public,private 或invite-only APIs。
  1. 主要组件
  1. Kong Server:基于nginx的服务器,用来接收 API 请求
  2. APache Cassandra:用来存储操作数据
  1. 请求流程:当Kong运行时,每个对API的请求将先被Kong命中,然后这个请求将会被代理到最终的API。在requests和responses之间,Kong将会执行已经事先安装和配置好的任何插件,授权您的API。Kong是每个API请求的入口点(point)。
  2. 监听
  • 8000:此端口是KONG用来监听来自客户端传入的HTTP请求,并将此请求转发到上有服务器
  • 8443:有的地方使用8443代替8000, 此端口是KONG用来监听来自客户端传入的HTTP请求的。它跟8000端口的功能类似,但是它只是用来监听HTTP请求的,没有转发功能。可以通过修改配置文件来禁止它
  • 8001:Admin API,通过此端口,管理者可以对KONG的监听服务进行配置
  • 8444:有的地方使用8444代替8001,通过此端口,管理者可以对HTTP请求进行监控

安装

  1. 下载,官网
$ wget https://bintray.com/kong/kong-community-edition-rpm/download_file?file_path=centos/7/kong-community-edition-1.0.2.el7.noarch.rpm
  1. 安装Kong
$ yum install epel-release
$ yum install kong-community-edition-1.0.2.el7.noarch.rpm --nogpgcheck
  1. 安装Postgresql,下载
$ yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
	$ yum install postgresql11
	$ yum install postgresql11-server
	$ yum install postgresql11-libs
  1. 初始化及配置Postgresql
$ /usr/pgsql-11/bin/postgresql-11-setup initdb
$ systemctl enable postgresql-11
$ systemctl start postgresql-11

$ netstat -tlun | grep 5432  # 查看状态,postgres是占用5432端口

# 修改监听端口,将listen_addresses 修改为 ‘*‘
$ vim /var/lib/pgsql/11/data/postgresql.conf
# 修改IP访问权限,(host all all 0.0.0.0/0 md5)
# 此处可能出现用户无权限操作的问题,本机测试时所有权限都改为 'trust'
$ vim /var/lib/pgsql/11/data/pg_hba.conf

$ systemctl restart postgresql-11
  1. 准备数据库
# 切换Postgresql用户
$ sudo -s -u postgres
# 进入数据库界面
$ psql
# 创建一个名为 kong 的用户,并且创建一个名为 kong 的数据库
postgres=# CREATE USER kong WITH PASSWORD 'kong';
postgres=# CREATE DATABASE kong OWNER kong;
postgres=# GRANT ALL PRIVILEGES ON DATABASE kong to kong;
  1. Kong配置数据库连接
# 创建kong.conf
$ cp /etc/kong/kong.conf.default /etc/kong/kong.conf
# 编辑/etc/kong/kong.conf,配置以下内容(参考第五步创建的用户)
## database=postgres
## pg_host=127.0.0.1
## pg_port=5432
## pg_user=kong
## pg_password=123456
## pg_database=kong 
## pg_ssl = off  #设置kong和postgres的连接方式
## pg_ssl_verify = off

$ vi /etc/kong/kong.conf
  1. 环境变量
$ vim /etc/profile  
# 加入环境变量 export PATH=$PATH:/usr/pgsql-11/bin  
$ source /etc/profile
$ systemctl restart postgresql-11
  1. Kong应用配置
$ kong migrations bootstrap -c /etc/kong/kong.conf
  1. 启动 KONG。--vv 可以打印更多的启动日志
$ kong start -c /etc/kong/kong.conf --vv
  1. 检查KONG运行状态
$ curl -i http://localhost:8001/
或者
$ kong health
  1. 停止 Kong
$ kong stop
  1. 安装 Kong Dashboard,需要先安装 npm
$ npm install -g kong-dashboard
$ kong-dashboard start --kong-url http://localhost:8001

# 访问 http://localhost:8080,使用Kong-Dashboard对Kong进行管理
# 常用功能
# 用自定义端口启动 Kong Dashboard 
$ kong-dashboard start --kong-url http://localhost:8001 --port [port]
# 使用权限认证启动 Kong Dashboard
$ kong-dashboard start --kong-url http://kong:8001 --basic-auth user1=password1 user2=password2
# Kong Dashboard 帮助文档
$ kong-dashboard start --help

使用指南

配置

默认安装配置文件 /etc/kong/kong.conf.default,创建自定义配置,通过在CLI中使用 -c / -conf 使用自定义配置文件 $ cp /etc/kong/kong.conf.default /etc/kong/kong.conf $ kong start --conf /path/to/kong.conf

  1. 验证配置
# configuration at /etc/kong/kong.conf is valid
$ kong check <path/to/kong.conf>
  1. 定制Nginx配置和嵌入Kong
    Kong可以用 --nginx-conf 的参数启动,重新加载和重新启动,该参数必须指定Nginx配置模板。当Kong开始运行时,在开始Nginx之前,它将这两个文件(nginx-kong.conf/nginx.conf)复制到前缀目录中。
  1. 自定义Nginx配置
  2. 在OpenResty里嵌入Kong
  3. Kong为网站和你的Api提供服务
  1. 属性详解
  1. 常规属性
  1. prefix
  2. log_level
  3. proxy_access_log
  1. Nginx属性
  2. 数据存储属性
  3. 数据缓存属性
  4. DNS解析属性
  5. 开发与其他属性

代理

身份验证

上游API服务都需要客户端有身份认证,且不允许错误的认证或无认证的请求通过。认证插件可以实现这一需求

  1. 流程
  1. 向一个API或全局添加AUTH插件(此插件不作用于consumers);
  2. 创建一个consumer对象;
  3. 为consumer提供指定的验证插件方案的身份验证凭据;
  4. 现在,只要有请求进入Kong,都将检查其提供的身份验证凭据(取决于auth类型),如果该请求无法被验证或者验证失败,则请求会被锁定,不执行向上有服务转发的操作
  1. 简单验证
# 创建service
$ curl -i -X POST \
      --url http://localhost:8001/services/ \
      --data 'name=auth-service-test' \
      --data 'url=http://mockbin.org/request'
# 创建route
$ curl -i -X POST \
      --url http://localhost:8001/services/auth-service-test/routes \
      --data 'paths[]=/auth-request'

此时访问:http://localhost:8000/auth-request,就可以转发到http://mockbin.org/request

# 给Service配置一个key-auth(关键词认证)插件,获得一个plugin_id
$ curl -i -X POST \
      --url http://localhost:8001/services/auth-service-test/plugins/ \
      --data 'name=key-auth'
# 添加一个匿名消费者,获得consumer_id
$ curl -i -X POST \
      --url http://localhost:8001/consumers/ \
      --data "username=auth-user-test"
# 关联匿名消费者与key-auth插件
$ curl -i -X PATCH \
      --url http://localhost:8001/plugins/{plugin_id} \
      --data "config.anonymous={consumer_id}"
# 添加关键字认证
$ curl -X POST http://localhost:8001/consumers/auth-user-test/key-auth \
    -d 'key=test'

正常访问:http://localhost:8000/auth-request?apiKey=test

负载均衡

健康检查和断路器

集群

网络和防火墙

共有Lua API

管理API安全保护

插件

身份验证

Basic验证

Key验证

OAuth2.0验证

权限安全

ACL鉴权

动态SSL

IP限制(黑白名单)

爬虫控制

流量控制

请求大小限制

请求速率限制

请求终止

Serverless

Serverless功能

分析与监控

Zipkin

数据转换

日志

Kong网关Admin API使用指南

SERVICE服务

  1. 说明

服务(SERVICE)实体,是用户服务的抽象。
服务的主要属性是它的URL(在这里,Kong应该代理流量),它可以被设置为单个字符串,或者通过单独指定其协议、主机、端口和路径。
服务与路由相关联(服务可以有许多与之相关联的路由)。路由是在Kong的入口点,并定义了匹配客户端请求的规则。一旦匹配了路由,Kong就会将请求委托给它的相关服务。

  1. 示例
# 添加 service,成功返回 HTTP/1.1 201 Created
	curl -i -X POST \
	--url http://localhost:8001/services/ \
	--data 'name=example-service-testsample' \
	--data 'url=http://mockbin.org'
	# 添加当前服务的路由 route,成功返回 HTTP/1.1 201 Created
	# 一个IP地址可以对应多个域名,服务器根据Host这一行中的值来确定本次请求的是哪个具体的网站
	curl -i -X POST \
	--url http://localhost:8001/services/example-service-testsample/routes \
	--data 'hosts[]=example.com'
	# Kong 做一个请求转发,成功返回 HTTP/1.1 200 OK
	curl -i -X GET \
	--url http://localhost:8000/ \
	--header 'Host:example.com'
  1. API
  1. 查找service列表
# 请求地址 /services/
# 请求方法 GET
# 属性
    > offset(可选):用于分页的游标。偏移量是定义列表中的位置的对象标识符
    > size(可选,默认是100 max是1000):每个页面返回的对象数量的限制
$ curl -i -X GET \
--url http://localhost:8001/services/ \
--data 'size=2' \
--data 'offset=1'
  1. 查找单个service
  1. 单service查找
# 请求地址 /services/{name or id}
	# 请求方法 GET
	# 属性
	> name or id(必填):要更新的服务的id或name属性
curl -i -X GET \
	--url http://localhost:8001/services/service-thistest
  1. 根据route_id更新service
# 请求地址 /routes/{route id}/service
# 请求方法 GET
# 属性
    > route id(必填):要更新服务的路由的id属性
同上
  1. 添加service
# 请求地址 /service/
# 请求方法 POST
# 属性
    # 不可同时声明两个相同name的service
    > name(可选):服务名称.
    > protocol:该协议用于与upstream通信。它可以是http(默认)或https。
    > host:upstream服务器的主机。
    > port:upstream服务器端口,默认为80
    > path(可选):在向upstream服务器请求中使用的路径。默认为空。
    > retries(可选):在代理失败的情况下执行的重试次数。默认值是5。
    > connect_ timeout(可选):建立到upstream服务器的连接的超时时间。默认为60000。
    > write timeout(可选):将请求发送到upstream服务器的两个连续写操作之间的超时时间。默认为60000。
    > read_timeout(可选):将请求发送到upstream服务器的两个连续读取操作之间的超时时间。默认为60000。
    > url(简写属性):将协议、主机、端口和路径立即设置成简短的属性。这个属性是只写的(管理API从来不“返回”url)。
curl -i -X POST \
  --url http://localhost:8001/services/ \
  --data 'name=service-thistest' \
  --data 'url=http://mockbin.org/request'
  1. 删除service
# 请求地址 /services/{name or id}
# 请求方法 DELETE
# 属性
    # 当service下有route时,无法删除该service
    > name or id(PATH参数,必填):要删除的服务的id或name属性
$ curl -i -X DELETE \
--url http://localhost:8001/services/service-thistest
  1. 更新service
  1. 单service更新
# 请求地址 /services/{name or id}
# 请求方法 PATCH
# 属性
    > name or id(必填):要更新的服务的id或name属性
curl -i -X PATCH \
  --url http://localhost:8001/services/service-thistest
  1. 根据route_id更新service
# 请求地址 /routes/{route id}/service
# 请求方法 PATCH
# 属性
    > route id(必填):要更新服务的路由的id属性
同上

ROUTE路由

  1. 说明

Route实体定义匹配客户端请求的规则。
每个路由都与一个服务相关联,而服务可能有多个与之相关联的路由。
每一个匹配给定路线的请求都将被提交给它的相关服务。

  1. API
  1. 添加route
# 请求地址:/routes/
# 请求方法:POST
# 属性:
    > methods(半可选):与此路由相匹配的HTTP方法列表。例如: ["GET", "POST"].至少有一个主机、路径或方法必须被设置。用表单编码参数是methods[]=GET&methods[]=OPTIONS。使用JSON,使用数组
    > hosts(半可选):与此路径匹配的域名列表。例如:example.com. 至少有一个主机、路径或方法必须被设置。用表单编码参数是 hosts[]=foo.com&hosts[]=bar.com。使用JSON,使用数组
    > paths(半可选):与此路径相匹配的路径列表。例如: /my-path.至少有一个主机、路径或方法必须被设置。用表单编码参数是 paths[]=/foo&paths[]=/bar. 使用JSON,使用数组
    > service:这条路线的服务是相关的。这是路由代理通信的地方。用表单编码参数是service.id=<service_id>。如果是JSON,则使用"service":{"id":"<service_id>"}
$ curl -i -X POST \
  --url http://localhost:8001/services/{service name}/routes \
  --data 'paths[]=/route-testadd&paths[]=/route-testadd2'
  1. 检索route
# 请求地址:/routes/{id}
# 请求方法:GET
# 属性:
    > id(必填):检索路由的id属性
$ curl -i -X GET \
    --url http://localhost:8001/routes/id
  1. route列表
# 请求地址:/routes
# 请求方法:GET
# 属性:
    > offset(可选):用于分页的游标。偏移量是定义列表中的位置的对象标识符
    > size(可选,默认是100 max是1000):每个页面返回的对象数量的限制
$ curl -i -X GET \
    --url http://localhost:8001/routes
  1. 列出service相关route
# 请求地址:/services/{service name or id}/routes
# 请求方法 GET
# 属性
    > service name or id(PATH参数,必填):要检索路由的服务的id或name属性。当使用这个API时,只有属于指定服务的路由才会被列出
$ curl -i -X GET \
    --url http://localhost:8001/services/{service name or id}/routes
  1. 更新route
# 请求地址 /routes/{id}
# 请求方法 PATCH
# 属性
    > id(PATH参数,必填):更新路由的id属性
$ curl -i -X PATCH \
    --url http://localhost:8001/routes/{id}
  1. 删除route
# 请求地址 /routes/{id}
# 请求方法 DELETE
# 属性
    > id(PATH参数,必填):删除路由的id属性
$ curl -i -X DELETE \
    --url http://localhost:8001/routes/{id}

API对象

CONSUMER消费者

表示服务的消费者或使用者。您既可以依赖于Kong作为主数据存储,也可以使用数据库映射消费者列表,以保持Kong和现有主数据存储之间的一致性

  1. API
  1. 创建consumer
# 请求地址 /consumers/
# 请求方法 POST
# 属性
    > username(半可选):用户的唯一用户名。username或custom_id二选一
    > custom_id(半可选):消费者存储唯一ID - 用于现有数据库中的用户进行映射。username或custom_id二选一
$ curl -i -X POST \
    --url http://localhost:8001/consumers/ \
    --data 'username=mt-consumer1'
  1. 检索consumer
# 请求地址 /consumers/{username or custom_id}
# 请求方法 GET
# 属性
    > username or custom_id(必选):要检索的消费者的唯一标识符或用户名
$ curl -i -X GET \
    --url http://localhost:8001/consumers/ \
    --data 'username=mt-consumer1'
  1. consumer列表
# 请求地址 /consumers/
# 请求方法 GET
$ curl -i -X GET \
    --url http://localhost:8001/consumers/
  1. 更新consumer
# 请求地址 /consumers/{username or custom_id}
# 请求方法 PATCH
# 属性
    > username or custom_id(必选):要检索的消费者的唯一标识符或用户名
$ curl -i -X PATCH \
    --url http://localhost:8001/consumers/ \
    --data 'username=mt-consumer1'
  1. 更新或创建consumer
# 请求地址 /consumers/
# 请求方法 PUT
$ curl -i -X PUT \
    --url http://localhost:8001/consumers/
  1. 删除consumer
# 请求地址 /consumers/{username or custom_id}
# 请求方法 DELETE
# 属性
    > username or custom_id(必选):要检索的消费者的唯一标识符或用户名
$ curl -i -X DELETE \
    --url http://localhost:8001/consumers/ \
    --data 'username=mt-consumer1'

Kong最佳实践

Kong整合Consul

Kong整合SpringSecurity实现OAuth2.0验证

实现Kong的Java管理API

Docker 安装

  1. 完整安装
# Create a Docker network
$ docker network create kong-net
# 开启数据库
$ docker run -d --name kong-database \
    --network=kong-net \
    -p 5432:5432 \
    -e "POSTGRES_USER=kong" \
    -e "POSTGRES_DB=kong" \
    postgres:latest
# 准备数据库
$ docker run --rm \
     --network=kong-net \
     -e "KONG_DATABASE=postgres" \
     -e "KONG_PG_HOST=kong-database" \
     -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
     kong:0.14-centos kong migrations up
# 启动kong
$ docker run -d --name kong \
     --network=kong-net \
     -e "KONG_DATABASE=postgres" \
     -e "KONG_PG_HOST=kong-database" \
     -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
     -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
     -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
     -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \
     -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \
     -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \
     -p 8000:8000 \
     -p 8443:8443 \
     -p 8001:8001 \
     -p 8444:8444 \
     kong:0.14-centos
# 启动 kong-dashboard
$ docker run --rm -p 8080:8080 --network kong-net -d --name kong-dashboard pgbi/kong-dashboard start --kong-url http://kong:8001
  1. 安装 postgresql
# 查找
$ docker search postgresql
$ docker pull postgres
# 运行
$ docker run --name postgres1 -e POSTGRES_PASSWORD=kong -p 54321:5432 -d postgres:latest
# 登录docker
$ docker exec -it {image_ps_id} /bin/bash
# 登录postgresql
$ su postgres
$ psql
# 创建用户
postgres=#: CREATE USER kong WITH PASSWORD 'kong';
postgres=#: CREATE DATABASE kong OWNER kong;
postgres=#: GRANT ALL PRIVILEGES ON DATABASE kong to kong;