容器运行时合同

本页面列出了 Cloud Run 中容器的主要要求和行为。Cloud Run 服务和 Cloud Run 作业之间存在一些差异:我们会对存在差异的地方进行说明。

支持的语言和映像

您的容器映像可以运行以您选择的编程语言编写的代码并使用任何基础映像,前提是该映像遵循本页面中列出的限制条件。

必须针对 Linux 64 位编译容器映像中的可执行文件。Cloud Run 明确支持 Linux x86_64 ABI 格式。

Cloud Run 接受 Docker Image Manifest V2、架构 1架构 2OCI 映像格式的容器映像。 Cloud Run 还接受 Zstd 压缩的容器映像。

如果部署多架构映像,则清单列表必须包含 linux/amd64

对于通过 Cloud Run 部署的函数,您可以使用 Google Cloud 的 Buildpack 发布的某个 Cloud Run 运行时基础映像来接收自动安全和维护更新。如需了解受支持的运行时,请参阅运行时支持时间表

侦听正确的端口上的请求(服务)

Cloud Run 服务会启动 Cloud Run 实例来处理传入请求。一个 Cloud Run 实例始终有一个用于监听请求的入站流量容器,以及一个或多个可选边车容器。以下端口配置详细信息仅适用于入站流量容器,而不适用于边车。

实例中的入站流量容器必须在接收请求的端口上的 0.0.0.0 上监听请求。 值得注意的是,入站流量容器不应监听 127.0.0.1。默认情况下,请求会发送到 8080,但您可以配置 Cloud Run 以将请求发送到您选择的端口。Cloud Run 会将 PORT 环境变量注入入站流量容器中。

作业执行中运行的容器必须在完成时退出

对于 Cloud Run 作业,容器必须在作业成功完成时退出并显示退出代码 0,在作业失败时退出则显示非零退出代码。

由于作业不应处理请求,因此容器不应监听端口或启动 Web 服务器。

传输层加密 (TLS)

容器不应直接实现任何传输层安全协议。应由 Cloud Run 为 HTTPS 和 gRPC 终止 TLS,之后将请求以 HTTP/1 或 gRPC 形式通过代理转发到不具备 TLS 的容器。

如果您将 Cloud Run 服务配置为使用 HTTP/2 端到端连接,则容器必须处理 HTTP/2 明文 (h2c) 格式的请求,因为 TLS 仍会被 Cloud Run 自动终止。

响应(服务)

对于 Cloud Run 服务,容器必须在收到请求后,于请求超时设置中指定的时间内(包括容器启动时间)发送响应。否则,请求将结束并返回 504 错误。

响应缓存和 Cookie

如果 Cloud Run 服务的响应包含 Set-Cookie 标头,Cloud Run 会将 Cache-Control 标头设置为 private,以确保响应不会被缓存。这样做可以防止其他用户检索 Cookie。

环境变量

Cloud Run 服务和作业具有不同的环境变量。

服务的环境变量

以下环境变量会自动添加到所有正在运行的容器中(PORT 除外)。PORT 变量只会添加到入站流量容器:

名称 说明 示例
PORT 您的 HTTP 服务器应侦听的端口。 8080
K_SERVICE 正在运行的 Cloud Run 服务的名称。 hello-world
K_REVISION 正在运行的 Cloud Run 修订版本的名称。 hello-world.1
K_CONFIGURATION 创建了该修订版本的 Cloud Run 配置的名称。 hello-world

作业的环境变量

对于 Cloud Run 作业,系统会设置以下环境变量:

名称 说明 示例
CLOUD_RUN_JOB 正在运行的 Cloud Run 作业的名称。 hello-world
CLOUD_RUN_EXECUTION 正在运行的 Cloud Run 执行的名称。 hello-world-abc
CLOUD_RUN_TASK_INDEX 此任务的索引。从 0 开始(表示第一项任务),然后每次连续执行任务时递增 1,上限为最大任务数减 1。如果您将 --parallelism 设置为大于 1 的值,任务可能不会按照索引顺序执行。例如,任务 2 可能在任务 1 之前开始。 0
CLOUD_RUN_TASK_ATTEMPT 此任务已经重试的次数。从 0 开始(表示第一次尝试),然后每次连续重试时递增 1,上限为最大重试值。 0
CLOUD_RUN_TASK_COUNT --tasks 参数中定义的任务数。 1

请求和响应标头要求(服务)

对于 Cloud Run 服务,标头名称仅限于可打印的非空格 ASCII,且不能包含英文冒号。根据 IETF RFC 7230 的规定,标头值仅限于可见的 ASCII 字符,以及空格和水平制表符

文件系统访问

每个容器中的文件系统都是可写的,并且受以下行为的约束:

  • 这是一个内存内文件系统,因此向其中写入数据会使用实例的内存。
  • 停止实例时,写入文件系统的数据不会保留。

请注意,无法为此文件系统指定大小限制,因此,如果写入内存中文件系统,可能会耗尽分配给实例的所有内存,从而导致实例崩溃。如果您使用具有大小限制的专用内存中卷,则可以避免此问题。

实例生命周期

Cloud Run 作业和服务的生命周期特征不同,因此以下各子部分分别介绍了这些特征。

对于服务

以下内容仅适用于服务。

服务扩缩

默认情况下,Cloud Run 服务会自动扩缩到处理所有传入请求、事件或 CPU 利用率所需的实例数。如果您需要更好地控制扩缩行为,可以视情况使用手动扩缩

每个实例运行固定数量的容器(一个入站流量容器,以及可选的一个或多个 Sidecar 容器)。

当修订版本未收到任何流量时,它会缩减为配置的实例数下限(默认为零)。

启动

对于 Cloud Run 服务,实例必须在启动后的 4 分钟内监听请求,并且实例中的所有容器都需要运行状况良好。在此启动期间,系统会向实例分配 CPU。您可以启用启动 CPU 加速,在实例启动期间临时增加 CPU 分配,以缩短启动延迟时间。

一旦入站流量容器监听已配置的端口,请求就会立即发送到该容器。

等待实例的请求将在队列中保持待处理状态,如下所示:

请求将等待,最长为此服务容器实例平均启动时间的 3.5 倍或 10 秒(以较长者为准)。

您可以配置启动探测以确定容器是否已启动并已准备好处理请求。

对于由多容器实例组成的 Cloud Run 服务,您可以通过配置容器启动顺序来指定容器在实例中的启动顺序。

处理请求

对于 Cloud Run 服务,只要 Cloud Run 修订版本处理至少一个请求,CPU 就会始终分配给实例中的所有容器,包括边车。

空闲

对于 Cloud Run 服务,空闲实例是指未处理任何请求的实例。

分配给空闲实例中所有容器的 CPU 取决于所配置的结算设置

除非实例因实例数下限配置设置而必须保持空闲状态,否则它将保持空闲状态超过 15 分钟。

关停

对于 Cloud Run 服务,空闲实例可以随时关停,包括因所配置最少数量的实例保持备用状态的实例。如果需要关停正在处理请求的实例,系统会给予一定时间让正在处理的请求完成,并将新的传入请求路由到其他实例。在异常情况下,Cloud Run 可能会启动关停操作,并向仍在处理请求的容器发送 SIGTERM 信号。

在关停实例之前,Cloud Run 会向实例中的所有容器发送一个 SIGTERM 信号,指示实例将于 10 秒后进行实际的关停,届时 Cloud Run 则会发送一个 SIGKILL 信号。在此期间,系统会为实例分配 CPU 并计费。在使用第一代执行环境的服务中,如果实例未捕获 SIGTERM 信号,则会立即关停。在使用第二代执行环境的服务中,我们建议在容器上安装 SIGTERM 处理程序,以在 Cloud Run 即将关停实例时收到警告。

强制终止

如果一个或多个 Cloud Run 容器超过容器总内存限制,则实例将终止。所有仍在该实例上处理的请求都会被终止并显示 HTTP 500 错误。

对于作业

对于 Cloud Run 作业,容器实例会一直运行,直到容器实例退出、达到任务超时或容器崩溃。

退出代码

您可以使用作业退出代码来查看作业是否已成功完成,或者是否遇到了任何错误。退出代码是数值,用于表示成功完成或特定类型的错误。

下表列出了常见的退出代码及其定义:

退出代码 信号 说明
0 任务已成功完成。
4 SIGILL 任务尝试访问错误地址处的内存。
7 SIGBUS 任务尝试访问其分配边界之外的内存。
9 SIGKILL 任务被强制终止,无论是通过用户操作还是人工干预。
11 SIGSEGV 任务尝试访问未经授权的内存。
15 SIGTERM 当任务超出配置的超时时间时,会收到 SIGTERM 信号。应用服务器发送 SIGTERM 信号,以关停容器实例。如果实例在收到 SIGTERM 信号后的几秒内未自行关停,Cloud Run 会发送 SIGKILL 信号以强制终止。如果实例以 SIGTERM 正确退出,则可能会报告其他错误代码;否则,它会返回 SIGTERM

强制终止

如果 Cloud Run 容器实例超出允许的内存限制,则该容器实例会被终止。所有仍在该容器实例上处理的请求都会被终止并显示 HTTP 500 错误。

如果任务超出任务超时,Cloud Run 会发送“SIGTERM”信号,指示容器实例将于 10 秒后实际关停,届时 Cloud Run 会发送 SIGKILL 信号,关闭容器实例。

在此期间,容器实例在整个生命周期中都会被分配 CPU 并计费。

请参阅 SIGTERM 代码示例,了解如何捕获 SIGTERM 信号。

容器实例资源

以下部分介绍了容器实例的资源:

CPU

默认情况下,系统会为实例中的每个 Cloud Run 容器分配已配置的 vCPU(默认 1 个)vCPU。您可以分别配置每个容器的 CPU 限制。

vCPU 是底层硬件的抽象,可提供可变 CPU 平台上单个硬件超线程的大致等效 CPU 时间。Cloud Run 使用的所有 CPU 平台都支持 AVX2 指令集。请注意,容器合同不包含任何其他 CPU 平台详细信息。

容器可以同时在多个核心上执行。

对于 Cloud Run 服务,CPU 分配取决于所选结算方式。

如果您选择基于实例的结算方式,则系统会在实例的生命周期内分配 CPU。如果您选择基于请求的结算方式(默认),则系统会在实例处理请求时分配 CPU。如需了解详情,请参阅结算设置

如果您配置了一些实例数下限,则必须使用基于实例的结算方式,以便在请求之外分配 CPU。

您可以启用启动 CPU 加速,在实例启动期间临时增加 CPU 分配,以缩短启动延迟时间。

内存

默认情况下,系统会为每个 Cloud Run 容器分配已配置的内存(默认为 512 MiB)。您可以分别配置每个容器的内存限制。

内存的典型用途包括:

  • 将代码加载到内存中以运行服务
  • 写入文件系统
  • 在容器中运行的额外进程(例如 nginx 服务器)
  • PHP OpCache 等内存缓存系统
  • 每个请求的内存用量
  • 共享内存中卷

GPU

您可以在 Cloud Run 实例中配置容器以访问 GPU。如果 Cloud Run 服务是与边车容器一起部署的,则部署中只有一个容器可以访问 GPU。如需了解要求和详细信息,请参阅配置 GPU

NVIDIA 库

默认情况下,所有 NVIDIA L4 驱动程序库都会装载到 /usr/local/nvidia/lib64 下。 Cloud Run 会自动将此路径附加到包含 GPU 的容器的 LD_LIBRARY_PATH 环境变量(即 ${LD_LIBRARY_PATH}:/usr/local/nvidia/lib64)。这可让动态链接器找到 NVIDIA 驱动程序库。该链接器会按照您在 LD_LIBRARY_PATH 环境变量中列出的顺序搜索和解析路径。您在此变量中指定的任何值的优先级都高于默认的 Cloud Run 驱动程序库路径 /usr/local/nvidia/lib64

如果您想使用大于 12.2 的 CUDA 版本,最简单的方法是依赖于已安装向前兼容性软件包的较新 NVIDIA 基础映像。另一种方法是手动安装 NVIDIA 向前兼容性软件包,并将其添加到 LD_LIBRARY_PATH。请参阅 NVIDIA 的兼容性矩阵,确定哪些 CUDA 版本与提供的 NVIDIA 驱动程序版本 (535.216.03) 向后兼容。

并发(服务)

对于 Cloud Run 服务,每个 Cloud Run 实例默认设置为多个并发,其中入站流量容器可以同时接收多个请求。您可以通过设置并发来更改此设置。

容器沙盒

如果您使用第一代执行环境,则会使用 gVisor 容器运行时沙盒对 Cloud Run 容器进行沙盒化。如 gVisor syscall 兼容性参考文档中所述,此容器沙盒可能不支持某些系统调用。

如果您使用第二代执行环境,则可完全兼容 Linux。Cloud Run 作业始终使用第二代执行环境。在第二代执行环境中,/sys/class/dmi/id/product_name 设置为 Google Compute Engine

第二代执行环境在单独的进程命名空间中运行您的服务代码,因此它会作为具有特殊进程语义的容器 init 进程启动。在第一代执行环境中,服务代码不会作为容器 init 进程运行。

文件描述符限制

Cloud Run 第一代和第二代环境将进程可打开的文件描述符数量上限设置为 25,000。这适用于容器以及它创建的任何子进程(分支)。这是硬性限制。如果超出此限制,则实例可能会用尽文件描述符/套接字。

第二代环境中的限制

第二代环境中的限制是标准 Linux 限制。

例如,对可打开的文件描述符数量的限制(如 /proc/sys/fs/file-max 中所述)使用默认值,即大约 10% 的内存。如需了解详情,请参阅内核文档中的 file-maxfile-nr

同样,max_map_count(如 /proc/sys/vm/max_map_count 中所捕获的那样)用于设置进程可以拥有的内存区域数,默认值为 65,535。如需了解详情,请参阅内核文档中的 max-map-count

特权容器和 setuid 二进制文件

Cloud Run 不支持特权容器。因此,Cloud Run 不支持使用 setuid 标志(例如 gcsfusesudo)的非根用户二进制文件,并且可能会因权限不足而失败。

一种替代方法是以根用户身份执行这些二进制文件,然后在运行时使用 su 命令切换到其他用户。

例如,在 Dockerfile 中,移除 USER 指令,并在入口点脚本中使用以下序列:

gcsfuse ...                 # Run gcsfuse as root
su myuser -c "/yourapp.sh"  # Switch to 'myuser' and run 'yourapp.sh'

执行用户

如果用户名不存在,Cloud Run 会以根用户 (uid=0) 身份运行容器。

实例元数据服务器

Cloud Run 实例公开一个元数据服务器,您可以使用该服务器检索容器的详细信息,例如项目 ID、区域、实例 ID 或服务账号。您还可以使用元数据服务器为服务身份生成令牌

如需访问元数据服务器数据,请使用带有 Metadata-Flavor: Google 标头的 HTTP 请求向 http://metadata.google.internal/ 端点提出请求:不需要客户端库。如需了解详情,请参阅获取元数据

下表列出了部分可用的元数据服务器信息:

路径 说明
/computeMetadata/v1/project/project-id Cloud Run 服务或作业所属项目的 ID
/computeMetadata/v1/project/numeric-project-id Cloud Run 服务或作业所属项目的编号
/computeMetadata/v1/instance/region 此 Cloud Run 服务或作业所在的区域,返回 projects/PROJECT-NUMBER/regions/REGION
/computeMetadata/v1/instance/id 实例的唯一标识符(也可在日志中提供)。
/computeMetadata/v1/instance/service-accounts/default/email 此 Cloud Run 服务或作业的服务身份的电子邮件。
/computeMetadata/v1/instance/service-accounts/default/token 此 Cloud Run 服务或作业的服务账号生成 OAuth2 访问令牌。Cloud Run 服务代理用于提取令牌。此端点将返回包含 access_token 属性的 JSON 响应。详细了解如何提取和使用此访问令牌。

请注意,Cloud Run 不会提供实例在其中运行的 Google Cloud 可用区的详细信息。因此,元数据属性 /computeMetadata/v1/instance/zone 始终返回 projects/PROJECT-NUMBER/zones/REGION-1

文件名

您在容器中使用的文件名必须与 UTF-8 兼容,要么使用 UTF-8 编码,要么使用可以安全自动转换为 UTF-8 的编码方式。如果您的文件名使用不同的编码,请使用与 UTF-8 兼容的文件名在机器上运行 Docker 构建,并避免将文件复制到包含不兼容 UTF-8 名称的容器。

如果文件名与 UTF-8 不兼容,则容器部署将失败。请注意,您在文件中使用的字符编码没有限制。

出站请求超时

对于 Cloud Run 服务和作业,从容器到 VPC 的请求在经历 10 分钟的空闲时间后会超时。对于从容器到互联网的请求,空闲时间达到 20 分钟后超时。

出站连接重置

在底层基础架构重启或更新时,从容器到 VPC 和互联网的连接流可能会偶尔被终止和替换。如果您的应用重复使用长期有效的连接,我们建议您将应用配置为重新建立连接,以避免重用无效连接。