在微服务与云原生架构下,Kubernetes Ingress 提供的基础七层路由能力已无法满足企业级应用对流量治理、安全防护和精细化观测的复杂需求。本文面向正在或计划构建云原生 API 网关的中高级工程师与架构师,我们将跳出“如何使用”的层面,深入探讨基于 Kong Ingress Controller 的网关方案。我们将从网络协议与操作系统 I/O 模型的基础原理出发,剖析其控制平面与数据平面的核心设计,分析关键的架构权衡(DB-less vs. DB-backed),并给出从零到一的架构演进与落地路径,确保你构建的不仅是一个能工作的网关,更是一个高性能、高可用、易于扩展的企业级流量中枢。
现象与问题背景
随着业务从单体架构向微服务演进,服务间的调用关系呈指数级增长,系统边界变得模糊。过去由单体应用内部方法调用解决的问题,如今变成了跨网络的 RPC 调用。这带来了全新的挑战:流量入口如何统一管理?谁来负责服务的认证、授权和安全?如何对全链路进行有效的速率限制、熔断降级和监控告警?
在 Kubernetes 生态中,原生的 `Ingress` 资源对象提供了一个基础的答案。它定义了从集群外部访问集群内部 `Service` 的规则,本质上是一个七层反向代理的规范。然而,`Ingress` 规范本身极其简单,只覆盖了主机名(Host)、路径(Path)到服务(Service)的基础路由功能。对于认证、限流、WAF、gRPC 转换、自定义可观测性等高级功能,规范并未定义,而是交由具体的 Ingress Controller 实现,通常通过非标准的 `Annotations` 来完成。这导致了严重的厂商锁定和配置管理的混乱。当我们需要的功能组合超过几十个 `Annotations` 时,YAML 文件会变得难以维护和理解,缺乏结构化的、面向 API 的管理模型。
此时,我们需要一个真正的 **API 网关**,而不仅仅是一个 Ingress Controller。API 网关作为所有外部流量的唯一入口,除了反向代理,还承担了“横切关注点”(Cross-cutting Concerns)的重任。Kong,基于 Nginx 和 OpenResty 构建的高性能网关,及其与 Kubernetes 深度集成的 Kong Ingress Controller,正是应对这一挑战的有力竞争者。
关键原理拆解
要真正掌握 Kong Ingress Controller,我们必须回归到底层的计算机科学原理,理解其高性能和高扩展性从何而来。
- L7 代理与非阻塞 I/O 模型: 从大学教授的视角看,Kong 的核心(Nginx)是一个典型的事件驱动、异步非阻塞的 L7 代理。它工作在 OSI 模型的应用层,能够解析 HTTP/1.1, HTTP/2, gRPC, WebSocket 等协议的报文内容。其高性能的基石在于操作系统提供的 I/O 多路复用机制,如 Linux 上的 `epoll`。传统的阻塞 I/O 模型是“一个连接一个进程/线程”,当连接空闲时,线程被阻塞,浪费了大量 CPU 和内存资源。而 `epoll` 允许单个工作进程(Worker Process)监听成千上万个网络连接(Socket)。当某个连接有数据到达时,内核会通知工作进程,进程才去处理该连接上的读写事件。这种模型极大减少了进程/线程创建和上下文切换的开销,使得 Kong 能以极低的资源消耗处理海量的并发连接。
- 控制平面与数据平面的分离 (Control Plane vs. Data Plane): 这是现代网络和分布式系统的核心设计思想。
- 数据平面 (Data Plane): 由 `kong` 代理容器组成,它们是无状态的,直接处理南北向的业务流量。其核心职责是快速、高效地执行路由、插件链等逻辑。数据平面的实例可以根据流量负载进行水平伸缩(Horizontal Scaling)。
- 控制平面 (Control Plane): 由 `controller` 容器(即 Kong Ingress Controller)担任。它不处理任何业务流量,唯一的职责是监听 Kubernetes API Server 的资源变化(如 `Ingress`, `KongPlugin`, `Service` 等 CRDs),然后将这些声明式的配置翻译成 Kong 数据平面能够理解的配置格式,并通过 Kong Admin API 或配置文件的方式下发给数据平面。
这种分离使得配置变更与流量处理解耦,控制平面的故障不会立刻影响正在运行的数据平面,保证了流量的稳定性,同时也让各自的扩缩容策略更加独立和清晰。
- 声明式 API 与终态一致性: Kubernetes 的核心是声明式 API。用户通过 YAML 文件描述“系统的期望状态”,而不是下发“如何达到该状态”的命令式指令。Kong Ingress Controller 正是这一理念的践行者。它持续地对比“期望状态”(来自 K8s API Server 的 CRD 配置)和“当前状态”(Kong 数据平面的实际配置),并执行必要的动作(增、删、改)来消除差异,这个过程被称为“Reconciliation Loop”(调和循环)。这确保了系统的自愈能力和配置管理的幂等性,是实现 GitOps 的基础。
系统架构总览
一个典型的生产级 Kong Ingress Controller 部署架构通常包含以下组件:
首先,外部用户流量通过公网进入云厂商提供的外部负载均衡器(External Load Balancer,如 AWS ELB, GCP Cloud Load Balancer)。这个 LB 主要负责 L4 的负载均衡,将 TCP 流量转发到 Kubernetes 集群中 Kong 数据平面 Pod 所暴露的 `NodePort` 或 `LoadBalancer` 类型的 `Service` 上。
进入集群后,流量到达 Kong 数据平面(Data Plane)。这是一组由 `Deployment` 或 `DaemonSet` 管理的 `kong` 代理 Pod。这些 Pod 是无状态的,它们的核心任务就是执行路由和插件逻辑。为了实现高可用和负载分担,通常会部署多个副本,并配置反亲和性(Anti-Affinity)规则,使其分布在不同的物理节点上。这些 Pod 监听着一个内部的 Admin API 端口,用于接收来自控制平面的配置更新。
在集群的某个命名空间中,运行着 Kong 控制平面(Control Plane),即 `ingress-controller` Pod。这个 Pod 内的控制器进程通过 `WATCH` 机制实时监听 Kubernetes API Server 上的特定资源,包括标准的 `Ingress` 资源和 Kong 自定义的 CRDs(Custom Resource Definitions),如 `KongIngress`, `KongPlugin`, `KongConsumer` 等。当检测到这些资源发生变化时,控制器会生成一份新的 Kong 配置,并通过调用数据平面 Pod 的 Admin API 将配置推送过去。为了保证控制平面的高可用,它通常也以多副本方式部署,并通过 leader-election 机制确保同一时间只有一个实例在工作,避免配置冲突。
最后,这套架构还有一个关键的选择点:Kong 的配置持久化方式。在 DB-backed 模式下,所有配置信息(路由、服务、插件等)都存储在一个独立的数据库中(如 PostgreSQL)。控制平面将配置写入数据库,数据平面则从数据库中拉取。而在更云原生的 DB-less 模式下,控制平面直接将所有配置聚合成一个内存中的 JSON/YAML 文件,通过 Admin API 的 `/config` 端点一次性推送到数据平面。数据平面将配置全量加载到内存中,无需任何外部数据库依赖。
核心模块设计与实现
从极客工程师的视角来看,理论最终要落地为代码和配置。下面我们通过具体的 YAML 和代码片段来剖析核心模块。
路由配置: `Ingress` 与 `KongIngress`
标准的 `Ingress` 资源只能定义基础路由。例如,将 `example.com/foo` 路由到 `foo-service`。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
kubernetes.io/ingress.class: "kong"
spec:
rules:
- host: example.com
http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: foo-service
port:
number: 80
这很简单,但如果我们想为这条路由配置5秒超时、3次重试,或者指定上游协议为 gRPC 呢?这就需要使用 `KongIngress` 这个 CRD 来“增强” `Ingress`。通过一个 annotation,我们将 `Ingress` 与 `KongIngress` 关联起来。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-grpc-ingress
annotations:
kubernetes.io/ingress.class: "kong"
# 关键:通过 annotation 关联 KongIngress 配置
konghq.com/override: "example-grpc-options"
spec:
rules:
# ... 省略 ...
---
apiVersion: configuration.konghq.com/v1
kind: KongIngress
metadata:
name: example-grpc-options
# `proxy` 字段直接映射到 Kong 的 Route 对象的 proxy 部分
proxy:
protocol: grpcs
connect_timeout: 5000
read_timeout: 5000
write_timeout: 5000
retries: 3
这种关注点分离的设计非常优雅:`Ingress` 负责定义“路由是什么”,`KongIngress` 负责定义“路由的行为是怎样的”。
插件化扩展: `KongPlugin`
插件是 Kong 的灵魂。通过 `KongPlugin` CRD,我们可以用声明式的方式管理插件。例如,为所有服务启用一个每分钟100次的速率限制。
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
# 全局插件
name: global-rate-limit
config:
minute: 100
policy: local # `local` 表示计数器在单个 Kong 节点内存中,`redis` 可实现集群限流
plugin: rate-limiting
如果只想对某个特定的 `Ingress` 或 `Service` 应用插件,只需在对应的资源上添加 `konghq.com/plugins` annotation 即可。这种灵活的绑定机制使得策略应用非常精确。
自定义插件开发:深入 Lua 世界
当内置插件不满足需求时,例如需要对接内部的认证系统,或者实现特定的请求转换逻辑,我们就需要编写自定义 Lua 插件。这才是 Kong 真正强大的地方。
一个 Kong 插件本质上是一个遵循特定目录结构和 API 的 Lua table。其核心是实现请求处理生命周期中的各个阶段(phases)的钩子函数,如 `init_worker`, `certificate`, `rewrite`, `access`, `header_filter`, `body_filter`, `log`。
下面是一个简单的插件,它会在请求的 `access` 阶段,给上游请求添加一个固定的 `X-Transaction-ID` 头。这在线上问题排查时非常有用。
-- a-custom-plugin/handler.lua
local BasePlugin = require "kong.plugins.base_plugin"
local uuid = require "uuid"
local CustomPluginHandler = BasePlugin:extend()
CustomPluginHandler.PRIORITY = 1000 -- 插件执行优先级
CustomPluginHandler.VERSION = "0.1.0"
function CustomPluginHandler:new()
CustomPluginHandler.super.new(self, "a-custom-plugin")
end
-- 在 access 阶段执行
function CustomPluginHandler:access(conf)
-- 调用父类的 access 方法
CustomPluginHandler.super.access(self)
-- 生成一个 UUID 作为交易 ID
local tx_id = uuid()
-- 设置请求头,转发给上游服务
-- `kong.service.request` 是 Kong 提供的核心 API
kong.service.request.set_header("X-Transaction-ID", tx_id)
end
return CustomPluginHandler
这段代码展示了 Kong 插件开发的核心:在指定的生命周期阶段(`access`),通过 `kong.*` 这个全局 Lua API 来读取和修改请求/响应。一旦开发完成,通过 `ConfigMap` 和 `VolumeMount` 将插件代码挂载到 Kong Pod 的 `LUA_PATH` 中,再通过 `KongPlugin` CRD 启用它,即可生效。这为平台工程团队提供了无限的扩展能力。
性能优化与高可用设计
架构权衡:DB-less vs. DB-backed
这是部署 Kong 时面临的第一个,也是最重要的架构决策。
- DB-backed 模式:
- 优点: 配置可以动态、增量地更新,Admin API 功能完整,非常灵活。多个控制平面可以共享同一个数据库,实现高可用。
- 缺点: 引入了外部依赖(PostgreSQL),增加了架构的复杂性和潜在故障点。数据库本身可能成为性能瓶颈。灾备和迁移相对复杂。
- DB-less 模式:
- 优点: 纯粹的声明式,配置即代码。数据平面完全无状态,极易于水平扩展和灾难恢复。整个部署遵循不可变基础设施(Immutable Infrastructure)的原则,完美契合 GitOps 流程。性能更好,因为配置直接加载在内存中,没有数据库查询开销。
- 缺点: 配置变更是“全量替换”,而非“增量更新”。对于超大规模配置(成千上万条路由),重新加载可能会有短暂的内存和 CPU 峰值。部分依赖数据库的插件(如 `rate-limiting` 的集群模式)需要额外配置(如 Redis)。
实战建议: 对于绝大多数 Kubernetes 场景,强烈推荐使用 DB-less 模式。它更符合云原生的哲学,运维成本更低,也更稳定。只有在需要极其频繁、动态地通过 API 修改配置,且无法通过 K8s CRD 管理的特殊场景下,才考虑 DB-backed 模式。
高可用性与性能调优
- 数据平面高可用: 使用 `Deployment` 部署多个 `kong` Pod,并设置 `podAntiAffinity`,确保它们分散在不同物理节点上。利用 `HorizontalPodAutoscaler` (HPA) 基于 CPU 和内存使用率自动扩缩容。
- 配置热加载: 在 DB-less 模式下,当 Ingress Controller 推送新配置时,它会触发 Kong 内部的 `nginx -s reload` 命令。Nginx 主进程(Master Process)会启动新的工作进程(Worker Process)加载新配置,同时旧的工作进程会继续处理完存量连接后优雅退出。这个过程对客户端是无感的,不会中断服务。但要注意,在 reload 期间,新旧两份配置会同时存在于内存中,需要为 Pod 规划足够的内存 `limit`。
- CPU 与内存调优: Kong 的性能很大程度上取决于 Nginx worker 的调优。`worker_processes` 参数应设置为 `auto` 或与 Pod 请求的 CPU 核数相等。使用 `worker_cpu_affinity` 可以将 worker 进程绑定到特定的 CPU 核,减少核间缓存失效(cache invalidation)带来的性能抖动。对于内存,需要监控 LuaJIT 的内存使用情况,特别是自定义插件中是否存在内存泄漏。
- 缓存: Kong 内部有多种缓存机制,如 DNS 解析缓存、插件配置缓存(`db_cache`)。合理配置缓存 TTL 可以显著降低对上游服务和配置源(在 DB-backed 模式下是数据库)的压力,是降低延迟的关键手段。
架构演进与落地路径
一个成熟的网关方案不是一蹴而就的,而是分阶段演进的。以下是一个可行的落地路线图。
- 阶段一:统一流量入口,替换现有 Ingress。
此阶段的目标是使用 Kong Ingress Controller 替换集群中原有的 Nginx Ingress Controller 或其他方案,实现所有南北向流量的统一接入。初期只使用其基础的路由功能,让业务团队熟悉通过 `Ingress` 资源来发布服务。关键在于建立起 CI/CD 流程,将 `Ingress` 配置纳入 Git 版本管理。
- 阶段二:标准化横切关注点。
在流量统一后,开始利用 Kong 的插件能力,将通用能力从微服务中下沉到网关层。首先从认证(如 `jwt`, `oauth2`)、限流(`rate-limiting`)、安全(`bot-detection`, `ip-restriction`)等标准插件入手。通过 `KongPlugin` CRD 定义标准化的策略,并推广给业务方使用。这个阶段的目标是为所有微服务提供一层统一、标准的安全和流量控制基座。
- 阶段三:深度定制与可观测性建设。
当标准插件无法满足特定业务场景时,平台工程团队应介入,开发自定义 Lua 插件。例如,与内部统一认证平台(SSO)集成、实现定制化的服务发现逻辑、或生成符合内部规范的分布式追踪头。同时,深度集成可观测性体系:通过 `Prometheus` 插件暴露丰富的指标(请求延迟、状态码、上游健康状况等),建立 Grafana 监控大盘;通过 `Jaeger/Zipkin` 插件实现全链路追踪。
- 阶段四:向联邦网关与服务网格演进。
当业务扩展到多集群或混合云环境时,需要考虑网关的联邦管理。可以探索使用如 Kong Konnect 这样的商业工具,或者自研控制平面来统一管理分布在各处的 Kong 数据平面。此外,需要明确 API 网关与服务网格(Service Mesh, 如 Istio)的边界。通常的模式是:Kong 作为南北向流量网关,负责处理来自外部的流量;Service Mesh 负责处理集群内部服务间的(东西向)流量。 在某些高级场景下,Kong 也可以作为 Mesh 的 Ingress Gateway,实现两者无缝集成,共同构成一个完整的流量治理体系。
遵循这样的演进路径,可以平滑、低风险地在企业内部署和推广 Kong 网关方案,逐步释放其全部潜力,最终构建一个强大、可靠且面向未来的云原生流量基础设施。
延伸阅读与相关资源
-
想系统性规划股票、期货、外汇或数字币等多资产的交易系统建设,可以参考我们的
交易系统整体解决方案。 -
如果你正在评估撮合引擎、风控系统、清结算、账户体系等模块的落地方式,可以浏览
产品与服务
中关于交易系统搭建与定制开发的介绍。 -
需要针对现有架构做评估、重构或从零规划,可以通过
联系我们
和架构顾问沟通细节,获取定制化的技术方案建议。