Kong动态负载均衡与服务发现

news/2024/7/7 21:44:28 标签: kong, 负载均衡, 服务发现, openresty, nginx

Kong动态负载均衡

  • 一、背景
  • 二、通过docker 安装 Kong
  • 三、分布式API网关存在的意义
  • 四、Kong 的相关特性
  • 五、Kong 体系结构
  • 六、Kong 工作流程
  • 七、从 nginx 配置到 Kong 配置
    • 7.1、Kong 核心四对象
    • 7.2、四对象关系
  • 八、插件机制
  • 九、Kong 网关插件
  • 十、使用konga
    • 10.1、实现一个负载均衡
    • 10.2、实现黑白名单
    • 10.3、实现限流
    • 10.4、实现鉴权验证
  • 总结
  • 后言

一、背景

Kong 是一款基于 openresty 编写的高可用、易扩展的开源 API Gateway 项目。

Kong 支持两种工作模式:一种是不使用数据库;另一种是使用数据库;可用的数据库为 PostgreSQL、Cassandra(分布式NoSQL 数据库)。
官方网站
官方文档
项目地址
中文文档:基于1.1.x版本

二、通过docker 安装 Kong

(1)创建 Kong 网络。创建自定义 Docker 网络以允许容器相互发现和通信:

sudo docker network create kong-net

(2)安装 PostgreSQL。

# 创建 PostgreSQL 容器
sudo docker run -d --name kong-database --network=kong-net -p 5432:5432 -e "POSTGRES_USER=kong" -e "POSTGRES_DB=kong" -e "POSTGRES_PASSWORD=kong" --restart always postgres:9.6

# 使用 Kong 容器运行进行数据库初始化
sudo docker run --rm --network=kong-net -e "KONG_DATABASE=postgres" -e "KONG_PG_HOST=kong-database" -e "KONG_PG_USER=kong" -e "KONG_PG_PASSWORD=kong" -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" kong:2.5.0 kong migrations bootstrap

(3)创建 Kong 容器。

# -u -root: Kong 启动过程中,需要权限创建一些文件和文件夹
sudo docker run -d --name kong --network=kong-net -u root -e "KONG_DATABASE=postgres" -e "KONG_PG_HOST=kong-database" -e "KONG_PG_USER=kong" -e "KONG_PG_PASSWORD=kong" -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 --restart always kong:2.5.0

(4)搭建和运行Konga。Konga 是 Kong 的可视化 API 操作工具。

# 复用上面的数据库容器
sudo docker run --rm --network=kong-net pantsel/konga:0.14.9 -c prepare -a postgres -u postgresql://kong:kong@kong-database/konga
# 运行 Konga 容器
sudo docker run -d -p 1337:1337 --network=kong-net -e "DB_ADAPTER=postgres" -e "DB_URI=postgresql://kong:kong@kong-database/konga" -e "NODE_ENV=production" --name konga pantsel/konga:0.14.9

(5)测试 Kong 和 Konga。

# 输入下列命令,若返回一个大的 json 串,说明安装成功
curl http://localhost:8001
# 浏览器运行
http://192.168.0.102:1337

<a class=konga_user" />

三、分布式API网关存在的意义

在微服务架构之下,服务被拆的非常零散,降低了耦合度的同时也给服务的统一管理增加了难度。在旧的服务治理体系之下,鉴权,限流,日志,监控等通用功能需要在每个服务中单独实现,这使得系统维护者没有一个全局的视图来统一管理这些功能。API 网关致力于解决的问题便是为微服务纳管这些通用的功能,在此基础上提高系统的可扩展性。微服务搭配上 API网关,可以使得服务本身更专注于自己的领域,很好地对服务调用者和服务提供者做了隔离。
<a class=kong_api" />

四、Kong 的相关特性

  1. 云原生:与平台无关,Kong 可以从裸机运行到 Kubernetes。
  2. 动态路由:Kong 的背后是 OpenResty,所以从 OpenResty 继承了动态路由的特性。
  3. 熔断。
  4. 健康检查。
  5. 日志:可以记录通过 Kong 的 HTTP,TCP,UDP 请求和响应。
  6. 鉴权:权限控制,IP 黑白名单,同样是 OpenResty 的特性。
  7. SSL:Setup a Specific SSL Certificate for an underlying service or API。
  8. 监控:Kong 提供了实时监控插件。
  9. 认证:支持 HMAC, JWT,Basic,OAuth2.0 等常用协议。
  10. 限流。
  11. REST API:通过 Rest API 进行配置管理,从繁琐的配置文件中解放。
  12. 可用性:天然支持分布式。
  13. 高性能:利用 nginx 的非阻塞 io 模型。
  14. 插件机制:提供众多开箱即用的插件,且有易于扩展的自定义插件接口,用户可以使用 Lua 自行开发插件。

五、Kong 体系结构

Kong_arch

  1. Kong 核心基于 Openresty 构建,实现了请求/响应的 lua 处理化。
  2. Kong 插件拦截请求/响应,等价于拦截器,实现请求/响应的AOP 处理。
  3. Kong Restful 管理 API 提供了 API / API 消费者 / 插件的管理。
  4. 数据中心用于存储 Kong 集群节点信息、API、消费者、插件等信息,目前提供了 PostgreSQL 和 Cassandra支持,如果需要高可用建议使用 Cassandra。
  5. Kong 集群中的节点通过 gossip 协议(redis cluster)自动发现其他节点,当通过一个 Kong 节点的管理 API 进行一些变更时也会通知其他节点。每个 Kong 节点的配置信息是会缓存的,如插件,那么当在某一个 Kong 节点修改了插件配置时,需要通知其他节点配置的变更。

六、Kong 工作流程

Kong_work
API 网关可以通过实现一些中间组件来解决一些问题,这些中间组件的功能就不需要到每个微服务中实现了,这样不同的团队可使用不同的方式来实现了不同的微服务。

API 网关不仅可以帮你解决 API 的管理部分,而且还可以解决下面两件事情:

  1. 分析(Analytics)。API 网关可以和你的分析基础设施保持透明的交互和通信,因为 API 网关是每个请求(request)的入口,必经地。API 网关可以看到所有的数据,可以知道经过你的 service 的流量。这就相当于你有一个集中的地方,你可以把所有的这些信息 push 到你的监控或分析工具,比如 Kibana 或者 Splunk。
  2. 自动化(Automation)。网关有助于自动化部署,还可以实现自动化登入验证。 什么是登入呢? 如果你有 API,并且你希望有身份验证,你可能需要一些功能可以允许用户为该API 创建登入凭据(credentials)然后开始使用(消费)API。 开发人员门户网站或你的文档中心等都可以与网关集
    成来配置这些凭据(credentials),这样就不用从头开始构建一些功能了。

Kong 默认是缺失如 API 级别的超时、重试、fallback 策略、缓存、API 聚合、AB 测试等功能,这些功能插件需要企业开发人员通过 Lua 语言进行定制和扩展。

init_by_lua_block {
    kong = require 'kong'
   	kong.init() -- 完成 Kong 的初始化,路由创建,插件预加载等
}
init_worker_by_lua_block {
   kong.init_worker() -- 初始化 Kong 事件,worker之间的事件,由 worker_events 来处理, cluster 节点之间的事件,由 cluster_events 来处理,缓存机制
}
upstream kong_upstream {
    server 0.0.0.1;
    
    balancer_by_lua_block {
       kong.balancer() --负载均衡
   }
    keepalive 60;
}
server {
    server_name kong;
    listen 0.0.0.0:8000 reuseport backlog=16384;
    listen 0.0.0.0:8443 ssl http2 reuseport backlog=16384;
    rewrite_by_lua_block {
       kong.rewrite() --插件生效策略的筛选,并执行对应的操作,只能处理全局插件(kong插件级别,全局(作用于所有请求),route(作用于当前路由),service(作用于匹配到当前service的所有请求)),路由匹配未开始。
   }
    access_by_lua_block {
    	kong.access() --1.完成路由匹配,2.确认加载的插件(并加入缓存) 3.进入balancer阶段
   }
    header_filter_by_lua_block {
       kong.header_filter() --遍历在缓存中的插件列表,并执行
   }
    body_filter_by_lua_block {
       kong.body_filter() --遍历在缓存中的插件列表,并执行
   }
    log_by_lua_block {
       kong.log() --遍历在缓存中的插件列表,并执行
   }
    location / {
        proxy_pass $upstream_scheme://kong_upstream$upstream_uri;
   }
}

nginx__Kong__128">七、从 nginx 配置到 Kong 配置

nginx

upstream my_upstream {
    server 192.168.0.106:3000 weight=100;
}
server {
    listen 80;
    location /hello {
        proxy_pass my_upstream;
   }
}

Kong:

# 配置 upstream
curl -X POST http://localhost:8001/upstreams --data "name=mark_upstream"
# 配置 target
curl -X POST http://localhost:8001/upstreams/mark_upstream/tar gets --data "target=192.168.31.91:8888" --data "weight=100"
curl -X POST http://localhost:8001/upstreams/mark_upstream/tar gets --data "target=192.168.31.91:9999" --data "weight=100"
# 配置 service
curl -X POST http://localhost:8001/services --data "name=hello" --data "host=mark_upstream"
# 配置 route
curl -X POST http://localhost:8001/routes --data "paths[]=/hello" --data "service.id=15722364-296f-4624-9026-ceff2d2166f2"

7.1、Kong 核心四对象

Kong 涉及到 upstream,target,service,route 概念。

  1. upstream 是对上游服务器的抽象。
  2. target 代表了一个物理服务,是 ip + port 的抽象。
  3. service 是抽象层面的服务,他可以直接映射到一个物理服务(host 指向 ip + port),也可以指向一个 upstream 来做到负载均衡
  4. route 是路由的抽象,他负责将实际的 request 映射到service。

consumer 是使用 service 的用户,可以为 consumer 添加plugin 插件,从而定义 consumer 的请求行为。

7.2、四对象关系

  1. upstream 和 target :1 : n。
  2. service 和 upstream :1 : 1 或 1 : 0;(service 也可以直接指向具体的 target,相当于不做负载均衡)。
  3. service 和 route:1 : n。
    Kong_4_object

八、插件机制

Kong 的插件机制是 Kong 最核心的功能;Kong 要解决的问题是承担所有服务共同需要的那部分功能;插件可能是作用全局的,也可能是作用局部的,比如大部分插件是作用在 service 或route 上。
Kong 的插件列表

# 为 hello 服务添加 50/s 的限流,作用在 service 上
curl -X POST http://localhost:8001/services/hello/plugins \
--data "name=rate-limiting" \
--data "config.second=50"
# 为某个 routeId 添加 50/s 的限流,作用在 routes 上
curl -X POST http://localhost:8001/routes/{routeId}/plugins \
--data "name=rate-limiting" \
--data "config.second=50"

九、Kong 网关插件

  1. 身份认证插件:Kong提供了 Basic Authentication、Key authentication、OAuth2.0 Authentication、HMAC authentication、JWT、LDAP authentication 认证实现。
  2. 安全控制插件:ACL(访问控制)、CORS(跨域资源共享)、动态 SSL、IP限制、爬虫检测实现。
  3. 流量控制插件:请求限流(基于请求计数限流)、上游响应限流(根据 upstream 响应计数限流)、请求大小限制。限流支持本地、Redis 和集群限流模式。
  4. 分析监控插件:Galileo(记录请求和响应数据,实现 API 分析)、Datadog(记录 API Metric 如请求次数、请求大小、响应状态和延迟,可视化 API Metric)、Runscope(记录请求和响应数据,实现 API 性能测试和监控)。
  5. 协议转换插件:请求转换(在转发到 upstream 之前修改请求)、响应转换(在 upstream 响应返回给客户端之前修改响应)。
  6. 日志应用插件:TCP、UDP、HTTP、File、Syslog、StatsD、Loggly 等。

konga_189">十、使用konga

10.1、实现一个负载均衡

输入IP和端口号即可进入konga。比如:192.168.0.106:1337

(1)第一次进入需要注册一个用户。
<a class=konga_register" />
(2)创建完用户后需要登录。
<a class=konga_login" />
(2)创建connections。
<a class=konga_connections" />
<a class=konga_create" />
(3)创建完成后激活。
<a class=konga_active" />
(4)先使用openresty创建三个后台服务器:创建两个文件夹conf和logs,在conf文件夹下创建nginx.conf文件并输入以下内容:

worker_processes 2;
events {
        worker_connections 10240;
}

http {
        server {
                listen 7001;
                location / {
                        content_by_lua_block {
                                ngx.say(7001,"\t",ngx.var.remote_addr)
                        }
                }
        }
        server {
                listen 7002;
                location / {
                        content_by_lua_block {
                                ngx.say(7002,"\t",ngx.var.remote_addr)
                        }
                }
        }
        server {
                listen 7003;
                location / {
                        content_by_lua_block {
                                ngx.say(7003,"\t",ngx.var.remote_addr)
                        }
                }
        }


}

(5)启动后台服务器。

openresty -p . -c conf/nginx.conf

查看:

ps aux | grep nginx

(6)konga中创建upstream。
<a class=konga_upstream" />
然后直接点击提交。
(7)创建tagets。
<a class=konga_details" />
<a class=konga_taget" />
(8)创建service。
<a class=konga_service" />
然后点击提交。
(9)创建route。
<a class=konga_service_enter" />
<a class=konga_route" />
然后点击提交。
(10)现在配置完成了7001,可以测试一下访问了。网页输入IP和端口。
<a class=kong_test" />
此时会发现,网页返回的IP地址是docker容器的IP地址,客户端的IP地址丢失了。其实kong已经把IP地址传过去了,只是我们还没有使用而已。它在头信息里面,需要自己提取出来。

可以把nginx.conf修改一下:

worker_processes 2;
events {
        worker_connections 10240;
}

http {
        server {
                listen 7001;
                location / {
                        content_by_lua_block {
                                local header = ngx.req.get_headers()
                                local cjson = require "cjson"
                                ngx.say(7001,"\t",ngx.var.remote_addr)
                                ngx.say(cjson.encode(header))
                        }
                }
        }
        server {
                listen 7002;
                location / {
                        content_by_lua_block {
                                ngx.say(7002,"\t",ngx.var.remote_addr)
                        }
                }
        }
        server {
                listen 7003;
                location / {
                        content_by_lua_block {
                                ngx.say(7003,"\t",ngx.var.remote_addr)
                        }
                }
        }


}

然后重写加载一下:

openresty -p . -s reload

重新访问一下就可以看到真正的客户端IP:
<a class=kong_cjson" />
(11)上面已经添加了一个taget,为了演示负载均衡,继续添加创建两个tagets:7002和7003。
<a class=konga_targets_7002" />
(12)然后在网址输入IP和端口,每次访问的返回信息就有改变了。至此实现一个负载均衡器。

10.2、实现黑白名单

有了前面的基础,我们可以在service上加上黑白名单的插件。插件是 ip restriction。
<a class=konga_ip" />
<a class=konga_ip_create" />
加完之后,再次访问就会出现如下信息:
<a class=kong_error" />
要移出黑名单直接叉掉就可以。

10.3、实现限流

限流可以是限制次数和限制大小。限流使用的插件是rate limiting。
<a class=konga_rate_limiting" />
<a class=konga_second" />
限流效果:
<a class=kong_limiting" />

10.4、实现鉴权验证

(1)先创建consumer。
<a class=konga_consumer" />
(2)然后创建用户和密码:
consumer_pwd
(3)添加验证插件,basic auth。
basic_auth
basic_auth_ok
(4)浏览器访问时就会弹出登录验证。
<a class=konga_access" />

总结

  1. kongopenresty的一个应用,开箱即用,可以不开发只使用。kong的功能基本涵盖不部分问题。

  2. kong重要的特性:抽象对象,不需要写nginx配置;插件机制,使用一个功能,直接用插件应用在对象上(service、route、consume)就行。

  3. openresty如何解决问题:在nginx的关键阶段嵌入lua;openresty实现了cosocket,通过协程黏合异步事件回调,可以写同步的代码。

  4. kong可以是我们不需要写复杂的nginx配置文件,它抽象了四个对象,这几个对象的关系需要清楚;而且kong提供了丰富的插件。

后言

本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对c/c++linux系统提升感兴趣的读者,可以点击链接查看详细的服务:C/C++服务器开发 。


http://www.niftyadmin.cn/n/23856.html

相关文章

Qt6 中如何使用 qsb

【写在前面】 Qt 5 的图形体系结构非常依赖 OpenGL 作为底层 3D 图形 API。但过去 8 年来随着 Metal 和 Vulkan 的推出&#xff0c;市场发生了巨大变化。现在&#xff0c;Qt 6 加入了大量不同平台的图形 API&#xff0c;以确保用户可以在所有平台上以最高性能运行 Qt。 在 Qt Q…

linphone android sdk 源码下载编译

前言 前面的有写过Android 使用Linphone SDK开发SIP客户端相关的文章, 在后续的开发过程中, 为了更深入了解linphone, 便尝试下载SDK源码自行编译. 关于linphone这里不作过多介绍, 可以参考前面的文章. Linphone-SDK 是一个将 Liblinphone 及其依赖项捆绑为 git 子模块的项目&a…

肠道微生物在天然产物生物转化中的潜在作用

谷禾健康 什么是天然产物&#xff1f; 天然产物是指动物、植物、昆虫或微生物体内的组成成分或其代谢产物以及人和动物体内许多内源性的化学成分&#xff0c;是自然产生的小分子。值得注意的是&#xff0c;天然产物来源中&#xff0c;植物来源占85%以上。 谷禾在这里主要介绍植…

【Docker】三 镜像容器常用命令

这里写目录标题1 配置镜像加速器2 Docker镜像常用命令2.1 搜索镜像2.2 下载镜像[重要]2.3 列出镜像[重要]2.3 删除本地镜像[重要]2.4 保存镜像2.5 加载镜像2.6 构建镜像[重要]3 容器常用命令3.1 新建并启动容器[重要]3.2 列出容器[重要]3.3 停止容器[重要]3.4 强制停止容器[重要…

【回答问题】ChatGPT上线了!给我推荐20个比较流行的图像实例分割模型

给我推荐20个比较流行的图像实例分割模型 U-Net Mask R-CNN FCN SegNet PSPNet DeepLabv3 DenseASPP LinkNet RefineNet ENet ICNet BiSeNet CRF-RNN GCN Tiramisu FRRN DeepLabv3 PANet MaskLab Hybrid Task Cascade给我推荐20个比较流行的图像实例分割模型源码 好的&#x…

tomcat组件-Server

目录 概述 tomcat 启动 大致流程 Server StandardServer 利用8005端口关闭tomcat 总结 概述 了解一个程序&#xff0c;一定要知道他是干什么的&#xff0c;以及内部架构如何支撑这么干的&#xff0c;以及牵扯的到的概念、模式等知识点的解析(这里只介绍组件)。 Tomcat是…

【计算机体系结构】指令集并行(ILP)动态调度算法:Tomasulo实现代码(Tomasulo Algorithm Implementation)

Tomasulo Algorithm Implementation &#xff08;本文章仅提供算法实现过程&#xff0c;具体算法思想请查阅教科书&#xff09; 如果觉得这篇文章有用&#xff0c;请记得点个赞并收藏哦&#xff01; 1.Introduction Tomasulo算法用于指令的动态调度&#xff0c;允许乱序执行…

DALLE2-文本图像生成

文章目录摘要算法解码器prior图像处理变体插值文本差异限制论文&#xff1a; 《Hierarchical Text-Conditional Image Generation with CLIP Latents》github&#xff1a; https://github.com/lucidrains/DALLE2-pytorchhttps://github.com/LAION-AI/dalle2-laion摘要 CLIP已经…