news 2026/6/23 9:21:59

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 一下就完事”的黑盒,那很快就会在函数冷启动超时、日志无法聚合、健康检查反复失败这些地方撞墙。

核心关键词OpenFaaSKubernetesDigitalOceanserverlessfaas-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 initdoctl 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 functionNamespace=openfaas-fn显式指定命名空间,又发现自定义域名的 TLS 证书始终无法注入到 Gateway 的 Envoy 实例中。问题根源不在 Chart 本身,而在它试图“抹平”K8s 原生能力差异的设计哲学。

  • 代价一:Operator 模式被弱化为静态 DaemonSet
    Chart 默认将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: 1+podAntiAffinity确保单实例高可用。

  • 代价二:Gateway 的 Service 类型硬编码为 LoadBalancer
    DigitalOcean 的 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.enabled=true的开关看似方便,但它要求你提前在openfaas命名空间里部署 Cert-Manager 的 CRD 和控制器。而 DigitalOcean 的 DOKS 集群默认不启用ValidatingWebhookConfiguration,Cert-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 --cert=tls.crt --key=tls.key -n openfaas注入,Gateway Deployment 中通过 volumeMount 挂载该 Secret。

2.2 我们选择的最小可行架构(MVA)

基于上述教训,我们为 DigitalOcean Kubernetes 设计了一套“去 Helm 化”的最小可行架构(Minimal Viable Architecture),它只包含 4 个核心组件,全部用原生 K8s YAML 管理:

  1. openfaas 命名空间:带istio-injection=disabled标签(避免与 Istio 冲突),资源配额限制 CPU 200m / 内存 512Mi;
  2. faas-netesd Operator Deployment:单副本,使用nodeSelector锁定到专用控制节点(避免与业务 Pod 争抢资源),livenessProbe 检查/healthz端点;
  3. gateway Service + Deployment:Service 类型为 ClusterIP,Deployment 启用--set gateway.replicas=2并配置 HPA(CPU 使用率 >70% 时扩容);
  4. NATS Streaming StatefulSet:3 副本,使用 DigitalOcean Block Storage 的 PVC(storageClassName: do-block-storage),确保消息持久化不丢。

这套架构放弃了一切“自动化便利”,换来的是对每个组件生命周期的绝对掌控。比如当需要升级 OpenFaaS 版本时,我们不再运行helm upgrade,而是直接kubectl set image deploy/gateway gateway=openfaas/gateway:0.28.0 -n openfaas,整个过程耗时 <12 秒,且滚动更新期间函数调用零中断——因为 Gateway 的 readinessProbe 会精确等待新 Pod 的/system/health返回 200 后才将其加入 Endpoints。

提示:DigitalOcean 的 DOKS 集群默认启用了PodSecurityPolicy(PSP),而 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.xv1.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-role=control。这不是可选项,而是为后续 Operator 部署做准备。我们将 Operator 限定在此类节点上运行,避免其与业务函数 Pod 共享 CPU CFS 配额,导致函数冷启动延迟飙升。命令行创建方式为:doctl kubernetes cluster create my-openfaas-cluster --version 1.27.10-do.0 --node-pool "name=control;count=2;size=s-2vcpu-4gb;tags=openfaas-role=control"

  • VPC 与防火墙策略:创建集群时,必须勾选“Use existing VPC”并选择你已配置好的私有网络。更重要的是,在“Firewall Rules”部分,必须放行 TCP 端口 8080 和 8081。这是 OpenFaaS Gateway 的默认监听端口(HTTP 和 HTTPS),DigitalOcean 的默认防火墙规则会阻止所有入站流量,即使你后续配置了 Ingress,LB 也无法将流量转发到 Gateway Pod。

3.2 断点二:faas-cli 的安装与身份认证不是“下一步”,而是安全基线

faas-cli看似只是个命令行工具,但它承载着 OpenFaaS 的全部访问控制逻辑。DigitalOcean 的 DOKS 集群默认启用 RBAC,而 OpenFaaS 的gatewayServiceAccount 默认只有openfaas命名空间内的读写权限。如果你跳过认证步骤直接faas-cli list,会得到Unauthorized错误。

正确流程是四步闭环:

  1. 获取集群凭证doctl kubernetes cluster kubeconfig save my-openfaas-cluster
  2. 创建专用 ServiceAccount
    kubectl create serviceaccount openfaas-admin -n openfaas kubectl create clusterrolebinding openfaas-admin --clusterrole=cluster-admin --serviceaccount=openfaas:openfaas-admin
  3. 提取 Token 并配置 faas-cli
    TOKEN=$(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
  4. 验证权限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 的函数运行时(如python3node)不是通用容器,而是预置了特定入口点(entrypoint)和健康检查路径的定制镜像。如果你直接docker build -t myfunc .,生成的镜像缺少/healthz端点和/function的 HTTP handler,Gateway 会持续返回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.http=true注解:

faas-cli deploy \ -f hello-world.yml \ --annotation com.openfaas.health.http=true \ --gateway https://gateway.openfaas.svc.cluster.local:8080

这个注解的作用是告诉 Gateway:“请为该函数创建一个 HTTP 健康检查端点”,而 Gateway 的内部路由引擎会自动将此函数注册到httphttps两个协议的路由表中。没有它,函数永远处于“半激活”状态——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_timeout=30s设置的是函数进程的写超时,即函数 handler 执行的最大时长。超过此值,fwatchdog 会发送 SIGTERM 终止进程。

  • 第二层:Gateway 的--set writeTimeout=30s
    这是 Gateway 对函数 Pod 的 HTTP 客户端超时。它必须 ≥ 第一层的值,否则 Gateway 会在函数 handler 还未结束时就关闭连接,返回504 Gateway Timeout

  • 第三层:Ingress Controller 的proxy-read-timeout
    DigitalOcean 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-logs='kubectl 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 "name=control;count=2;size=s-2vcpu-4gb;tags=openfaas-role=control" \ --node-pool "name=workers;count=3;size=s-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-cli(macOS 示例,Linux/Windows 类似)

# 下载最新版(截至 2024 年 6 月为 0.14.10) curl -sL https://cli.openfaas.com | sudo sh # 验证 faas-cli version # 输出应为:faas-cli: 0.14.10

4.2 OpenFaaS 核心组件部署:纯 YAML 方式(非 Helm)

创建openfaas-namespace.yaml

apiVersion: 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-url=http://gateway.openfaas:8080 - --nats-address=nats.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.yaml

apiVersion: 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-auth=true - --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

应用所有 YAML:

kubectl apply -f openfaas-namespace.yaml kubectl apply -f openfaas-operator.yaml kubectl apply -f openfaas-gateway.yaml # 等待所有 Pod Running kubectl get pods -n openfaas -w

4.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 f"Hello, {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 状态为 Ready

4.4 公网访问配置:Ingress + TLS + DNS

创建openfaas-ingress.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" 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

应用 Ingress:

kubectl 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.com159.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:33

4.5 监控与扩缩容:让函数真正“Serverless”

OpenFaaS 原生支持基于 Prometheus 指标的自动扩缩容。DigitalOcean 的 DOKS 集群默认已部署 Prometheus Operator,我们只需配置 HorizontalPodAutoscaler(HPA):

创建hello-world-hpa.yaml

apiVersion: 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

应用 HPA:

kubectl 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.yamlvolumeMountsmountPath是否为/run/secrets,Secret 名称是否匹配
faas-cli logs -f funcdial tcp ...:4222: i/o timeoutNATS Streaming Pod 未就绪或网络策略阻止 UDPkubectl get pods -n openfaas查看natsPod 状态;kubectl get networkpolicy -A检查是否有拒绝 UDP 的策略
函数调用返回504 Gateway TimeoutGateway 的writeTimeout小于函数write_timeouthello-world.yml中增加environment.write_timeout: "120s",并helm upgradekubectl set env更新 Gateway
Ingress 暴露后,HTTPS 访问正常,但 HTTP 返回308 Permanent Redirectnginx.ingress.kubernetes.io/force-ssl-redirect: "true"导致删除该 annotation,或确保所有客户端都使用 HTTPS

5.2 独家避坑技巧:来自三次生产事故的总结

技巧一:用kubectl wait替代sleep做部署同步

很多脚本用sleep 30等待 Pod 就绪,这极不可靠。正确做法是:

# 等待 Gateway Pod 全部 Running kubectl wait --for=condition=ready pod -l app=gateway -n openfaas --timeout=120s # 等待函数 Deployment 的 rollout 完成 kubectl wait --for=condition=available deploy/hello-world -n openfaas-fn --timeout=120s

kubectl wait会实时监听 K8s 事件,一旦条件满足立即返回,比固定延时快 3-5 倍,且 100% 可靠。

技巧二:函数镜像 Tag 必须包含 Git Commit SHA

不要用latestv1.0这样的模糊 Tag。每次faas-cli build前,先执行:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/23 9:20:05

医疗AI模型输入表示优化:数值离散化与时间编码的工程实践

1. 项目概述&#xff1a;为什么医疗AI的“喂食”方式如此关键&#xff1f;在医疗AI领域&#xff0c;我们常常把模型比作一个需要精心喂养的“大脑”。你给它喂什么&#xff0c;它就能学会什么&#xff0c;最终能解决什么问题。这个“喂什么”的过程&#xff0c;在技术上被称为“…

作者头像 李华
网站建设 2026/6/23 9:19:40

Debian 10 手动部署 ClickHouse 23.x 生产级实践指南

1. 项目概述&#xff1a;为什么在 Debian 10 上亲手部署 ClickHouse 是件值得花两小时的事ClickHouse 不是另一个“又一个数据库”&#xff0c;它是为实时分析而生的引擎——当你需要在十亿行日志里秒级响应“过去一小时每个城市订单量Top10”&#xff0c;或者在毫秒内完成广告…

作者头像 李华
网站建设 2026/6/23 9:19:29

Playwright网络请求精细化控制:allowedOrigins与blockedOrigins实战指南

1. 项目概述&#xff1a;为什么需要精细化控制网络请求&#xff1f; 在自动化测试和网页爬虫的世界里&#xff0c;Playwright 已经成为了一个绕不开的名字。它以其强大的跨浏览器支持、可靠的自动等待机制和丰富的 API 赢得了开发者的青睐。然而&#xff0c;当我们深入到复杂的…

作者头像 李华
网站建设 2026/6/23 9:16:41

Python http.server 深度解析:从命令行到HTTPS生产级实践

1. 项目概述&#xff1a;为什么一个“简单HTTP服务器”值得你花20分钟认真读完“How to Create a Simple HTTP Server in Python”——这个标题看起来像教科书里的入门小节&#xff0c;甚至可能被当成“Python安装完后第一个Hello World”的附属练习。但我在带过37个不同行业&a…

作者头像 李华
网站建设 2026/6/23 9:16:19

MC68SZ328芯片选择与DRAM控制器配置实战:时序、避坑与性能优化

1. 项目概述与核心价值在嵌入式硬件开发的深水区&#xff0c;尤其是面对像MC68SZ328这类集成了丰富外设的经典微控制器时&#xff0c;芯片选择&#xff08;Chip-Select&#xff09;和DRAM控制器的配置往往是决定系统稳定性和性能上限的关键。这不仅仅是照着数据手册填几个寄存器…

作者头像 李华
网站建设 2026/6/23 9:16:11

Java应用安全新防线:RASP技术原理、部署与实战防御

1. 项目概述&#xff1a;为什么RASP是Java安全的新防线&#xff1f;在Java应用安全领域&#xff0c;我们经历了从“边界防护”到“运行时免疫”的深刻转变。传统的WAF&#xff08;Web应用防火墙&#xff09;和IDS/IPS&#xff08;入侵检测/防御系统&#xff09;像是守在城堡门口…

作者头像 李华