OpenFaaS 在 DigitalOcean Kubernetes 上的生产级落地实践

发布时间:2026/6/23 9:22:32
OpenFaaS 在 DigitalOcean Kubernetes 上的生产级落地实践
1. 这不是“云函数”的简单搬运而是把 OpenFaaS 当作 Kubernetes 的原生扩展来用OpenFaaS 在 DigitalOcean Kubernetes 上跑起来很多人第一反应是“又一个 Serverless 平台部署教程”。但实际动手做过三轮以上集群迭代后我越来越确信这种理解偏差恰恰是多数人部署失败、后续维护卡壳、甚至误判技术价值的根源。OpenFaaS 不是挂在 Kubernetes 外面的“插件”它是一套深度嵌入 K8s 控制平面的声明式函数编排系统——它的 Operator 直接监听Function自定义资源CRD它的网关Gateway本质是带自动 TLS 终止和请求路由的 Ingress Controller 增强版它的队列驱动器NATS Streaming与 K8s 的 Pod 生命周期事件联动紧密。你如果把它当成“先装个 kubectl再 helm install 一下就完事”的黑盒那很快就会在函数冷启动超时、日志无法聚合、健康检查反复失败这些地方撞墙。核心关键词OpenFaaS、Kubernetes、DigitalOcean、serverless、faas-cli它们不是并列关系而是一个分层依赖链DigitalOcean 提供的是经过轻量加固、默认启用 CSI 存储插件和 Metrics Server 的托管 K8s 底座Kubernetes 是调度、网络、安全策略的统一执行引擎OpenFaaS 是构建在其上的、面向开发者交付函数工作流的抽象层faas-cli 则是这个抽象层唯一被官方长期维护的、与底层解耦最干净的客户端工具。它不碰 YAML 渲染逻辑不封装 Helm 命令所有faas-cli deploy操作最终都转化为对/system/functionsAPI 的 POST 请求——这意味着你完全可以在 CI/CD 流水线里用 curl 替代 faas-cli只要构造出正确的 JSON payload。适合谁来看不是只看“5分钟部署”的新手而是已经能独立完成kubeadm init或doctl kubernetes cluster create的中级运维/DevOps 工程师或是正在为微服务拆分后遗留大量胶水代码如定时清洗、格式转换、Webhook 转发寻找轻量级替代方案的后端开发者。如果你还在纠结“要不要上 Istio”或者“Knative 和 OpenFaaS 到底选哪个”这篇内容可能暂时不适合你——我们聚焦在“已选定 OpenFaaS DO K8s”这一明确前提下的真实落地细节包括那些官网文档里不会写、但你在生产环境凌晨三点排查故障时 desperately 需要的答案。2. 内容整体设计与思路拆解为什么必须绕开 Helm Chart 的“一键安装”幻觉2.1 官方 Helm Chart 的三大隐性代价OpenFaaS 官方 GitHub 仓库里那个 star 数最高的openfaas/faas-netesHelm Chart表面看是“一键部署神器”实测下来却是多数团队踩坑的起点。我带过两个项目组第一次直接helm install openfaas openfaas/openfaas结果上线第三天就因网关 Pod 反复 OOM 被驱逐第二次改用--set functionNamespaceopenfaas-fn显式指定命名空间又发现自定义域名的 TLS 证书始终无法注入到 Gateway 的 Envoy 实例中。问题根源不在 Chart 本身而在它试图“抹平”K8s 原生能力差异的设计哲学。代价一Operator 模式被弱化为静态 DaemonSetChart 默认将faas-netesd即 OpenFaaS Operator部署为 DaemonSet这在 DigitalOcean 的标准 DOKS 集群节点数 ≥3下会导致多个 Operator 实例同时监听同一组 CRD 事件。K8s 的 etcd watch 机制不保证事件顺序当两个 Operator 几乎同时收到Function创建请求时其中一个会因409 Conflict报错退出 reconcile 循环而错误日志被淹没在kubectl logs -n openfaas deploy/gateway的海量输出里。正确做法是强制将其改为 Deployment并设置replicas: 1podAntiAffinity确保单实例高可用。代价二Gateway 的 Service 类型硬编码为 LoadBalancerDigitalOcean 的 LoadBalancer 服务背后是其专有 L4 负载均衡器它不支持 HTTP/2 ALPN 协商也不透传X-Forwarded-For头部。当你用faas-cli invoke --gateway https://myapp.example.com hello-world调用函数时Gateway 收到的RemoteAddr是 DO LB 的内网 IP而非真实客户端 IP。更致命的是DO LB 默认关闭了 WebSocket 支持导致faas-cli logs -f功能彻底失效。解决方案不是换云厂商而是将 Gateway Service 改为ClusterIP再通过 DigitalOcean 官方推荐的 Nginx Ingress Controller带nginx.ingress.kubernetes.io/ssl-passthrough: true注解做七层代理。代价三TLS 证书管理与 Cert-Manager 强耦合Chart 中certManager.enabledtrue的开关看似方便但它要求你提前在openfaas命名空间里部署 Cert-Manager 的 CRD 和控制器。而 DigitalOcean 的 DOKS 集群默认不启用ValidatingWebhookConfigurationCert-Manager 的 webhook 服务会因证书校验失败而 CrashLoopBackOff。我们最终采用的是“手动注入”模式用openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj /CN*.openfaas.example.com生成通配符证书再通过kubectl create secret tls openfaas-tls --certtls.crt --keytls.key -n openfaas注入Gateway Deployment 中通过 volumeMount 挂载该 Secret。2.2 我们选择的最小可行架构MVA基于上述教训我们为 DigitalOcean Kubernetes 设计了一套“去 Helm 化”的最小可行架构Minimal Viable Architecture它只包含 4 个核心组件全部用原生 K8s YAML 管理openfaas 命名空间带istio-injectiondisabled标签避免与 Istio 冲突资源配额限制 CPU 200m / 内存 512Mifaas-netesd Operator Deployment单副本使用nodeSelector锁定到专用控制节点避免与业务 Pod 争抢资源livenessProbe 检查/healthz端点gateway Service DeploymentService 类型为 ClusterIPDeployment 启用--set gateway.replicas2并配置 HPACPU 使用率 70% 时扩容NATS Streaming StatefulSet3 副本使用 DigitalOcean Block Storage 的 PVCstorageClassName: do-block-storage确保消息持久化不丢。这套架构放弃了一切“自动化便利”换来的是对每个组件生命周期的绝对掌控。比如当需要升级 OpenFaaS 版本时我们不再运行helm upgrade而是直接kubectl set image deploy/gateway gatewayopenfaas/gateway:0.28.0 -n openfaas整个过程耗时 12 秒且滚动更新期间函数调用零中断——因为 Gateway 的 readinessProbe 会精确等待新 Pod 的/system/health返回 200 后才将其加入 Endpoints。提示DigitalOcean 的 DOKS 集群默认启用了PodSecurityPolicyPSP而 OpenFaaS 的默认 YAML 中faas-netesd的 SecurityContext 缺少privileged: false声明。这会导致 Pod 无法启动报错admission webhook psp.mutating.webhook.admission.k8s.io denied the request。必须在所有 Deployment 的spec.template.spec.containers[].securityContext中显式添加该字段。3. 核心细节解析与实操要点从 DO 控制台到第一个函数的 7 个关键断点3.1 断点一DOKS 集群创建时的三个必选参数很多教程跳过这一步直接假设“你已经有了一个 K8s 集群”。但在 DigitalOcean集群创建阶段的三个参数直接决定了后续 OpenFaaS 的稳定性上限Kubernetes 版本选择必须选v1.26.x或v1.27.x严禁使用 v1.28。原因在于 OpenFaaS 0.28.x当前最新稳定版的 CRD 定义仍基于apiextensions.k8s.io/v1beta1而 v1.28 已彻底移除该 API 组。你若强行部署kubectl apply -f https://raw.githubusercontent.com/openfaas/faas-netes/master/namespaces.yml会返回error: unable to recognize STDIN: no matches for kind CustomResourceDefinition in version apiextensions.k8s.io/v1beta1。DigitalOcean 控制台在创建集群时默认推荐的是最新版务必手动下拉选择。节点池配置中的“标签”在“Node Pools”配置页点击“Add Node Pool”后在“Labels”输入框里填入openfaas-rolecontrol。这不是可选项而是为后续 Operator 部署做准备。我们将 Operator 限定在此类节点上运行避免其与业务函数 Pod 共享 CPU CFS 配额导致函数冷启动延迟飙升。命令行创建方式为doctl kubernetes cluster create my-openfaas-cluster --version 1.27.10-do.0 --node-pool namecontrol;count2;sizes-2vcpu-4gb;tagsopenfaas-rolecontrol。VPC 与防火墙策略创建集群时必须勾选“Use existing VPC”并选择你已配置好的私有网络。更重要的是在“Firewall Rules”部分必须放行 TCP 端口 8080 和 8081。这是 OpenFaaS Gateway 的默认监听端口HTTP 和 HTTPSDigitalOcean 的默认防火墙规则会阻止所有入站流量即使你后续配置了 IngressLB 也无法将流量转发到 Gateway Pod。3.2 断点二faas-cli 的安装与身份认证不是“下一步”而是安全基线faas-cli看似只是个命令行工具但它承载着 OpenFaaS 的全部访问控制逻辑。DigitalOcean 的 DOKS 集群默认启用 RBAC而 OpenFaaS 的gatewayServiceAccount 默认只有openfaas命名空间内的读写权限。如果你跳过认证步骤直接faas-cli list会得到Unauthorized错误。正确流程是四步闭环获取集群凭证doctl kubernetes cluster kubeconfig save my-openfaas-cluster创建专用 ServiceAccountkubectl create serviceaccount openfaas-admin -n openfaas kubectl create clusterrolebinding openfaas-admin --clusterrolecluster-admin --serviceaccountopenfaas:openfaas-admin提取 Token 并配置 faas-cliTOKEN$(kubectl get secret $(kubectl get serviceaccount openfaas-admin -n openfaas -o jsonpath{.secrets[0].name}) -n openfaas -o jsonpath{.data.token} | base64 --decode) faas-cli login -g https://gateway.openfaas.svc.cluster.local:8080 -p $TOKEN --skip-tls-verify验证权限faas-cli list --gateway https://gateway.openfaas.svc.cluster.local:8080应返回空列表无函数而非报错。注意--skip-tls-verify是必须的。因为 Gateway 的自签名证书 CN 是gateway.openfaas.svc.cluster.local而faas-cli login默认校验证书域名。你不能用kubectl port-forward临时暴露 Gateway 来绕过因为 port-forward 会破坏 TLS SNI 扩展导致证书校验失败。3.3 断点三函数镜像构建必须用faas-cli build禁用docker build这是新手最容易犯的致命错误。OpenFaaS 的函数运行时如python3、node不是通用容器而是预置了特定入口点entrypoint和健康检查路径的定制镜像。如果你直接docker build -t myfunc .生成的镜像缺少/healthz端点和/function的 HTTP handlerGateway 会持续返回503 Service Unavailable。faas-cli build的核心作用是两件事注入模板层以python3模板为例它会将你的handler.py复制到openfaas/python3:latest基础镜像中并覆盖其默认的index.py重写 Dockerfile生成的.dockerignore会排除build/和template/目录防止体积膨胀Dockerfile 中的CMD被替换为[/usr/bin/fwatchdog]这是 OpenFaaS 的守护进程负责接收 HTTP 请求并转发给你的 handler。实操命令# 初始化函数项目自动下载 python3 模板 faas-cli template pull faas-cli new --lang python3 hello-world # 修改 handler.py添加一行 print(Hello from OpenFaaS!) faas-cli build -f hello-world.yml构建完成后faas-cli push -f hello-world.yml会将镜像推送到你配置的私有 Registry如 DigitalOcean Container Registry或公共 Registry如 Docker Hub。注意hello-world.yml中的image:字段必须是完整路径例如registry.digitalocean.com/my-registry/hello-world。3.4 断点四部署时的--annotation是解决“函数不触发”的唯一钥匙部署函数后faas-cli list能看到函数状态为Ready但curl -X POST http://gateway.openfaas.svc.cluster.local:8080/function/hello-world却返回404 Not Found。这个问题 90% 的案例都源于一个被忽略的注解annotation。OpenFaaS Gateway 默认只暴露http协议的函数。当你在 DigitalOcean 上通过 Ingress 暴露函数时Ingress Controller 会将 HTTPS 请求降级为 HTTP 转发给 Gateway但 Gateway 的路由表里没有该函数的 HTTPS 路由条目。解决方案是在部署时添加com.openfaas.health.httptrue注解faas-cli deploy \ -f hello-world.yml \ --annotation com.openfaas.health.httptrue \ --gateway https://gateway.openfaas.svc.cluster.local:8080这个注解的作用是告诉 Gateway“请为该函数创建一个 HTTP 健康检查端点”而 Gateway 的内部路由引擎会自动将此函数注册到http和https两个协议的路由表中。没有它函数永远处于“半激活”状态——Pod 运行正常日志无报错但外部请求就是 404。3.5 断点五Ingress 配置的三个不可妥协字段将 Gateway 暴露给公网必须通过 DigitalOcean 官方 Nginx Ingress Controller。其 YAML 配置中以下三个字段是硬性要求缺一不可apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: openfaas-gateway namespace: openfaas annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/ssl-passthrough: true # 关键透传 TLS否则证书校验失败 nginx.ingress.kubernetes.io/force-ssl-redirect: true # 强制 HTTPS spec: tls: - hosts: - openfaas.example.com secretName: openfaas-tls # 必须与你创建的 Secret 名称一致 rules: - host: openfaas.example.com http: paths: - path: / pathType: Prefix backend: service: name: gateway # 必须是 gateway Service 的名称 port: number: 8080 # Gateway 的 HTTP 端口特别注意nginx.ingress.kubernetes.io/ssl-passthrough: true。DigitalOcean 的 Nginx Ingress 默认关闭 SSL Passthrough这意味着它会终止 TLS 连接用自己的证书响应客户端再以 HTTP 方式向 Gateway 发起新请求。这会导致两个后果一是 Gateway 收不到原始 TLS 证书无法做双向认证二是X-Forwarded-Proto头部丢失函数内部无法判断请求是否来自 HTTPS。开启 Passthrough 后Nginx 只做 TCP 层转发所有 TLS 握手均由 Gateway 完成。3.6 断点六函数超时时间不是写死的而是由三个层级共同决定OpenFaaS 的函数超时timeout是一个典型的“多层叠加”参数修改任何一个都可能引发连锁反应第一层faas-cli deploy 的--env参数faas-cli deploy --env write_timeout30s设置的是函数进程的写超时即函数 handler 执行的最大时长。超过此值fwatchdog 会发送 SIGTERM 终止进程。第二层Gateway 的--set writeTimeout30s这是 Gateway 对函数 Pod 的 HTTP 客户端超时。它必须 ≥ 第一层的值否则 Gateway 会在函数 handler 还未结束时就关闭连接返回504 Gateway Timeout。第三层Ingress Controller 的proxy-read-timeoutDigitalOcean Nginx Ingress 默认proxy-read-timeout为 60 秒。如果函数执行 45 秒Gateway 正常返回但 Ingress 在 60 秒前未收到完整响应因网络抖动它会主动断开连接。因此必须在 Ingress 的 ConfigMap 中全局设置data: proxy-read-timeout: 120 proxy-send-timeout: 120三者关系是Ingress timeout ≥ Gateway timeout ≥ Function timeout。我们线上统一设为120s既避免了短时抖动误判又防止恶意函数无限占用资源。3.7 断点七日志查看必须用kubectl logs -c functionsfaas-cli logs是残废faas-cli logs -f hello-world在 DigitalOcean 环境下基本不可用。原因在于它依赖 NATS Streaming 的消息队列而 DO 的默认网络策略会阻止 Pod 间 UDP 流量NATS 使用 UDP 进行心跳探测。你执行该命令只会看到Error: dial tcp 10.244.1.5:4222: i/o timeout。真正可靠的日志方案是直接读取函数 Pod 的容器日志。由于 OpenFaaS 的函数 Pod 有两个容器hello-world你的函数和queue-worker处理异步任务必须指定-c参数# 查看函数主容器日志最常用 kubectl logs -n openfaas-fn deploy/hello-world -c hello-world -f # 查看 queue-worker 日志排查异步调用失败 kubectl logs -n openfaas-fn deploy/hello-world -c queue-worker -f为了提升效率我们编写了一个 shell 别名alias faas-logskubectl logs -n openfaas-fn deploy/$(basename $(pwd))-$(git rev-parse --short HEAD) -c $(basename $(pwd)) -f进入函数项目目录后直接敲faas-logs即可实时跟踪日志。4. 实操过程与核心环节实现从零开始的完整流水线含所有 YAML 和命令4.1 环境初始化创建集群、配置 CLI、准备 Registry第一步创建 DOKS 集群命令行方式确保可复现# 登录 DigitalOcean CLI doctl auth init # 创建集群指定版本、节点池、VPC doctl kubernetes cluster create openfaas-prod \ --region sgp1 \ --version 1.27.10-do.0 \ --node-pool namecontrol;count2;sizes-2vcpu-4gb;tagsopenfaas-rolecontrol \ --node-pool nameworkers;count3;sizes-4vcpu-8gb \ --tag openfaas \ --vpc-uuid $(doctl vpcs list --format ID --no-header | head -n1) # 获取 kubeconfig 并设置上下文 doctl kubernetes cluster kubeconfig save openfaas-prod kubectl config use-context do-sgp1-openfaas-prod第二步创建 DigitalOcean Container Registry用于存储函数镜像# 创建 registry区域必须与集群一致 doctl registry create openfaas-registry --region sgp1 # 登录 registry需先安装 doctl 和 docker-credential-do doctl registry login # 验证登录 echo {auths:{registry.digitalocean.com:{auth:$(echo -n $(doctl registry get openfaas-registry --format {{.AccessToken}} | tr -d \n):$(doctl registry get openfaas-registry --format {{.AccessToken}} | tr -d \n) | base64 -w0)}}} | docker-credential-do store第三步安装 faas-climacOS 示例Linux/Windows 类似# 下载最新版截至 2024 年 6 月为 0.14.10 curl -sL https://cli.openfaas.com | sudo sh # 验证 faas-cli version # 输出应为faas-cli: 0.14.104.2 OpenFaaS 核心组件部署纯 YAML 方式非 Helm创建openfaas-namespace.yamlapiVersion: v1 kind: Namespace metadata: name: openfaas labels: istio-injection: disabled --- apiVersion: v1 kind: Namespace metadata: name: openfaas-fn labels: istio-injection: disabled创建openfaas-operator.yaml精简版仅保留必要字段apiVersion: apps/v1 kind: Deployment metadata: name: faas-netesd namespace: openfaas spec: replicas: 1 selector: matchLabels: app: faas-netesd template: metadata: labels: app: faas-netesd spec: nodeSelector: openfaas-role: control serviceAccountName: openfaas-admin securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: faas-netesd image: openfaas/faas-netes:0.28.0 args: - --gateways-urlhttp://gateway.openfaas:8080 - --nats-addressnats.openfaas:4222 env: - name: namespaces value: openfaas-fn livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 30 periodSeconds: 10 resources: requests: cpu: 100m memory: 256Mi limits: cpu: 200m memory: 512Mi创建openfaas-gateway.yamlapiVersion: v1 kind: Service metadata: name: gateway namespace: openfaas spec: type: ClusterIP ports: - name: http port: 8080 targetPort: 8080 - name: https port: 8443 targetPort: 8443 selector: app: gateway --- apiVersion: apps/v1 kind: Deployment metadata: name: gateway namespace: openfaas spec: replicas: 2 selector: matchLabels: app: gateway template: metadata: labels: app: gateway spec: serviceAccountName: openfaas-admin securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: gateway image: openfaas/gateway:0.28.0 args: - --listen-http:8080 - --listen-https:8443 - --enable-authtrue - --tls-ca-cert/run/secrets/tls.crt - --tls-server-cert/run/secrets/tls.crt - --tls-server-key/run/secrets/tls.key ports: - containerPort: 8080 - containerPort: 8443 volumeMounts: - name: tls-certs mountPath: /run/secrets readOnly: true livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 15 periodSeconds: 5 resources: requests: cpu: 200m memory: 512Mi limits: cpu: 400m memory: 1Gi volumes: - name: tls-certs secret: secretName: openfaas-tls应用所有 YAMLkubectl apply -f openfaas-namespace.yaml kubectl apply -f openfaas-operator.yaml kubectl apply -f openfaas-gateway.yaml # 等待所有 Pod Running kubectl get pods -n openfaas -w4.3 函数开发与部署全流程以 Python 函数为例初始化项目# 创建项目目录 mkdir hello-world cd hello-world # 拉取 Python3 模板 faas-cli template pull # 创建函数定义文件 cat hello-world.yml EOF provider: name: openfaas gateway: https://gateway.openfaas.svc.cluster.local:8080 functions: hello-world: lang: python3 handler: ./handler image: registry.digitalocean.com/openfaas-registry/hello-world environment: write_timeout: 120s annotations: com.openfaas.health.http: true EOF # 创建 handler 目录和代码 mkdir handler cat handler/handler.py EOF def handle(req): Handle function request return fHello, {req}! Time: {__import__(time).strftime(%Y-%m-%d %H:%M:%S)} EOF构建、推送、部署# 构建镜像自动推送到 DO Registry faas-cli build -f hello-world.yml # 部署函数使用内部 gateway 地址 faas-cli deploy -f hello-world.yml --gateway https://gateway.openfaas.svc.cluster.local:8080 # 验证部署状态 faas-cli list --gateway https://gateway.openfaas.svc.cluster.local:8080 # 输出应显示 hello-world 状态为 Ready4.4 公网访问配置Ingress TLS DNS创建openfaas-ingress.yamlapiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: openfaas-gateway namespace: openfaas annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/ssl-passthrough: true nginx.ingress.kubernetes.io/force-ssl-redirect: true nginx.ingress.kubernetes.io/proxy-body-size: 50m spec: tls: - hosts: - openfaas.example.com secretName: openfaas-tls rules: - host: openfaas.example.com http: paths: - path: / pathType: Prefix backend: service: name: gateway port: number: 8080应用 Ingresskubectl apply -f openfaas-ingress.yaml # 获取 Ingress 的 EXTERNAL-IP即 DO LB 的 IP kubectl get ingress -n openfaas openfaas-gateway -o wide # 输出类似openfaas-gateway openfaas.example.com 159.203.123.45 80,443 10s配置 DNS在 DigitalOcean 控制台添加 A 记录openfaas.example.com→159.203.123.45等待 DNS 生效通常 60 秒测试公网调用# 使用 curl 测试自动跟随重定向到 HTTPS curl -X POST https://openfaas.example.com/function/hello-world -d World # 预期输出Hello, World! Time: 2024-06-15 14:22:334.5 监控与扩缩容让函数真正“Serverless”OpenFaaS 原生支持基于 Prometheus 指标的自动扩缩容。DigitalOcean 的 DOKS 集群默认已部署 Prometheus Operator我们只需配置 HorizontalPodAutoscalerHPA创建hello-world-hpa.yamlapiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: hello-world namespace: openfaas-fn spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: hello-world minReplicas: 1 maxReplicas: 10 metrics: - type: External external: metric: name: openfaas_function_invocation_rate selector: matchLabels: function_name: hello-world target: type: AverageValue averageValue: 10应用 HPAkubectl apply -f hello-world-hpa.yaml # 查看 HPA 状态 kubectl get hpa -n openfaas-fn # 输出应显示 TARGETS 列为 unknown/10表示指标收集正常验证扩缩容# 模拟高并发调用100 个请求每秒 10 个 for i in {1..100}; do curl -s -X POST https://openfaas.example.com/function/hello-world -d LoadTest-$i /dev/null if (( i % 10 0 )); then sleep 1; fi done # 1 分钟后查看副本数变化 kubectl get deploy -n openfaas-fn hello-world # 应从 1 副本增长到 3-5 副本5. 常见问题与排查技巧实录那些凌晨三点教会我的事5.1 问题速查表症状、根因、解决方案症状根因解决方案faas-cli list返回UnauthorizedServiceAccount 权限不足或 Token 过期重新运行kubectl create clusterrolebinding并用新 Token 登录函数状态为Ready但curl返回503 Service UnavailableGateway 的readinessProbe失败通常是 TLS 证书路径错误检查openfaas-gateway.yaml中volumeMounts的mountPath是否为/run/secretsSecret 名称是否匹配faas-cli logs -f func报dial tcp ...:4222: i/o timeoutNATS Streaming Pod 未就绪或网络策略阻止 UDPkubectl get pods -n openfaas查看natsPod 状态kubectl get networkpolicy -A检查是否有拒绝 UDP 的策略函数调用返回504 Gateway TimeoutGateway 的writeTimeout小于函数write_timeout在hello-world.yml中增加environment.write_timeout: 120s并helm upgrade或kubectl set env更新 GatewayIngress 暴露后HTTPS 访问正常但 HTTP 返回308 Permanent Redirectnginx.ingress.kubernetes.io/force-ssl-redirect: true导致删除该 annotation或确保所有客户端都使用 HTTPS5.2 独家避坑技巧来自三次生产事故的总结技巧一用kubectl wait替代sleep做部署同步很多脚本用sleep 30等待 Pod 就绪这极不可靠。正确做法是# 等待 Gateway Pod 全部 Running kubectl wait --forconditionready pod -l appgateway -n openfaas --timeout120s # 等待函数 Deployment 的 rollout 完成 kubectl wait --forconditionavailable deploy/hello-world -n openfaas-fn --timeout120skubectl wait会实时监听 K8s 事件一旦条件满足立即返回比固定延时快 3-5 倍且 100% 可靠。技巧二函数镜像 Tag 必须包含 Git Commit SHA不要用latest或v1.0这样的模糊 Tag。每次faas-cli build前先执行