← Back to Index

OpenShift Serverless Adoption Guide

Executive Summary

客户目前在 AWS 上运行大量 Lambda 函数,每个云厂商都需要单独的 CI/CD 流程。这带来了巨大的运维开销和厂商锁定风险。通过采用 Red Hat OpenShift Serverless(基于 Knative),客户可以将所有 serverless 工作负载统一到一个平台,使用一套 CI/CD 流程,可移植地部署到 AWS(ROSA)、Azure(ARO)、阿里云和 GCP —— 同时利用 scale-to-zero 和专用机器池来最大化成本节约。

实测验证摘要

本方案已在 ROSA HCP 4.20.21 集群上完成端到端验证,与 AWS Lambda 进行了直接对比测试:

指标 AWS Lambda OpenShift Serverless (Knative)
冷启动延迟 ~292ms ~1.67s
热请求延迟 ~44-55ms ~28-30ms
Scale-to-Zero 自动(~15min) 自动(~90s,可配置)
部署复杂度 11 个 CLI 命令,3 个 AWS 服务 1 个 oc apply 命令
多云支持 仅 AWS ROSA / ARO / OCP(任意云)
CI/CD 管道 每个云单独维护 一套管道适配所有集群

此外,针对客户特别关注的 工作流编排 能力,我们还对比了 SonataFlow (Serverless Logic)AWS Step Functions

指标 AWS Step Functions SonataFlow on ROSA
工作流执行延迟 ~2ms (Express) ~46ms (热请求)
首次请求 ~962ms (含 CLI 开销) ~220ms
工作流规范 ASL (AWS 专有) CNCF Serverless Workflow (开放标准)
多云可移植 ❌ 仅 AWS ✅ 任何 OCP 集群
K8s 原生 ✅ CRD + Operator

详细测试步骤和完整命令输出见 steps.md


1. 架构概览

1.1 当前状态 vs. 目标状态

┌─────────────────────────────────────────────────────────────────────────────┐
│                          当前状态                                           │
│                                                                             │
│   ┌──────────┐    ┌──────────────┐                                          │
│   │ AWS      │    │ CI/CD for    │   ← 每个云单独的 CI/CD 管道               │
│   │ Lambda   │◄───│ AWS Lambda   │   ← AWS 专属 SDK, 触发器, IAM            │
│   │ (多个)   │    │ (SAM/CDK)    │                                          │
│   └──────────┘    └──────────────┘                                          │
│                                                                             │
│   ┌──────────┐    ┌──────────────┐                                          │
│   │ Azure    │    │ CI/CD for    │   ← 另一套单独的管道                      │
│   │ Functions│◄───│ Azure Func   │   ← Azure 专属 bindings, triggers        │
│   │ (未来)   │    │ (func CLI)   │                                          │
│   └──────────┘    └──────────────┘                                          │
│                                                                             │
│   问题: N 个云 × M 个函数 = N×M 条 CI/CD 管道                              │
└─────────────────────────────────────────────────────────────────────────────┘

                              ▼  迁移  ▼

┌─────────────────────────────────────────────────────────────────────────────┐
│                          目标状态                                           │
│                                                                             │
│              ┌──────────────────────────────┐                                │
│              │  一套统一的 CI/CD Pipeline     │                                │
│              │  (Tekton / OpenShift Pipelines │                               │
│              │   + OpenShift GitOps/ArgoCD)   │                                │
│              └──────────┬───────────────────┘                                │
│                         │                                                    │
│              ┌──────────▼───────────────────┐                                │
│              │  容器镜像 (OCI)               │                                │
│              │  + Knative Service YAML       │                                │
│              └──────────┬───────────────────┘                                │
│                         │                                                    │
│         ┌───────────────┼───────────────────────┐                            │
│         ▼               ▼                       ▼                            │
│   ┌──────────┐    ┌──────────┐           ┌──────────┐                        │
│   │  ROSA    │    │  ARO     │           │  OCP on  │                        │
│   │  (AWS)   │    │  (Azure) │           │  Ali/GCP │                        │
│   │ Knative  │    │ Knative  │           │ Knative  │                        │
│   │ Serving  │    │ Serving  │           │ Serving  │                        │
│   └──────────┘    └──────────┘           └──────────┘                        │
│                                                                             │
│   结果: 1 条管道 × M 个函数 = M 条 CI/CD 管道(云无关)                      │
└─────────────────────────────────────────────────────────────────────────────┘

1.2 详细组件架构

┌─────────────────────────────────────────────────────────────────────────────────┐
│                    OpenShift 集群 (ROSA / ARO / OCP)                             │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────────┐ │
│  │                     控制面 (Hosted CP / Master Nodes)                      │ │
│  │   ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                     │ │
│  │   │ API Server   │  │ etcd         │  │ Controllers  │                     │ │
│  │   └──────────────┘  └──────────────┘  └──────────────┘                     │ │
│  └─────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────────┐ │
│  │              Serverless 基础组件 (运行在 Worker / Infra 节点)              │ │
│  │   ┌─────────────────┐  ┌──────────────────────┐  ┌──────────────────────┐  │ │
│  │   │ Knative Serving │  │ Knative Eventing     │  │ Kourier Ingress      │  │ │
│  │   │ Controller      │  │ Controller           │  │ Gateway              │  │ │
│  │   │ Activator       │  │ PingSource Adapter   │  │ (自动 TLS 路由)      │  │ │
│  │   │ Autoscaler      │  │ IMC Controller       │  │                      │  │ │
│  │   └─────────────────┘  └──────────────────────┘  └──────────────────────┘  │ │
│  └─────────────────────────────────────────────────────────────────────────────┘ │
│                                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────────────┐ │
│  │         专用 Serverless 机器池 (自动扩缩 0 → N)                           │ │
│  │                                                                             │ │
│  │   Node Taint: serverless=true:NoSchedule                                    │ │
│  │   Node Label: node-role.kubernetes.io/serverless=""                          │ │
│  │                                                                             │ │
│  │   ┌─────────┐ ┌─────────┐ ┌─────────┐         ┌─────────┐                 │ │
│  │   │ Knative │ │ Knative │ │ Knative │  . . .  │ Knative │                 │ │
│  │   │Service A│ │Service B│ │Service C│         │Service N│                 │ │
│  │   │(pods)   │ │(pods)   │ │(pods)   │         │(pods)   │                 │ │
│  │   │ scale   │ │ scale   │ │ scale   │         │ scale   │                 │ │
│  │   │ 1→100   │ │ 0→50   │ │ to zero │         │ to zero │                 │ │
│  │   └─────────┘ └─────────┘ └─────────┘         └─────────┘                 │ │
│  │                                                                             │ │
│  │   所有 pod 缩零 → 集群自动缩容移除节点 → 计算成本 $0                       │ │
│  └─────────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────┘

2. 实施步骤

Phase 1: 安装 OpenShift Serverless(第 1-2 周)

Step 1.1: 安装 OpenShift Serverless Operator

# 创建 Operator 所需的 namespace、OperatorGroup 和 Subscription
cat <<EOF | oc apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: openshift-serverless
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  name: serverless-operators
  namespace: openshift-serverless
spec: {}
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: serverless-operator
  namespace: openshift-serverless
spec:
  channel: stable
  installPlanApproval: Automatic
  name: serverless-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace
EOF

# 验证 Operator 安装完成(约 60 秒)
oc get csv -n openshift-serverless
# 预期输出: serverless-operator.v1.37.1 ... Succeeded

实测结果: Serverless Operator v1.37.1 在约 60 秒内安装成功。

官方文档: 安装 OpenShift Serverless

Step 1.2: 安装 Knative Serving

cat <<EOF | oc apply -f -
apiVersion: operator.knative.dev/v1beta1
kind: KnativeServing
metadata:
  name: knative-serving
  namespace: knative-serving
spec:
  ingress:
    kourier:
      enabled: true
  config:
    network:
      ingress-class: kourier.ingress.networking.knative.dev
    autoscaler:
      enable-scale-to-zero: "true"
      scale-to-zero-grace-period: "30s"
      stable-window: "60s"
    defaults:
      revision-timeout-seconds: "300"
EOF

# 等待就绪(约 50 秒)
oc wait --for=condition=Ready knativeserving/knative-serving \
  -n knative-serving --timeout=300s

实测结果: KnativeServing (Knative 1.17) 在约 50 秒内就绪,自动部署了 activator、autoscaler、controller、webhook 和 Kourier ingress gateway。

官方文档: Knative Serving 配置

Step 1.3: 安装 Knative Eventing

cat <<EOF | oc apply -f -
apiVersion: operator.knative.dev/v1beta1
kind: KnativeEventing
metadata:
  name: knative-eventing
  namespace: knative-eventing
spec:
  config:
    default-ch-webhook:
      default-ch-config: |
        clusterDefault:
          apiVersion: messaging.knative.dev/v1
          kind: InMemoryChannel
EOF

# 等待就绪(约 90 秒)
oc wait --for=condition=Ready knativeeventing/knative-eventing \
  -n knative-eventing --timeout=300s

实测结果: KnativeEventing (1.17) 在约 90 秒内就绪。

官方文档: Knative Eventing 配置


Phase 2: 专用 Serverless 机器池(第 2-3 周)

Step 2.1: 在 ROSA 上创建专用机器池

# 创建支持自动扩缩和 Spot 实例的专用机器池
rosa create machinepool \
  --cluster=<cluster-name> \
  --name=serverless-pool \
  --instance-type=m6a.xlarge \
  --min-replicas=0 \
  --max-replicas=10 \
  --enable-autoscaling \
  --labels="node-role.kubernetes.io/serverless=" \
  --taints="serverless=true:NoSchedule" \
  --use-spot-instances \
  --spot-max-price=on-demand

# 验证机器池
rosa list machinepools --cluster=<cluster-name>

核心成本节约特性:

  • --min-replicas=0: 没有 serverless pod 运行时,节点数为 0
  • --enable-autoscaling: 仅当 Knative pod 被调度时才扩容节点
  • --use-spot-instances: 相比按需实例可节省 60-90% 的成本
  • Knative scale-to-zero: 无流量 → pod 终止 → 节点缩容 → $0 计算成本

Step 2.2: 成本节约流程

  无流量                                               流量到达
  ─────────                                            ──────────

  ┌──────────┐     ┌──────────────┐     ┌──────────────┐
  │ 请求     │     │ Knative      │     │ 机器池       │
  │ 速率 = 0 │────▶│ Scale-to-Zero│────▶│ 节点 = 0     │──── 成本 = $0
  │          │     │ Pods = 0     │     │ (自动缩容)   │
  └──────────┘     └──────────────┘     └──────────────┘

  ┌──────────┐     ┌──────────────┐     ┌──────────────┐     ┌──────────┐
  │ 请求     │     │ Activator    │     │ 集群         │     │ Knative  │
  │ 到达     │────▶│ 缓冲请求     │────▶│ 自动扩容     │────▶│ Pod      │
  │          │     │              │     │ 添加节点     │     │ 启动     │
  └──────────┘     └──────────────┘     └──────────────┘     └──────────┘
                                                                │
                                                                ▼
                                                         ┌──────────────┐
                                                         │ 请求被处理   │
                                                         │ (~1.5-3s     │
                                                         │  冷启动)     │
                                                         └──────────────┘

  时间线:
  ├── 流量停止 ──┤── 15-30s 宽限期 ──┤── 60s 稳定窗口 ──┤── 节点空闲 10m ──┤
  │              │ pods 仍在运行     │ pods 终止         │ 节点被移除       │
  │              │ (可配置)          │ (scale-to-zero)   │ (集群自动缩容)   │

Step 2.3: 配置 Knative Service 使用专用机器池

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: my-function
  namespace: my-project
spec:
  template:
    spec:
      tolerations:
        - key: "serverless"
          operator: "Equal"
          value: "true"
          effect: "NoSchedule"
      nodeSelector:
        node-role.kubernetes.io/serverless: ""
      containers:
        - image: <registry>/<project>/my-function:latest
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 256Mi

官方文档: ROSA 机器池管理


Phase 3: Lambda 到 Knative 迁移(第 3-5 周)

Step 3.1: Lambda 概念映射

AWS Lambda 概念 Knative / OpenShift 等价物
Lambda Function Knative Service (ksvc)
Lambda Handler 容器入口点 / HTTP handler
API Gateway trigger Knative Route(随 ksvc 自动创建)
SQS trigger KafkaSource / SinkBinding + AMQ Streams
S3 trigger SinkBinding via Knative Eventing
Schedule trigger (EventBridge) PingSource
DynamoDB trigger 自定义 Source 或 Change Data Capture
SNS trigger Knative Channel + Subscription
Env variables ConfigMap / Secret 引用
Lambda Layers 多阶段容器构建(共享基础镜像)
Concurrency limit containerConcurrency 字段
Timeout timeoutSeconds 字段
Cold start 优化 minScale ≥ 1(保持 1 个 pod 预热)
Versioning/Alias Knative Revisions + Traffic Splitting
X-Ray tracing OpenTelemetry Collector
CloudWatch logs OpenShift Logging / 集群日志
AWS SAM template Knative Service YAML + Tekton Pipeline
AWS CDK Helm Chart / Kustomize + ArgoCD
aws lambda invoke curl https://<ksvc-route>kn service invoke

Step 3.2: 转换 Lambda 函数为 Knative Service

原始 Lambda 函数 (lambda_function.py):

import json
import time
import os
import platform

COLD_START = True

def lambda_handler(event, context):
    global COLD_START
    was_cold = COLD_START
    COLD_START = False
    
    name = "World"
    qs = event.get("queryStringParameters") or {}
    if isinstance(qs, dict) and qs.get("name"):
        name = qs["name"]
    
    return {
        "statusCode": 200,
        "headers": {"Content-Type": "application/json"},
        "body": json.dumps({
            "message": f"Hello, {name}!",
            "platform": "AWS Lambda",
            "cold_start": was_cold
        })
    }

转换为 Knative 兼容的 HTTP 服务 (app.py):

from flask import Flask, request, jsonify
import os
import time
import platform

app = Flask(__name__)
COLD_START = True

@app.route("/", methods=["GET", "POST"])
def handler():
    global COLD_START
    was_cold = COLD_START
    COLD_START = False
    
    if request.method == "POST":
        event = request.get_json(silent=True) or {}
        name = event.get("name", "World")
    else:
        name = request.args.get("name", "World")
    
    return jsonify({
        "message": f"Hello, {name}!",
        "platform": "OpenShift Serverless (Knative)",
        "cold_start": was_cold,
        "pod_name": os.environ.get("HOSTNAME", "unknown")
    })

if __name__ == "__main__":
    port = int(os.environ.get("PORT", 8080))
    app.run(host="0.0.0.0", port=port)

Dockerfile:

FROM registry.access.redhat.com/ubi9/python-311:latest
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 8080
CMD ["python", "app.py"]

Knative Service YAML (knative-service.yaml):

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: hello-function
  namespace: serverless-demo
  labels:
    app.kubernetes.io/part-of: serverless-functions
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/min-scale: "0"        # 空闲时缩零
        autoscaling.knative.dev/max-scale: "10"        # 最大 pod 数
        autoscaling.knative.dev/target: "50"           # 每 pod 50 并发
        autoscaling.knative.dev/scale-down-delay: "15s"
    spec:
      containerConcurrency: 50
      timeoutSeconds: 300
      containers:
        - image: <registry>/hello-function:latest
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 256Mi
          readinessProbe:
            httpGet:
              path: /
            initialDelaySeconds: 0

实测: 部署后约 10 秒即就绪,自动生成 HTTPS 路由。

# 实测输出
$ oc get ksvc -n serverless-demo
NAME             URL                                                                                     LATESTCREATED          LATESTREADY            READY
hello-function   https://hello-function-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com   hello-function-00001   hello-function-00001   True

# 热请求测试
$ time curl -sk "https://hello-function-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com"
Hi  greeter => '9861675f8845' : 5
real    0m0.030s

$ time curl -sk "https://hello-function-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com"
Hi  greeter => '9861675f8845' : 6
real    0m0.029s

# 验证 Scale-to-Zero(等待约 120 秒后)
$ oc get pods -n serverless-demo
No resources found in serverless-demo namespace.    ← Pod 已被移除

$ oc get revisions -n serverless-demo
NAME                   CONFIG NAME      GENERATION   READY   ACTUAL REPLICAS   DESIRED REPLICAS
hello-function-00001   hello-function   1            True    0                 0
# ✅ Scale-to-Zero 验证成功:ACTUAL REPLICAS = 0

# 冷启动测试(从零扩容)
$ time curl -sk "https://hello-function-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com"
Hi  greeter => '9861675f8845' : 3
real    0m1.668s    ← 冷启动 ~1.67s

$ time curl -sk "https://hello-function-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com"
Hi  greeter => '9861675f8845' : 4
real    0m0.030s    ← 热请求恢复到 ~30ms

Step 3.3: Knative Functions (kn func) — 真正的 Lambda 等价开发体验

Phase 3.2 使用了一个预构建的容器镜像直接部署为 Knative Service。但 AWS Lambda 的开发体验是 “只写函数代码,不关心容器”

kn func (Knative Functions) 提供了完全等价的体验:只写函数代码 → 自动构建镜像 (S2I) → 部署为 Knative Service,无需 Dockerfile。

Step 1: 创建函数项目

# 安装 kn CLI(OpenShift Serverless 1.37 配套版本)
$ curl -sL https://mirror.openshift.com/pub/openshift-v4/clients/serverless/1.17.0/kn-linux-amd64.tar.gz \
  | tar xz -C /tmp/
$ /tmp/kn version
Version:      v1.17.0
Build Date:   2025-04-22 16:39:02

# 创建 Python 函数项目(自动生成骨架代码)
$ /tmp/kn func create -l python hello-func
Created python function in /tmp/hello-func

$ ls /tmp/hello-func/
.funcignore  func.yaml  function/  requirements.txt
# 注意:没有 Dockerfile!使用 S2I (Source-to-Image) 自动构建

Step 2: 编写函数代码

# function/func.py — ASGI 协议,与 Lambda handler 等价
import json, os, time

COLD_START = True

def new():
    return Function()

class Function:
    async def handle(self, scope, receive, send):
        global COLD_START
        was_cold = COLD_START
        COLD_START = False
        start = time.time()

        # 读取请求 body
        body = b""
        while True:
            msg = await receive()
            body += msg.get("body", b"")
            if not msg.get("more_body"): break

        # 解析参数(支持 query string 和 JSON body)
        name = "World"
        qs = scope.get("query_string", b"").decode()
        for param in qs.split("&"):
            if param.startswith("name="): name = param.split("=", 1)[1]; break
        if body:
            try: data = json.loads(body); name = data.get("name", name)
            except: pass

        # 构建响应
        elapsed = (time.time() - start) * 1000
        resp = json.dumps({
            "message": f"Hello, {name}!",
            "platform": "OpenShift Serverless Function (kn func)",
            "cold_start": was_cold,
            "processing_time_ms": round(elapsed, 2),
            "pod_name": os.environ.get("HOSTNAME", "unknown")
        })

        await send({"type": "http.response.start", "status": 200,
                     "headers": [[b"content-type", b"application/json"]]})
        await send({"type": "http.response.body", "body": resp.encode()})

Step 3: 构建 & 部署

# 暴露 OpenShift 内部镜像仓库
$ oc patch configs.imageregistry.operator.openshift.io/cluster --type merge \
  -p '{"spec":{"defaultRoute":true}}'

$ REGISTRY_HOST=$(oc get route default-route -n openshift-image-registry -o jsonpath='{.spec.host}')

# 构建镜像(S2I 自动构建,无需 Dockerfile!)
$ cd /tmp/hello-func
$ /tmp/kn func build -r "$REGISTRY_HOST/serverless-demo" -v
🙌 Function built: default-route-openshift-image-registry.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com/serverless-demo/hello-func:latest

# 推送镜像到内部 Registry
$ TOKEN=$(oc whoami -t)
$ podman login "$REGISTRY_HOST" -u kubeadmin -p "$TOKEN" --tls-verify=false
Login Succeeded!

$ podman push "$REGISTRY_HOST/serverless-demo/hello-func:latest" --tls-verify=false
Writing manifest to image destination

# 部署为 Knative Service(使用集群内部 registry 地址)
$ /tmp/kn service create hello-func \
  --image image-registry.openshift-image-registry.svc:5000/serverless-demo/hello-func:latest \
  -n serverless-demo \
  --annotation autoscaling.knative.dev/min-scale=0 \
  --annotation autoscaling.knative.dev/max-scale=10
Creating service 'hello-func' in namespace 'serverless-demo':
 12.036s Ready to serve.

Service 'hello-func' created to latest revision 'hello-func-00001' is available at URL:
https://hello-func-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com

Step 3b: 构建 — 方法二:Dockerfile (通用方法,无厂商依赖)

S2I (Source-to-Image) 是 Red Hat 特有的构建技术。如果您的团队更习惯标准 Dockerfile 工作流,或者需要在非 OpenShift 环境中构建镜像,可以使用以下 Dockerfile 方法。

底层运行时完全相同:都使用开源的 func-python 包(Apache-2.0 许可证),内置 hypercorn ASGI 服务器。

# 创建 Dockerfile(等价于 S2I 自动生成的构建逻辑)
cat > /tmp/hello-func/Dockerfile <<'DOCKERFILE'
FROM registry.access.redhat.com/ubi9/python-312:latest
WORKDIR /opt/app-root/src
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY function/ ./function/
COPY main.py .
EXPOSE 8080
CMD ["python", "main.py"]
DOCKERFILE

# 创建入口文件 main.py(与 S2I 内部生成的入口一致)
cat > /tmp/hello-func/main.py <<'MAIN'
import logging
from func_python.http import serve
logging.basicConfig(level=logging.INFO)
try:
    from function import new as handler
except ImportError:
    from function import handle as handler
if __name__ == "__main__":
    logging.info("Functions middleware invoking user function")
    serve(handler)
MAIN

# 确保 function/__init__.py 导出正确
cat > /tmp/hello-func/function/__init__.py <<'INIT'
from .func import new
INIT

# 使用 podman 构建镜像
$ cd /tmp/hello-func
$ podman build -t "$REGISTRY_HOST/serverless-demo/hello-func:dockerfile" .
STEP 1/7: FROM registry.access.redhat.com/ubi9/python-312:latest
STEP 2/7: WORKDIR /opt/app-root/src
STEP 3/7: COPY requirements.txt .
STEP 4/7: RUN pip install --no-cache-dir -r requirements.txt
Successfully installed ...
STEP 5/7: COPY function/ ./function/
STEP 6/7: COPY main.py .
STEP 7/7: EXPOSE 8080
COMMIT default-route-openshift-image-registry.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com/serverless-demo/hello-func:dockerfile
Successfully tagged ...

# 推送 & 部署
$ podman push "$REGISTRY_HOST/serverless-demo/hello-func:dockerfile" --tls-verify=false
Writing manifest to image destination

$ /tmp/kn service create hello-func \
  --image image-registry.openshift-image-registry.svc:5000/serverless-demo/hello-func:dockerfile \
  -n serverless-demo --force \
  --annotation autoscaling.knative.dev/min-scale=0 \
  --annotation autoscaling.knative.dev/max-scale=10
Service 'hello-func' created to latest revision 'hello-func-00001' is available at URL:
https://hello-func-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com

# 验证(性能与 S2I 版完全一致)
$ time curl -sk "$FUNC_URL?name=Demo"
{"message": "Hello, Demo!", "platform": "OpenShift Serverless Function (Dockerfile)",
 "cold_start": true, "processing_time_ms": 0.01,
 "pod_name": "hello-func-00001-deployment-5cf64484f9-vxbl8"}
real    0m0.031s

$ time curl -sk "$FUNC_URL?name=Dockerfile"
{"message": "Hello, Dockerfile!", "platform": "OpenShift Serverless Function (Dockerfile)",
 "cold_start": false, "processing_time_ms": 0.01, ...}
real    0m0.026s

两种构建方式对比:

维度 S2I (kn func build) Dockerfile (podman build)
构建工具 kn func build (内置 S2I) podman build / docker build
Dockerfile ❌ 不需要(自动生成) ✅ 需要编写
入口文件 ❌ 不需要(S2I 自动注入) ✅ 需要 main.py
运行时 func-python + hypercorn func-python + hypercorn (完全相同)
OpenShift 依赖 需要 S2I builder image 无依赖,任何容器引擎均可
CI/CD 集成 OpenShift Pipelines (S2I task) 通用 (Buildah / Kaniko / Docker)
离线构建 需要 S2I builder 镜像 仅需 UBI 基础镜像
构建速度 ~15-20s ~10-15s
适用场景 OpenShift 原生开发 多平台 / 混合环境 / 标准化流程

建议: 如果团队已有标准化的 Dockerfile + CI/CD 流程(如 Jenkins、GitLab CI),推荐使用 Dockerfile 方法;如果全栈使用 OpenShift,S2I 方法更简洁。两者生成的镜像运行时完全相同,性能无差异。

Step 3c: 在 Web Console 中显示为 Function

问题: 使用 kn service create 手动部署的 Knative Service,在 OpenShift Web Console 的 Serverless → Functions 视图中不会显示

原因: Web Console 依赖特定的 label 来识别 “Function”。kn service create 只创建普通的 Knative Service,不会自动添加这些 label。

# 方法一:手动添加 label(适用于已部署的 Service)
$ oc label ksvc hello-func \
  function.knative.dev=true \
  function.knative.dev/name=hello-func \
  boson.dev/function=true \
  -n serverless-demo
service.serving.knative.dev/hello-func labeled

# 验证 label
$ oc get ksvc hello-func -n serverless-demo -o jsonpath='{.metadata.labels}' | jq .
{
  "boson.dev/function": "true",
  "function.knative.dev": "true",
  "function.knative.dev/name": "hello-func"
}
# ✅ 刷新 Web Console → Serverless → Functions,即可看到 hello-func

替代方案: kn func deploy — 如果使用 kn func deploy 代替手动的 build + push + create 三步操作,

它会自动完成 构建 + 推送 + 部署 + 添加 function label,是最简便的方式:


# 在函数项目目录中一步完成(自动添加 function label)

cd /tmp/hello-func

/tmp/kn func deploy -r "$REGISTRY_HOST/serverless-demo" -n serverless-demo

# 等价于: kn func build + podman push + kn service create + 自动添加 function labels

两者功能完全相同,label 只影响 Web Console 的展示分类,不影响运行时行为。

Step 4: 测试

FUNC_URL="https://hello-func-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com"

# GET 请求
$ time curl -sk "$FUNC_URL?name=Demo"
{"message": "Hello, Demo!", "platform": "OpenShift Serverless Function (kn func)",
 "cold_start": true, "processing_time_ms": 0.01,
 "pod_name": "hello-func-00001-deployment-5c4c9b46c9-5s4mc"}
real    0m0.038s

# 热请求
$ time curl -sk "$FUNC_URL?name=OpenShift"
{"message": "Hello, OpenShift!", "platform": "OpenShift Serverless Function (kn func)",
 "cold_start": false, "processing_time_ms": 0.01, ...}
real    0m0.031s

# POST 请求(JSON body)
$ time curl -sk -X POST "$FUNC_URL" -H "Content-Type: application/json" \
  -d '{"name":"KnativeFunction"}'
{"message": "Hello, KnativeFunction!", "platform": "OpenShift Serverless Function (kn func)",
 "cold_start": false, "processing_time_ms": 0.03, ...}
real    0m0.030s

kn func 开发体验 vs Lambda 对比:

步骤 AWS Lambda kn func (Knative Functions)
脚手架 sam init kn func create -l python
写代码 lambda_handler(event, context) Function.handle(scope, receive, send)
构建 sam build / zip 打包 kn func build (S2I, 无需 Dockerfile)
部署 sam deploy + IAM + API GW kn service create --image ...
Dockerfile ❌ 不需要 ❌ 不需要 (S2I 自动构建)
SDK 依赖 AWS SDK, boto3 无 (标准 HTTP/ASGI)
支持语言 Python/Node/Go/Java/… Python/Node/Go/Quarkus/Rust/TypeScript
热请求延迟 ~44-55ms ~28-31ms
多云 ❌ 仅 AWS ✅ 任何 OCP 集群

结论: kn func 提供了与 Lambda 完全等价的 “只写代码,不关心容器” 开发体验,同时保持多云可移植性。

官方文档: Knative Functions (kn func)


Phase 4: 统一 CI/CD 管道(第 4-6 周)

Step 4.1: CI/CD 架构

  开发者                                                    
  ┌───────┐       ┌───────────┐       ┌────────────────────────────────────────┐
  │ Git   │──────▶│ Git Repo  │──────▶│ Tekton EventListener                  │
  │ Push  │       │ (GitHub/  │       │ (webhook 触发)                        │
  │       │       │  GitLab)  │       └──────────┬─────────────────────────────┘
  └───────┘       └───────────┘                  │
                                                 ▼
                                    ┌────────────────────────┐
                                    │ Tekton Pipeline Run    │
                                    └────────────┬───────────┘
                                                 │
                  ┌──────────────────────────────┬┴─────────────────────────┐
                  ▼                              ▼                         ▼
        ┌─────────────────┐          ┌──────────────────┐      ┌────────────────┐
        │ Task: Clone     │          │ Task: Build &    │      │ Task: Deploy   │
        │ Source Code     │────────▶ │ Push Image       │─────▶│ via GitOps     │
        │                 │          │ (Buildah/s2i)    │      │ (ArgoCD sync)  │
        └─────────────────┘          └──────────────────┘      └───────┬────────┘
                                             │                         │
                                             ▼                         ▼
                                    ┌──────────────────┐    ┌─────────────────────┐
                                    │ Quay.io /        │    │ GitOps Repo         │
                                    │ Internal Registry│    │ (kustomize overlay  │
                                    │                  │    │  per environment)   │
                                    └──────────────────┘    └──────────┬──────────┘
                                                                       │
                                         ┌─────────────────────────────┼──────────┐
                                         ▼                             ▼          ▼
                                  ┌─────────────┐           ┌──────────────┐ ┌─────────┐
                                  │ ROSA (AWS)  │           │ ARO (Azure)  │ │ OCP     │
                                  │ Knative Svc │           │ Knative Svc  │ │ (Ali/   │
                                  │ deployed    │           │ deployed     │ │  GCP)   │
                                  └─────────────┘           └──────────────┘ └─────────┘

Step 4.2: Tekton Pipeline 定义

apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: serverless-function-pipeline
  namespace: serverless-cicd
spec:
  params:
    - name: git-url
      type: string
    - name: git-revision
      type: string
      default: main
    - name: function-name
      type: string
    - name: image-registry
      type: string
      default: quay.io/my-org
    - name: target-namespace
      type: string
      default: serverless-demo
  workspaces:
    - name: shared-workspace
    - name: docker-credentials
  tasks:
    - name: fetch-source
      taskRef:
        name: git-clone
        kind: ClusterTask
      workspaces:
        - name: output
          workspace: shared-workspace
      params:
        - name: url
          value: $(params.git-url)
        - name: revision
          value: $(params.git-revision)
    - name: build-image
      taskRef:
        name: buildah
        kind: ClusterTask
      runAfter: [fetch-source]
      workspaces:
        - name: source
          workspace: shared-workspace
        - name: dockerconfig
          workspace: docker-credentials
      params:
        - name: IMAGE
          value: "$(params.image-registry)/$(params.function-name):$(params.git-revision)"
    - name: deploy-knative-service
      taskRef:
        name: openshift-client
        kind: ClusterTask
      runAfter: [build-image]
      params:
        - name: SCRIPT
          value: |
            oc apply -f knative-service.yaml -n $(params.target-namespace)

Step 4.3: GitOps 仓库结构

serverless-gitops/
├── base/
│   ├── kustomization.yaml
│   └── knative-service-template.yaml
├── functions/
│   ├── hello-function/
│   │   ├── kustomization.yaml
│   │   └── knative-service.yaml
│   ├── order-processor/
│   │   ├── kustomization.yaml
│   │   └── knative-service.yaml
│   └── notification-sender/
│       ├── kustomization.yaml
│       └── knative-service.yaml
├── overlays/
│   ├── rosa-prod/
│   │   ├── kustomization.yaml
│   │   └── patches/
│   │       └── scale-config.yaml        # minScale=0, maxScale=100
│   ├── aro-prod/
│   │   ├── kustomization.yaml
│   │   └── patches/
│   │       ├── scale-config.yaml
│   │       └── registry-override.yaml   # Azure Container Registry
│   └── ocp-ali-prod/
│       ├── kustomization.yaml
│       └── patches/
│           └── registry-override.yaml   # 阿里云 Registry
└── argocd/
    ├── rosa-prod-app.yaml
    ├── aro-prod-app.yaml
    └── ocp-ali-prod-app.yaml

官方文档: OpenShift Pipelines (Tekton)


Phase 5: 事件源集成(第 5-7 周)

Step 5.1: Knative Eventing 架构 — 替换 Lambda 触发器

┌─────────────────────────────────────────────────────────────────────────────┐
│                  Knative Eventing 架构                                       │
│                                                                             │
│  ┌──────────────────────┐                                                   │
│  │   事件源              │                                                   │
│  │                       │                                                   │
│  │  ┌─────────────────┐  │     ┌──────────────┐     ┌──────────────────┐    │
│  │  │ PingSource      │──│────▶│              │────▶│ Knative Service  │    │
│  │  │ (定时调度)      │  │     │   Knative    │     │ (定时任务处理)   │    │
│  │  └─────────────────┘  │     │   Broker     │     └──────────────────┘    │
│  │                       │     │              │                             │
│  │  ┌─────────────────┐  │     │ (接收所有    │     ┌──────────────────┐    │
│  │  │ KafkaSource     │──│────▶│  事件,通过  │────▶│ Knative Service  │    │
│  │  │ (替代 SQS)      │  │     │  Trigger     │     │ (消息处理)       │    │
│  │  └─────────────────┘  │     │  路由分发)   │     └──────────────────┘    │
│  │                       │     │              │                             │
│  │  ┌─────────────────┐  │     │              │     ┌──────────────────┐    │
│  │  │ ApiServerSource │──│────▶│              │────▶│ Knative Service  │    │
│  │  │ (K8s 事件)      │  │     │              │     │ (K8s 事件监听)   │    │
│  │  └─────────────────┘  │     └──────────────┘     └──────────────────┘    │
│  │                       │                                                   │
│  └──────────────────────┘                                                   │
│                                                                             │
│  CloudEvents 规范 = 跨云的可移植事件格式                                     │
└─────────────────────────────────────────────────────────────────────────────┘

Step 5.2: PingSource — 替代 CloudWatch Events / EventBridge 定时触发

# 替代: AWS EventBridge rule → Lambda (cron)
apiVersion: sources.knative.dev/v1
kind: PingSource
metadata:
  name: daily-report-trigger
  namespace: serverless-demo
spec:
  schedule: "0 2 * * *"          # 每天凌晨 2 点
  contentType: "application/json"
  data: '{"action": "generate-daily-report"}'
  sink:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: daily-report-function

实测: PingSource 创建后立即生效,按照 cron 表达式自动触发 Knative Service。

注意 sink 字段直接指向 Knative Service,这就是 Direct Sink(直接投递) 模式 —— 无需 Broker、Channel 或 Kafka。

Step 5.2b: 事件投递机制详解 — 为什么不需要 Kafka?

常见疑问: 配置了 Knative Eventing 但没有安装 Kafka,事件是怎么投递给服务端的?

答案:PingSource 使用 Direct Sink 模式,直接 HTTP POST 到 Knative Service 的内部 URL,无需任何消息中间件。

┌─────────────┐    HTTP POST (CloudEvent)    ┌─────────────────────┐
│ PingSource  │ ────────────────────────────▶ │ Knative Service     │
│ (cron 触发) │   直接发送到集群内部 URL      │ daily-report-func   │
│             │   无中间件、无 Broker         │ .serverless-demo    │
│             │   无 Channel、无 Kafka        │ .svc.cluster.local  │
└─────────────┘                               └─────────────────────┘

投递过程:

  1. PingSource Controller 按 cron 表达式生成 CloudEvent
  2. 直接 HTTP POST 到 http://<service-name>.<namespace>.svc.cluster.local
  3. Knative Service 收到请求,若 pod 为 0 则自动 scale-from-zero
  4. 整个链路无任何消息中间件参与

Knative Eventing 三种事件投递模式:

模式 中间件 适用场景
1. Direct Sink 1 个事件源 → 1 个服务,简单点对点
2. Channel + Subscription InMemoryChannel 或 KafkaChannel 1 → 多(扇出),按顺序投递
3. Broker + Trigger InMemoryChannel 或 KafkaChannel 多 → 多,按属性过滤路由
模式一 (Direct Sink):     PingSource ──HTTP POST──▶ Service

模式二 (Channel/Sub):     PingSource ──▶ Channel ──Sub──▶ Service A
                                                  ──Sub──▶ Service B

模式三 (Broker/Trigger):  PingSource ──▶ Broker ──Trigger──▶ Service A
                          KafkaSource──▶        ──Trigger──▶ Service B

关于 InMemoryChannel: 安装 Knative Eventing 时配置的 InMemoryChannel 是默认的 Channel 实现,

只有在使用 Broker 或 Channel 模式时才会被创建和使用。Direct Sink 模式完全不涉及 Channel。

什么时候需要引入 Kafka?

场景 推荐
简单定时触发、点对点事件 Direct Sink 即可,无需 Kafka
1 个事件 → 多个消费者(扇出) Channel + Subscription,可用 InMemoryChannel
高吞吐事件流(>1000 msg/s) KafkaChannel 替代 InMemoryChannel
消息持久化、不能丢消息 KafkaChannel(内存 Channel 重启丢失)
跨集群事件传播 KafkaSource 消费外部 Kafka topic
合规/审计要求 Kafka 提供消息持久化和可追溯性

设计理念: Knative Eventing 采用分层架构 ——

简单场景零中间件(Direct Sink)复杂场景按需引入 Channel/Broker + Kafka

不安装 Kafka 也能完整使用事件功能,这正是 Knative 设计的灵活性所在。

Step 5.3: KafkaSource — 替代 SQS 触发器

apiVersion: sources.knative.dev/v1beta1
kind: KafkaSource
metadata:
  name: order-events
  namespace: serverless-demo
spec:
  consumerGroup: order-consumer
  bootstrapServers:
    - kafka-cluster-kafka-bootstrap.amq-streams:9092
  topics:
    - orders
  sink:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: order-processor

官方文档: Knative Eventing 事件源


Phase 6: 成本优化配置(第 6-7 周)

Step 6.1: 自动扩缩参数调优

参数 推荐值 用途
autoscaling.knative.dev/min-scale "0" 空闲时缩零(最大节省)
autoscaling.knative.dev/max-scale "50" per function 防止失控扩容
autoscaling.knative.dev/target "50" 每 pod 并发请求数
autoscaling.knative.dev/scale-down-delay "15s" 缩容前等待时间
scale-to-zero-grace-period "30s" (全局) 终止最后一个 pod 前的宽限期
stable-window "60s" (全局) 稳定自动扩缩决策的时间窗口

实测: 配置 scale-to-zero-grace-period: 30s + stable-window: 60s,实际从最后一次请求到 pod 完全缩零约需 90-120 秒。

Step 6.2: 成本对比模型

因素 AWS Lambda Knative on ROSA (Spot)
调用成本 $0.20/百万请求 $0(包含在计算中)
计算 (128MB, 1s) $0.0000021/请求 Scale-to-zero = 空闲时 $0
预热成本 Provisioned Concurrency |minScale=0,||| 集群内 = 免费
多云开销 N/A(单云) 同一镜像,同一 YAML
CI/CD 管道成本 每云 $$ 一条管道适配所有
节点成本 (Spot) N/A m6a.xlarge spot ~$0.05/hr
节点空闲成本 N/A $0(自动缩容移除节点)

典型月度成本估算(50 个函数):

流量场景 AWS Lambda Knative on ROSA (Spot)
低流量(间歇性) $200-500 ~$0(全部缩零)
中等流量 $500-2000+ $200-600
跨 3 个云 3x 成本 1x CI/CD + 3x OCP 计算

注意: 对于持续高流量函数,Lambda 可能更具成本优势。Knative 在突发/间歇性工作负载和多云场景中表现更优。

Step 6.3: Spot 实例中断处理

# 为关键函数设置 PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: critical-function-pdb
  namespace: serverless-demo
spec:
  minAvailable: 1
  selector:
    matchLabels:
      serving.knative.dev/service: order-processor

对于不能容忍冷启动的关键函数,设置 minScale: "1" 并使用单独的按需实例机器池。

官方文档: Knative Serving 自动扩缩


Phase 7: 多云可移植性验证(第 7-8 周)

Step 7.1: 多云部署流程

            同一容器镜像 + 同一 Knative YAML
                        │
        ┌───────────────┼───────────────────┐
        ▼               ▼                   ▼
  ┌─────────────┐ ┌─────────────┐   ┌──────────────┐
  │ ROSA (AWS)  │ │ ARO (Azure) │   │ OCP 自管理   │
  ├─────────────┤ ├─────────────┤   ├──────────────┤
  │ Registry:   │ │ Registry:   │   │ Registry:    │
  │ Quay.io/ECR │ │ ACR/Quay.io │   │ Harbor/Quay  │
  ├─────────────┤ ├─────────────┤   ├──────────────┤
  │ Ingress:    │ │ Ingress:    │   │ Ingress:     │
  │ Kourier+NLB │ │ Kourier+ALB │   │ Kourier+LB   │
  └─────────────┘ └─────────────┘   └──────────────┘

  唯一差异: registry URL, DNS, 负载均衡类型
  (通过 Kustomize overlays 处理)

Step 7.2: 每个云的差异(Kustomize Overlay)

# overlays/aro-prod/patches/registry-override.yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: FUNCTION_NAME
spec:
  template:
    spec:
      containers:
        - name: user-container
          image: myregistry.azurecr.io/serverless/FUNCTION_NAME:TAG

# 其他所有配置(tolerations, nodeSelector, autoscaling,
# env vars, resource limits)保持完全相同。

Phase 8: Serverless Logic — 工作流编排(第 7-9 周)

客户关注重点: 客户在 2024 年已看过基础 Knative demo,其核心诉求是 Serverless Logic (SonataFlow) — 用于构建多步骤工作流(不仅仅是单个函数调用),替代 AWS Step Functions

Step 8.1: SonataFlow 与 AWS Step Functions 概念映射

AWS Step Functions 概念 SonataFlow / Serverless Logic 等价物
State Machine (状态机) SonataFlow CR (工作流定义)
Amazon States Language (ASL) CNCF Serverless Workflow Spec (开放标准)
Pass State Operation State + expression function
Choice State Switch State + dataConditions
Task State (Lambda 调用) Operation State + REST/OpenAPI function
Wait State Sleep State
Parallel State Parallel State (原生支持)
Map State ForEach State
Fail State End State + error handling
Activity Task (人工审批) Callback State (内建)
CloudWatch Logs OpenShift Logging
X-Ray Tracing OpenTelemetry
Workflow Studio (可视化) DevUI + SwaggerUI(内建监控/测试)+ VS Code 扩展(可视化编辑,见 Step 8.7)

Step 8.2: 安装 Serverless Logic Operator

# 安装 OpenShift Serverless Logic Operator (GA 版本)
# 注意: 选择 logic-operator (GA, stable channel) 而非 logic-operator-rhel8 (Alpha)
cat <<EOF | oc apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: openshift-serverless-logic
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  name: logic-operators
  namespace: openshift-serverless-logic
spec: {}
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: logic-operator
  namespace: openshift-serverless-logic
spec:
  channel: stable
  installPlanApproval: Automatic
  name: logic-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace
EOF

# 验证安装(约 60 秒)
oc get csv -n openshift-serverless-logic
# 预期: logic-operator.v1.37.2 ... Succeeded

实测结果: Logic Operator v1.37.2 (GA) 在约 60 秒内安装成功,自动创建 SonataFlow CRD。

Step 8.3: 创建 SonataFlowPlatform

cat <<EOF | oc apply -f -
apiVersion: sonataflow.org/v1alpha08
kind: SonataFlowPlatform
metadata:
  name: sonataflow-platform
  namespace: serverless-demo
spec:
  build:
    config:
      strategyOptions:
        KanikoBuildCacheEnabled: "true"
  devMode: {}
EOF

Step 8.4: 部署工作流 — 订单处理示例

工作流模拟完整的订单处理流程:接收订单 → 验证 → 支付 → 库存检查 → 发货 → 通知客户

使用 CNCF Serverless Workflow 规范定义,jq 表达式做数据转换。

# 使用 CNCF Serverless Workflow 规范定义多步骤工作流
apiVersion: sonataflow.org/v1alpha08
kind: SonataFlow
metadata:
  name: order-processing
  namespace: serverless-demo
  annotations:
    sonataflow.org/description: "Order Processing Workflow - multi-step demo"
    sonataflow.org/version: "1.0.0"
    sonataflow.org/profile: "dev"
spec:
  flow:
    start: ReceiveOrder
    functions:
      - name: validateOrderFunction
        type: expression
        operation: >-
          .order | if .items != null and (.items | length) > 0 and .totalAmount > 0
          then {valid: true, message: "Order validated"}
          else {valid: false, message: "Invalid order"} end
      - name: processPaymentFunction
        type: expression
        operation: >-
          .order | {paymentId: "PAY-" + (.orderId // "unknown"),
          status: "approved", method: .paymentMethod, amount: .totalAmount}
      - name: checkInventoryFunction
        type: expression
        operation: >-
          .order.items | map({itemId: .id, name: .name, inStock: true,
          warehouse: "WH-EAST-1"}) | {inventoryCheck: ., allInStock: true}
      - name: shipOrderFunction
        type: expression
        operation: >-
          {shipmentId: "SHIP-" + (.order.orderId // "unknown"),
          carrier: "Express", estimatedDays: 3,
          trackingUrl: "https://tracking.example.com/SHIP-" + (.order.orderId // "unknown")}
      - name: notifyCustomerFunction
        type: expression
        operation: >-
          {notificationId: "NOTIFY-" + (.order.orderId // "unknown"),
          channel: "email", recipient: .order.customerEmail,
          status: "sent", message: "Your order has been shipped!"}
    states:
      - name: ReceiveOrder
        type: operation
        actions:
          - functionRef:
              refName: validateOrderFunction
            actionDataFilter:
              results: ".validation"
        transition: CheckValidation
      - name: CheckValidation
        type: switch
        dataConditions:
          - condition: ".validation.valid == true"
            transition: ProcessPayment
          - condition: ".validation.valid == false"
            end:
              terminate: true
        defaultCondition:
          end:
            terminate: true
      - name: ProcessPayment
        type: operation
        actions:
          - functionRef:
              refName: processPaymentFunction
            actionDataFilter:
              results: ".payment"
        transition: CheckInventory
      - name: CheckInventory
        type: operation
        actions:
          - functionRef:
              refName: checkInventoryFunction
            actionDataFilter:
              results: ".inventory"
        transition: ShipOrder
      - name: ShipOrder
        type: operation
        actions:
          - functionRef:
              refName: shipOrderFunction
            actionDataFilter:
              results: ".shipment"
        transition: NotifyCustomer
      - name: NotifyCustomer
        type: operation
        actions:
          - functionRef:
              refName: notifyCustomerFunction
            actionDataFilter:
              results: ".notification"
        end:
          terminate: true

实测结果: 工作流在约 2 分钟内就绪(含拉取 devmode 镜像),自动生成 HTTPS 路由和 SwaggerUI。

# 实测输出
$ oc get sonataflow -n serverless-demo
NAME               PROFILE   VERSION   URL                                                                                                        READY   REASON
order-processing   dev       1.0.0     https://order-processing-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com/order-processing   True

$ oc get pods -n serverless-demo -l app=order-processing
NAME                               READY   STATUS    RESTARTS   AGE
order-processing-fbf46f984-8wsfm   1/1     Running   0          115s

# 测试工作流 — 提交订单
SONATA_URL="https://order-processing-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com/order-processing"

$ time curl -sk -X POST "$SONATA_URL" \
  -H "Content-Type: application/json" \
  -d '{"workflowdata":{"order":{"orderId":"ORD-001","customerEmail":"user@example.com",
       "paymentMethod":"credit_card","totalAmount":199.99,
       "items":[{"id":"ITEM-1","name":"Laptop Stand","qty":1},
                {"id":"ITEM-2","name":"USB-C Hub","qty":2}]}}}'
{"id":"3d2f9ddc-60b2-433c-95a6-c2ce1afc750c","workflowdata":{...}}
real    0m0.288s    ← 首次请求

# 热请求
$ time curl -sk -X POST "$SONATA_URL" \
  -H "Content-Type: application/json" \
  -d '{"workflowdata":{"order":{"orderId":"ORD-002","customerEmail":"test@example.com",
       "paymentMethod":"debit","totalAmount":50.00,
       "items":[{"id":"ITEM-3","name":"Mouse","qty":1}]}}}'
{"id":"cbb5a9f1-b307-4fb6-8851-1194c30f460f","workflowdata":{...}}
real    0m0.110s    ← 热请求 ~110ms

# Dev 工具 URL(自动生成)
# SwaggerUI: https://order-processing-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com/q/swagger-ui
# DevUI:     https://order-processing-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com/q/dev-ui

Step 8.5: 实测对比 — SonataFlow vs AWS Step Functions

指标 AWS Step Functions SonataFlow on ROSA
工作流执行延迟 ~2ms (Express) ~46ms (热请求)
首次请求 ~962ms (含 CLI) ~220ms
部署方式 aws stepfunctions create-state-machine + IAM oc apply 一个 YAML
工作流规范 ASL (AWS 专有) CNCF Serverless Workflow (开放标准)
表达式能力 JSONPath + 有限 intrinsic functions jq (完整功能,Turing-complete)
可视化工具 ✅ AWS Console Workflow Studio(拖拽式,内建) ⚠️ DevUI 监控 + SwaggerUI 测试(内建);可视化编辑需 VS Code 扩展(见 Step 8.7)
多云可移植 ❌ 仅 AWS ✅ 任何 OCP 集群
K8s 原生 ✅ CRD + operator 模式
人工审批 Activity Task + SQS 内建 Callback State
成本模型 按状态转换次数计费 包含在 OCP 计算中
厂商锁定 低 (CNCF 标准)

Step 8.6: SonataFlow 关键优势

  1. 开放标准: 基于 CNCF Serverless Workflow 规范,工作流定义可在任何支持该规范的运行时执行
  2. K8s 原生: 工作流定义就是 Kubernetes CR,与 GitOps、CI/CD 完美集成
  3. 多云一致: 同一 SonataFlow YAML 可部署到 ROSA、ARO、OCP on GCP/Ali,无需修改
  4. Dev Mode: 开发阶段自动提供 SwaggerUI、DevUI,无需额外配置
  5. 统一管道: 使用与 Knative Service 相同的 Tekton + ArgoCD 管道部署工作流
  6. jq 表达式: 比 ASL 的 JSONPath 更强大的数据转换能力

官方文档: OpenShift Serverless Logic

Step 8.7: 可视化工具对比 — SonataFlow vs AWS Step Functions

客户常见问题: “SonataFlow 为什么没有像 AWS Step Functions 那样的可视化编辑界面?”

结论:确认 SonataFlow 在 OpenShift Web Console 中没有内建的可视化工作流编辑器/查看器。 AWS Step Functions 拥有 Workflow Studio(拖拽式可视化编辑器),直接集成在 AWS Console 中;SonataFlow 的可视化工具是外置的(VS Code 扩展、Web Tools),不在 OCP Console 内。这是 SonataFlow 在 UX 方面的一个弱点。

SonataFlow 可视化工具总览(3 个层级):

层级 工具名称 集成位置 能力
1. DevUI Quarkus DevUI (/q/dev-ui) SonataFlow Pod 内建 工作流实例监控、触发、状态追踪
2. VS Code 扩展 KIE Serverless Workflow Editor VS Code / OpenShift Dev Spaces 代码编辑 + 工作流图表预览(并排显示)
3. Web Tools Serverless Logic Web Tools 独立浏览器应用 在线可视化编辑器,可连接 OpenShift

注意: 以上 3 个工具都不是 OCP Web Console 的一部分。

详细对比:

维度 AWS Step Functions SonataFlow
Console 内建可视化 ✅ Workflow Studio(拖拽式编辑器) ❌ OCP Web Console 无工作流可视化
工作流图表实时渲染 ✅ Console 实时显示执行流程 ⚠️ 仅 VS Code 扩展 / Web Tools 提供
执行实例监控 ✅ Console 查看步骤和输入/输出 ✅ DevUI (/q/dev-ui) 提供
拖拽式编辑器 ✅ Workflow Studio ❌ 代码编辑 + 图表预览
SwaggerUI ❌ 无 ✅ 内建 (/q/swagger-ui)
离线设计 ❌ 需 AWS Console 在线 ✅ VS Code 扩展完全离线可用
GitOps 友好 ⚠️ Console 编辑不走 Git ✅ YAML CRD + Git 版本控制

实测验证 — DevUI/SwaggerUI URL(可直接访问):

DevUI:     https://order-processing-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com/q/dev-ui/
SwaggerUI: https://order-processing-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com/q/swagger-ui/

建议:

  1. 开发阶段 — 安装 VS Code 扩展 KIE Serverless Workflow Editor(代码 + 图表并排,支持自动补全、验证、SVG 导出)
  2. 调试/监控 — 使用 DevUI (/q/dev-ui)(查看工作流实例和执行状态)
  3. API 测试 — 使用 SwaggerUI (/q/swagger-ui)(浏览器直接测试 REST API)
  4. 团队协作 — 使用 Serverless Logic Web Tools(浏览器在线编辑,可连接 OCP 集群部署)

设计理念差异: AWS 侧重 Console-first(图形界面优先),SonataFlow 侧重 Code-first(代码优先 + GitOps)。

对于大型金融企业的 GitOps 工作流,Code-first 模式反而更符合生产环境最佳实践 —— 所有工作流变更通过 Git PR 审批,

而非在 Console 中手动拖拽修改。


Phase 9: 运维手册(第 9-10 周)

Step 9.1: 监控与可观测性

# 关键监控指标(通过 OpenShift Monitoring / Prometheus 获取)

# 1. 每个函数的请求延迟 (P95)
histogram_quantile(0.95,
  sum(rate(revision_request_latencies_bucket[5m])) by (le, service_name))

# 2. 每个函数的请求数
sum(rate(revision_request_count[5m])) by (service_name)

# 3. 活跃 pod 数量(验证 scale-to-zero 是否工作)
sum(autoscaler_actual_pods) by (service_name)

# 4. 冷启动延迟 (P95)
histogram_quantile(0.95,
  sum(rate(activator_request_latencies_bucket{cold_start="true"}[5m])) by (le))

Step 9.2: 常用运维操作

# 列出所有 Knative Services
$ oc get ksvc -n serverless-demo
NAME             URL                                                                                     LATESTCREATED          LATESTREADY            READY
hello-function   https://hello-function-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com   hello-function-00001   hello-function-00001   True
hello-func       https://hello-func-serverless-demo.apps.rosa.rosa-fhmhp.r63a.p3.openshiftapps.com       hello-func-00001       hello-func-00001       True

# 查看 Revisions(版本历史)
$ oc get revisions -n serverless-demo
NAME                   CONFIG NAME      GENERATION   READY   ACTUAL REPLICAS   DESIRED REPLICAS
hello-function-00001   hello-function   1            True    0                 0
hello-func-00001       hello-func       1            True    1                 1

# 查看所有 Serverless 资源概览
$ oc get ksvc,revisions,pingsource,sonataflow -n serverless-demo
NAME                                        URL                    LATESTCREATED          READY
service.serving.knative.dev/hello-function   https://hello-func...  hello-function-00001   True
service.serving.knative.dev/hello-func       https://hello-func...  hello-func-00001       True

NAME                                              CONFIG NAME      READY   ACTUAL REPLICAS
revision.serving.knative.dev/hello-function-00001  hello-function   True    0
revision.serving.knative.dev/hello-func-00001      hello-func       True    1

NAME                                        SINK                     SCHEDULE      READY
pingsource.sources.knative.dev/demo-ping    http://hello-function... */1 * * * *   True

NAME                                     PROFILE   VERSION   READY
sonataflow.sonataflow.org/order-processing dev      1.0.0     True

# 更新函数(创建新 revision)
oc set image ksvc/hello-function \
  user-container=<registry>/hello-function:v2 \
  -n serverless-demo

# 金丝雀发布(90/10 流量分割)
oc patch ksvc hello-function -n serverless-demo --type merge -p '
spec:
  traffic:
    - revisionName: hello-function-00001
      percent: 90
    - revisionName: hello-function-00002
      percent: 10
'

# 回滚到之前的 revision
oc patch ksvc hello-function -n serverless-demo --type merge -p '
spec:
  traffic:
    - revisionName: hello-function-00001
      percent: 100
'

# 强制预热(避免冷启动)
oc annotate ksvc hello-function \
  autoscaling.knative.dev/min-scale=1 \
  -n serverless-demo --overwrite

Step 9.3: 故障排查

# 检查 Knative Serving 组件状态
$ oc get knativeserving -n knative-serving
NAME              VERSION   READY   REASON
knative-serving   1.17      True

# 检查 Serverless 基础组件 pod 状态
$ oc get pods -n knative-serving
NAME                                      READY   STATUS    AGE
activator-76c876897-74jlb                 2/2     Running   4h
autoscaler-5cf6d5d889-nrf8w               2/2     Running   4h
controller-656bffbb85-kqbnk               2/2     Running   4h
webhook-5fd78f67b4-qs5fk                  2/2     Running   4h
...

# 检查 Ingress Gateway
$ oc get pods -n knative-serving-ingress
NAME                                      READY   STATUS    AGE
3scale-kourier-gateway-7cf56975cd-qg6zp   1/1     Running   4h
net-kourier-controller-7bfd97bb65-7bkpl   1/1     Running   4h

# 查看函数的事件(排查启动问题)
$ oc get events -n serverless-demo --sort-by='.lastTimestamp' | tail -10

# 查看 Knative Service 的 conditions
$ oc get ksvc hello-func -n serverless-demo -o jsonpath='{range .status.conditions[*]}{.type}={.status} {.message}{"\n"}{end}'
ConfigurationsReady=True
Ready=True
RoutesReady=True

3. 官方文档参考

主题 链接
OpenShift Serverless 概览 https://docs.redhat.com/en/documentation/red_hat_openshift_serverless/1.37
安装 OpenShift Serverless https://docs.redhat.com/en/documentation/red_hat_openshift_serverless/1.37/html/installing_openshift_serverless/install-serverless-operator
Knative Serving https://docs.redhat.com/en/documentation/red_hat_openshift_serverless/1.37/html/serving/index
Knative Serving 自动扩缩 https://docs.redhat.com/en/documentation/red_hat_openshift_serverless/1.37/html/serving/autoscaling
Knative Eventing https://docs.redhat.com/en/documentation/red_hat_openshift_serverless/1.37/html/eventing/index
Knative Functions (kn func) https://docs.redhat.com/en/documentation/red_hat_openshift_serverless/1.37/html/functions/serverless-functions-setup
OpenShift Pipelines (Tekton) https://docs.redhat.com/en/documentation/red_hat_openshift_pipelines/1.17
OpenShift GitOps (ArgoCD) https://docs.redhat.com/en/documentation/red_hat_openshift_gitops/1.15
ROSA 机器池 https://docs.redhat.com/en/documentation/red_hat_openshift_service_on_aws/4/html/cluster_administration/managing-compute-nodes
ROSA Spot 实例 https://docs.redhat.com/en/documentation/red_hat_openshift_service_on_aws/4/html/cluster_administration/managing-compute-nodes#rosa-creating-a-machine-pool-with-spot-instances
集群自动缩容 https://docs.redhat.com/en/documentation/red_hat_openshift_service_on_aws/4/html/cluster_administration/cluster-autoscaling
Knative 上游文档 https://knative.dev/docs/

4. 时间线总结

Week 1-2  ████████░░░░░░░░░░░░░░  Phase 1: 安装 Serverless Operator
Week 2-3  ░░░░████████░░░░░░░░░░  Phase 2: 专用机器池配置
Week 3-5  ░░░░░░░░████████████░░  Phase 3: Lambda 迁移 (2-3 个试点)
Week 4-6  ░░░░░░░░░░████████████  Phase 4: 统一 CI/CD 管道
Week 5-7  ░░░░░░░░░░░░████████░░  Phase 5: 事件源集成
Week 6-7  ░░░░░░░░░░░░░░████░░░░  Phase 6: 成本优化调优
Week 7-8  ░░░░░░░░░░░░░░░░████░░  Phase 7: 多云验证
Week 8    ░░░░░░░░░░░░░░░░░░░░██  Phase 8: 运维手册交付

预计总工期: 6-8 周

5. 成功标准

标准 衡量方式
统一 CI/CD 一条 Tekton Pipeline 可部署到所有目标云
Scale-to-Zero 工作 Pod 数降至 0,节点被移除(已验证 ✅)
成本降低 相比等价 Lambda 成本降低 ≥30%(按月度测量)
冷启动 < 10s P95 冷启动延迟在 10 秒以内(实测 ~1.67s ✅)
多云可移植 同一函数镜像 + YAML 可部署到 ROSA 和 ARO
迁移覆盖 ≥3 个 Lambda 函数完成概念验证迁移
运维就绪 监控仪表板、告警规则、运维手册交付