跳到主要内容

· 阅读需 4 分钟

前置准备

配置 WSL2

详情参看步骤1-5,顺便在微软商店中下载Terminal。

WSL手动安装步骤

下载 Docker Desktop

  1. 访问 Docker Desktop 官方下载页面

    在浏览器中打开 Docker Desktop 的官方下载页面

  2. 下载 Docker Desktop

    在下载页面,找到适用于 Windows 的 Docker Desktop 版本,然后点击下载。

  3. 运行安装程序

    下载完成后,找到下载的安装程序(通常在你的 "下载" 文件夹中),然后双击运行。

安装 Cygwin

cygwin官网

选择setup-x86_64.exe,等待安装完成。

验证 Cygwin 安装是否成功

cygcheck -c cygwin

7.png

为 Cygwin 配置环境变量

8.png

9.png

10.png

11.png

点击确定即可添加成功

安装 Higrees

准备 Nacos

nacos官网手册

我们这里选择nacos-docker的模式安装

A.png

下载解压zip文件,进入 nacos-docker-master 文件夹右键选择终端打开,执行命令,我们这里选择单机模式部署

    docker-compose -f example/standalone-derby.yaml up

等待出现界面,即安装成功

B.png

使用 Higrees 对接 Nacos

安装命令:使用独立部署的 Nacos

当访问docker容器互相访问时候本地回环地址并不是真正的地址,所以需要在cygwin中执行获取本地网卡地址

ipconfig

C.png

curl -fsSL https://higress.io/standalone/get-higress.sh | bash -s -- -c nacos://192.168.0.1:8848 --nacos-username=nacos --nacos-password=nacos

请将 192.168.0.1 替换为 Nacos 服务器的 IP(如果 Nacos 部署在本机,请不要使用如 localhost127.0.0.1 的 Loopback 地址),并按需调整 --nacos-username--nacos-password 的取值。如果 Nacos 服务未开启认证功能,则可以移除这两个参数。

在这里未开启授权服务,直接使用WLANIP替换对应的IP

curl -fsSL https://higress.io/standalone/get-higress.sh | bash -s -- -c nacos://10.30.0.225:8848

输入命令等待部署,即可看到生成的用户名与密码

D.png

Higress 控制台配置

访问 http://localhost:8080/, 登录 Higress 控制台。首次访问时需要先设置用户名密码

13.png

点击左侧“服务来源”导航栏,然后点击页面右侧的“创建服务来源”按钮。按照下图所示内容填写表单并点击“确定”按钮。

14.png

点击左侧“域名管理”导航栏,然后点击页面右侧的“创建域名”按钮。按照下图所示内容填写表单并点击“确定”按钮。

15.png

点击左侧“路由管理”导航栏,然后点击页面右侧的“创建路由”按钮。按照下图片所示内容填写表单并点击“确定”按钮。

16.png

请求验证

# should output a JSON object containing request data 
curl http://localhost/get?foo=bar -H 'host: foo.bar.com'

E.png

更多详情与部署方案可参考 quick start

· 阅读需 12 分钟

Higress 有个全局配置 ConfigMap 对象 higress-config,参考配置如下:

apiVersion: v1
data:
higress: |-
tracing:
enable: true
sampling: 100
timeout: 500
skywalking:
service: skywalking-oap-server.op-system.svc.cluster.local
port: 11800
...
...
kind: ConfigMap
metadata:
name: higress-config
namespace: higress-system

具体配置说明请参考 Higress 全局配置说明文档, 本文介绍以 Tracing 为例,详细说明 Tracing 全局配置是如何转成 EnvoyFilter 和如何同时实现实时下发到 Higress Gateway过程。

本文涉及整体架构流程、初始化过程和启动、higress-config 变更和处理流程、通知 XDSUpdater、构建 EnvoyFilter 和下发以及如何扩展全局配置等内容。

整体架构流程

1. 整体架构

img.png

2. 核心组件

  • IngressConfig

IngressConfig 是 Higress 一个核心结构体, 负责监控 Ingress, McpBridge, Http2Rpc, WasmPlugin 等 k8s 资源, 同时集成 ConfigStore Interface,通过 List 接口下发 VirtualService, DestinationRule, EnvoyFilter, ServiceEntry, WasmPlugin 等 CR 资源。

  • ConfigmapMgr

ConfigmapMgr 结构体负责整个核心流程,包括通过 Informer List/Watch 机制监控 higress-config 的变更,同时遍历 ItemControllers 下发变更通知,提供构建 EnvoyFilter 列表等功能。

  • TracingController

TracingController 结构体负责具体的 Tracing 数据校验,构建 Tracing EnvoyFilter, 以及通过 ItemEventHandler 下发变更通知等。

  • HigressConfig

HigressConfig 是 higress-config Configmap 所对应数据的结构体。

3. 核心流程

  • 用 Informer List/Watch 机制监控 higress-config 变更,校验变更,同时保存变更后数据。
  • 用变更数据构建 EnvoyFilter。
  • 通知 XDSUpdater,EnvoyFilter 有变更,重新拉取新的 EnvoyFilter 列表。

初始化过程

1. 初始化入口

初始化过程入口在 NewIngressConfig, 初始化 IngressConfig 时同时构建 HigressConfigController 和 ConfigmapMgr。

// pkg/ingress/config/ingress_config.go
func NewIngressConfig(localKubeClient kube.Client, XDSUpdater model.XDSUpdater, namespace, clusterId string) *IngressConfig {
// ...

// 构建 controller 和 configmapMgr
higressConfigController := configmap.NewController(localKubeClient, clusterId, namespace)
config.configmapMgr = configmap.NewConfigmapMgr(XDSUpdater, namespace, higressConfigController, higressConfigController.Lister())

return config
}

2. HigressConfigController 初始化

通过 Higress 提供 NewCommonController 初始化 HigressConfigController 用于监听 higress-system 命名空间下 Configmap 的变化。

// pkg/ingress/kube/configmap/controller.go
type HigressConfigController controller.Controller[listersv1.ConfigMapNamespaceLister]

func NewController(client kubeclient.Client, clusterId string, namespace string) HigressConfigController {
informer := client.KubeInformer().Core().V1().ConfigMaps().Informer()
return controller.NewCommonController("higressConfig", client.KubeInformer().Core().V1().ConfigMaps().Lister().ConfigMaps(namespace),
informer, GetConfigmap, clusterId)
}

func GetConfigmap(lister listersv1.ConfigMapNamespaceLister, namespacedName types.NamespacedName) (controllers.Object, error) {
return lister.Get(namespacedName.Name)
}

3. ConfigmapMgr 初始化

ConfigmapMgr 初始化具体步骤如下:

  • 构建 ConfigmapMgr
  • 设置 HigressConfigController configmap 新增或者更新回调函数为 configmapMgr.AddOrUpdateHigressConfig
  • 设置 HigressConfig 结构体默认值
  • 初始化 TracingController
  • 把 tracingController 添加到 configmapMgr itemControllers 数组里
  • 初始化 ItemEventHandler, 同时遍历 itemControllers,设置 ItemEventHandler
// pkg/ingress/kube/configmap/controller.go
func NewConfigmapMgr(XDSUpdater model.XDSUpdater, namespace string, higressConfigController HigressConfigController, higressConfigLister listersv1.ConfigMapNamespaceLister) *ConfigmapMgr {
// 构建 ConfigmapMgr
configmapMgr := &ConfigmapMgr{
XDSUpdater: XDSUpdater,
Namespace: namespace,
HigressConfigController: higressConfigController,
HigressConfigLister: higressConfigLister,
higressConfig: atomic.Value{},
}
// 设置 HigressConfigController configmap 新增或者更新回调函数 configmapMgr.AddOrUpdateHigressConfig
configmapMgr.HigressConfigController.AddEventHandler(configmapMgr.AddOrUpdateHigressConfig)
// 设置 HigressConfig 结构体默认值
configmapMgr.SetHigressConfig(NewDefaultHigressConfig())

// 初始化 TracingController
tracingController := NewTracingController(namespace)
// 把 tracingController 添加到 configmapMgr itemControllers 里
configmapMgr.AddItemControllers(tracingController)
// 初始化 itemEventHandler, 同时遍历 itemControllers,设置 itemEventHandler
configmapMgr.initEventHandlers()

// 返回 configmapMgr
return configmapMgr
}

启动

在 IngressConfig 添加 HigressConfigController Run() 和 HasSynced() 控制流程。

// pkg/ingress/config/ingress_config.go
func (m *IngressConfig) Run(stop <-chan struct{}) {
// ...
// 启动 HigressConfigController
go m.configmapMgr.HigressConfigController.Run(stop)
}

func (m *IngressConfig) HasSynced() bool {
// ....
if !m.configmapMgr.HigressConfigController.HasSynced() {
return false
}
}

higress-config 变更和处理流程

1. configmapMgr 变更处理

ConfigmapMgr 通过收到 HigressConfigController 通知来处理变更请求。

具体变更流程如下:

  • 判断是否 higress-system 命名空间下 name 为 higress-config Configmap 发生了变化,如果不是就返回。
  • 获取 higress-config 内容。
  • 遍历 ItemControllers, 校验 higress-config 配置是否合法,如果有一个返回不合法,就返回。
  • 和上次保存在本地 higressConfig 比对, 检查这次数据是否有变化,如果没有变化就返回。
  • 如果数据有变化,就遍历 ItemControllers 通知每个 itemController 数据有变化,同时保存这次变化到本地 higressConfig。
// pkg/ingress/kube/configmap/controller.go
func (c *ConfigmapMgr) AddOrUpdateHigressConfig(name util.ClusterNamespacedName) {
// 只监听 higress-system 命名空间下 name 为 higress-config Configmap 的变化
if name.Namespace != c.Namespace || name.Name != HigressConfigMapName {
return
}
// ...
// 获取 higress-config 内容
higressConfigmap, err := c.HigressConfigLister.Get(HigressConfigMapName)

// 通过 yaml.Unmarshal 转成 HigressConfig
newHigressConfig := NewDefaultHigressConfig()
if err = yaml.Unmarshal([]byte(higressConfigmap.Data[HigressConfigMapKey]), newHigressConfig); err != nil {
IngressLog.Errorf("data:%s, convert to higress config error, error: %+v", higressConfigmap.Data[HigressConfigMapKey], err)
return
}

// ...
// 遍历 ItemControllers, 校验配置是否合法
for _, itemController := range c.ItemControllers {
if itemErr := itemController.ValidHigressConfig(newHigressConfig); itemErr != nil {
IngressLog.Errorf("configmap %s controller valid higress config error, error: %+v", itemController.GetName(), itemErr)
return
}
}

// 和上次比对这次数据是否有变更
oldHigressConfig := c.GetHigressConfig()
result, _ := c.CompareHigressConfig(oldHigressConfig, newHigressConfig)
// ...
// 如果数据有变更,就遍历 ItemControllers 通知每个 itemController 数据有变更,同时保存这次变更到本地。
if result == ResultReplace || result == ResultDelete {
for _, itemController := range c.ItemControllers {
IngressLog.Infof("configmap %s controller AddOrUpdateHigressConfig", itemController.GetName())
if itemErr := itemController.AddOrUpdateHigressConfig(name, oldHigressConfig, newHigressConfig); itemErr != nil {
IngressLog.Errorf("configmap %s controller AddOrUpdateHigressConfig error, error: %+v", itemController.GetName(), itemErr)
}
}
// 保存这次变更
c.SetHigressConfig(newHigressConfig)
}
}

2. TracingController 变更处理

TracingController 变更处理就比较简单:

  • 检查 Tracing 这部分数据是否有变更。
  • 如果有变更,DeepCopy 一份 Tracing 数据保存到本地,同时通过 eventHandler 下发变更通知。
// pkg/ingress/kube/configmap/tracing.go
func (t *TracingController) AddOrUpdateHigressConfig(name util.ClusterNamespacedName, old *HigressConfig, new *HigressConfig) error {
// ...
// 检查 Tracing 部分数据是否有变更
result, _ := compareTracing(old.Tracing, new.Tracing)

// 如果有变更,DeepCopy 一份 Tracing 数据保存到本地,同时通过 eventHandler 下发变更通知
switch result {
case ResultReplace:
if newTracing, err := deepCopyTracing(new.Tracing); err != nil {
IngressLog.Infof("tracing deepcopy error:%v", err)
} else {
t.SetTracing(newTracing)
IngressLog.Infof("AddOrUpdate Higress config tracing")
t.eventHandler(higressTracingEnvoyFilterName)
IngressLog.Infof("send event with filter name:%s", higressTracingEnvoyFilterName)
}
case ResultDelete:
t.SetTracing(NewDefaultTracing())
IngressLog.Infof("Delete Higress config tracing")
t.eventHandler(higressTracingEnvoyFilterName)
IngressLog.Infof("send event with filter name:%s", higressTracingEnvoyFilterName)
}

return nil
}

通知 XDSUpdater

在 ConfigmapMgr 初始化时候调用 configmapMgr.initEventHandlers(), 这个 func 会创建 ItemEventHandler, 同时遍历 ItemControllers 设置 ItemEventHandler。

// pkg/ingress/kube/configmap/config.go
type ItemEventHandler = func(name string)

// pkg/ingress/kube/configmap/controller.go
func (c *ConfigmapMgr) initEventHandlers() error {
itemEventHandler := func(name string) {
c.XDSUpdater.ConfigUpdate(&model.PushRequest{
Full: true,
ConfigsUpdated: map[model.ConfigKey]struct{}{{
Kind: gvk.EnvoyFilter,
Name: name,
Namespace: c.Namespace,
}: {}},
Reason: []model.TriggerReason{ModelUpdatedReason},
})
}

for _, itemController := range c.ItemControllers {
itemController.RegisterItemEventHandler(itemEventHandler)
}

return nil
}

这里 XDSUpdater 是从 IngressConfig 初始化传入, XDSUpdater.ConfigUpdate() 用于更新通知下发。

进一步跟踪可以发现在 Higress controller server 启动时执行 s.initXdsServer 函数创建 s.xdsServer,具体逻辑不在本文讨论范围, 有兴趣可以进一步阅读源码。

// pkg/bootstrap/server.go
func NewServer(args *ServerArgs) (*Server, error) {
// ...
s := &Server{
ServerArgs: args,
httpMux: http.NewServeMux(),
environment: e,
readinessProbes: make(map[string]readinessProbe),
server: server.New(),
}
s.environment.Watcher = mesh.NewFixedWatcher(&v1alpha1.MeshConfig{})
s.environment.Init()
initFuncList := []func() error{
s.initKubeClient,
s.initXdsServer,
s.initHttpServer,
s.initConfigController,
s.initRegistryEventHandlers,
s.initAuthenticators,
}

for _, f := range initFuncList {
if err := f(); err != nil {
return nil, err
}
}

// ...
return s, nil
}

// pkg/bootstrap/server.go
func (s *Server) initXdsServer() error {
log.Info("init xds server")
s.xdsServer = xds.NewDiscoveryServer(s.environment, nil, PodName, PodNamespace, s.RegistryOptions.KubeOptions.ClusterAliases)
// ...
return s.initGrpcServer()
}

构建和下发 EnvoyFilters

1. IngressConfig List 下发 EnvoyFilters 列表

IngressConfig List 用于 VirtualService, DestinationRule, EnvoyFilter, ServiceEntry, WasmPlugin 等 CR 资源下发, 这里主要关注 EnvoyFilter CR 资源下发。

// pkg/ingress/config/ingress_config.go
func (m *IngressConfig) List(typ config.GroupVersionKind, namespace string) ([]config.Config, error) {
if typ != gvk.Gateway &&
typ != gvk.VirtualService &&
typ != gvk.DestinationRule &&
typ != gvk.EnvoyFilter &&
typ != gvk.ServiceEntry &&
typ != gvk.WasmPlugin {
return nil, common.ErrUnsupportedOp
}
// ...
if typ == gvk.EnvoyFilter {
m.mutex.RLock()
defer m.mutex.RUnlock()
var envoyFilters []config.Config

// 调用 ConfigmapMgr ConstructEnvoyFilters 获取需要下发 EnvoyFilter 列表
configmapEnvoyFilters, err := m.configmapMgr.ConstructEnvoyFilters()
if err != nil {
IngressLog.Errorf("Construct configmap EnvoyFilters error %v", err)
} else {
for _, envoyFilter := range configmapEnvoyFilters {
envoyFilters = append(envoyFilters, *envoyFilter)
}
IngressLog.Infof("Append %d configmap EnvoyFilters", len(configmapEnvoyFilters))
}
if len(envoyFilters) == 0 {
IngressLog.Infof("resource type %s, configs number %d", typ, len(m.cachedEnvoyFilters))
return m.cachedEnvoyFilters, nil
}
// 需要下发 configmap EnvoyFilter 列表 和 m.cachedEnvoyFilters 列表聚合一下下发
envoyFilters = append(envoyFilters, m.cachedEnvoyFilters...)
IngressLog.Infof("resource type %s, configs number %d", typ, len(envoyFilters))
return envoyFilters, nil
}

}

调用 ConfigmapMgr ConstructEnvoyFilters 获取需要下发 EnvoyFilter 列表, 同时和 m.cachedEnvoyFilters 列表聚合一下再下发。

这里 m.cachedEnvoyFilters 是在构建 VirtualService 时生成,有兴趣可以进一步阅读 IngressConfig 源码。

2. ConfigmapMgr 构建 EnvoyFilter 列表

这里比较简单,遍历一下 ItemControllers,聚合每个 itemController 返回的 EnvoyFilters.

// /pkg/ingress/kube/configmap/controller.go
func (c *ConfigmapMgr) ConstructEnvoyFilters() ([]*config.Config, error) {
configs := make([]*config.Config, 0)
for _, itemController := range c.ItemControllers {
IngressLog.Infof("controller %s ConstructEnvoyFilters", itemController.GetName())
if itemConfigs, err := itemController.ConstructEnvoyFilters(); err != nil {
IngressLog.Errorf("controller %s ConstructEnvoyFilters error, error: %+v", itemController.GetName(), err)
} else {
configs = append(configs, itemConfigs...)
}
}
return configs, nil
}

3. TracingController 构建 EnvoyFilters

这里就比较简单,根据保存的 Tracing 数据构建对应的 EnvoyFilter

// pkg/ingress/kube/configmap/tracing.go
func (t *TracingController) ConstructEnvoyFilters() ([]*config.Config, error) {
// ...
tracingConfig := t.constructTracingTracer(tracing, namespace)
if len(tracingConfig) == 0 {
return configs, nil
}

config := &config.Config{
Meta: config.Meta{
GroupVersionKind: gvk.EnvoyFilter,
Name: higressTracingEnvoyFilterName,
Namespace: namespace,
},
Spec: &networking.EnvoyFilter{
ConfigPatches: []*networking.EnvoyFilter_EnvoyConfigObjectPatch{
{
ApplyTo: networking.EnvoyFilter_NETWORK_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.filters.network.http_connection_manager",
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: util.BuildPatchStruct(tracingConfig),
},
},
{
ApplyTo: networking.EnvoyFilter_HTTP_FILTER,
Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{
Context: networking.EnvoyFilter_GATEWAY,
ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_Listener{
Listener: &networking.EnvoyFilter_ListenerMatch{
FilterChain: &networking.EnvoyFilter_ListenerMatch_FilterChainMatch{
Filter: &networking.EnvoyFilter_ListenerMatch_FilterMatch{
Name: "envoy.filters.network.http_connection_manager",
SubFilter: &networking.EnvoyFilter_ListenerMatch_SubFilterMatch{
Name: "envoy.filters.http.router",
},
},
},
},
},
},
Patch: &networking.EnvoyFilter_Patch{
Operation: networking.EnvoyFilter_Patch_MERGE,
Value: util.BuildPatchStruct(`{
"name":"envoy.filters.http.router",
"typed_config":{
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router",
"start_child_span": true
}
}`),
},
},
},
},
}

configs = append(configs, config)
return configs, nil
}

如何扩展全局配置

1. HigressConfig 结构体添加对应的扩展配置

type HigressConfig struct {
Tracing *Tracing `json:"tracing,omitempty"`
// 在这里添加对应的数据结构来扩展配置
}

2. 增加扩展配置默认值

// pkg/ingress/kube/configmap/config.go
func NewDefaultHigressConfig() *HigressConfig {
higressConfig := &HigressConfig{
Tracing: NewDefaultTracing(),
// 在这里增加扩展配置默认值
}
return higressConfig
}

3. 实现 ItemController interface

type ItemController interface {
GetName() string
AddOrUpdateHigressConfig(name util.ClusterNamespacedName, old *HigressConfig, new *HigressConfig) error
ValidHigressConfig(higressConfig *HigressConfig) error
ConstructEnvoyFilters() ([]*config.Config, error)
RegisterItemEventHandler(eventHandler ItemEventHandler)
}

4. 初始化扩展配置,同时添加到 ItemControllers

func NewConfigmapMgr(XDSUpdater model.XDSUpdater, namespace string, higressConfigController HigressConfigController, higressConfigLister listersv1.ConfigMapNamespaceLister) *ConfigmapMgr {
// ...
tracingController := NewTracingController(namespace)
configmapMgr.AddItemControllers(tracingController)
// ...
// 在这里初始化扩展配置,同时添加到 ItemControllers
configmapMgr.initEventHandlers()

return configmapMgr
}

参与社区贡献

Higress 开源贡献小组正在火热招募贡献者。早期参与开源更容易成为项目 Committer,并有更多机会成为 Higress PMC(Project Management Committee) 的一员,参与主导 Higress 社区的前进方向。 欢迎加入 Higress 社区群:

· 阅读需 16 分钟

以 ChatGPT 为代表的 AIGC 技术为企业生产带来了巨大的变化,并在企业应用开发领域占据一席之地。AI 大模型凭借其强大的学习能力,可以帮助人们完成各种复杂的任务,例如帮助开发人员编写与调试代码、研究人员快速了解科研领域、营销人员撰写产品描述、设计人员设计新作品等等。许多企业探索如何降低 AI 大模型的使用成本。通过网关进行 AI 大模型的 API 管理成为了很常规的需求。

Higress 如何降低 AI 大模型使用成本?

Higress GitHub: https://github.com/alibaba/higress

以 OpenAI 为例,OpenAI 的 API 调用并不是基于请求量或者订阅时间来计费,而是基于每个请求的使用量来计费。对于 AI 大模型来说,模型输入与输出的 token 数可以比较好的衡量当前模型进行推理任务的复杂度。因此基于 token 作为请求使用量进行计费是 OpenAI-API 的标准计费策略。对于不同的模型 token 的计费标准也不同,越复杂的模型会生成越好的结果,但也会带来更高的计费。OpenAI 通过为用户分发 API 密钥来完成用户的鉴权与收费等功能。

image.png

对于组织来说,为每位成员申请 AI 大模型的访问权限( API-Key )显然是不现实的。分散的 API 密钥将不利于组织进行 API 的用量计算、管理与付费,从而增加 AI 大模型的使用成本。其次,对于组织来说,AI 模型的选型、使用频率和成员使用权限、以及向 AI 大模型暴露哪些数据都是在管理中需要着重关注的功能。

Higress 基于丰富的插件能力,提供了认证鉴权、请求过滤、流量控制、用量监测和安全防护等功能,能够帮助组织与 AI 大模型的 API 交互变得更加安全、可靠和可观察:基于 Higress 提供的认证鉴权能力,组织可以实现通过统一的 API 密钥进行 AI 模型的调用量管理和付费,并为团队成员授予不同的 AI 模型访问权限;基于 Higress 提供的流量控制能力,组织能为不同的模型与用户设置差异化的访问速率限制,有效降低 AI 模型的使用成本;基于 Higress 提供的请求拦截能力,组织能够有效过滤含敏感信息的访问请求,防护部分内部站点资源不对外暴露,从而有效保障内部数据安全;基于商业版 Higress提供的开箱即用的指标查询和日志记录的能力,组织能够完成对不同用户的 AI 模型调用的用量观测与分析,从而制定更加合理的 AI 模型使用策略。

image.png

Higress 对接 OpenAI 大语言模型实战

下面我们将以 Higress 对接 OpenAI 大语言模型为例,介绍 Higress 如何无缝对接 AI 大模型。整体方案如图所示,我们基于 WASM 拓展了 Higress 插件,实现了对 OpenAI 语言模型的请求代理转发。基于 Higress 提供的 Key-Auth 认证插件的能力,我们实现统一 API-Key 下的多租户认证。基于 Higress 提供的 Request-Block 请求过滤的能力,我们将实现含敏感信息的请求拦截,保障用户数据安全。

前提条件:

  1. 安装 Higress ,参考Higress 安装部署文档
  2. 准备 Go 语言开发 WASM 插件的开发环境,参考使用 GO 语言开发 WASM 插件

基于 WASM 的 AI Proxy Plugin

下文将给出基于 Higress 与 WASM 实现的 AI 大模型 API 代理插件方案。Higress 支持基于 WASM 实现对外扩展的能力。WASM 插件提供的多语言生态和热插拔机制为插件的实现和部署提供了便利。Higress 同时支持在插件中请求外部服务,为 AI 代理插件的实现提供了高效的解决路径。

实现示例:

我们给出 OpenAI-API 的代理插件的实现示例,详情请参考AI proxy plugin。下列代码实现了插件相关配置完成之后,基于 HTTP 自动将请求代理转发到 OpenAI-API ,并接收来自 OpenAI-API 的响应,从而完成 AI 模型的调用,具体实现步骤如下:

  1. 通过 RouteCluster 方法指定具体的 OpenAI-API 的 host ,确认用户请求转发的具体路径,并新建用于请求代理转发的 HTTP Client 。
func parseConfig(json gjson.Result, config *MyConfig, log wrapper.Log) error {
chatgptUri := json.Get("chatgptUri").String()
var chatgptHost string
if chatgptUri == "" {
config.ChatgptPath = "/v1/completions"
chatgptHost = "api.openai.com"
} //请求默认转发到 OpenAI-API
...
config.client = wrapper.NewClusterClient(wrapper.RouteCluster{
Host: chatgptHost,
}) //通过 RouteCluster 方法确认请求转发的具体 host
...
}
  1. 对用户请求进行 OpenAI-API 的格式封装,通过 HTTP Client 进行请求转发与响应接受,并将响应转发给用户。
//OpenAI API 接收的请求体模版,详见: https://platform.openai.com/docs/api-reference/chat
const bodyTemplate string = `
{
"model":"%s",
"prompt":"%s",
"temperature":0.9,
"max_tokens": 150,
"top_p": 1,
"frequency_penalty": 0.0,
"presence_penalty": 0.6,
"stop": ["%s", "%s"]
}
`
func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig, log wrapper.Log) types.Action {
...
//根据用户的请求内容进行 OpenAI-API 请求体封装
body := fmt.Sprintf(bodyTemplate, config.Model, prompt[0], config.HumanId, config.AIId)
//通过 HTTP Client 进行转发
err = config.client.Post(config.ChatgptPath, [][2]string{
{"Content-Type", "application/json"},
{"Authorization", "Bearer " + config.ApiKey},
}, []byte(body),
func(statusCode int, responseHeaders http.Header, responseBody []byte) {
var headers [][2]string
for key, value := range responseHeaders {
headers = append(headers, [2]string{key, value[0]})
}
//接收来自于 OpenAI-API 的响应并转发给用户
proxywasm.SendHttpResponse(uint32(statusCode), headers, responseBody, -1)
}, 10000)
...
}

在 Higress 中启用自定义的 AI-Proxy-Wasm 插件流程如下:

本示例提供已经编译好的 AI-proxy-plugin-wasm 文件并完成对应 docker 镜像的构建和推送,推荐配置如下所示:

名称推荐配置
镜像地址oci://registry.cn-hangzhou.aliyuncs.com/zwj_test/chatgpt-proxy:1.0.0
插件执行阶段鉴权阶段
插件执行优先级1

插件配置说明:

插件配置简单,支持全局/域名级/路由级的代理转发。推荐进行路由级配置:选中对应的路由配置-选中对应路由-策略-启用插件。配置字段包括:

名称数据类型填写要求默认值描述
modelstring选填text-davinci-003调用的模型名称
apiKeystring必填-OpenAI-API 密钥,详情可参考
promptParamstring选填promptprompt 的来源字段名称,URL 参数
chatgptUristring选填api.openai.com/v1/completions调用 AI 模型服务的 URL 路径,默认值为 OpenAI 的 API 调用路径

示例配置如下:

apiKey: "xxxxxxxxxxxxxxxxxx"
model: "curie"
promptParam: "text"

根据该配置,网关代理到 OpenAI-API 下的 curie 模型,用户通过 text 关键字在 url 中输入文本。

curl "http://{GatewayIP}/?text=Say,hello"

得到 OpenAI-API 的响应: image.png

基于 Key Auth 的多租户认证

不同于为每位成员颁发 OpenAI-API 密钥的形式,企业可以基于 Higress 网关提供的认证鉴权能力,依靠内部授权(如 Key Auth 等)来管理成员对 AI 模型对访问权限,从而限制成员可以使用的服务和模型,并依靠统一的 AI-API 密钥进行请求代理转发实现对 API 用量的统一管理。接下来以 Key Auth 为例介绍 Higress 的多租户认证能力。

Key Auth 插件实现了基于网关内 API Key 进行认证和鉴权的功能,支持从 HTTP 请求的 URL 参数或者请求头解析 API Key ,同时验证该 API 是否有权限访问。通过在Higress 控制台-插件市场-Key Auth进行全局配置路由级配置,即可实现 Higress 网关的多租户认证。

consumers:
- credential: "xxxxxx"
name: "consumer1"
- credential: "yyyyyy"
name: "consumer2"
global_auth: false
in_header: true
keys:
- "apikey"

allow: [consumer1]

以上配置定义了指向 AI 模型服务的消费者组consumers,并且只有consumer1具备访问当前路由下 AI 模型服务的权限。

curl "http://{GatewayIP}/?text=Say,hello"
#请求未提供 API-Key ,返回 401

curl "http://{GatewayIP}/?text=Say,hello" -H "apikey:zzzzzz"
#请求提供的 API-Key 未在消费者组内,无权访问,返回 401

curl "http://{GatewayIP}/?text=Say,hello" -H "apikey:yyyyyy"
#根据请求提供的 API-Keyy 匹配到的调用者无 AI 模型服务的访问权限,返回 403

curl "http://{GatewayIP}/?text=Say,hello" -H "apikey:xxxxxx"
#请求合法且有 AI 模型服务访问权限,请求将被代理到 AI 模型,正常得到 OpenAI-API 的响应

Higress 除了提供网关级多租户认证外,还能提供限流等能力。Key Rate Limit 插件可以根据用户在消费组中的成员资格对用户请求速率进行限制,从而限制应用程序对高成本 AI 大模型服务的消耗。基于多租户认证与限流等功能,Higress 可以完全控制 AI 大模型 API 的访问权限、访问数量与调用成本。

基于 Request Block 保障数据安全

对于 AI 大模型尤其是语言模型来说,要得到良好的返回往往需要用户提供足够的提示( prompt )作为模型输入。这也意味着组织和个人可能会在提供提示的过程中面临数据泄漏的风险。因此如何在使用 AI 模型的过程中保障数据安全也是 API 调用方面临重要问题。保护数据安全涉及到对 AI 模型的 API 调用渠道进行严格的控制。一种方式是使用特定的经批准的模型与其发布的 API 。另一种方式是对含敏感信息的用户请求进行拦截。这可以通过在网关级别设置特定的请求拦截来实现。Higress 基于 Request Block 插件提供请求拦截能力,既能防止未经授权的模型访问用户信息,又能防止含敏感信息的用户请求暴露到外网。

Request Block 插件基于 URL 、请求头等特征屏蔽 HTTP 请求,可以用于防护站点资源不对外暴露。 通过在Higress 控制台-插件市场-Request Block进行屏蔽字段配置,即可防止含敏感字段的请求对外发送。

blocked_code: 404
block_urls:
- password
- pw
case_sensitive: false

以上配置定义了当前路由下基于 URL 的屏蔽字段,其中含敏感信息(如 password 、pw )的请求将被屏蔽。

curl "http://{GatewayIP}/?text=Mypassword=xxxxxx" -H "apikey:xxxxxx"
curl "http://{GatewayIP}/?text=pw=xxxxxx" -H "apikey:xxxxxx"
#上述请求将被禁止访问,返回 404

基于商业版 Higress 的用量观测与分析

对于组织来说,对各用户进行 AI 模型调用的用量观测和分析有助于了解其使用情况与产生的成本。对于个人用户,了解自己的调用量和开销也是必要的。因此,在网关层进行调用的观测和分析对于 AI 大模型的 API 管理是必要的能力。商业版 Higress与各种指标与日志系统进行了深度集成,提供了开箱即用的用量观测分析报告构建机制,可以实时查看各种 API 的使用情况,并根据各类参数进行过滤,从而更好的了解 API 使用情况。

以观察各用户对 OpenAI-Curie 模型的调用量为例,用户可通过MSE 管理控制台-云原生网关-网关实例-参数配置-日志格式调整中设置区分用户的可观测性参数请求头:x-mse-consumer,将其列入观测列表。之后进入观测分析-日志中心中设置使用统计图表功能即可完成对 API 的用量观测和分析。如下图所示,用户consumer1与用户consumer2的对 OpenAI-Curie 模型的调用量以饼状图形式呈现。 image.png

加入 Higress 社区

image.png

如果您觉得 Higress 对您有帮助,欢迎前往github: Higress为我们 star 一下!

· 阅读需 11 分钟

关于美洽

美洽是一家全球智能云客服服务商,提供一站式智能客服解决方案,旗下拥有在线客服、工单系统、呼叫中心、客服机器人、语音机器人、营销机器人等产品及服务。美洽成立于2014年,总部位于成都,目前服务企业用户已超过40万家,覆盖多个行业领域。美洽的客服系统支持多平台使用,包括Web 网页端、手机客户端、PC 客户端,同时美洽也提供了开放 API 平台。

需求背景

  1. 多条业务线使用了了不同编程语言,在微服务化演进的路上困难重重;
  2. 历史架构使用多个流量转发中间件导致流量路径冗长、复杂且故障排查困难(LB + OpenResty + Nginx + Caddy + SpringCloud-Gateway);
  3. WebSocket 长连接服务在多重路由层上不支持热更新,维护成本高。

历史架构的流量拓扑图如下:

需求目标

  1. 找到一个统一网关,能够一次性解决流量网关和业务网关的路由转发需求;
  2. 支持路由规则热更新,解决 WebSocket 连接在路由更新或网络抖动时产生的重连风暴;
  3. 前置API 请求权限校验、签名校验、WAF 拦截、CC 拦截;
  4. 可视化统一网关的后台操作,让普通员工也能上手;
  5. 多云架构下私有化部署支持。

方案横向对比

通过对目前市面上流行的网关产品进行详细的横向对比,再结合美洽对统一网关的需求目标,我们从对比的表格当中,看到了 Higress 所带来的最佳对比结果。

同时美洽重点关注的几个点:K8S Ingress 支持、WebSocket支持、Nacos 服务发现、路由配置热更新、WASM 插件都得到了很好的支持。

为什么选择 Higress

面向多云架构友好

Higress 在阿里云上有成熟的企业版产品:MSE 云原生网关,我们从 2021 年开始使用这款产品,这是一款全托管,完全免运维的 SaaS 网关产品,并且具备强劲的性能和丰富的功能,相比自建同吞吐的网关,整体成本是更低的,因此我们在阿里云上直接使用了这款产品。

美洽除了阿里云,在其他云上也有部署业务,我们希望能统一多云的统一网关技术架构,开源版 Higress 正好符合我们的需求,相比商业版,在控制台功能上,开源版目前的能力相对较少,但大部分功能也都可以通过自己定义 K8s CRD 配置的方式来实现,完全满足我们的需求。

原生支持 K8s Ingress

美洽从 2021 年便已经全面迁移到 Kubernetes 进行资源调度,遇到最大的困难是历史的网关中间件,在容器化的架构里面,各种水土不服,要么需要借助 Nginx-Ingress-Controller,要么需要外部的 SLB 进行服务之间的负载均衡与网络通信。这导致了比容器化之前更加复杂的流量路径,一度让我们下定决心,必须、必须、必须要解决统一网关的问题,还必须云原生的。

2021 年底开始,我们开始尝试使用阿里云 MSE 网关 SaaS 产品,开始将部分服务从 Nginx 路由迁移到 MSE 网关上,很快解决了Ngxin Configuration 配置维护复杂,故障频发的问题,尝到甜头后,我们便开始计划进一步扩大 MSE 网关的使用,结合 Nacos 和 K8S 的服务发现,将 80% 大部分容器化服务路由转发全部迁移到了云原生网关上。

这带来的收益就包括:

  1. 简化了流量路径,公网流量通过 SLB 直接到达网关,网关路由直达容器 Pod;
  2. 释放了使用 ECS 自建的 Nginx 、OpenResty 、Caddy 服务,降低了大量服务器成本;
  3. 服务发现和服务治理,以及各个服务当前的健康状态都以可视化的 Dashborad 呈现出来;

控制面和数据面解耦的架构

控制面和数据面解耦是一种很好的设计模式,把管理控制逻辑和运行处理逻辑分开,这样可以更好地管理和扩展系统。

  1. Console 负责管理 和 Gateway 负责处理请求,灵活可扩展,互补干扰;
  2. 整个系统的性能和可用性可以得到很好的保障;
  3. 即使控制面出现问题,数据面仍然可以继续处理请求,反之亦然。

在美洽客服自己的产品中,也大量试用了控制面和数据面分离的这种架构设计模式,在选择 Higress 统一网关的落地实践中,也更好的可以和美洽产品的架构进行配合,例如控制台采用微前端技术统一美洽运维控制台,Higress 控制台,Nacos 控制台。

容易上手的后台 Dashboard

在早期,美洽在 2021 年开始使用阿里云 MSE 云原生网关时,就已经对网关的控制台使用有了很多的经验基础,团队中 QA 同学也能熟练使用了。目前在其他云上的项目,私有化部署的开源版Higress,在控制台方面功能与操作和阿里云 MSE 产品的交互保持一致,团队使用很快便上手了。

插件方面,美洽使用了 JWT Auth 鉴权,Key Rate Limit 限流,HMAC Auth 请求签名,Bot Detect 和 WAF 功能有涉及。

美洽的落地实践

采用 Helm 在 K8s node 上 一键部署

helm repo add higress.io <https://higress.io/helm-charts>
helm install higress higress.io/higress -n higress-system --create-namespace

完全替代了 Nginx 、OpenResty、Caddy 、SLB-Intranet

彻底解决 WebSocket 断线重连问题

美洽的智能客服产品侧试用了 WebSocket 进行长连接保持和消息通信,所以非常依赖网络的稳定,以及更新网关配置所带来的副作用。在使用 Nginx + OpenResty 方案的期间,每一次的配置变更都会带来极大的代价,断线重连风暴时常发生。一次配置变更 Pendding 或者变更失败带来的瞬时断联是及其痛苦的。

在迁移到 Higress 上之后,路由配置热更新特性,不在需要像 Nginx 一样需要 Reload Gateway,解决配置更新 reload 带来的断线重连风暴问题。

另外,在 WebSocket Server 服务升级过程中,通过给 Pod 打上 stage 标签,在 Higress 侧通过标签路由进行新老版本无损流量切换,给产品快速迭代升级带了巨大的杠杆效应。

熔断限流

在面向 2B 的 SaaS 产品业务场景中,经常会发生某一个客户突发海量流量,占据大量带宽,影响其他客户正常使用的情况,这时我们需要针对客户规模对单个客户的 API 并发上限做灵活的动态限流,使用 Higress 的插件Key Rate Limit 就很好的解决了这个问题,根据流量大盘随时调整限流水位红线,做到精准,灵活的限流。

经验总结

Higress 网关的落地,给企业全面落地云原生微服务架构提供强有力的支持,对我们技术人员来说,这绝对是一个杠杆级别的开源产品,另外,在阿里云上又有对等的 SaaS 产品,这样的配合,将公有云和私有化部署的统一网关一次性全部解决,对企业来说是绝对的利好。

  1. 统一流量网关+业务网关能力,实现了给企业降本,为研发增效;
  2. 为云原生架构提供很好的基座,在异构语言服务化层面排除了网络通信难题;
  3. 路由热更新、无损升级、可视化 Console、开放的插件、基于 Kubernetes 和 Istio,给技术演进带来了更多的可能性。

最后,我们祝愿 Higress 在云原生的道路上越走越远,大家一起用开源、开放、分享的心态将 Higress 建设地越来越好。

· 阅读需 14 分钟

Higress 一个遵循开源Ingress/Gateway API标准,提供流量调度、服务治理、安全防护三合一的高集成、易使用、易扩展、热更新的云原生API网关。

Skywalking 是一个开源的可观测平台,用于从服务和云原生基础设施收集,分析, 聚合及可视化数据。

Httpbin 是基于 Gin 开发,用于快速测试基于云原生微服务可观测性和流量管理等功能。

本文介绍 Higress 集成 Skywalking 实现可观测性,主要内容涉及整体架构、Skywalking 调用链路跟踪原理、Higress 架构、业务应用集成 Skywalking、本地测试环境搭建、Higress 配置、应用安装、调用链路跟踪配置以及 Higress gateway 指标和监控面板。

这次可观测性探索相关 manifests 下载地址

一、整体架构图

img.png

整体包含四大块内容:

  • Higress 组件: higress-gateway, higress-console, higress-controller
  • Skywalking 组件: skywalking dashboard ui, skywalking aop server
  • 业务应用组件: bff, middle service, backend service
  • Ingress 组件: skywalking.higress.io, httpbin.example.com

二、Skywalking 调用链路跟踪原理

SkyWalking为服务(service),服务实例(service instance),以及端点(endpoint)提供了可观测能力。

  • 服务(service):表示对请求提供相同行为的一组工作负载。在使用打点代理或 SDK 的时候,可以定义服务的名字。
  • 服务实例(Service Instance):一组工作负载中的每一个工作负载称为一个实例。
  • 端点(Endpoint): 对于特定服务所接收的请求路径,如 HTTP 的 URI 路径和 gRPC 服务的类名 + 方法签名。
  • 进程(Process): 操作系统进程. 在某些场景下,一个服务实例和进程不是一一对应, 在k8s部署下,一个POD对应多个进程。

Skywalking 整体架构

img.png

主要由四个核心组件组成:

  • 探针: 探针用于收集监测数据包括指标,链路跟踪,日志和事件
  • 数据接收和聚合: 平台后端支持数据聚合,数据分析以及驱动数据流从探针到用户界面的处理
  • 存储: 通过开放接口支持后端存储系统支持ElasticSearch, H2, MySQL, TiDB, BanyanDB等
  • UI: 一个定制化的Web系统,用户可以可视化查看和管理 SkyWalking 数据

分布式链路追踪原理分析

  1. 分布式链路介绍

分布式链路追踪是记录来源于用户请求在各个系统或者服务中所传播的路径。

A distributed trace, more commonly known as a trace, records the paths taken by requests (made by an application or end-user) as they propagate through multi-service architectures, like microservice and serverless applications.

分布式链路追踪图示如下:

img.png

  1. Skywalking 分布式链路追踪

主要包含四个内容:

  • Trace: 一个完整的链路由多个 Segment 组成
  • Segment: 一个请求在一个进程内的轨迹
  • Span: 一个请求在某个进程里的一个组件逻辑内的轨迹, 有 Entry Span, Local Span 和 Exit Span 三类
  • Span context: 跨进程或者服务 Trace 传递,这里讨论 http 传递头 sw8

基本组件图示如下:

img.png

从上图可以看出:

  • 一个 Trace 内的所有 span 的 Trace ID 是相同的
  • 一个 Segment 中有一个 EntrySpan,是 Segment 内其他 Span 的根 Parent
  • 后一个 Segment的 Entryspan 总是与前一个 Segment 中的某个 ExitSpan 关联
  1. Skywalking Trace 的数据协议

具体数据协议参考 Skywalking Trace Data Protocol, 这里主要讲一下 sw8 格式和组成。

sw8 格式: XXXXX-XXXXX-XXXX-XXXX,以 - 分割。 样例: 1-MzYzMzM1NDctNTc0YS00MzZlLTgzNWEtNTY1YTQyNzk3YTY3-ZWQ3ODA2ZjYwNTI0MTFlZWE5ZDdmZTFhNTA5YTRmYTk=-1-bWlkZGxl-bWlkZGxlLTZmNGRkN2JmNmMtcWJ4cm0=-L0dFVC9zZXJ2aWNl-aHR0cDovL2JhY2tlbmQv

具体内容如下:

  • 采样标记(Sample): 0 或者 1, 0 表示不采样 1 表示采样
  • 跟踪ID(Trace ID): 字符(BASE64 编码)
  • 父Sengment ID (Parent trace segment ID): 字符(BASE64 编码)
  • 父 Span ID(Parent span ID): 整型
  • 父服务名称(Parent service): 字符(BASE64 编码)
  • 父服务实例(Parent service instance): 字符(BASE64 编码)
  • 父Endpoint(Parent endpoint): 字符(BASE64 编码)
  • 目标地址:字符(BASE64 编码)

三、Higress 架构

Higress是基于阿里内部的Envoy Gateway实践沉淀、以开源 Istio + Envoy 为核心构建的下一代云原生网关,实现了流量网关 + 微服务网关 + 安全网关三合一的高集成能力,深度集成Dubbo、Nacos、Sentinel等微服务技术栈,能够帮助用户极大的降低网关的部署及运维成本且能力不打折;

在标准上全面支持 Ingress与 Gateway API,积极拥抱云原生下的标准API规范;

同时,Higress Controller也支持Nginx Ingress平滑迁移,帮助用户零成本快速迁移到Higress。

img.png

四、业务应用集成 Skywalking

业务应用通过与 go2sky 项目集成 SkyWalking 监控 Golang 应用程序,主要通过 Gin middleware 和 Http 请求手动埋点。

1、集成 Gin middleware

func middleware(engine *gin.Engine, tracer *go2sky.Tracer) gin.HandlerFunc {
if engine == nil || tracer == nil {
return func(c *gin.Context) {
c.Next()
}
}
return func(c *gin.Context) {
if strings.HasPrefix(c.Request.URL.String(), skipProbPrefix) || strings.HasPrefix(c.Request.URL.String(), skipMetricsPrefix) {
c.Next()
return
}
span, ctx, err := tracer.CreateEntrySpan(c.Request.Context(), getOperationName(c), func(key string) (string, error) {
return c.Request.Header.Get(key), nil
})
if err != nil {
c.Next()
return
}
span.SetComponent(componentIDGINHttpServer)
span.Tag(go2sky.TagHTTPMethod, c.Request.Method)
span.Tag(go2sky.TagURL, c.Request.Host+c.Request.URL.Path)
span.SetSpanLayer(agentv3.SpanLayer_Http)

c.Request = c.Request.WithContext(ctx)

c.Next()

if len(c.Errors) > 0 {
span.Error(time.Now(), c.Errors.String())
}
span.Tag(go2sky.TagStatusCode, strconv.Itoa(c.Writer.Status()))
span.End()
}
}

func getOperationName(c *gin.Context) string {
return fmt.Sprintf("/%s%s", c.Request.Method, c.FullPath())
}

2、Http请求手动埋点

func traceHttpCall(c *gin.Context, req *http.Request, url string, fn func(req *http.Request) (*http.Response, error)) (*http.Response, error) {
tracer := go2sky.GetGlobalTracer()
if tracer == nil {
resp, err := fn(req)
return resp, err
}

reqSpan, err := go2sky.GetGlobalTracer().CreateExitSpan(c.Request.Context(), "invoke", url, func(headerKey, headerValue string) error {
req.Header.Set(headerKey, headerValue)
return nil
})

reqSpan.SetComponent(2)
reqSpan.SetSpanLayer(v3.SpanLayer_Http)
resp, err2 := fn(req)
reqSpan.Tag(go2sky.TagHTTPMethod, http.MethodGet)
reqSpan.Tag(go2sky.TagURL, url)
reqSpan.End()
return resp, err2

}

五、本地测试环境搭建

  1. 本地安装 kubectl, kind, helm

可以参考 Higress 快速开始安装 kubectl, kind。 helm 安装参考安装文档

  1. 安装 higress 和 istio CRD

可以参考 higress 快速开始安装部署 来部署,这里需要安装 Istio CRD。

下面是一个参考安装命令:

helm install higress -n higress-system --set global.onlyPushRouteCluster=false --set higress-core.skywalking.enabled=true  --set higress-core.skywalking.service.address=skywalking-oap-server.op-system.svc.cluster.local  --set higress-core.skywalking.service.port=11800 higress.io/higress
  1. 部署 Skywalking,业务应用和 Ingress
$ export KUBECONFIG=${HOME}/.kube/config_higress
$ kubectl apply -f skywalking.yaml
$ kubectl apply -f app.yaml
$ kubectl apply -f ingress.yaml

检查 POD 运行状态和 Ingress 状态

$ export KUBECONFIG=${HOME}/.kube/config_higress

$ kubectl get pods -n higress-system

NAME READY STATUS RESTARTS AGE
higress-console-6f554978dc-cclg7 1/1 Running 0 100m
higress-console-grafana-7495766db4-4flq5 1/1 Running 0 131m
higress-console-prometheus-6d7bdccfb-hxtsq 1/1 Running 0 131m
higress-controller-689c5b965f-7wsmt 2/2 Running 0 131m
higress-gateway-59966b45d9-z7ltd 1/1 Running 0 131m

$ kubectl get pods -n op-system

NAME READY STATUS RESTARTS AGE
skywalking-oap-dashboard-65f496ccc9-dr96l 1/1 Running 0 99m
skywalking-oap-server-859694656b-p8vcq 1/1 Running 0 99m

$ kubectl get pods -n app-system

NAME READY STATUS RESTARTS AGE
backend-6b9549bc64-f98tr 1/1 Running 0 99m
backend-6b9549bc64-x2btl 1/1 Running 0 99m
bff-766967f8db-8ght7 1/1 Running 0 99m
bff-766967f8db-gflbh 1/1 Running 0 99m
middle-6f4dd7bf6c-qdjqj 1/1 Running 0 99m
middle-6f4dd7bf6c-stzf4 1/1 Running 0 99m

$ kubectl get svc -n app-system

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
backend ClusterIP 10.96.179.140 <none> 80/TCP 99m
bff ClusterIP 10.96.121.62 <none> 80/TCP 99m
middle ClusterIP 10.96.55.8 <none> 80/TCP 99m

$ kubectl get ingress -n higress-system

NAME CLASS HOSTS ADDRESS PORTS AGE
httpbin higress httpbin.example.com 80 8s
skywalking-dashboard higress skywalking.higress.io 80 8s
  1. 测试 Higress Console, Skywalking Dashboard, Bff 服务

1)编辑 /etc/hosts 文件添加以下三个域名

127.0.0.1 skywalking.higress.io
127.0.0.1 httpbin.example.com

2)打开 higress-gateway 端口转发

$ export KUBECONFIG=${HOME}/.kube/config_higress
$ kubectl -n higress-system port-forward service/higress-gateway 8080:80
$ kubectl -n higress-system port-forward service/higress-console 18080:8080

3)通过浏览器打开访问上面三个域名

Higress 控制台: http://127.0.0.1:8080。首次访问控制台时需要先初始化管理员用户。初始化完成后使用对应的用户名密码登录即可。

img.png

Skywalking Dashboard: http://skywalking.higress.io:8080

img.png

Bff 服务: http://httpbin.example.com:8080/hostname

img.png

六、Higress 集成 Skywalking 调用链路跟踪配置

通过修改 Higress configmap 全局配置 higress-config 来激活 Higress 集成 Skywalking 调用链路跟踪。

$ export KUBECONFIG=${HOME}/.kube/config_higress
$ kubectl edit configmap higgress-config -n higress-system

在 data 下增加 higress 配置项然后保存,具体配置内容如下:

data:
higress: |-
tracing:
enable: true
sampling: 100
timeout: 500
skywalking:
service: skywalking-oap-server.op-system.svc.cluster.local
port: 11800

七、Skywalking 链路跟踪

运行压测脚本

for i in $(seq 1 1000)
do
curl -v -H "Host:httpbin.example.com" http://127.0.0.1:8080/hostname
curl -v -H "Host:httpbin.example.com" http://127.0.0.1:8080/
curl -v -H "Host:httpbin.example.com" http://127.0.0.1:8080/service?services=middle,backend
done

调用 bff 服务 /service 接口来模拟调用链路

curl -v -H "Host:httpbin.example.com" http://127.0.0.1:8080/service?services=middle,backend

部分返回响应体情况如下:

{
"args": {
},
"form": {
},
"headers": {
"accept-encoding": "gzip",
"sw8": "1-MzYzMzM1NDctNTc0YS00MzZlLTgzNWEtNTY1YTQyNzk3YTY3-ZWQ3ODA2ZjYwNTI0MTFlZWE5ZDdmZTFhNTA5YTRmYTk=-1-bWlkZGxl-bWlkZGxlLTZmNGRkN2JmNmMtcWJ4cm0=-L0dFVC9zZXJ2aWNl-aHR0cDovL2JhY2tlbmQv",
"sw8-correlation": "",
"user-agent": "Go-http-client/1.1",
"x-httpbin-trace-host": "bff-766967f8db-jwn2g/middle-6f4dd7bf6c-qbxrm/backend-6b9549bc64-8twnx",
"x-httpbin-trace-service": "bff/middle/backend",
"x-request-id": "e5a1b250-ebe3-931d-91d7-90e3ee2fc867"
},
"method": "GET",
"origin": "",
"url": "/",
"envs": {
"NODE_NAME": "higress-worker2",
"PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"POD_IP": "10.244.1.7",
"POD_NAME": "backend-6b9549bc64-8twnx",
"POD_NAMESPACE": "app-system",
"SERVICE_ACCOUNT": "backend",
"SERVICE_NAME": "backend",
"VERSION": "v1"
},
"host_name": "backend-6b9549bc64-8twnx",
"body": ""
}

响应头中和调用链路跟踪相关有如下:

"sw8": "1-MzYzMzM1NDctNTc0YS00MzZlLTgzNWEtNTY1YTQyNzk3YTY3-ZWQ3ODA2ZjYwNTI0MTFlZWE5ZDdmZTFhNTA5YTRmYTk=-1-bWlkZGxl-bWlkZGxlLTZmNGRkN2JmNmMtcWJ4cm0=-L0dFVC9zZXJ2aWNl-aHR0cDovL2JhY2tlbmQv",
"x-httpbin-trace-host": "bff-766967f8db-jwn2g/middle-6f4dd7bf6c-qbxrm/backend-6b9549bc64-8twnx",
"x-httpbin-trace-service": "bff/middle/backend",

其中:

  • sw8: Skywalking 用于跟踪的 Http Header
  • x-httpbin-trace-host: 调用链路经过 POD_NAME
  • x-httpbin-trace-service: 调用链路经过 SERVICE_NAME

在 Skywalking dashboard 中查看如下:

  • 服务截图

img.png

  • 调用链路截图

img.png

  • 调用链路拓扑截图

img.png

八、Higress gateway 指标和监控面板

可以通过度量各个组件的性能指标,例如响应时间、吞吐量、错误率、资源使用率等指标来了解系统的状态和性能。

指标数据包含指标名称,指标标签,和指标值,下面是 envoy_cluster_upstream_cx_total upstream(总连接数)部分指标数据,

其中 envoy_cluster_upstream_cx_total 是指标名称,cluster_name 是指标标签,16 是指标值。

# TYPE envoy_cluster_upstream_cx_total counter
envoy_cluster_upstream_cx_total{cluster_name="outbound|80||bff.app-system.svc.cluster.local"} 16

Higress 指标数据大体可以分为三类:

  • Downstream 下游: 指标与外来的连接/请求有关,主要由侦听器,HTTP连接管理器等
  • UpStream 上游: 指标与外向的连接/请求有关,主要由连接池,路由器,过滤器,熔断等
  • Server 负载: 指标信息记录 Higress gateway 服务器实例的负载等

Higress 指标数据类型主要有三类:

  • Counter: 无符号整数,只会增加而不会减少。例如,总请求
  • Gauge: 增加和减少的无符号整数。例如,当前活动的请求
  • Histogram: 作为指标流的一部分的无符号整数,然后由收集器聚合以最终产生汇总的百分位值(percentile,即平常说的 P99/P50/Pxx)。例如,Upstream 响应时间

通过以下命令可以获取 Higress gateway 支持的指标和类型

$ export HIGRESS_GATEWAY_POD=$(kubectl get pods -l app=higress-gateway -o 'jsonpath={.items[0].metadata.name}' -n higress-system)
$ kubectl exec "$HIGRESS_GATEWAY_POD" -n higress-system -- curl -sS http://127.0.0.1:15020/stats/prometheus | grep "# TYPE"

部分指标内容如下:

...
# TYPE envoy_cluster_upstream_cx_total counter
# TYPE envoy_cluster_upstream_cx_tx_bytes_total counter
# TYPE envoy_cluster_upstream_flow_control_backed_up_total counter
# TYPE envoy_cluster_upstream_flow_control_drained_total counter
# TYPE envoy_cluster_upstream_flow_control_paused_reading_total counter
# TYPE envoy_cluster_upstream_flow_control_resumed_reading_total counter
# TYPE envoy_cluster_upstream_internal_redirect_failed_total counter
# TYPE envoy_cluster_upstream_internal_redirect_succeeded_total counter
# TYPE envoy_cluster_upstream_rq counter
# TYPE envoy_cluster_upstream_rq_101 counter
# TYPE envoy_cluster_upstream_rq_200 counter
# TYPE envoy_cluster_upstream_rq_201 counter
# TYPE envoy_cluster_upstream_rq_301 counter
# TYPE envoy_cluster_upstream_rq_302 counter
# TYPE envoy_cluster_upstream_rq_304 counter
# TYPE envoy_cluster_upstream_rq_401 counter
# TYPE envoy_cluster_upstream_rq_404 counter
# TYPE envoy_cluster_upstream_rq_cancelled counter
# TYPE envoy_cluster_upstream_rq_completed counter
# TYPE envoy_cluster_upstream_rq_maintenance_mode counter
# TYPE envoy_cluster_upstream_rq_max_duration_reached counter
# TYPE envoy_cluster_upstream_rq_pending_failure_eject counter
# TYPE envoy_cluster_upstream_rq_pending_overflow counter
# TYPE envoy_cluster_upstream_rq_pending_total counter
# TYPE envoy_cluster_upstream_rq_per_try_idle_timeout counter
# TYPE envoy_cluster_upstream_rq_per_try_timeout counter
# TYPE envoy_cluster_upstream_rq_retry counter
# TYPE envoy_cluster_upstream_rq_retry_backoff_exponential counter
# TYPE envoy_cluster_upstream_rq_retry_backoff_ratelimited counter
# TYPE envoy_cluster_upstream_rq_retry_limit_exceeded counter
# TYPE envoy_cluster_upstream_rq_retry_overflow counter
# TYPE envoy_cluster_upstream_rq_retry_success counter
# TYPE envoy_cluster_upstream_rq_rx_reset counter
# TYPE envoy_cluster_upstream_rq_timeout counter
# TYPE envoy_cluster_upstream_rq_total counter
# TYPE envoy_cluster_upstream_rq_tx_reset counter
...
# TYPE envoy_http_downstream_cx_total counter
# TYPE envoy_http_downstream_cx_tx_bytes_total counter
# TYPE envoy_http_downstream_cx_upgrades_total counter
# TYPE envoy_http_downstream_flow_control_paused_reading_total counter
# TYPE envoy_http_downstream_flow_control_resumed_reading_total counter
# TYPE envoy_http_downstream_rq counter
# TYPE envoy_http_downstream_rq_completed counter
# TYPE envoy_http_downstream_rq_failed_path_normalization counter
# TYPE envoy_http_downstream_rq_header_timeout counter
# TYPE envoy_http_downstream_rq_http1_total counter
# TYPE envoy_http_downstream_rq_http2_total counter
# TYPE envoy_http_downstream_rq_http3_total counter
# TYPE envoy_http_downstream_rq_idle_timeout counter
# TYPE envoy_http_downstream_rq_max_duration_reached counter
# TYPE envoy_http_downstream_rq_non_relative_path counter
# TYPE envoy_http_downstream_rq_overload_close counter
# TYPE envoy_http_downstream_rq_redirected_with_normalized_path counter
# TYPE envoy_http_downstream_rq_rejected_via_ip_detection counter
# TYPE envoy_http_downstream_rq_response_before_rq_complete counter
# TYPE envoy_http_downstream_rq_rx_reset counter
# TYPE envoy_http_downstream_rq_timeout counter
# TYPE envoy_http_downstream_rq_too_large counter
# TYPE envoy_http_downstream_rq_total counter
# TYPE envoy_http_downstream_rq_tx_reset counter
# TYPE envoy_http_downstream_rq_ws_on_non_ws_route counter
...

具体指标定义参考如下:

如何查看 Higress 指标数据:

通过 Skywalking Dashboard 查看 Higress gateway 监控数据部分截图如下:

img.png img.png img.png

参考文档

· 阅读需 9 分钟

开源之夏介绍

开源之夏是由中科院软件所“开源软件供应链点亮计划”发起并长期支持的一项暑期开源活动,旨在鼓励在校学生积极参与开源软件的开发维护,培养和发掘更多优秀的开发者,促进优秀开源软件社区的蓬勃发展,助力开源软件供应链建设。

目前开源之夏官网已经开启了学生报名,只要你满足以下要求即可进行项目申请:

  • 本活动面向年满 18 周岁在校学生。
  • 暑期即将毕业的学生,只要在申请时学生证处在有效期内,就可以提交申请。
  • 中国籍学生参与活动需提供身份证、学生证、教育部学籍在线验证报告(学信网)或在读证明。
  • 外籍学生参与活动需提供护照,同时提供录取通知书、学生卡、在读证明等文件用于证明学生身份。

参与项目不仅可以为开源世界做出自己的贡献,还能获得丰厚的结项奖金(基础难度8000 RMB/进阶难度12000 RMB),项目经验也会成为你毕业简历上的亮点,快来报名吧!

报名截止时间为 6 月 3 日 15 点,具体参考官网活动流程和参与指南介绍:

Higress 介绍

Higress 是基于阿里内部两年多的实践沉淀,以开源 Istio 与 Envoy 为核心构建的下一代云原生网关。Higress 实现了安全防护网关、流量网关、微服务网关三层网关合一,可以显著降低网关的部署和运维成本。

Higress 在阿里内部的诞生和演进历程可以看这篇文章:

阿里巴巴重磅开源云原生网关: Higress

Higress 开源半年时间,GitHub star 数已经破千,在上个月 Higress 已经 Release 出了第一个 RC 版本,作为正式 GA 的候选发布版本,详情可以查看这篇文章:

上线控制台,降低使用门槛|Higress 1.0.0 RC 版本发布

在本次开源之夏活动中,Higress 有两个进阶难度的项目可以申请,欢迎各位同学踊跃报名。

项目介绍

项目一:Higress Wasm 插件构建/调试/部署的命令行实现

Higress 提供了很方便的 Wasm 插件扩展框架,具体可以查看这篇文章: 30行代码写一个Wasm Go插件

更详细的插件开发和调试流程可以查看这篇文章:使用 Go 语言开发 WASM 插件

这里对插件的生效机制简单做个说明:

  1. 用户将代码编译成 wasm 文件
  2. 用户将 wasm 文件构建成 oci 镜像
  3. 用户将 oci 镜像推送至镜像仓库
  4. 用户创建 WasmPlugin 资源
  5. Istio watch 到 WasmPlugin 资源的变化
  6. Higress Gateway 中的 xDS proxy 进程从 Istio 获取到配置,发现插件的镜像地址
  7. xDS proxy 从镜像仓库拉取镜像
  8. xDS proxy 从镜像中提取出 wasm 文件
  9. Higress Gateway 中的 envoy 进程从 xDS proxy 获取到配置,发现 wasm 文件的本地路径
  10. envoy 从本地文件中加载 wasm 文件

这里 envoy 获取配置并加载 wasm 文件使用到了 ECDS (Extension Config Discovery Service)的机制,实现了 wasm 文件更新,直接热加载,不会导致任何连接中断,业务流量完全无损。

这个项目的初衷是希望能基于 Higress 的 CLI 命令行工具(hgctl) 来进一步简化 Higress Wasm 插件的开发调试和安装部署步骤,使之更容易上手使用。

需要实现的 hgctl 命令如下:

  • hgctl plugin build:构建 wasm OCI 镜像并推送到指定仓库
  • hgctl plugin test:启动 docker compose 测试插件功能
  • hgctl plugin install/uninstall :在当前higress集群中安装或卸载插件
  • hgctl plugin config:修改制定插件的配置

Higress Wasm 插件配置基于 Openapi Specification (OAS 3.0)进行约束,需要能从代码中解析出插件配置字段格式,自动生成对应的 OAS 约束,用于添加到 OCI 镜像中,并同时用于 install/uninstall/config 等命令的参数配置校验

项目二:基于 Wasm 实现 OIDC 认证插件

Higress 作为一个云原生网关,需要实现 OIDC 认证的能力,方便用户对接外部认证服务。

OIDC (OpenID Connect) 是基于 OAuth 2.0 的身份认证协议,可以用于实现 SSO(Single Sign On)单点登录,即通过网关统一完成用户的身份认证,在身份认证成功后,再将资源请求转发给后端服务。

流程简介如下:

  1. 客户端向网关发起认证请求。
  2. 网关将认证请求直接转发到给认证服务。
  3. 认证服务读取请求中的验证信息(例如用户名、密码)进行验证,验证通过后返回Code给网关。
  4. 网关将携带Code的应答返回给客户端。
  5. 客户端向网关请求回调接口,请求中携带Code。
  6. 网关请求认证服务颁发Token,请求中携带Code、Client ID、Client Secret。
  7. 认证服务验证合法性,并返回ID Token。
  8. 认证成功,网关将携带ID Token的应答返回给客户端。
  9. 客户端向网关发起业务请求,请求中携带ID Token,网关校验请求中是否携带ID Token和合法性。
  10. 网关校验客户端的业务请求合法,将请求透传给业务服务。
  11. 业务服务进行业务处理后应答。
  12. 网关将业务应答返回给客户端。

目前 Higress 也可以基于 Envoy 的 Ext Authz 机制对接外置的 oauth2-proxy 来实现鉴权,不过这个方案一方面有额外的请求开销,另一方面 oauth2-proxy 只能作一组 OIDC 配置,无法对接多个不同的认证服务

加入社区

GitHub:https://github.com/alibaba/higress

官网: https://higress.io

对于报名方式有任何疑问,或者对某一个任务非常感兴趣,并且想要深入了解的同学,欢迎扫码添加微信,备注开源之夏

相关项目推荐

  • 对于微服务注册发现和配置管理有兴趣的同学,可以尝试填报 Nacos 开源之夏;
  • 对于微服务分布式事务有兴趣的同学,可以尝试填报 Seata 开源之夏;
  • 对于微服务框架和RPC框架有兴趣的同学,可以尝试填报 Spring Cloud AlibabaDubbo 开源之夏;
  • 对于分布式高可用防护有兴趣的同学,可以尝试填报 Sentinel 开源之夏;
  • 对于微服务治理有兴趣的同学,可以尝试填报 OpenSergo 开源之夏。

· 阅读需 7 分钟

前言

历时 5 个多月,Higress 推出了首个 RC (Release Candidate,即正式发布的候选)版本 1.0.0-rc,用户可以通过控制台,开箱即用地使用云原生网关。

选用 Higress 作为云原生网关的核心优势如下:

  • 易用性

    “云原生”已经不再是一个新鲜词,但企业对云原生技术的学习使用成本仍有许多顾虑,对云原生新标准的追赶又有很多焦虑;

    Higress 同时提供了本地安装/生产部署的 quickstart,可以一键部署,并通过控制台操作快速上手;基于简单易用的控制台,Higress 可以封装 Ingress/Gateway API 的标准细节,根治技术追赶焦虑。

  • 标准化

    K8s 带来了云原生的路由标准 Ingress/Gateway API,如同 POSIX 定义 Unix 可移植操作系统标准,历时 35 年经久不衰,云原生的路由标准的生命周期一定会远超过 K8s 本身;

    Higress 结合阿里内部实践以及阿里云产品沉淀,积累了基于 Ingress API 的丰富的路由策略扩展能力,同时还兼容大部分 Nginx Ingress 能力,这些能力后续也将在 Gateway API 上支持。

  • 高集成

    企业内有大量传统架构部署的服务,会成为向云原生架构演进的技术负担,要求云原生网关具备对接异构服务架构的能力;

    基于 Higress 提供的多种服务发现机制,网关路由不仅可以转发到 K8s 服务,也可以直接配置 IP 转发到到物理机上的服务;基于 Nacos/ZooKeeper 等注册中心对接,还可以轻松实现 Spring CloudDubbo 微服务的路由,无论其是否部署在 K8s 内。

  • 易扩展

    基于扩展机制进行二次开发的能力,是云原生网关在不同业务场景下都能适配落地的关键;

    Higress提供了灵活的插件扩展机制,目前插件市场已经推出多个官方插件,并支持用户通过控制台直接上传自己开发的插件,同时开源社区的插件市场生态也在不断建设中。

  • 热更新

    传统 Nginx 更新规则需要 reload 会导致链接抖动,导致流量损失,对实时通信、视频、IOT无法容忍;

    对于路由规则,Wasm 插件逻辑更新,以及证书改动等等,Higress 全部支持热更新,不会造成任何连接抖动。

企业落地支持

在 RC 版本阶段使用 Higress 的企业用户,社区会在落地阶段提供更多帮助,我们建立了 Higress 企业落地群,可以联系我(微信:nomadao 钉钉:chengtanzty),会将你加进群,群里有社区核心研发同学,可以提供更及时的响应和帮助。

安装升级方式

安装 RC 版本,需要 helm 安装升级时需要指定--devel参数,例如:helm upgrade higress -n higress-system --devel

1.0.0 RC 版本已经在社区小伙伴的协作下完成了多轮测试和修复工作,欢迎大家使用。最终的正式版本,也将在近期很快推出。

控制台功能速览

  • 丰富的可观测

    提供开箱即用的可观测,Grafana&Prometheus 可以使用内置的也可对接自建的,具体可以参考文档

  • 插件扩展机制

    官方提供了多种插件,用户也可以开发自己的插件,构建成 docker/oci 镜像后在控制台配置,可以实时变更插件逻辑,对流量完全无损。

  • 多种服务发现

    默认提供 K8s Service 服务发现,通过配置可以对接 Nacos/ZooKeeper 等注册中心实现服务发现,也可以基于静态 IP 或者 DNS 来发现

  • 域名和证书

    可以创建管理 TLS 证书,并配置域名的 HTTP/HTTPS 行为,域名策略里支持对特定域名生效插件

  • 丰富的路由能力

    基于上面配置的服务发现机制,发现的服务会出现在服务列表中;创建路由时,选择域名,定义路由匹配机制,再选择目标服务进行路由;路由策略里支持对特定路由生效插件

进阶使用

Higress 控制台的功能还在不断丰富和演进中,当前还有很多 Higress Ingress 注解的能力没有支持,如果有这部分深度使用的需求,可以参考这篇文档进行进阶配置

如果希望使用 Istio 的能力进行流量治理,可以参考这篇文档的支持 Istio CRD 一节。基于 Istio 的 EnvoyFilter API 可以实现更多细粒度的管控能力。

社区

欢迎认领 Higress Issue 任务:https://github.com/alibaba/higress/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22

完成一定数量的 Issues 就可以成为 Higress Committer,也有机会获得开源社区的礼物和荣誉🏆

欢迎加入 Higress 社区群,及时了解更多 Higress 动向:

· 阅读需 4 分钟

UU跑腿介绍

UU跑腿隶属于郑州时空隧道信息技术有限公司,是更专业的同城即时生活服务平台,以共享劳动力与时间为众包理念,人人都可注册成为跑腿师傅,并为附近的人提供帮取送、帮买、全能帮、帮排队等多样化同城即时服务,为中小企业、电商、本地商户提供安全专业的高端配送服务。UU跑腿秉承“让生活更美好”的理念,不断创新、不断进步,为用户提供更加优质的服务体验。

背景需求

UU跑腿对于云原生网关的要求是,能同时满足流量网关,微服务网关,以及安全网关的场景诉求,用一个网关来解决之前需要部署多个网关才能解决的问题:

  1. 具备高可靠性和高性能,可以替代之前部署的 Nginx Ingress 流量网关
  2. 同时支持 K8s 生态和传统微服务生态接入,支持(HTTP转Dubbo)协议转换,可以替代之前部署的 Spring Cloud Gateway 微服务网关
  3. 能够支持在网关入口处完成鉴权,避免每个后端服务重复实现鉴权功能,实现安全网关的能力
  4. 具备易用的控制台进行 API 的治理,以及具备丰富的可观测指标

迁移 Higress 前的架构

old-arch

之前存在的主要痛点:

  1. Spring Cloud Gateway 自身参数调整改动需要重新部署影响流量,且动态路由需要进行复杂的配置,包括路由规则,容易出现配置错误导致系统异常
  2. 运维需要同时维护 Nginx Ingress 和 Spring Cloud Gateway,面对流量高峰进行进行扩容相关操作时,运维负担比较重,而且这样两层网关的请求的链路较长,可用性低、成本高

迁移 Higress 后的架构

new-arch

Higress云原生网关实现负载均衡、路由、安全认证等功能。通过网关对外提供服务统一入口,并对请求进行鉴权、限流和监控等操作,用简单的架构保证了整体系统的稳定性和可靠性。

  1. 合并流量网关(K8s Nginx Ingress)和微服务网关(Spring Cloud Gateway ),降低网关成本,高性能服务;
  2. 同时支持 K8s service 和 Nacos 服务注册发现,满足技术需求对 K8s 生态和传统微服务生态接入。
  3. Nginx Ingress 完美迁移到 Higress,十分丝滑

· 阅读需 5 分钟

进展概要

  1. Higress 控制台正式 release,涵盖 Higress 的服务/路由/域名/证书管理能力,并提供开箱即用的可观测功能
  2. 安装/升级 Higress 时支持自动安装对应版本的 Higress Console,避免版本不适配的问题
  3. 支持开启 Istio API,实现更多复杂的功能,并且也可以用于平滑替换 Istio Ingress Gateway

版本特性

Higress 控制台

现在通过 helm 命令安装 Higress 时将自动安装对应版本的 Higress Console, 这里通过 higress-console.domain 参数,可以指定控制台的域名。

# 已经添加过 repo 的,请执行 helm repo update
helm repo add higress.io https://higress.io/helm-charts
helm install higress -n higress-system higress.io/higress --create-namespace --render-subchart-notes --set higress-console.domain=console.higress.io

image

注意:安装完成后会输出一段文本,其中包含获取控制台登录信息的命令。请执行该命令并记录用户名和密码。

image

正式环境部署时,建议控制台开启强制 HTTPS 访问,具体操作方式是,在 higress-system 命名空间下先创建好 TLS 证书和私钥对应的 secret,例如:

apiVersion: v1
kind: Secret
type: kubernetes.io/tls
data:
tls.crt: -----BEGIN CERTIFICATE-----...
tls.key: -----BEGIN RSA PRIVATE KEY-----...
metadata:
name: my-tls-secret
namespace: higress-system

然后通过下面 helm 命令开启强制 HTTPS 访问

helm upgrade higress -n higress-system higress.io/higress --set higress-console.tlsSecretName=my-tls-secret

如果希望启用 Higress 自带的 Prometheus&Grafana,可以通过下面 helm 命令进行安装:

helm upgrade higress -n higress-system higress.io/higress --set higress-console.o11y.enabled=true

这样 Higress 控制台就可以看到自带的可观测大盘了:

image

当然,你也可以对接已有的 Prometheus&Grafana,使用这份 Higress 官方提供的 Dashboard 配置即可:https://higress.io/grafana/dashboard.json

可以登陆 Higress 控制台 Demo 试用现有所有功能: http://demo.higress.io

开启 Istio API

通过开启 Istio API,可以实现使用 Higress 平滑替换 Istio Ingress Gateway,具体 helm 命令如下:

helm upgrade higress -n higress-system higress.io/higress --set global.enableIstioAPI=true

基于 Istio API,可以实现目前 Higress 还未提供相应 Ingress 注解的能力,例如基于 Istio EnvoyFilter 来实现 HTTP to Dubbo 的协议转换配置方式:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: http-dubbo-transcoder
namespace: higress-system
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
subFilter:
name: envoy.filters.http.router
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.http_dubbo_transcoder
typed_config:
'@type': type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.http_dubbo_transcoder.v3.HttpDubboTranscoder
- applyTo: HTTP_ROUTE
match:
context: GATEWAY
routeConfiguration:
vhost:
route:
name: test
patch:
operation: MERGE
value:
route:
upgrade_configs:
- connect_config:
allow_post: true
upgrade_type: CONNECT
typed_per_filter_config:
envoy.filters.http.http_dubbo_transcoder:
'@type': type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.http_dubbo_transcoder.v3.HttpDubboTranscoder
value:
request_validation_options:
reject_unknown_method: true
reject_unknown_query_parameters: true
services_mapping:
- group: dev
method_mapping:
- name: sayName
parameter_mapping:
- extract_key: p
extract_key_spec: ALL_QUERY_PARAMETER
mapping_type: java.lang.String
passthrough_setting:
passthrough_all_headers: true
path_matcher:
match_http_method_spec: ALL_GET
match_pattern: /dubbo/hello
name: com.alibaba.nacos.example.dubbo.service.DemoService
version: 1.0.0
url_unescape_spec: ALL_CHARACTERS_EXCEPT_RESERVED

上述配置比较复杂,原因是为了方便 Envoy 数据面程序逻辑处理而设计的 Schema。目前 Higress 社区已经在设计更方便 Ingress 配置使用的 CRD,后续也会在 Higress 控制台上提供对应的配置功能。

GA 版本规划

Higress 预计将在3月底/4月初发布首个 GA 版本, 这个版本的主要规划如下:

  1. 实现 HTTP to Dubbo 协议转换的控制面配置简化
  2. Higress 控制台提供 Wasm 插件能力,支持配置自定义插件
  3. 推出第一版 Higress Admin API,可以被其他平台/工具集成
  4. 全面完善 Higress 官网文档,覆盖 Higress 全部功能的详细说明

Higress 社区

欢迎认领 Higress Issue 任务:https://github.com/alibaba/higress/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22

完成一定数量的 Issues 就可以成为 Higress Committer,也有机会获得开源社区的礼物和荣誉🏆

欢迎加入 Higress 社区群,及时了解更多 Higress 动向: