🤔 Introducing APISIX AI Gateway – Built for LLMs and AI workloads. Learn More

workflow

描述

workflow 插件支持根据给定的规则集有条件地执行对客户端流量的用户定义操作,这些规则集使用 lua-resty-expr 定义。这为流量管理提供了一种细粒度的方法。

属性

名称类型必选项默认值有效值描述
rulesarray[object]一对或多对匹配条件和要执行的操作组成的数组。
rules.casearray[array]一个或多个匹配条件的数组,形式为 lua-resty-expr,例如 {"arg_name", "==", "json"}
rules.actionsarray[array]条件匹配成功后要执行的操作的数组。目前数组只支持一个操作,必须是 returnlimit-countlimit-conn。当操作配置为 return 时,可以配置条件匹配成功时返回给客户端的 HTTP 状态码。当操作配置为 limit-count 时,可以配置 limit-count 插件除 group 之外的所有选项。当操作配置为 limit-conn 时,可以配置 limit-conn 插件的所有选项。

示例

以下示例演示了如何在不同场景中使用 workflow 插件。

NOTE

您可以这样从 config.yaml 中获取 admin_key 并存入环境变量:

admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g')

有条件地返回响应 HTTP 状态码

以下示例演示了一个简单的规则,其中包含一个匹配条件和一个关联操作,用于有条件地返回 HTTP 状态码。

使用 workflow 插件创建路由:

admin-api

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "id": "workflow-route",
    "uri": "/anything/*",
    "plugins": {
      "workflow":{
        "rules":[
          {
            "case":[
              ["uri", "==", "/anything/rejected"]
            ],
            "actions":[
              [
                "return",
                {"code": 403}
              ]
            ]
          }
        ]
      }
    },
    "upstream": {
      "type": "roundrobin",
      "nodes": {
        "httpbin.org": 1
      }
    }
  }'

adc

adc.yaml
services:
  - name: httpbin
    routes:
      - uris:
          - /anything/*
        name: workflow-route
        plugins:
          workflow:
            rules:
              - case:
                  - ["uri", "==", "/anything/rejected"]
                actions:
                  - - return
                    - code: 403
    upstream:
      type: roundrobin
      nodes:
        - host: httpbin.org
          port: 80
          weight: 1

将配置同步到网关:

adc sync -f adc.yaml

aic

gateway-api

workflow-ic.yaml
apiVersion: v1
kind: Service
metadata:
  namespace: aic
  name: httpbin-external-domain
spec:
  type: ExternalName
  externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
  namespace: aic
  name: workflow-plugin-config
spec:
  plugins:
    - name: workflow
      config:
        rules:
          - case:
              - ["uri", "==", "/anything/rejected"]
            actions:
              - - return
                - code: 403
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  namespace: aic
  name: workflow-route
spec:
  parentRefs:
    - name: apisix
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /anything/
      filters:
        - type: ExtensionRef
          extensionRef:
            group: apisix.apache.org
            kind: PluginConfig
            name: workflow-plugin-config
      backendRefs:
        - name: httpbin-external-domain
          port: 80

apisix-crd

workflow-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
  namespace: aic
  name: httpbin-external-domain
spec:
  ingressClassName: apisix
  externalNodes:
  - type: Domain
    name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  namespace: aic
  name: workflow-route
spec:
  ingressClassName: apisix
  http:
    - name: workflow-route
      match:
        paths:
          - /anything/*
      upstreams:
      - name: httpbin-external-domain
      plugins:
      - name: workflow
        enable: true
        config:
          rules:
            - case:
                - ["uri", "==", "/anything/rejected"]
              actions:
                - - return
                  - code: 403

将配置应用到集群:

kubectl apply -f workflow-ic.yaml

发送与任何规则都不匹配的请求:

curl -i "http://127.0.0.1:9080/anything/anything"

您应该收到 HTTP/1.1 200 OK 响应。

发送与配置的规则匹配的请求:

curl -i "http://127.0.0.1:9080/anything/rejected"

您应该收到以下 HTTP/1.1 403 Forbidden 响应:

{"error_msg":"rejected by workflow"}

通过 URI 和查询参数有条件地应用速率限制

以下示例演示了一条具有两个匹配条件和一个关联操作的规则,用于有条件地限制请求速率。

使用 workflow 插件创建路由:

admin-api

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "id": "workflow-route",
    "uri": "/anything/*",
    "plugins":{
      "workflow":{
        "rules":[
          {
            "case":[
              ["uri", "==", "/anything/rate-limit"],
              ["arg_env", "==", "v1"]
            ],
            "actions":[
              [
                "limit-count",
                {
                  "count":1,
                  "time_window":60,
                  "rejected_code":429
                }
              ]
            ]
          }
        ]
      }
    },
    "upstream": {
      "type": "roundrobin",
      "nodes": {
        "httpbin.org": 1
      }
    }
  }'

adc

adc.yaml
services:
  - name: httpbin
    routes:
      - uris:
          - /anything/*
        name: workflow-route
        plugins:
          workflow:
            rules:
              - case:
                  - ["uri", "==", "/anything/rate-limit"]
                  - ["arg_env", "==", "v1"]
                actions:
                  - - limit-count
                    - count: 1
                      time_window: 60
                      rejected_code: 429
    upstream:
      type: roundrobin
      nodes:
        - host: httpbin.org
          port: 80
          weight: 1

将配置同步到网关:

adc sync -f adc.yaml

aic

gateway-api

workflow-ic.yaml
apiVersion: v1
kind: Service
metadata:
  namespace: aic
  name: httpbin-external-domain
spec:
  type: ExternalName
  externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
  namespace: aic
  name: workflow-plugin-config
spec:
  plugins:
    - name: workflow
      config:
        rules:
          - case:
              - ["uri", "==", "/anything/rate-limit"]
              - ["arg_env", "==", "v1"]
            actions:
              - - limit-count
                - count: 1
                  time_window: 60
                  rejected_code: 429
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  namespace: aic
  name: workflow-route
spec:
  parentRefs:
    - name: apisix
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /anything/
      filters:
        - type: ExtensionRef
          extensionRef:
            group: apisix.apache.org
            kind: PluginConfig
            name: workflow-plugin-config
      backendRefs:
        - name: httpbin-external-domain
          port: 80

apisix-crd

workflow-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
  namespace: aic
  name: httpbin-external-domain
spec:
  ingressClassName: apisix
  externalNodes:
  - type: Domain
    name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  namespace: aic
  name: workflow-route
spec:
  ingressClassName: apisix
  http:
    - name: workflow-route
      match:
        paths:
          - /anything/*
      upstreams:
      - name: httpbin-external-domain
      plugins:
      - name: workflow
        enable: true
        config:
          rules:
            - case:
                - ["uri", "==", "/anything/rate-limit"]
                - ["arg_env", "==", "v1"]
              actions:
                - - limit-count
                  - count: 1
                    time_window: 60
                    rejected_code: 429

将配置应用到集群:

kubectl apply -f workflow-ic.yaml

生成两个符合规则的连续请求:

curl -i "http://127.0.0.1:9080/anything/rate-limit?env=v1"

您应该收到 HTTP/1.1 200 OK 响应和 HTTP 429 Too Many Requests 响应。

生成不符合条件的请求:

curl -i "http://127.0.0.1:9080/anything/anything?env=v1"

您应该收到所有请求的 HTTP/1.1 200 OK 响应,因为它们不受速率限制。

按消费者有条件地应用速率限制

以下示例演示了如何配置插件以根据以下规范执行速率限制:

  • 消费者 john 在 30 秒内应有 5 个请求的配额
  • 消费者 jane 在 30 秒内应有 3 个请求的配额
  • 所有其他消费者在 30 秒内应有 2 个请求的配额

虽然此示例将使用 key-auth,但您可以轻松地将其替换为其他身份验证插件。

admin-api

创建消费者 john

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "username": "john"
  }'

为消费者创建 key-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/john/credentials" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "id": "cred-john-key-auth",
    "plugins": {
      "key-auth": {
        "key": "john-key"
      }
    }
  }'

创建第二个消费者 jane

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "username": "jane"
  }'

为消费者创建 key-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/jane/credentials" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "id": "cred-jane-key-auth",
    "plugins": {
      "key-auth": {
        "key": "jane-key"
      }
    }
  }'

创建第三个消费者 jimmy

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "username": "jimmy"
  }'

为消费者创建 key-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/jimmy/credentials" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "id": "cred-jimmy-key-auth",
    "plugins": {
      "key-auth": {
        "key": "jimmy-key"
      }
    }
  }'

使用 workflowkey-auth 插件创建路由,并设置所需的速率限制规则:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "id": "workflow-route",
    "uri": "/anything",
    "plugins":{
      "key-auth": {},
      "workflow":{
        "rules":[
          {
            "actions": [
              [
                "limit-count",
                {
                  "count": 5,
                  "key": "consumer_john",
                  "key_type": "constant",
                  "rejected_code": 429,
                  "time_window": 30,
                  "policy": "local"
                }
              ]
            ],
            "case": [
              [
                "consumer_name",
                "==",
                "john"
              ]
            ]
          },
          {
            "actions": [
              [
                "limit-count",
                {
                  "count": 3,
                  "key": "consumer_jane",
                  "key_type": "constant",
                  "rejected_code": 429,
                  "time_window": 30,
                  "policy": "local"
                }
              ]
            ],
            "case": [
              [
                "consumer_name",
                "==",
                "jane"
              ]
            ]
          },
          {
            "actions": [
              [
                "limit-count",
                {
                  "count": 2,
                  "key": "$consumer_name",
                  "key_type": "var",
                  "rejected_code": 429,
                  "time_window": 30,
                  "policy": "local"
                }
              ]
            ]
          }
        ]
      }
    },
    "upstream": {
      "type": "roundrobin",
      "nodes": {
        "httpbin.org": 1
      }
    }
  }'

adc

创建三个消费者以及启用按消费者速率限制的路由:

adc.yaml
consumers:
  - username: john
    credentials:
      - name: key-auth
        type: key-auth
        config:
          key: john-key
  - username: jane
    credentials:
      - name: key-auth
        type: key-auth
        config:
          key: jane-key
  - username: jimmy
    credentials:
      - name: key-auth
        type: key-auth
        config:
          key: jimmy-key
services:
  - name: httpbin
    routes:
      - uris:
          - /anything
        name: workflow-route
        plugins:
          key-auth: {}
          workflow:
            rules:
              - case:
                  - ["consumer_name", "==", "john"]
                actions:
                  - - limit-count
                    - count: 5
                      key: consumer_john
                      key_type: constant
                      rejected_code: 429
                      time_window: 30
                      policy: local
              - case:
                  - ["consumer_name", "==", "jane"]
                actions:
                  - - limit-count
                    - count: 3
                      key: consumer_jane
                      key_type: constant
                      rejected_code: 429
                      time_window: 30
                      policy: local
              - actions:
                  - - limit-count
                    - count: 2
                      key: "$consumer_name"
                      key_type: var
                      rejected_code: 429
                      time_window: 30
                      policy: local
    upstream:
      type: roundrobin
      nodes:
        - host: httpbin.org
          port: 80
          weight: 1

将配置同步到网关:

adc sync -f adc.yaml

aic

创建三个消费者以及启用按消费者速率限制的路由。当使用 Ingress Controller 配置消费者时,消费者名称以 namespace_consumername 格式生成。因此,workflow 插件中的 consumer_name 逻辑应以此格式匹配消费者名称。

gateway-api

workflow-ic.yaml
apiVersion: apisix.apache.org/v1alpha1
kind: Consumer
metadata:
  namespace: aic
  name: john
spec:
  gatewayRef:
    name: apisix
  credentials:
    - type: key-auth
      name: primary-key
      config:
        key: john-key
---
apiVersion: apisix.apache.org/v1alpha1
kind: Consumer
metadata:
  namespace: aic
  name: jane
spec:
  gatewayRef:
    name: apisix
  credentials:
    - type: key-auth
      name: primary-key
      config:
        key: jane-key
---
apiVersion: apisix.apache.org/v1alpha1
kind: Consumer
metadata:
  namespace: aic
  name: jimmy
spec:
  gatewayRef:
    name: apisix
  credentials:
    - type: key-auth
      name: primary-key
      config:
        key: jimmy-key
---
apiVersion: v1
kind: Service
metadata:
  namespace: aic
  name: httpbin-external-domain
spec:
  type: ExternalName
  externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
  namespace: aic
  name: workflow-plugin-config
spec:
  plugins:
    - name: key-auth
      config:
        _meta:
          disable: false
    - name: workflow
      config:
        rules:
          - case:
              - ["consumer_name", "==", "aic_john"]
            actions:
              - - limit-count
                - count: 5
                  key: consumer_john
                  key_type: constant
                  rejected_code: 429
                  time_window: 30
                  policy: local
          - case:
              - ["consumer_name", "==", "aic_jane"]
            actions:
              - - limit-count
                - count: 3
                  key: consumer_jane
                  key_type: constant
                  rejected_code: 429
                  time_window: 30
                  policy: local
          - actions:
              - - limit-count
                - count: 2
                  key: "$consumer_name"
                  key_type: var
                  rejected_code: 429
                  time_window: 30
                  policy: local
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  namespace: aic
  name: workflow-route
spec:
  parentRefs:
    - name: apisix
  rules:
    - matches:
        - path:
            type: Exact
            value: /anything
      filters:
        - type: ExtensionRef
          extensionRef:
            group: apisix.apache.org
            kind: PluginConfig
            name: workflow-plugin-config
      backendRefs:
        - name: httpbin-external-domain
          port: 80

apisix-crd

workflow-ic.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixConsumer
metadata:
  namespace: aic
  name: john
spec:
  ingressClassName: apisix
  authParameter:
    keyAuth:
      value:
        key: john-key
---
apiVersion: apisix.apache.org/v2
kind: ApisixConsumer
metadata:
  namespace: aic
  name: jane
spec:
  ingressClassName: apisix
  authParameter:
    keyAuth:
      value:
        key: jane-key
---
apiVersion: apisix.apache.org/v2
kind: ApisixConsumer
metadata:
  namespace: aic
  name: jimmy
spec:
  ingressClassName: apisix
  authParameter:
    keyAuth:
      value:
        key: jimmy-key
---
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
  namespace: aic
  name: httpbin-external-domain
spec:
  ingressClassName: apisix
  externalNodes:
  - type: Domain
    name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
  namespace: aic
  name: workflow-route
spec:
  ingressClassName: apisix
  http:
    - name: workflow-route
      match:
        paths:
          - /anything
      upstreams:
      - name: httpbin-external-domain
      plugins:
      - name: key-auth
        enable: true
      - name: workflow
        enable: true
        config:
          rules:
            - case:
                - ["consumer_name", "==", "aic_john"]
              actions:
                - - limit-count
                  - count: 5
                    key: consumer_john
                    key_type: constant
                    rejected_code: 429
                    time_window: 30
                    policy: local
            - case:
                - ["consumer_name", "==", "aic_jane"]
              actions:
                - - limit-count
                  - count: 3
                    key: consumer_jane
                    key_type: constant
                    rejected_code: 429
                    time_window: 30
                    policy: local
            - actions:
                - - limit-count
                  - count: 2
                    key: "$consumer_name"
                    key_type: var
                    rejected_code: 429
                    time_window: 30
                    policy: local

将配置应用到集群:

kubectl apply -f workflow-ic.yaml

为了验证,请使用 john 的密钥发送 6 个连续请求:

resp=$(seq 6 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: john-key' -o /dev/null -s -w "%{http_code}\n") && \
  count_200=$(echo "$resp" | grep "200" | wc -l) && \
  count_429=$(echo "$resp" | grep "429" | wc -l) && \
  echo "200": $count_200, "429": $count_429

您应该看到以下响应,显示在 6 个请求中,5 个请求成功(状态码 200),而其他请求被拒绝(状态码 429)。

200:    5, 429:    1

使用 jane 的密钥发送 6 个连续请求:

resp=$(seq 6 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: jane-key' -o /dev/null -s -w "%{http_code}\n") && \
  count_200=$(echo "$resp" | grep "200" | wc -l) && \
  count_429=$(echo "$resp" | grep "429" | wc -l) && \
  echo "200": $count_200, "429": $count_429

您应该看到以下响应,显示在 6 个请求中,3 个请求成功(状态码 200),而其他请求被拒绝(状态码 429)。

200:    3, 429:    3

使用 jimmy 的密钥发送 3 个连续请求:

resp=$(seq 3 | xargs -I{} curl "http://127.0.0.1:9080/anything" -H 'apikey: jimmy-key' -o /dev/null -s -w "%{http_code}\n") && \
  count_200=$(echo "$resp" | grep "200" | wc -l) && \
  count_429=$(echo "$resp" | grep "429" | wc -l) && \
  echo "200": $count_200, "429": $count_429

您应该看到以下响应,显示在 3 个请求中,2 个请求成功(状态码 200),而其他请求被拒绝(状态码 429)。

200:    2, 429:    1