前言:为什么要学Kong?
如果你正在阅读这篇文章,说明你可能遇到了以下几种情况之一:
- 老板说:"我们需要一个API网关",然后看向了你
- 你被微服务架构搞得焦头烂额,急需一个统一入口
- 你厌倦了在每个服务里都写一遍认证、限流、日志的代码
- 你只是单纯地想装X
无论是哪种情况,Kong都是一个值得了解的选择。当然,"了解"和"精通"之间隔着一条叫做"踩坑"的银河。
一、Kong是个啥?
1.1 官方定义(催眠版)
Kong是一个云原生、快速、可扩展、分布式的API网关。它基于Nginx和OpenResty构建,使用Lua语言开发插件系统。
1.2 人话翻译版
想象一下,你开了一家大型商场(微服务集群),里面有几十家店铺(各种服务)。Kong就是那个坐在商场入口的保安大叔,负责:
- 身份验证:你是VIP吗?让我看看你的会员卡(JWT/OAuth)
- 流量控制:商场太挤了,一次只能进100人(Rate Limiting)
- 路由指引:你要去哪家店?我帮你指路(Routing)
- 记录日志:几点几分,谁进来了,干了啥(Logging)
- 安全检查:这位客人,麻烦把包打开看看(WAF)
1.3 Kong的核心架构
二、安装Kong(踩坑第一站)
2.1 安装方式选择
Kong提供了多种安装方式,让我用一张表来帮你做选择:
| 安装方式 | 适合场景 | 难度 | 翻车概率 |
|---|---|---|---|
| Docker | 开发测试、快速体验 | ⭐ | 低 |
| Docker Compose | 本地完整环境 | ⭐⭐ | 中 |
| Kubernetes/Helm | 生产环境 | ⭐⭐⭐⭐ | 看运气 |
| 包管理器安装 | 传统部署 | ⭐⭐⭐ | 中高 |
| 源码编译 | 大佬专属 | ⭐⭐⭐⭐⭐ | 极高(但很酷) |
2.2 Docker方式安装(推荐新手)
这是最不容易翻车的方式,除非你的Docker也有问题。
Step 1: 创建Docker网络
docker network create kong-netStep 2: 启动PostgreSQL
docker run -d --name kong-database \
--network=kong-net \
-p 5432:5432 \
-e "POSTGRES_USER=kong" \
-e "POSTGRES_DB=kong" \
-e "POSTGRES_PASSWORD=kongpass" \
postgres:13Step 3: 初始化数据库
docker run --rm --network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_PASSWORD=kongpass" \
kong/kong-gateway:3.4 kong migrations bootstrap看到这条命令跑完没报错?恭喜你,你已经超越了30%的新手。
Step 4: 启动Kong
docker run -d --name kong-gateway \
--network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_PASSWORD=kongpass" \
-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" \
-e "KONG_ADMIN_GUI_URL=http://localhost:8002" \
-p 8000:8000 \
-p 8443:8443 \
-p 8001:8001 \
-p 8444:8444 \
-p 8002:8002 \
-p 8445:8445 \
kong/kong-gateway:3.42.3 验证安装
# 检查Kong是否启动成功
curl -i http://localhost:8001/
# 如果看到类似下面的返回,说明成功了
# HTTP/1.1 200 OK
# {
# "version": "3.4.x.x",
# "configuration": { ... }
# }2.4 端口说明(重要!)
初学者经常被Kong的端口搞晕,让我来解释一下:
| 端口 | 用途 | 协议 |
|---|---|---|
| 8000 | 代理端口,接收客户端HTTP请求 | HTTP |
| 8443 | 代理端口,接收客户端HTTPS请求 | HTTPS |
| 8001 | Admin API,管理Kong配置 | HTTP |
| 8444 | Admin API(HTTPS版) | HTTPS |
| 8002 | Kong Manager GUI界面 | HTTP |
| 8445 | Kong Manager GUI(HTTPS版) | HTTPS |
记忆口诀:8000系列对外服务,8001管理配置,8002看界面。
三、核心概念(划重点!)
3.1 四大金刚
Kong的核心概念其实就四个,搞懂了你就入门了:
3.1.1 Service(服务)
Service代表你的后端API服务。你可以把它理解为"我要代理的那个东西"。
# 创建一个Service
curl -i -X POST http://localhost:8001/services \
--data name=my-service \
--data url='http://httpbin.org'3.1.2 Route(路由)
Route定义了请求如何匹配到Service。简单说就是"什么样的请求应该转发到哪个服务"。
# 为Service创建Route
curl -i -X POST http://localhost:8001/services/my-service/routes \
--data 'paths[]=/demo' \
--data name=my-route3.1.3 Upstream(上游)
Upstream用于负载均衡,当你的后端服务有多个实例时使用。
# 创建Upstream
curl -i -X POST http://localhost:8001/upstreams \
--data name=my-upstream
# 添加Target
curl -i -X POST http://localhost:8001/upstreams/my-upstream/targets \
--data target='192.168.1.100:8080' \
--data weight=1003.1.4 Plugin(插件)
Plugin是Kong的灵魂。没有插件的Kong就像没有配料的火锅——能吃,但没意思。
# 给Service添加限流插件
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=rate-limiting \
--data config.minute=5 \
--data config.policy=local3.2 概念关系图
API调用者] subgraph RouteBlock[Route 路由匹配规则] RouteInfo[paths, methods
hosts, headers] end subgraph ServiceBlock[Service 后端服务抽象] ServiceInfo[url, protocol
host, port] end subgraph UpstreamBlock[Upstream 负载均衡] Target1[Target 1
:8080] Target2[Target 2
:8080] Target3[Target 3
:8080] end Consumer --> RouteBlock RouteBlock --> ServiceBlock ServiceBlock --> UpstreamBlock
四、常用插件详解
4.1 认证类插件
Key Authentication(API Key认证)
最简单的认证方式,适合内部服务或简单场景。
# 1. 启用插件
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=key-auth
# 2. 创建Consumer
curl -i -X POST http://localhost:8001/consumers \
--data username=joey
# 3. 为Consumer创建API Key
curl -i -X POST http://localhost:8001/consumers/joey/key-auth \
--data key=my-secret-key
# 4. 使用API Key访问
curl -i http://localhost:8000/demo \
-H 'apikey: my-secret-key'JWT认证
生产环境更常用的方式:
# 1. 启用JWT插件
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=jwt
# 2. 创建Consumer
curl -i -X POST http://localhost:8001/consumers \
--data username=jwt-user
# 3. 创建JWT凭证
curl -i -X POST http://localhost:8001/consumers/jwt-user/jwt \
--data algorithm=HS256 \
--data secret=my-jwt-secret4.2 流量控制类插件
Rate Limiting(限流)
防止你的服务被打爆的好帮手:
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=rate-limiting \
--data config.second=5 \
--data config.minute=100 \
--data config.hour=1000 \
--data config.policy=local策略说明:
local: 每个Kong节点独立计数(简单但不精确)cluster: 所有节点共享计数(需要数据库)redis: 使用Redis存储计数(推荐生产使用)
计数: 50] K2[Kong Node 2
计数: 30] K3[Kong Node 3
计数: 45] end subgraph Redis策略 KR1[Kong Node 1] KR2[Kong Node 2] KR3[Kong Node 3] Redis[(Redis
统一计数: 125)] KR1 --> Redis KR2 --> Redis KR3 --> Redis end
Request Size Limiting
防止有人上传1TB的文件把你服务搞挂:
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=request-size-limiting \
--data config.allowed_payload_size=10 \
--data config.size_unit=megabytes4.3 日志类插件
File Log
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=file-log \
--data config.path=/tmp/kong.logHTTP Log(推荐)
把日志发送到你的日志收集系统:
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=http-log \
--data config.http_endpoint=http://your-log-server:8080/logs \
--data config.method=POST \
--data config.timeout=10004.4 安全类插件
CORS
解决前端同学的跨域问题:
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=cors \
--data config.origins=* \
--data config.methods=GET,POST,PUT,DELETE \
--data config.headers=Accept,Authorization,Content-Type \
--data config.max_age=3600IP Restriction
只允许特定IP访问:
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=ip-restriction \
--data config.allow=192.168.1.0/24 \
--data config.allow=10.0.0.0/84.5 插件执行顺序
当多个插件同时存在时,它们的执行顺序是固定的。Kong通过优先级数字来控制(数字越大越先执行):
优先级: 1000000] P3[2. bot-detection
优先级: 2500] P5[3. jwt
优先级: 1005] P4[4. key-auth
优先级: 1003] P2[5. ip-restriction
优先级: 990] P6[6. rate-limiting
优先级: 910] P7[7. request-transformer
优先级: 801] P1 --> P3 --> P5 --> P4 --> P2 --> P6 --> P7 end Proxy[Proxy 转发请求] subgraph 响应阶段[响应阶段 Response Phase] direction TB R1[8. response-transformer
优先级: 800] R2[9. file-log
优先级: 9] R3[10. post-function
优先级: -1000] R1 --> R2 --> R3 end 请求阶段 --> Proxy --> 响应阶段
五、实战案例
5.1 案例一:为后端API添加统一认证
场景:你有3个微服务,都需要JWT认证。
JWT Plugin] Kong --> US[User Service
/api/users] Kong --> OS[Order Service
/api/orders] Kong --> PS[Product Service
/api/products]
# 1. 创建Services
for svc in user-service order-service product-service; do
curl -i -X POST http://localhost:8001/services \
--data name=$svc \
--data url=http://$svc:8080
done
# 2. 创建Routes
curl -i -X POST http://localhost:8001/services/user-service/routes \
--data 'paths[]=/api/users' --data name=user-route
curl -i -X POST http://localhost:8001/services/order-service/routes \
--data 'paths[]=/api/orders' --data name=order-route
curl -i -X POST http://localhost:8001/services/product-service/routes \
--data 'paths[]=/api/products' --data name=product-route
# 3. 全局启用JWT认证
curl -i -X POST http://localhost:8001/plugins \
--data name=jwt5.2 案例二:灰度发布
场景:新版本服务只让10%的流量访问。
weight: 90] New[新版本
weight: 10] end Kong -->|90%| Old Kong -->|10%| New
# 1. 创建Upstream
curl -i -X POST http://localhost:8001/upstreams \
--data name=my-app-upstream
# 2. 添加旧版本Target(权重90)
curl -i -X POST http://localhost:8001/upstreams/my-app-upstream/targets \
--data target='old-version:8080' \
--data weight=90
# 3. 添加新版本Target(权重10)
curl -i -X POST http://localhost:8001/upstreams/my-app-upstream/targets \
--data target='new-version:8080' \
--data weight=10
# 4. 创建Service指向Upstream
curl -i -X POST http://localhost:8001/services \
--data name=my-app \
--data host=my-app-upstream5.3 案例三:请求/响应转换
场景:需要在请求头中添加内部标识,同时隐藏响应中的敏感头信息。
添加 X-Internal-Request: true Kong->>Backend: GET /api/data
X-Internal-Request: true Backend->>Kong: 200 OK
X-Powered-By: Express
Server: nginx Note over Kong: Response Transformer
移除敏感Header Kong->>Client: 200 OK
(无敏感Header)
# 请求转换
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=request-transformer \
--data 'config.add.headers=X-Internal-Request:true' \
--data 'config.add.headers=X-Request-ID:$(uuid)'
# 响应转换
curl -i -X POST http://localhost:8001/services/my-service/plugins \
--data name=response-transformer \
--data 'config.remove.headers=X-Powered-By' \
--data 'config.remove.headers=Server'六、DB-less模式(声明式配置)
6.1 什么是DB-less模式?
DB-less模式让Kong不依赖数据库运行,所有配置通过YAML文件声明。这种模式特别适合:
- Kubernetes环境
- CI/CD流水线
- 不想维护数据库的场景
6.2 配置文件示例
# kong.yaml
_format_version: "3.0"
_transform: true
services:
- name: user-service
url: http://user-service:8080
routes:
- name: user-route
paths:
- /api/users
strip_path: false
plugins:
- name: rate-limiting
config:
minute: 100
policy: local
- name: order-service
url: http://order-service:8080
routes:
- name: order-route
paths:
- /api/orders
plugins:
- name: key-auth
consumers:
- username: internal-service
keyauth_credentials:
- key: internal-secret-key
plugins:
- name: cors
config:
origins:
- "*"
methods:
- GET
- POST
- PUT
- DELETE6.3 使用DB-less模式启动
docker run -d --name kong-dbless \
-v $(pwd)/kong.yaml:/kong/declarative/kong.yaml \
-e "KONG_DATABASE=off" \
-e "KONG_DECLARATIVE_CONFIG=/kong/declarative/kong.yaml" \
-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" \
-p 8000:8000 \
-p 8001:8001 \
kong/kong-gateway:3.4七、踩坑指南(血泪史)
7.1 坑1:数据库迁移失败
症状:kong migrations bootstrap 报错
排查流程:
解决方案:
# 检查数据库连接
docker exec -it kong-database psql -U kong -d kong -c "SELECT 1;"
# 如果有旧数据,强制重置(危险!仅测试环境使用)
docker run --rm --network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_PASSWORD=kongpass" \
kong/kong-gateway:3.4 kong migrations reset --yes
# 然后重新bootstrap
docker run --rm --network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_PASSWORD=kongpass" \
kong/kong-gateway:3.4 kong migrations bootstrap7.2 坑2:插件不生效
症状:明明配置了插件,但请求直接穿透了
排查流程:
排查命令:
# 1. 检查插件是否真的创建成功
curl http://localhost:8001/plugins | jq .
# 2. 检查插件的作用域是否正确
# 插件可以绑定到:全局、Service、Route、Consumer
# 3. 检查请求是否匹配到了正确的Route
curl -i http://localhost:8000/your-path -H "Host: your-host"
# 4. 查看Kong日志
docker logs kong-gateway 2>&1 | tail -1007.3 坑3:上游服务连接失败
症状:502 Bad Gateway 或 connect() failed
可能原因:
- 上游服务地址错误
- Kong容器无法访问上游服务网络
- 上游服务未启动
解决方案:
# 进入Kong容器测试网络连通性
docker exec -it kong-gateway sh
curl -v http://your-upstream:8080/health
# 如果是Docker网络问题,确保服务在同一网络
docker network inspect kong-net7.4 坑4:性能问题
症状:响应时间变长,CPU飙高
优化建议:
# 1. 增加worker数量(默认auto)
KONG_NGINX_WORKER_PROCESSES=4
# 2. 调整连接池
KONG_NGINX_HTTP_KEEPALIVE_TIMEOUT=60s
KONG_UPSTREAM_KEEPALIVE_POOL_SIZE=512
# 3. 限流插件改用Redis
curl -X PATCH http://localhost:8001/plugins/{plugin-id} \
--data config.policy=redis \
--data config.redis_host=redis \
--data config.redis_port=63797.5 坑5:证书配置问题
症状:HTTPS不工作或证书错误
# 上传证书
curl -X POST http://localhost:8001/certificates \
-F "cert=@/path/to/cert.pem" \
-F "key=@/path/to/key.pem" \
-F "snis[]=your-domain.com"
# 验证证书
curl http://localhost:8001/certificates | jq .八、生产环境建议
8.1 高可用部署架构
8.2 关键配置参数
# 性能相关
KONG_NGINX_WORKER_PROCESSES=auto
KONG_MEM_CACHE_SIZE=512m
KONG_UPSTREAM_KEEPALIVE_POOL_SIZE=512
# 安全相关
KONG_ADMIN_LISTEN=127.0.0.1:8001
KONG_ADMIN_SSL_CERT=/path/to/admin-cert.pem
KONG_ADMIN_SSL_CERT_KEY=/path/to/admin-key.pem
# 日志相关
KONG_PROXY_ACCESS_LOG=/var/log/kong/access.log
KONG_PROXY_ERROR_LOG=/var/log/kong/error.log
KONG_LOG_LEVEL=warn
# 数据库连接池
KONG_PG_POOL_SIZE=50
KONG_PG_TIMEOUT=50008.3 监控指标
Kong暴露了Prometheus格式的指标:
# 启用Prometheus插件
curl -X POST http://localhost:8001/plugins \
--data name=prometheus
# 访问指标端点
curl http://localhost:8001/metrics监控架构:
:8001/metrics] --> Prometheus[(Prometheus)] Prometheus --> Grafana[Grafana Dashboard] Prometheus --> AlertManager[Alert Manager] AlertManager --> Slack[Slack/钉钉]
重要指标:
kong_http_status: HTTP状态码分布kong_latency: 请求延迟kong_bandwidth: 带宽使用kong_upstream_target_health: 上游健康状态
九、与其他网关对比
| 特性 | Kong | APISIX | Nginx | Traefik |
|---|---|---|---|---|
| 语言 | Lua/OpenResty | Lua/OpenResty | C | Go |
| 配置方式 | Admin API/DB | Admin API/YAML | 文件 | 文件/API |
| 插件生态 | 丰富 | 丰富 | 一般 | 一般 |
| Kubernetes集成 | 好 | 好 | 一般 | 优秀 |
| 学习曲线 | 中等 | 中等 | 低 | 低 |
| 性能 | 高 | 极高 | 极高 | 高 |
| 商业支持 | 有(Kong Inc) | 有(API7) | 有(F5) | 有 |
⭐功能极强] APISIX[APISIX
⭐性能最高] end subgraph Q2[最佳选择 ✅] Kong[Kong
⭐均衡之选] end subgraph Q4[简单但够用] Traefik[Traefik
⭐K8s友好] end subgraph Q3[入门级] Nginx[Nginx
⭐老牌稳定] end end Q1 --- Q2 Q3 --- Q4
十、为什么"放弃"?
说是"放弃",其实是"放弃继续踩坑"的意思。当你:
- ✅ 理解了Service、Route、Plugin、Upstream的关系
- ✅ 能够根据业务需求配置合适的插件
- ✅ 知道怎么排查常见问题
- ✅ 能够部署一套高可用的Kong集群
恭喜你,你已经可以"放弃"入门阶段,进入实战阶段了!
附录:常用命令速查
# ===== Service操作 =====
# 创建Service
curl -X POST http://localhost:8001/services \
--data name=my-service \
--data url='http://example.com'
# 查看所有Service
curl http://localhost:8001/services
# 删除Service
curl -X DELETE http://localhost:8001/services/my-service
# ===== Route操作 =====
# 创建Route
curl -X POST http://localhost:8001/services/my-service/routes \
--data 'paths[]=/api' \
--data name=my-route
# 查看所有Route
curl http://localhost:8001/routes
# ===== Plugin操作 =====
# 查看可用插件
curl http://localhost:8001/plugins/enabled
# 创建全局插件
curl -X POST http://localhost:8001/plugins \
--data name=rate-limiting \
--data config.minute=100
# ===== Consumer操作 =====
# 创建Consumer
curl -X POST http://localhost:8001/consumers \
--data username=my-user
# ===== 健康检查 =====
# 检查Kong状态
curl http://localhost:8001/status
# 检查集群状态
curl http://localhost:8001/clustering/status参考资料:
写在最后:学技术就像吃火锅,刚开始总会被烫到嘴,但熟练了之后就能享受美味了。Kong也是一样,踩完坑之后,你会发现它真的是个好东西。