1. 云原生网关Higress介绍

1.1 Higress是什么

Higress是基于阿里内部的Envoy Gateway实践沉淀、以开源Istio + Envoy为核心构建的下一代云原生网关,实现了流量网关 + 微服务网关 + 安全网关三合一的高集成能力,深度集成Dubbo、Nacos、Sentinel等微服务技术栈,能够帮助用户极大的降低网关的部署及运维成本且能力不打折;在标准上全面支持Ingress与Gateway API,积极拥抱云原生下的标准API规范;同时,Higress Controller也支持Nginx Ingress平滑迁移,帮助用户零成本快速迁移到Higress。

**
**

1.2 Higress快速开始

基于docker compose安装Higress

使用独立部署的 Nacos

-

1
curl -fsSL https://higress.io/standalone/get-higress.sh | bash -s -- -c nacos://192.168.65.174:8848  -p admin

启动成功后,本机端口占用情况如下:

  • 80端口:Higress 暴露,用于 HTTP 协议代理

  • 443端口:Higress 暴露,用于 HTTPS 协议代理

  • 15020端口:Higress 暴露,用于暴露 Prometheus 指标

  • 8080端口:Higress 控制台 暴露

在浏览器中输入http://192.168.65.174:8080/,使用用户名 admin 和安装时设置的密码登录 Higress 控制台

**
**

配置 higress 域名

配置域名解析至 higress 所在机器的 80/443 端口

**
**

服务列表

服务列表自动同步指向的 nacos 中已注册服务列表

**
**

配置路由转发

在路由管理中创建两条新的路由,根据路由前缀将其转发至相应的微服务

**
**

测试

访问,验证测试路由可以正常工作

-

1
curl localhost/user/findOrderByUserId/1 -H 'host: mall.com'

基于 K8s 集群安装Higress

关于安装k8s,可以阅读我之前的文章:

利用sealos快速安装kubernetes集群

安装Higress

-

-

1
# 使用Helm 安装Higresshelm repo add higress.io https://higress.io/helm-chartshelm install higress -n higress-system higress.io/higress --create-namespace --render-subchart-notes --set higress-console.domain=console.higress.io

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

例如安装在 higress-system 命名空间下时,执行下面命令获取用户名密码:

-

-

1
export ADMIN_USERNAME=$(kubectl get secret --namespace higress-system higress-console -o jsonpath="{.data.adminUsername}" | base64 -d)  export ADMIN_PASSWORD=$(kubectl get secret --namespace higress-system higress-console -o jsonpath="{.data.adminPassword}" | base64 -d)  echo -e "Username: ${ADMIN_USERNAME}\nPassword: ${ADMIN_PASSWORD}"

获取 Higress Gateway 的 LoadBalancer IP,并记录下来。后续可以通过该 IP 的 80 和 443 端口访问 Higress Gateway

**
**

配置Higress

假设在 default 命名空间下已经部署了一个名为 foo 的服务,而我们希望创建一个对应 http://foo.bar.com/foo 的路由指向该服务。

如果需要的话,各位可以使用下方 YAML 来创建对应的测试服务。

-

-

-

1
kind: PodapiVersion: v1metadata:  name: foo-app  labels:    app: foospec:  containers:  - name: foo-app    image: higress-registry.cn-hangzhou.cr.aliyuncs.com/higress/http-echo:0.2.4-alpine    args:    - "-text=foo"---kind: ServiceapiVersion: v1metadata:  name: foo-servicespec:  selector:    app: foo  ports:  # Default port used by the image  - port: 5678

使用 Ingress CRD 进行路由配置,编写foo-ingress.yaml

-

-

-

-

-

-

-

-

-

1
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  name: foospec:  ingressClassName: higress  rules:  - host: foo.bar.com    http:      paths:      - pathType: Prefix        path: "/foo"        backend:          service:            name: foo-service            port:              number: 5678

执行如下命令生效规则:

-

1
kubectl apply -f foo-ingress.yaml

2. Higress流量治理实战

在Higress上可以使用Ingress并借助Annotation实现高阶流量治理

2.1 灰度发布

可以阅读我之前的文章:云原生网关Higress 实现灰度发布

2.2 跨域

测试页面

-

-

-

-

-

-

-

-

-

1
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title>    <script src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script></head><body>  <h3 id="demo"></h3></body><script>    $.get('http://192.168.65.130:30332/hello',function(data){        console.log(data)        $('#demo').html(data);    });</script></html>

存在跨域问题:

跨域资源共享CORS(Cross-Origin Resource Sharing)是指允许Web应用服务器进行跨域访问控制,从而实现跨域数据安全传输。

  • higress.io/enable-cors:”true” or “false”。开启或关闭跨域。

  • higress.io/cors-allow-origin:允许的第三方站点,支持泛域名,逗号分隔;支持通配符

  • higress.io/cors-allow-methods:允许的请求方法,如GET、POST,逗号分隔;支持通配符*。默认值为GET, PUT, POST, DELETE, PATCH, OPTIONS。

  • higress.io/cors-allow-headers:允许的请求头部,逗号分隔;支持通配符*。默认值为DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization。

  • higress.io/cors-expose-headers:允许的响应头部,逗号分隔。

  • higress.io/cors-allow-credentials:”true” or “false”。是否允许携带凭证信息。默认允许。

  • higress.io/cors-max-age:预检结果的最大缓存时间,单位为秒;默认值为1728000。

1
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  annotations:    higress.io/enable-cors: "true"    higress.io/cors-allow-origin: "*"    higress.io/cors-allow-methods: "GET,POST"        higress.io/cors-allow-credentials: "false"  name: higress-demospec:  ingressClassName: higress  rules:    - http:        paths:          - backend:              service:                name: nginx-v1                port:                   number: 80            path: /hello            pathType: Exact

部署之后测试,可以正常访问

2.3 Rewrite重写

在请求转发给目标后端服务之前,重写可以修改原始请求的路径(Path)和主机域(Host)。

  • higress.io/rewrite-target:重写Path。
  • higress.io/upstream-vhost:重写Host。

准备测试服务httpbin

httpbin.org 一个简单的 HTTP 请求和响应服务,用 Python + Flask 编写。

官网地址:https://httpbin.org/

使用helm安装httpbin

-

1
helm repo add rgnu https://gitlab.com/mulesoft-int/helm-repository/-/raw/master/helm install my-httpbin rgnu/httpbin --version 1.0.0

Rewrite重写Path

  1. 将请求example.com/test在转发至后端服务之前,重写为example.com/get

-

-

-

-

-

-

-

-

-

-

1
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  annotations:    higress.io/rewrite-target: "/get"  name: higress-demospec:  ingressClassName: higress  rules:    - host: example.com      http:        paths:          - backend:              service:                name: my-httpbin                port:                   number: 80            path: /test            pathType: Exact

部署之后执行以下命令进行测试

-

1
curl 10.96.1.19/test?name=fox -H "host: example.com"

2.将请求example.com/v1/get在转发至后端服务之前,去掉Path前缀/v1

-

-

-

-

-

-

-

-

-

-

1
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  annotations:    higress.io/rewrite-target: "/$2"  name: higress-demospec:  ingressClassName: higress  rules:    - host: example.com      http:        paths:          - backend:              service:                name: my-httpbin                port:                   number: 80            path: /v1(/|$)(.*)            pathType: ImplementationSpecific

$1表示路径中正则表达式匹配的第一个()的内容,$2为第二个,以此类推。

部署之后执行以下命令进行测试

-

1
curl 10.96.1.19/v1/get?name=fox -H "host: example.com"

2.4 Header控制

通过Header控制,您可以在转发请求到后端服务之前对请求Header进行增删改,在收到响应转发给客户端时对响应Header进行增删改。

请求Header控制

  • higress.io/request-header-control-add:请求在转发给后端服务时,添加指定Header。若该Header存在,则其值拼接在原有值后面。语法如下:

    • 单个Header:Key Value
    • 多个Header:使用yaml特殊符号 |,每对Key Value单独处于一行
  • higress.io/request-header-control-update:请求在转发给后端服务时,修改指定Header。若该header存在,则其值覆盖原有值。语法如下:

    • 单个Header:Key Value
    • 多个Header:使用yaml特殊符号 |,每对Key Value单独处于一行
  • higress.io/request-header-control-remove:请求在转发给后端服务时,删除指定Header。语法如下:

    • 单个Header:Key
    • 多个Header:逗号分隔

1.对于请求example.com/headers添加两个Header,foo: bar和test: true。

-

-

-

1
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  annotations:    higress.io/request-header-control-add: |      foo bar      test: true  name: demospec:  ingressClassName: higress  rules:    - host: example.com      http:        paths:          - backend:              service:                name: my-httpbin                port:                   number: 80            path: /headers            pathType: Exact

部署之后执行以下命令进行测试

-

1
curl 10.96.1.19/headers -H "host: example.com"
  1. Header控制可以结合灰度发布,对灰度流量进行染色。请求Header为higress:v2时将访问灰度服务nginx-v2,并添加Header,stage: gray;其他情况将访问正式服务nignx-v1,并添加Header,stage: prod。配置如下:

-

-

-

1
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  annotations:    higress.io/canary: "true"    higress.io/canary-by-header: "higress"    higress.io/canary-by-header-value: "v2"    higress.io/request-header-control-add: "stage gray"  name: higress-demo-canaryspec:  ingressClassName: higress  rules:    - http:        paths:          - backend:              service:                name: my-httpbin-canary                port:                   number: 80            path: /headers            pathType: Exact---apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  annotations:    higress.io/request-header-control-add: "stage prod"  name: higress-demospec:  ingressClassName: higress  rules:    - http:        paths:          - backend:              service:                name: my-httpbin                port:                   number: 80            path: /headers            pathType: Exact

部署灰度版本的httpbin

-

1
helm install my-httpbin-canary rgnu/httpbin --version 1.0.0

部署之后执行以下命令进行测试

-

1
curl 10.96.1.19/headers -H "higress: v2"

响应Header控制

  • higress.io/response-header-control-add:请求在收到后端服务响应之后并且转发响应给客户端之前,添加指定Header。若该Header存在,则其值拼接在原有值后面。语法如下:

    • 单个Header:Key Value
    • 多个Header:使用yaml特殊符号 |,每对Key Value单独处于一行
  • higress.io/response-header-control-update:请求在收到后端服务响应之后并且转发响应给客户端之前,修改指定Header。若该header存在,则其值覆盖原有值。语法如下:

    • 单个Header:Key Value
    • 多个Header:使用yaml特殊符号 |,每对Key Value单独处于一行
  • higress.io/response-header-control-remove:请求在收到后端服务响应之后并且转发响应给客户端之前,删除指定Header。语法如下:

    • 单个Header:Key
    • 多个Header:逗号分隔

对于请求example.com/headers的响应删除Header:req-cost-time。

-

-

-

-

-

-

-

-

-

-

1
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:  annotations:    higress.io/response-header-control-remove: "req-cost-time"  name: higress-demospec:  ingressClassName: higress  rules:    - host: example.com      http:        paths:          - backend:              service:                name: my-httpbin                port:                   number: 80            path: /headers            pathType: Exact

正常的响应结果

-

1
# -I 打印响应头curl 10.96.1.19/headers -H "host: example.com" -I

部署后测试

3. Higress插件实战

3.1 通过 Higress 控制台进行配置

Higress 控制台提供了 3 个入口进行插件配置:

  1. 全局配置:插件市场->选择插件进行配置
  2. 域名级配置:域名管理->选择域名->点击策略->选择插件进行配置
  3. 路由级配置: 路由配置->选择路由->点击策略->选择插件进行配置

这三个配置的生效优先级是: 路由级 > 域名级 > 全局

3.2 通过 Higress WasmPlugin CRD 进行配置

Higress WasmPlugin CRD 在 Istio WasmPlugin CRD 的基础上进行了扩展,新增以下配置字段:

字段名称 数据类型 填写要求 描述
defaultConfig object 选填 插件默认配置,全局生效于没有匹配具体域名和路由配置的请求
matchRules array of object 选填 匹配域名或路由生效的配置

matchRules中每一项的配置字段说明:

字段名称 数据类型 填写要求 配置示例 描述
ingress array of string ingress和domain中必填一项 [“default/foo”,”default/bar”] 匹配 ingress 资源对象,匹配格式为:命名空间/ingress名称
domain array of string ingress和domain中必填一项 [“example.com”,”*.test.com”] 匹配域名,支持泛域名
config object 选填 - 匹配后生效的插件配置

请求屏蔽

request-block插件实现了基于 URL、请求头等特征屏蔽 HTTP 请求,可以用于防护部分站点资源不对外部暴露

-

-

-

-

-

-

1
apiVersion: extensions.higress.io/v1alpha1kind: WasmPluginmetadata:  name: request-block  namespace: higress-systemspec:  defaultConfig:    block_urls:    - swagger.html    - foo=bar    case_sensitive: false  url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/request-block:1.0.0

部署后测试

-

1
curl -H "Host: foo.bar.com"   http://10.96.1.19/foo?foo=Bar

基于 Key 限流

key-rate-limit插件实现了基于特定键值实现限流,键值来源可以是 URL 参数、HTTP 请求头

识别请求头 x-api-key,进行区别限流

-

-

-

-

-

-

-

-

1
apiVersion: extensions.higress.io/v1alpha1kind: WasmPluginmetadata:  name: key-rate-limit-foospec:  matchRules:  - ingress:    - default/foo    config:      limit_by_header: "x-api-key"      limit_keys:      - key: "example-key-a"        query_per_second: 1      - key: "example-key-b"        query_per_minute: 3       url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/key-rate-limit:1.0.0

部署后测试

-

1
for i in {1..10}; do curl -H "Host: foo.bar.com" -H "x-api-key: example-key-a"  http://10.96.1.19/foo; done;

JWT 认证

jwt-auth插件实现了基于JWT(JSON Web Tokens)进行认证鉴权的功能,支持从HTTP请求的URL参数、请求头、Cookie字段解析JWT,同时验证该Token是否有权限访问。

**
**

基于token的认证流程

配置jwt插件

-

-

-

1
apiVersion: extensions.higress.io/v1alpha1kind: WasmPluginmetadata:  name: jwt-auth  namespace: higress-systemspec:  defaultConfig:    consumers:    - issuer: abcd      jwks: |        {          "keys": [            {              "kty": "oct",              "kid": "123",              "k": "hM0k3AbXBPpKOGg__Ql2Obcq7s60myWDpbHXzgKUQdYo7YCRp0gUqkCnbGSvZ2rGEl4YFkKqIqW7mTHdj-bcqXpNr-NOznEyMpVPOIlqG_NWVC3dydBgcsIZIdD-MR2AQceEaxriPA_VmiUCwfwL2Bhs6_i7eolXoY11EapLQtutz0BV6ZxQQ4dYUmct--7PLNb4BWJyQeWu0QfbIthnvhYllyl2dgeLTEJT58wzFz5HeNMNz8ohY5K0XaKAe5cepryqoXLhA-V-O1OjSG8lCNdKS09OY6O0fkyweKEtuDfien5tHHSsHXoAxYEHPFcSRL4bFPLZ0orTt1_4zpyfew",              "alg": "HS256"            }          ]        }      name: consumer1    global_auth: false  matchRules:  - config:      allow:      - consumer1    ingress:    - default/higress-demo  url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/jwt-auth:1.0.0

测试效果

未部署jwt插件之前,执行如下命令

-

1
curl 10.96.1.19/order/findOrderByUserId/1 -H "host: example.com"

部署jwt插件之后,执行如下命令

-

1
curl 10.96.1.19/order/findOrderByUserId/1 -H "host: example.com"

将 JWT 设置在 http 请求头中

-

1
curl 10.96.1.19/order/findOrderByUserId/1 -H "host: example.com" -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.eyJpc3MiOiJhYmNkIiwic3ViIjoidGVzdCIsImlhdCI6MTY2NTY2MDUyNywiZXhwIjoxODY1NjczODE5fQ.-vBSV0bKeDwQcuS6eeSZN9dLTUnSnZVk8eVCXdooCQ4'