排查 Cloud Run functions 问题

本文档介绍了如何在使用 Cloud Run functions 时排查错误消息并解决问题。

部署

本部分列出了您可能遇到的部署问题,并提供了有关如何解决这些问题的建议。您在部署期间可能遇到的许多问题都与角色和权限或错误配置有关。

您可以使用 Identity and Access Management 授权身份对使用 Cloud Functions v2 API 创建的函数执行管理操作,例如使用 gcloud functions、REST API 或 Terraform 执行操作。管理操作包括创建、更新和删除函数。如需了解详情,请参阅使用 IAM 授予访问权限

部署函数时,用户缺少运行时服务账号的权限

每个函数都与一个服务账号关联,该服务账号充当函数访问其他资源时的身份。此运行时服务账号可以是默认服务账号,也可以是用户管理的服务账号。在多个函数正在访问不同资源的环境中,通常的做法是使用每个函数身份,并使用命名的运行时服务账号而不是默认的运行时服务账号 (PROJECT_NUMBER-compute@developer.gserviceaccount.com)。

如需使用运行时服务账号,部署者必须具有该服务账号的 iam.serviceAccounts.actAs 权限。创建非默认运行时服务账号的用户将自动获得此权限,但其他部署者必须由某一用户授予此权限。

使用 Project Viewer、Cloud Functions Developer 或 Cloud Functions Admin 角色为用户分配运行时服务账号的 iam.serviceAccounts.actAs 权限。

错误消息

控制台

  You must have the iam.serviceAccounts.actAs permission on the selected service account. To obtain this permission, you can grant a role that includes it like the Service Account User role, on the project.

gcloud

默认服务账号:

ERROR: (gcloud.functions.deploy) ResponseError: status=[403], code=[Ok], message=[Caller is missing permission 'iam.serviceaccounts.actAs' on service account projects/-/serviceAccounts/PROJECT_NUMBER-compute@developer.gserviceaccount.com.Grant the role 'roles/iam.serviceAccountUser' to the caller on the service account projects/-/serviceAccounts/PROJECT_NUMBER-compute@developer.gserviceaccount.com.You can do that by running 'gcloud iam service-accounts add-iam-policy-binding projects/-/serviceAccounts/PROJECT_NUMBER-compute@developer.gserviceaccount.com --member MEMBER --role roles/iam.serviceAccountUser'where MEMBER has a prefix like 'user:' or 'serviceAccount:'

非默认服务账号:

ERROR: (gcloud.functions.deploy) ResponseError: status=[403], code=[Ok], message=[Caller is missing permission 'iam.serviceaccounts.actAs' on service account projects/-/serviceAccounts/
SERVICE_ACCOUNT_NAME@PROJECT_ID
.iam.gserviceaccount.com.Grant the role 'roles/iam.serviceAccountUser' to the caller on the service account projects/-/serviceAccounts/
SERVICE_ACCOUNT_NAME@PROJECT_ID
.iam.gserviceaccount.com.You can do that by running 'gcloud iam service-accounts add-iam-policy-binding projects/-/serviceAccounts/
SERVICE_ACCOUNT_NAME@PROJECT_ID
.iam.gserviceaccount.com --member MEMBER --role roles/iam.serviceAccountUser'where MEMBER has a prefix like 'user:' or 'serviceAccount:'

解决方案

在默认或非默认运行时服务账号上为用户分配 Service Account User 角色 (roles/iam.serviceAccountUser)。此角色可提供 iam.serviceAccounts.actAs 权限。

部署事件驱动的函数时,部署服务账号缺少 Pub/Sub 权限

执行管理操作时,Cloud Functions 服务会使用 Cloud Functions Service Agent 服务账号 (service-PROJECT_NUMBER@gcf-admin-robot.iam.gserviceaccount.com)。 默认情况下,此账号拥有 Cloud Functions cloudfunctions.serviceAgent 角色。为了部署事件驱动的函数,Cloud Functions 服务必须访问 Pub/Sub 以配置主题和订阅。如果您更改了分配给服务账号的角色,但未授予适当的权限,则 Cloud Functions 服务将无法访问 Pub/Sub,因此部署将失败。

错误消息

控制台

Validation failed for trigger projects/PROJECT_ID/locations/LOCATION/triggers/FUNCTION_NAME-EVENTARC_ID: Permission "iam.serviceAccounts.ActAs" denied on "EndUserCredentials to PROJECT_NUMBER-compute@developer.gserviceaccount.com"

gcloud

ERROR: (gcloud.functions.deploy) ResponseError: status=[403], code=[Ok], message=[Validation failed for trigger projects/test-project-356312/locations/LOCATION/triggers/FUNCTION_NAME-EVENTARC_ID: Permission "iam.serviceAccounts.ActAs" denied on "EndUserCredentials to PROJECT_NUMBER-compute@developer.gserviceaccount.com"]

解决方案

您可以重置服务账号为默认的 cloudfunctions.serviceAgent 角色。

默认运行时服务账号不存在

如果您未指定用户管理的运行时服务账号,Cloud Functions 会使用默认的计算服务账号作为运行时服务账号。如果您删除默认账号但未指定用户管理的账号,部署将会失败。

错误消息

gcloud

ERROR: (gcloud.functions.deploy) ResponseError: status=[404], code=[Ok], message=[Service account projects/-/serviceAccounts/PROJECT_NUMBER-compute@developer.gserviceaccount.com was not found.]

解决方案

如需解决此问题,请按以下任一解决方案操作:

部署函数时,Cloud Functions Service Agent 服务账号缺少项目存储桶权限

Cloud Run functions 只能由来自同一 Google Cloud Platform 项目中的 Cloud Storage 存储桶的事件触发。此外,Cloud Functions Service Agent 服务账号 (service-PROJECT_NUMBER@gcf-admin-robot.iam.gserviceaccount.com) 需要项目的 cloudfunctions.serviceAgent 角色。

错误消息

控制台

ERROR: (gcloud.functions.deploy) ResponseError: status=[403], code=[Ok], message=[Validation failed for trigger projects/PROJECT_ID/locations/LOCATION/triggers/FUNCTION_NAME-EVENTARC_ID: Permission "iam.serviceAccounts.ActAs" denied on "EndUserCredentials to PROJECT_NUMBER-compute@developer.gserviceaccount.com"]

gcloud

ERROR: (gcloud.functions.deploy) ResponseError: status=[403], code=[Ok], message=[Validation failed for trigger projects/<project-id>/locations/LOCATION/triggers/FUNCTION_NAME-EVENTARC_ID: Permission "iam.serviceAccounts.ActAs" denied on "EndUserCredentials to PROJECT_NUMBER-compute@developer.gserviceaccount.com"]

解决方案

如需解决此问题,请重置此服务账号为默认角色。

拥有 Project Editor 角色的用户无法公开函数

Project Editor 角色具有管理项目内资源的广泛权限,但它本身并不授予公开 Cloud Functions 的权限。部署该函数的用户或服务将需要 run.services.setIamPolicy 权限。

错误消息

gcloud

ERROR: (gcloud.run.services.add-iam-policy-binding) PERMISSION_DENIED: Permission 'run.services.setIamPolicy' denied on resource 'projects/PROJECT_ID/locations/LOCATION/functions/FUNCTION_NAME' (or resource may not exist).

解决方案

您可以:

使用资源位置限制条件组织政策时,函数部署失败

如果您的组织使用资源位置限制条件政策,则会限制将函数部署在受该政策限制的区域中。在 Google Cloud 控制台中,部署函数时,无法从区域下拉列表访问受限区域。

错误消息

gcloud

ResponseError: status=[400], code=[Ok], message=["LOCATION" violates constraint "constraints/gcp.resourceLocations" on the resource "projects/PROJECT_ID/locations/LOCATION/functions/FUNCTION_NAME".]

解决方案

您可以通过资源位置限制条件的 allowed_valuesdenied_values 列表添加或移除位置,以便成功部署。

执行函数的全局范围时函数部署失败

此错误表示您的代码存在问题。部署流水线已完成函数部署,但最后一步完成了,即向该函数发送健康检查。此健康检查用于执行函数的全局范围,这可能会导致异常、崩溃或超时。全局范围是您通常加载的库并初始化客户端的位置。

错误消息

在 Cloud Logging 日志中:

Could not create or update Cloud Run service FUNCTION_NAME, Container Healthcheck failed. Revision REVISION_NAMEE is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information.

解决方案

如需解决此问题,请按以下任一解决方案操作:

  • 如需更详细的错误消息,请查看函数的构建日志以及函数的运行时日志

  • 如果不清楚函数为何无法执行其全局范围,请考虑使用全局变量延迟加载,暂时将代码移动到请求调用中。这样,您就可以围绕您的客户端库添加额外的日志语句,这些语句可能会在其实例化时超时(尤其是当调用其他服务时),也可能完全崩溃/抛出异常。

  • 此外,请尝试增加函数超时。Cloud Run functions 的超时限制越长,初始化的喘息空间就越大,并且在 Cloud Run 环境中提供了可扩缩的资源分配,从而有可能缓解资源耗尽所造成的这个问题。

  • 源代码必须包含通过 Cloud 控制台gcloud 在部署中正确指定的入口点函数。

具有 Viewer 角色的用户无法部署函数

拥有 Project Viewer 或 Cloud Functions Viewer 角色的用户对函数和函数详细信息具有只读权限,并且无法部署新函数。创建函数功能在 Google Cloud 控制台中呈灰显状态,并显示以下错误:

错误消息

gcloud

ERROR: (gcloud.functions.deploy) ResponseError: status=[403], code=[Ok], message=[Permission 'cloudfunctions.functions.generateUploadUrl' denied on 'projects/PROJECT_ID/locations/LOCATION/functions']

解决方案

为用户分配 Cloud Functions Developer 角色。

Build 服务账号缺少权限

错误消息

在函数部署错误或构建日志中,您可能会看到以下错误之一:

The service account running this build does not have permission to write logs. To fix this, grant the Logs Writer (roles/logging.logWriter) role to the service account.
Step #0 - "fetch": failed to Fetch: failed to download archive gs://gcf-v2-sources-PROJECT_NUMBER-LOCATION/FUNCTION_NAME/version-VERSION_NUMBER/function-source.zip: Access to bucket gcf-v2-sources-PROJECT_NUMBER-LOCATION denied. You must grant Storage Object Viewer permission to PROJECT_NUMBER-compute@developer.gserviceaccount.com.
Step #2 - "build": ERROR: failed to create image cache: accessing cache image "LOCATION-docker.pkg.dev/PROJECT/gcf-artifacts/FUNCTION_NAME/cache:latest": connect to repo store "LOCATION-docker.pkg.dev/PROJECT/gcf-artifacts/FUNCTION_NAME/cache:latest": GET https://LOCATION-docker.pkg.dev/v2/token?scope=repository%3APROJECT%2Fgcf-artifacts%2FFUNCTION_NAME%2Fcache%3Apull&service=: DENIED: Permission "artifactregistry.repositories.downloadArtifacts" denied on resource "projects/PROJECT/locations/LOCATION/repositories/gcf-artifacts" (or it may not exist)
Could not build the function due to a missing permission on the build service account. If  you didn't revoke that permission explicitly, this could be caused by a change in the organization policies.

解决方案

Build 服务账号需要具备从源存储桶读取数据的权限以及对制品部署代码库的读写权限。如果 Cloud Build 使用服务账号的默认行为发生了变化,您可能会遇到此错误,详情请参阅 Cloud Build 服务账号更改

如需解决此问题,请使用以下任一解决方案:

Build 服务账号已停用

错误消息

Could not build the function due to disabled service account used by Cloud Build. Please make sure that the service account is active.

解决方案

您需要启用 Build 服务账号才能部署函数。如果 Cloud Build 使用服务账号的默认行为发生了变化,您可能会遇到此错误,详情请参阅 Cloud Build 服务账号更改

如需解决此问题,请使用以下任一解决方案:

服务

本部分列出了您可能遇到的服务问题,并提供了有关如何修复这些问题的建议。

由于函数需要身份验证,服务权限出错

未启用允许未经身份验证的调用的 HTTP 函数将会限制没有适当权限的最终用户和服务账号的访问。此错误消息表示调用者无权调用函数。

错误消息

HTTP 错误响应代码:403 禁止

HTTP 错误响应正文:

Error: Forbidden Your client does not have permission
to get URL /FUNCTION_NAME from this server.

解决方案

如需解决此问题,请按以下任一解决方案操作:

由于 allow internal traffic only 配置问题导致服务错误

入站流量设置限制是否可以通过您的 Google Cloud 项目或 VPC Service Controls 服务边界之外的资源调用 HTTP 函数。为入站网络配置仅允许内部流量设置时,此错误消息表示仅允许来自同一项目或 VPC Service Controls 边界中的 VPC 网络的请求。这也可能是默认 functions.net 网址的 404 错误

错误消息

HTTP 错误响应代码:404 未找到

解决方案

如需解决此错误,请按以下任一解决方案操作:

  • 确保请求来自您的 Google Cloud 项目或 VPC Service Controls 服务边界。

  • 将函数的入站流量设置更改为允许所有流量

  • Cloud Run functions 源代码也可能会因函数网址、HTTP 方法、逻辑错误等不正确而导致 404 错误。

函数调用缺少有效的身份验证凭据

调用用访问受限设置的 Cloud Run functions 需要 ID 令牌访问令牌刷新令牌不起作用。

错误消息

HTTP 错误响应代码:401 未授权

HTTP 错误响应正文:

Your client does not have permission to the requested URL 'FUNCTION_NAME'

解决方案

如需解决此错误,请按以下任一解决方案操作:

  • 确保您的请求包含 Authorization: Bearer ID_TOKEN 标头,并且该令牌是 ID 令牌,而不是访问令牌或刷新令牌。如果使用服务账号的私钥手动生成此令牌,则必须用自签名 JWT 令牌交换 Google 签名的身份令牌。如需了解详情,请参阅进行身份验证以便调用

    使用请求标头中的身份验证凭据调用 HTTP 函数。例如,您可以使用 gcloud 获取身份令牌,如下所示:

      curl  -H "Authorization: Bearer $(gcloud auth print-identity-token)" 
    https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
    如需了解详情,请参阅进行身份验证以便调用

  • 如果您的组织支持此函数,请重新部署您的函数以允许未经身份验证的调用。这在测试时非常有用。

函数停止执行,或在您的代码完成后继续运行

某些 Cloud Run functions 运行时允许用户运行异步任务。如果您的函数创建了此类任务,还必须明确等待这些任务完成。否则,可能会导致您的函数在错误时间停止执行。

错误行为

您的函数具有以下行为之一:

  • 您的函数会在异步任务仍在运行期间,但在指定的超时期限之前终止。
  • 当这些任务完成后,您的函数不会停止运行,而是继续运行,直到超时期结束。

解决方案

如果您的函数提前终止,则应确保在函数执行以下任何操作之前,函数的所有异步任务都已完成:

  • 返回一个值
  • 解决或拒绝返回的 Promise 对象(仅限 Node.js 函数)
  • 抛出未捕获的异常或错误
  • 发送 HTTP 响应
  • 调用回调函数

如果您的函数在完成异步任务后未能终止,您应在函数运行完成后验证其是否正确发出了 Cloud Run functions 信号。特别是,确保在函数完成其异步任务之后,立即执行上面列出的操作之一。

访问受 VPC Service Controls 保护的资源时出现运行时错误

默认情况下,Cloud Run functions 使用公共 IP 地址向其他服务发出出站请求。如果您的函数不在 VPC Service Controls 边界内,则在尝试访问受 VPC Service Controls 保护的 Google Cloud 服务时,可能由于服务边界拒绝而导致收到 HTTP 响应。

错误消息

在“已审核的资源”日志中,如下所示的条目:

"protoPayload": {
  "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
  "status": {
    "code": 7,
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.PreconditionFailure",
        "violations": [
          {
            "type": "VPC_SERVICE_CONTROLS",
  ...
  "authenticationInfo": {
    "principalEmail": "CLOUD_FUNCTION_RUNTIME_SERVICE_ACCOUNT",
  ...
  "metadata": {
    "violationReason": "NO_MATCHING_ACCESS_LEVEL",
    "securityPolicyInfo": {
      "organizationId": "ORGANIZATION_ID",
      "servicePerimeterName": "accessPolicies/NUMBER/servicePerimeters/SERVICE_PERIMETER_NAME"
  ...

解决方案

如需解决此错误,请按以下任一解决方案操作:

可伸缩性

本部分列出了可伸缩性问题,并提供了有关如何修复每个问题的建议。

与待处理队列请求中止相关的 Cloud Logging 错误

以下场景可能会发生扩缩故障:

  • 流量突然激增。
  • 冷启动时间较长。
  • 请求处理时间较长。
  • 函数错误率高。
  • 达到实例数上限,导致系统无法扩容。
  • 归因于 Cloud Run functions 服务的暂时性因素。

在每种情况下,Cloud Run functions 扩容速度可能不够快,无法管理流量。

错误消息

  • The request was aborted because there was no available instance
    • severity=WARNING(响应代码:429)由于您在配置期间设置的 max-instances 限制,导致 Cloud Run functions 无法扩缩。
    • severity=ERROR(响应代码:500)Cloud Run functions 本身无法管理流量速率。

解决方案

  • 如需解决此问题,请解决之前列出的原因。

  • 对于基于 HTTP 触发器的函数,让客户端对不能丢弃的请求实现指数退避和重试。如果您要通过 Workflows 触发 Cloud Run functions,则可以使用 try/retry 语法来实现此目的。

  • 对于后台或事件驱动型函数,Cloud Run functions 支持至少传送一次。即使未明确启用重试功能,事件也将自动重新传送,并且函数执行将重试。如需了解详情,请参阅重试事件驱动的函数

  • 如果问题的根本原因是仅归因于 Cloud Run functions 的严重瞬时错误,或者您需要有关问题的帮助,请与支持团队联系。

  • 对于与冷启动相关的问题,请配置实例数下限,以减少冷启动次数,从而降低结算费用。

日志记录

以下部分介绍了日志记录问题以及修复方法。

日志条目没有日志严重级别或具有不正确的日志严重级别

默认情况下,Cloud Run functions 包含运行时日志记录。写入 stdoutstderr 的日志会自动显示在 Cloud Logging 中。但在默认情况下,这些日志条目仅包含字符串消息。

错误消息

日志中没有严重级别或具有错误的严重级别。

解决方案

如需包含日志严重程度,您必须发送结构化日志条目

在崩溃时以不同方式处理或记录异常

您可能需要自定义如何管理和记录崩溃信息。

解决方案

try 块中封装您的函数,以自定义处理异常和记录堆栈轨迹。

示例

import logging
import traceback
def try_catch_log(wrapped_func):
  def wrapper(*args, **kwargs):
    try:
      response = wrapped_func(*args, **kwargs)
    except Exception:
      # Replace new lines with spaces so as to prevent several entries which
      # would trigger several errors.
      error_message = traceback.format_exc().replace('\n', '  ')
      logging.error(error_message)
      return 'Error';
    return response;
  return wrapper;

#Example hello world function
@try_catch_log
def python_hello_world(request):
  request_args = request.args

  if request_args and 'name' in request_args:
    1 + 's'
  return 'Hello World!'

Node.js 10+、Python 3.8、Go 1.13 和 Java 11 中的日志太大

这些运行时中常规日志条目的大小上限为 105 KiB。

解决方案

发送的日志条目未超出此限制。

尽管 Cloud Run functions 返回错误,但日志缺失

Cloud Run functions 将 Cloud Run functions 函数日志流式传输到默认存储桶。当您创建项目时,Cloud Run functions 会创建并启用默认存储桶。如果默认存储桶已停用,或者 Cloud Run functions 函数日志在排除项过滤器中,则日志不会显示在 Logs Explorer 中。

解决方案

启用默认日志。

Cloud Run functions 函数日志未显示在 Logs Explorer 中

某些 Cloud Logging 客户端库使用异步过程来写入日志条目。如果函数崩溃或终止,则某些日志条目可能尚未写入,稍后可能会显示。某些日志可能会丢失,也无法在 Logs Explorer 中查看。

解决方案

使用客户端库界面在退出函数之前刷新缓冲的日志条目,或使用库同步写入日志条目。此外,您还可以将日志直接同步写入 stdoutstderr

使用日志路由器接收器时缺少 Cloud Run functions 函数日志

日志路由器接收器会将日志条目路由到不同的目的地。

控制台日志路由器的屏幕截图,其中突出显示了“查看接收器详情”

排除项过滤条件定义您可以舍弃的条目。

解决方案

移除为 resource.type = "cloud_run_revision" 设置的排除项过滤条件。

数据库连接数

连接到数据库时可能会发生很多问题,这些问题多数都与超出连接限制或超时有关。如果您在日志中看到 Cloud SQL 警告(例如 Context deadline exceeded),则可能需要调整连接配置。如需了解详情,请参阅 Cloud SQL 最佳做法

网络

本部分列出了网络问题,并提供了有关如何修复这些问题的建议。

网络连接

如果在您配置出站流量设置后,来自 Cloud Run functions 函数的所有出站请求都失败,您可以运行 Connectivity Tests 以识别任何潜在的网络连接问题。如需了解详情,请参阅创建和运行 Connectivity Tests

无服务器 VPC 访问通道连接器未就绪或不存在

如果无服务器 VPC 访问通道连接器失败,则它可能未按要求使用专用于连接器的 /28 子网掩码。

错误消息

Problem connecting to VPC Connector projects/xxxxx/locations/REGION/connectors/xxxx: Serverless VPC Access is not found.

如果由于缺少 Google APIs Service Agent 服务账号 PROJECT_NUMBER@cloudservices.gserviceaccount.com 的权限而使用处于错误状态的连接器部署 Cloud Run functions,则会导致以下错误:

错误消息

Failed to prepare VPC connector. Please try again later.

解决方案

列出您的子网,以检查您的连接器是否使用 /28 子网掩码。如果您的连接器未使用 /28 子网掩码,请重新创建连接器或创建新连接器

如需解决此问题,请按以下任一解决方案操作:

  • 如果您重新创建连接器,则无需重新部署其他函数。在重新创建连接器时,您可能会遇到网络中断。

  • 如果您创建新的备用连接器,请重新部署您的函数以使用新连接器,然后删除原始连接器。此方法可避免网络中断。

  • 确保 Cloud Run functions 及其关联的连接器部署在同一区域中。

  • 对于共享 VPC 配置:

    • 确保 VPC Connector 用于在项目中预配资源的服务账号 SERVICE_PROJECT_NUMBER@cloudservices.gserviceaccount.comservice-SERVICE_PROJECT_NUMBER@gcp-sa-vpcaccess.iam.gserviceaccount.com 没有缺少权限。如果连接器位于服务项目中,这些服务账号应在共享 VPC 配置的宿主项目中具有 roles/compute.networkUser 角色。

    • 如果连接器是在宿主项目中创建,请确保在宿主项目中的 Cloud Run Service Agent授予 Serverless VPC Access User 角色。

  • 如果连接器状态显示 Connector is in a bad state, manual deletion recommended 错误,并且 Google APIs Service Agent 缺少在连接器项目中预配计算资源所需的权限,请向 PROJECT_NUMBER@cloudservices.gserviceaccount.com 服务账号授予 roles/compute.admin。在某些情况下,添加这些权限后,可能需要重新创建连接器。

使用 TCP 端口 25 发送到外部目标 IP 地址的 SMTP 流量被阻止

为了提高安全性,从函数发送电子邮件时,Google Cloud 会阻止与 TCP 目标端口 25 的连接。

解决方案

如需取消阻止这些连接,请按照以下任何解决方案操作:

默认 functions.net 网址出现 404 错误

在 Cloud Run 中停用 run.app 网址还会阻止访问 Cloud Run functions(第 2 代)的默认 cloudfunctions.net 网址。造成此错误的原因也可能是因“仅允许内部流量”配置而导致的服务错误

错误消息

HTTP 错误响应代码:404 未找到

解决方案

要重新启用 Cloud Run functions(第 2 代)的默认 cloudfunctions.net 网址,您必须通过将 service.yaml 文件替换为新配置(其中 annotations:run.googleapis.com/default-url-disabled: false在 Cloud Run 中重新启用 run.app 网址