这是本节可打印的多页视图 点击这里开始打印.

返回常规视图.

网络

1 - 简介

概述

从 v0.5.0 开始,OpenFunction 使用 Kubernetes Ingress 为同步函数提供统一的入口点,并且必须安装 nginx ingress 控制器。

随着 Kubernetes Gateway API 的成熟,我们决定在 OpenFunction v0.7.0 中实现基于 Kubernetes Gateway API 的 OpenFunction Gateway,以替代之前基于 ingress 的域方法。

你可以在这里找到 OpenFunction Gateway 的提案

OpenFunction Gateway 提供了一个更强大、更灵活的函数网关,包括以下特性:

  • 使用户能够以更简单、厂商中立的方式切换到任何支持 Kubernetes Gateway API网关实现,如 Contour、Istio、Apache APISIX、Envoy Gateway(未来)等。

  • 用户可以选择安装默认的网关实现(Contour),然后定义一个新的 gateway.networking.k8s.io,或者使用他们环境中的任何现有网关实现,然后引用现有的 gateway.networking.k8s.io

  • 允许用户自定义他们自己的函数访问模式,如 hostTemplate: "{{.Name}}.{{.Namespace}}.{{.Domain}}" 用于基于主机的访问。

  • 允许用户自定义他们自己的函数访问模式,如 pathTemplate: "{{.Namespace}}/{{.Name}}" 用于基于路径的访问。

  • 允许用户在函数定义中自定义每个函数的路由规则(基于主机、基于路径或两者都有),如果没有定义自定义的路由规则,将为每个函数提供默认的路由规则。

  • 直接将流量发送到 Knative 服务修订版,而不再通过 Knative 自己的网关。从 OpenFunction 0.7.0 开始,你只需要 OpenFunction Gateway 就可以访问 OpenFunction 同步函数,如果你不需要直接访问 Knative 服务,你可以忽略 Knative 的域配置错误。

  • 在函数修订版之间分割流量(未来)

下图说明了客户端流量如何通过 OpenFunction Gateway,然后直接到达函数:

2 - 网关

深入理解 OpenFunction 网关

OpenFunction 网关由 Kubernetes 网关支持,定义了用户如何访问同步函数。

每当创建一个 OpenFunction 网关 时,网关控制器将:

  • 如果 gatewaySpec.listeners 中没有,将添加一个名为 ofn-http-internal 的默认监听器。

  • 根据 domainclusterDomain 生成 gatewaySpec.listeners.[*].hostname

  • gatewaySpec.listenters 注入到 OpenFunction 网关gatewayRef 定义的现有 Kubernetes 网关 中。

  • 根据 OpenFunction 网关gatewayDef 中的 gatewaySpec.listenters 字段创建一个新的 Kubernetes 网关

  • 创建一个名为 gateway.openfunction.svc.cluster.local 的服务,该服务定义了同步函数的统一入口。

部署 OpenFunction 网关 后,你将能够在 OpenFunction 网关 状态中找到 Kubernetes 网关 和其 listeners 的状态:

status:
  conditions:
  - message: Gateway is scheduled
    reason: Scheduled
    status: "True"
    type: Scheduled
  - message: Valid Gateway
    reason: Valid
    status: "True"
    type: Ready
  listeners:
  - attachedRoutes: 0
    conditions:
    - message: Valid listener
      reason: Ready
      status: "True"
      type: Ready
    name: ofn-http-internal
    supportedKinds:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
  - attachedRoutes: 0
    conditions:
    - message: Valid listener
      reason: Ready
      status: "True"
      type: Ready
    name: ofn-http-external
    supportedKinds:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute

默认的 OpenFunction 网关

OpenFunction 网关 使用 Contour 作为默认的 Kubernetes 网关 实现。 安装 OpenFunction 后,将自动创建以下 OpenFunction 网关

apiVersion: networking.openfunction.io/v1alpha1
kind: Gateway
metadata:
  name: openfunction
  namespace: openfunction
spec:
  domain: ofn.io
  clusterDomain: cluster.local
  hostTemplate: "{{.Name}}.{{.Namespace}}.{{.Domain}}"
  pathTemplate: "{{.Namespace}}/{{.Name}}"
  httpRouteLabelKey: "app.kubernetes.io/managed-by"
  gatewayRef:
    name: contour
    namespace: projectcontour
  gatewaySpec:
    listeners:
      - name: ofn-http-internal
        hostname: "*.cluster.local"
        protocol: HTTP
        port: 80
        allowedRoutes:
          namespaces:
            from: All
      - name: ofn-http-external
        hostname: "*.ofn.io"
        protocol: HTTP
        port: 80
        allowedRoutes:
          namespaces:
            from: All

你可以像下面这样自定义默认的 OpenFunction 网关

kubectl edit gateway openfunction -n openfunction

切换到不同的 Kubernetes 网关

你可以以更简单、厂商中立的方式切换到任何支持 Kubernetes 网关 API网关实现,如 Contour、Istio、Apache APISIX、Envoy Gateway(未来)等。

这里 你可以找到更多详细信息。

多个 OpenFunction 网关

对于 OpenFunction,多个 Gateway 没有意义,我们目前只支持一个 OpenFunction Gateway

3 - 路由

什么是 Route

RouteFunction 定义的一部分。Route 定义了来自 Gateway 监听器的流量如何路由到函数。

RouteGatewayRef 中指定了它将附加到的 Gateway,使其能够从 Gateway 接收流量。

一旦创建了同步 Function,函数控制器将:

  • 查找 openfunction 命名空间中名为 openfunctionGateway,然后如果函数中没有定义 route.gatewayRef,则附加到此 Gateway
  • 如果函数中没有定义 route.hostnames,则根据 Gateway.spec.hostTemplate 自动生成 route.hostnames
  • 如果函数中没有定义 route.rules,则根据路径 / 自动生成 route.rules
  • 根据 Route 创建一个 HTTPRoute 自定义资源。BackendRefs 将自动链接到相应的 Knative 服务修订版,并将 HTTPRouteLabelKey 标签添加到此 HTTPRoute
  • 创建服务 {{.Name}}.{{.Namespace}}.svc.cluster.local,此服务定义了从集群内部访问函数的入口。
  • 如果 route.gatewayRef 引用的 Gateway 发生变化,将更新 HTTPRoute

部署同步 Function 后,你将能够在 Function 的状态字段中找到 Function 地址和 Route 状态,例如:

status:
  addresses:
    - type: External
      value: http://function-sample-serving-only.default.ofn.io/
    - type: Internal
      value: http://function-sample-serving-only.default.svc.cluster.local/
  build:
    resourceHash: "14903236521345556383"
    state: Skipped
  route:
    conditions:
      - message: Valid HTTPRoute
        reason: Valid
        status: "True"
        type: Accepted
    hosts:
      - function-sample-serving-only.default.ofn.io
      - function-sample-serving-only.default.svc.cluster.local
    paths:
      - type: PathPrefix
        value: /
  serving:
    lastSuccessfulResourceRef: serving-znk54
    resourceHash: "10715302888241374768"
    resourceRef: serving-znk54
    service: serving-znk54-ksvc-nbg6f
    state: Running

基于主机的路由

基于主机 是默认的路由模式。当 route.hostnames 未定义时, 将根据 gateway.spec.hostTemplate 自动生成 route.hostnames。 如果 route.rules 未定义,将根据路径 / 自动生成 route.rules

kubectl apply -f - <<EOF
apiVersion: core.openfunction.io/v1beta2
kind: Function
metadata:
  name: function-sample
spec:
  version: "v1.0.0"
  image: "openfunctiondev/v1beta1-http:latest"
  serving:
    template:
      containers:
        - name: function
          imagePullPolicy: Always
    triggers:
      http:
        route:
          gatewayRef:
            name: openfunction
            namespace: openfunction
EOF

如果你正在使用默认的 OpenFunction Gateway,函数的外部地址将如下:

http://function-sample.default.ofn.io/

基于路径的路由

如果你在函数中定义了 route.hostnames,将根据 gateway.spec.pathTemplate 自动生成 route.rules

kubectl apply -f - <<EOF
apiVersion: core.openfunction.io/v1beta2
kind: Function
metadata:
  name: function-sample
spec:
  version: "v1.0.0"
  image: "openfunctiondev/v1beta1-http:latest"
  serving:
    template:
      containers:
        - name: function
          imagePullPolicy: Always
    triggers:
      http:
        route:
          gatewayRef:
            name: openfunction
            namespace: openfunction
           hostnames:
           - "sample.ofn.io"
EOF

如果你正在使用默认的 OpenFunction Gateway,函数的外部地址将如下:

http://sample.default.ofn.io/default/function-sample/

基于主机和路径的路由

你可以同时定义主机名和路径,以自定义流量应如何路由到你的函数。

kubectl apply -f - <<EOF
apiVersion: core.openfunction.io/v1beta2
kind: Function
metadata:
  name: function-sample
spec:
  version: "v1.0.0"
  image: "openfunctiondev/v1beta1-http:latest"
  serving:
    template:
      containers:
        - name: function
          imagePullPolicy: Always
    triggers:
      http:
        route:
          gatewayRef:
            name: openfunction
            namespace: openfunction
          rules:
            - matches:
                - path:
                    type: PathPrefix
                    value: /v2/foo
          hostnames:
          - "sample.ofn.io"
EOF

如果你正在使用默认的 OpenFunction Gateway,函数的外部地址将如下:

http://sample.default.ofn.io/v2/foo/

4 - 函数入口

有几种方法可以访问同步函数。我们将在以下部分详细说明。

本文档假设你正在使用默认的 OpenFunction 网关 并且你有一个名为 function-sample 的同步函数。

从集群内部访问函数

通过内部地址访问函数

OpenFunction 会为每个同步 Function 创建此服务:{{.Name}}.{{.Namespace}}.svc.cluster.local。此服务将用于提供函数的内部地址。

通过运行以下命令获取 Function 内部地址:

export FUNC_INTERNAL_ADDRESS=$(kubectl get function function-sample -o=jsonpath='{.status.addresses[?(@.type=="Internal")].value}')

这个地址提供了在集群内部访问函数的默认方法,适合用作 EventSourcesink.url

在 pod 中使用 curl 访问 Function

kubectl run --rm ofn-test -i --tty --image=radial/busyboxplus:curl -- curl -sv $FUNC_INTERNAL_ADDRESS

从集群外部访问函数

通过 Kubernetes 网关的 IP 地址访问函数

获取 Kubernetes 网关的 ip 地址:

export IP=$(kubectl get node -l "! node.kubernetes.io/exclude-from-external-load-balancers" -o=jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')

获取函数的 HOST 和 PATH:

export FUNC_HOST=$(kubectl get function function-sample -o=jsonpath='{.status.route.hosts[0]}')
export FUNC_PATH=$(kubectl get function function-sample -o=jsonpath='{.status.route.paths[0].value}')

直接使用 curl 访问 Function

curl -sv -HHOST:$FUNC_HOST http://$IP$FUNC_PATH

通过外部地址访问函数

要通过外部地址访问同步函数,你需要先配置 DNS。Magic DNS 或真实 DNS 都可以:

  • Magic DNS

    获取 Kubernetes 网关的 ip 地址:

    export IP=$(kubectl get node -l "! node.kubernetes.io/exclude-from-external-load-balancers" -o=jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
    

    用 Magic DNS 替换 OpenFunction 网关中定义的域:

    export DOMAIN="$IP.sslip.io"
    kubectl patch gateway.networking.openfunction.io/openfunction -n openfunction --type merge --patch '{"spec": {"domain": "'$DOMAIN'"}}'
    

    然后,你可以在 Function 的状态字段中看到 Function 外部地址:

    kubectl get function function-sample -oyaml
    
    status:
      addresses:
      - type: External
        value: http://function-sample.default.172.31.73.53.sslip.io/
      - type: Internal
        value: http://function-sample.default.svc.cluster.local/
      build:
        resourceHash: "14903236521345556383"
        state: Skipped
      route:
        conditions:
        - message: Valid HTTPRoute
          reason: Valid
          status: "True"
          type: Accepted
        hosts:
        - function-sample.default.172.31.73.53.sslip.io
        - function-sample.default.svc.cluster.local
        paths:
        - type: PathPrefix
          value: /
      serving:
        lastSuccessfulResourceRef: serving-t56fq
        resourceHash: "2638289828407595605"
        resourceRef: serving-t56fq
        service: serving-t56fq-ksvc-bv8ng
        state: Running
    
  • Real DNS

    如果你有一个外部 IP 地址,你可以配置一个通配符 A 记录作为你的域:

    # 这里 example.com 是 OpenFunction 网关中定义的域
    *.example.com == A <external-ip>
    

    如果你有一个 CNAME,你可以配置一个 CNAME 记录作为你的域:

    # 这里 example.com 是 OpenFunction 网关中定义的域
    *.example.com == CNAME <external-name>
    

    用你上面配置的域替换 OpenFunction 网关中定义的域:

    export DOMAIN="example.com"
    kubectl patch gateway.networking.openfunction.io/openfunction -n openfunction --type merge --patch '{"spec": {"domain": "'$DOMAIN'"}}'
    

    然后,你可以在 Function 的状态字段中看到 Function 外部地址:

    kubectl get function function-sample -oyaml
    
    status:
      addresses:
      - type: External
        value: http://function-sample.default.example.com/
      - type: Internal
        value: http://function-sample.default.svc.cluster.local/
      build:
        resourceHash: "14903236521345556383"
        state: Skipped
      route:
        conditions:
        - message: Valid HTTPRoute
          reason: Valid
          status: "True"
          type: Accepted
        hosts:
        - function-sample.default.example.com
        - function-sample.default.svc.cluster.local
        paths:
        - type: PathPrefix
          value: /
      serving:
        lastSuccessfulResourceRef: serving-t56fq
        resourceHash: "2638289828407595605"
        resourceRef: serving-t56fq
        service: serving-t56fq-ksvc-bv8ng
        state: Running
    

然后,你可以通过运行以下命令获取 Function 外部地址:

export FUNC_EXTERNAL_ADDRESS=$(kubectl get function function-sample -o=jsonpath='{.status.addresses[?(@.type=="External")].value}')

现在,你可以直接使用 curl 访问 Function

curl -sv $FUNC_EXTERNAL_ADDRESS