How Higress Works
在 阿里巴巴开源下一代云原生网关Higress:基于Envoy,支持Nginx Ingress零成本快速迁移中,介绍了阿里开源的云原生网关。
我们今天就来探索下,这个项目是做了什么,他又是怎么工作的。
Intro
对于一个全新的系统,我们首先从架构上切入是一个比较的好的选择。
从架构图上,我们可以发现,整体还是分成了
控制面
: istio + Higress Controller数据面
: Higress Data Plane
从图上我们就可以猜测出,数据面
是基于 Envoy
+ 一些自定义的插件来构成的。而控制面
看起来并不是很直观。
从上图可以看出 istio
和 Envoy
通讯,而 higress
不直接和 Envoy
通讯,因此,我们可以大胆的猜测 Higress
作为 istio
的 MCP
远端数据源提供服务给 istio
。那么基于这的假设我们来看看它是如何工作的。
How it works
初始化环境
直接看代码是不明智的
,一般来说我们先从一个项目的 Statup
开始,对一个项目有自己的观感才是比较好的选择。那我们先按照社区的文档初始化这个项目
- 安装 istio
1 | kubectl create ns istio-system |
需要 helm 较高版本的,如果运行出现 failed to download “oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/charts/istio” (hint: running
helm repo update
may help),更新helm即可。
- 安装 higess
1 | kubectl create ns higress-system |
- 创建 Ingress 配置
假设在 default 命名空间下已经部署了一个 demo service
,服务端口为 80 ,则创建下面这个 K8s Ingress
1 | apiVersion: networking.k8s.io/v1 |
最终环境
1 | $ kubectl get pod -A |
- 执行访问
1 | $ curl "$(k get svc -n higress-system higress-gateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')"/demo -H 'host: demo.bar.com' |
从日志验证
首先第一步,我们可以从启动日志中去看出一些端倪,这是一个比较好的习惯。
从 istiod 日志中我们就可以获得如同我们猜想的日志信息。
1 | $ kubectl logs -n istio-system istiod-5bf74cd79b-9gzm9 |
从日志中,我们就可以比较明确的得到我们之前的判断了。
getaddrinfo for host "higress-controller.higress-system" port 15051: Name or service not known testing higress controller is ready to connect...
在启动之前会等待 higress-controller 的启动(应该是魔改版的 istio chart)- 在配置源中多了一个上游的 MCP XDS 服务
1
2
3{
"address": "xds://higress-controller.higress-system:15051"
} - higress 会向服务器推送 istio 的配置项
1
2
32022-11-07T02:22:11.993861Z info adsc Received higress-controller.higress-system:15051 type security.istio.io/v1beta1/PeerAuthentication cnt=0 nonce=273eca9d-b148-4b85-bf09-3b2bd7585353
2022-11-07T02:22:11.993879Z info adsc Received higress-controller.higress-system:15051 type security.istio.io/v1beta1/RequestAuthentication cnt=0 nonce=d8b6b803-58f3-4467-a176-db911ab829f8
2022-11-07T02:22:11.993908Z info adsc Received higress-controller.higress-system:15051 type telemetry.istio.io/v1alpha1/Telemetry cnt=0 nonce=5d222fc3-f44a-4a5a-a8d8-38464ec9da90
从配置项认证
当我们已经有了明确的认知的时候,我们再来看 Envoy
的配置项
首先生成了一个 80
的 Listener
1 | { |
然后生成了 Router
1 | { |
这么看起来也挺明显的。并且因为 Higress Gateway
连接的地址是 istiod
1 | $ kubectl logs -n higress-system higress-gateway-74cb5978cc-2sv8k |
那和我们猜测的架构一致。
阅读代码
最后我们来看看代码里面,做了些什么,从项目的结构上,我们就知道他分为 数据面和 控制面,数据面对 Envoy
做了一些扩展,这部分都在 extensions 中。这部分的逻辑就不做展开了。
重点还是看看控制面的逻辑。这部分的代码都在 ingress
之中。
控制面启动 XDS
对于任何的 Operator
组件来说,我们第一步需要关心的是它关注什么资源的变化,这里在下面的代码中,我们可以看出来,Ingress Controller
关注下面的几个配置类型。
1 | var IngressIR = collection.NewSchemasBuilder(). |
对于这些资源的处理在
1 | func (m *IngressConfig) RegisterEventHandler(kind config.GroupVersionKind, f model.EventHandler) { |
而执行逻辑就是把这个 handlers
挨个执行一遍
1 | for _, f := range c.gatewayHandlers { |
实际上,也只是通知下 istiod,Push 一个事件给 istiod,等 istiod 来拉取。
这是这个 Xds 的逻辑,我们来看看 higress
到底做了什么。
Controller
在 Controller
的 onEvent
事件中,我们发现也就是关注了 Ingress
这个 CR
资源,然后把所有的 Handlers
执行了一遍。
1 | func (c *controller) onEvent(namespacedName types.NamespacedName) error { |
当前的大部分代码逻辑都在 annotations
里面,也就是当前支持的各个功能
1 | func NewAnnotationHandlerManager() AnnotationHandler { |
这里以 cors
为例子。
1 | func (c cors) Parse(annotations Annotations, config *Ingress, _ *GlobalContext) error { |
处理逻辑衔接
1 | func (m *IngressConfig) List(typ config.GroupVersionKind, namespace string) ([]config.Config, error) { |
到这里其实我们把整个流程梳理下
到这里我们发现其实整个 Higress 的逻辑当前还是比较的简单的,就是处理一些 annotations
中的信息,转为 istio
的数据。
开发环境搭建
社区Readme 少了这部分,也就是初始化 submodules
1 | make prebuild |
即可。