本页面介绍了如何在 Google Kubernetes Engine (GKE) 中使用映像流式传输,以通过流式传输应用所需的映像数据来拉取容器映像。
Autopilot 集群会自动使用映像流式传输来拉取符合条件的映像。本页面中有关启用和停用映像流式传输的说明适用于 Standard 集群。
概览
映像流式传输是一种拉取容器映像的方法,在这种方法中,GKE 会按照您的应用的要求从符合条件的映像中流式传输数据。您可以使用映像流式传输来允许工作负载初始化,而无需等待整个映像下载,这会显著缩短初始化时间。缩短拉取时间具有以下优势:
- 更快的自动扩缩
- 缩短了拉取大型映像时的延迟时间
- 加快了 Pod 启动速度
如果使用映像流式传输,GKE 会将远程文件系统用作使用符合条件的容器映像的任何容器的根文件系统。GKE 会根据您的工作负载需要从远程文件系统流式传输映像数据。如果不使用映像流式传输,GKE 会将整个容器映像下载到每个节点上,并将其用作工作负载的根文件系统。
在流式传输映像数据时,GKE 会将整个容器映像下载到后台当地硬盘并缓存。然后,GKE 会传送来自缓存映像的未来数据读取请求。
当您部署需要读取容器映像中的特定文件的工作负载时,映像流式传输后端仅传送这些请求的文件。
要求
您必须满足以下要求才能在 GKE Autopilot 和 Standard 集群中使用映像流式传输:
您必须启用 Container File System API。
您必须将 Container-Optimized OS 与 containerd 节点映像搭配使用。 Autopilot 节点始终使用此节点映像。
您的容器映像必须存储在 Artifact Registry 中的标准制品库或远程制品库中,或者存储在 Docker Hub 上的公共注册表中。
如果您在集群上启用专用节点,则必须在子网上启用专用 Google 访问通道,这样节点才能访问映像流式传输服务。
如果 VPC Service Controls 在保护您的容器映像,并且您使用了映像流式传输,则还必须在服务边界内添加 Image Streaming API (
containerfilesystem.googleapis.com
)。如果集群中的 GKE 节点不使用默认服务账号,您必须确保自定义服务账号在托管容器映像的项目中具有 Service Usage Consumer (
roles/serviceusage.serviceUsageConsumer
) IAM 角色。
限制
- 使用 V2 映像清单,架构版本 1 的容器映像不符合条件。
- 不支持具有重复层的容器映像。GKE 下载这些映像,但不流式传输数据。检查容器映像是否存在空层或重复层。
- 如果您的工作负载在初始化期间读取映像中的许多文件,您可能会注意到初始化时间增加,因为远程文件读取导致的延迟。
- 如果您的工作负载需要映像的大部分内容可用才能执行代码,您可能会发现
kubelet
开始容器与容器实际开始发送日志之间存在延迟。 - 在符合条件的映像首次拉取期间,您可能不会注意到映像流式传输的优势。但是,在映像流缓存映像后,将来的映像将受益于任何映像流式传输。
- GKE Standard 集群使用集群级配置来确定是否在使用节点自动预配功能创建的新节点池上启用映像流式传输。但是,如果在集群级层停用映像流式传输,您无法使用工作负载分离来创建启用了映像流式传输的节点池。
准备工作
在开始之前,请确保您已执行以下任务:
- 启用 Google Kubernetes Engine API。 启用 Google Kubernetes Engine API
- 如果您要使用 Google Cloud CLI 执行此任务,请安装并初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行
gcloud components update
命令以获取最新版本。较早版本的 gcloud CLI 可能不支持运行本文档中的命令。
启用 Container File System API。
确保您已有 Standard 集群。如有需要,请创建一个 Standard 集群。
在集群上启用映像流式传输
您可以使用 gcloud CLI --enable-image-streaming
标志或使用Google Cloud 控制台在新的或现有的 Standard 集群上启用映像流式传输。使用 --enable-image-streaming
标志创建集群时,默认节点池中将启用映像流式传输。除非您在创建节点池时停用节点池,否则您创建的新节点池也会启用映像流式传输。
所有 Autopilot 集群都使用映像流式传输来拉取符合条件的映像。如需查看相关说明,请参阅设置新的 Autopilot 集群的版本和发布渠道。以下说明仅适用于 GKE Standard 集群。
您可以使用 gcloud CLI 或 Google Cloud 控制台在满足要求的现有集群上启用映像流式传输。
gcloud
如需更新现有集群以使用映像流式传输,请使用 gcloud CLI 运行以下命令:
gcloud container clusters update CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION \
--enable-image-streaming
替换以下内容:
CLUSTER_NAME
:您的集群的名称。CONTROL_PLANE_LOCATION
:集群控制平面的位置。
控制台
前往 Google Cloud 控制台中的 Google Kubernetes Engine 页面。
点击要修改的集群的名称。
在集群页面的功能部分中,点击映像流式传输旁边的 edit。
在修改映像流式传输对话框中,选中启用映像流式传输复选框。
点击保存更改。
修改集群后,默认情况下 GKE 会自动在现有节点池上启用映像流式传输。如果您在个别节点池上明确启用或停用了映像流式传输,则这些节点池不会继承对集群级层设置的更改。
在集群级层更新时,更改映像流式传输设置会遵循维护可用性,但在节点池级层更新时则不会。
此更改需要重新创建节点,这可能会导致正在运行的工作负载中断。如需详细了解此特定更改,请在使用节点升级策略并遵循维护政策重新创建节点的手动更改表格中找到相应的行。如需详细了解节点更新,请参阅规划节点更新中断。
验证集群上是否已启用映像流式传输
您可以使用 gcloud CLI 或 Google Cloud 控制台检查是否已在集群级层启用映像流式传输。
gcloud
运行以下命令:
gcloud container clusters describe CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION \
--flatten "nodePoolDefaults.nodeConfigDefaults"
替换以下内容:
CLUSTER_NAME
:您的集群的名称。CONTROL_PLANE_LOCATION
:集群控制平面的位置。
如果输出类似于以下内容,则表示设置已启用:
gcfsConfig:
enabled: true
...
如果输出类似于以下内容,则表示设置已停用:
gcfsConfig: {}
...
控制台
前往 Google Cloud 控制台中的 Google Kubernetes Engine 页面。
点击要检查的集群的名称。
在集群页面的功能部分中,映像流式传输旁边会显示该设置是否已启用。
在节点池上启用映像流式传输
默认情况下,节点池会继承集群级层的映像流式传输设置。您可以使用 gcloud CLI 在特定节点池上启用或停用映像流式传输。
在新节点池上
如需创建启用了映像流式传输的新节点池,请运行以下命令:
gcloud container node-pools create NODE_POOL_NAME \
--cluster=CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION \
--image-type="COS_CONTAINERD" \
--enable-image-streaming
替换以下内容:
NODE_POOL_NAME
:新节点池的名称。CLUSTER_NAME
:节点池的集群名称。CONTROL_PLANE_LOCATION
:集群控制平面的 Compute Engine 位置。为区域级集群提供区域,或为可用区级集群提供可用区。
在现有节点池上
您可以在满足要求的现有节点池上启用映像流式传输。
如需更新现有节点池以使用映像流式传输,请运行以下命令:
gcloud container node-pools update POOL_NAME \
--cluster=CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION \
--enable-image-streaming
替换以下内容:
POOL_NAME
:节点池的名称。CLUSTER_NAME
:节点池的集群名称。CONTROL_PLANE_LOCATION
:集群控制平面的位置。
在集群级层更新时,更改映像流式传输设置会遵循维护可用性,但在节点池级层更新时则不会。
此更改需要重新创建节点,这可能会导致正在运行的工作负载中断。如需详细了解此特定更改,请在使用节点升级策略(而不遵循维护政策)重新创建节点的手动更改表格中找到相应的行。如需详细了解节点更新,请参阅规划节点更新中断。
验证节点池上是否启用了映像流式传输
检查是否为节点池启用了映像流式传输:
gcloud container node-pools describe POOL_NAME \
--cluster=CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION
替换以下内容:
POOL_NAME
:节点池的名称。CLUSTER_NAME
:节点池的集群名称。CONTROL_PLANE_LOCATION
:集群控制平面的位置。
如果输出类似于以下内容,则表示设置已启用:
gcfsConfig:
enabled: true
...
如果输出类似于以下内容,则表示设置已停用:
gcfsConfig: {}
...
使用映像流式传输安排工作负载
在集群上启用映像流式传输后,GKE 会在从 Artifact Registry 中拉取符合条件的容器映像时自动使用映像流式传输,而无需进一步配置。
GKE 会向启用了映像流式传输的节点池中的节点添加 cloud.google.com/gke-image-streaming: "true"
标签。在 GKE Standard 中,如果您在特定节点池上启用或停用映像流式传输,以便集群混合使用映像流式传输的节点和不使用映像流式传输的节点,则可以在部署中使用节点选择器,以控制 GKE 是否在使用映像流式传输的节点上调度工作负载。
在以下示例中,您安排了在启用了映像流式传输的集群上使用大型容器映像的 Deployment。然后,您可以选择将性能与未启用映像流式传输的映像拉取进行比较。
创建启用了映像流式传输的新集群:
gcloud container clusters create CLUSTER_NAME \ --location=CONTROL_PLANE_LOCATION \ --enable-image-streaming \ --image-type="COS_CONTAINERD"
获取集群的凭据:
gcloud container clusters get-credentials CLUSTER_NAME \ --location=CONTROL_PLANE_LOCATION
将以下清单保存为
frontend-deployment.yaml
:apiVersion: apps/v1 kind: Deployment metadata: name: frontend spec: replicas: 1 selector: matchLabels: app: guestbook tier: frontend template: metadata: labels: app: guestbook tier: frontend spec: containers: - name: php-redis image: us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5 env: - name: GET_HOSTS_FROM value: "dns" resources: requests: cpu: 100m memory: 100Mi ports: - containerPort: 80
gb-frontend
容器映像的大小为 327 MB。将清单应用到您的集群:
kubectl apply -f frontend-deployment.yaml
验证 GKE 是否已创建 Deployment:
kubectl get pods -l app=guestbook
输出内容类似如下:
NAMESPACE NAME READY STATUS RESTARTS AGE default frontend-64bcc69c4b-pgzgm 1/1 Completed 0 3s
获取 Kubernetes 事件日志以查看映像拉取事件:
kubectl get events --all-namespaces
输出内容类似如下:
NAMESPACE LAST SEEN TYPE REASON OBJECT MESSAGE default 11m Normal Pulling pod/frontend-64bcc69c4b-pgzgm Pulling image "us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5" default 11m Normal Pulled pod/frontend-64bcc69c4b-pgzgm Successfully pulled image "us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5" in 1.536908032s default 11m Normal ImageStreaming node/gke-riptide-cluster-default-pool-f1552ec4-0pjv Image us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5 is backed by image streaming. ...
在此输出中:
Pulled
事件显示映像流式传输拉取映像所需的时间。ImageStreaming
事件表明该节点使用映像传送来传送容器映像。
比较标准映像拉取的性能
在此可选示例中,您将创建一个停用了映像流式传输的新集群,并部署 frontend
Deployment 以比较映像流式传输的性能。
创建停用了映像流式传输的新集群:
gcloud container clusters create CLUSTER2_NAME \ --location=CONTROL_PLANE_LOCATION \ --image-type="COS_CONTAINERD"
获取集群的凭据:
gcloud container clusters get-credentials CLUSTER2_NAME \ --location=CONTROL_PLANE_LOCATION
部署上一个示例中的
frontend
Deployment:kubectl apply -f frontend-deployment.yaml
获取 Kubernetes 事件日志:
kubectl get events --all-namespaces
输出内容类似如下:
NAMESPACE LAST SEEN TYPE REASON OBJECT MESSAGE default 87s Normal Pulled pod/frontend-64bcc69c4b-qwmfp Successfully pulled image "us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5" in 23.929723476s
请注意 GKE 拉取整个映像所花费的时间。在此示例输出中,GKE 几乎需要 24 秒。启用映像流式传输后,GKE 只需要 1.5 秒即可拉取工作负载启动所需的映像数据。
清理
为避免产生费用,请删除您在之前示例中创建的集群:
gcloud container clusters delete CLUSTER_NAME CLUSTER2_NAME \
--location=CONTROL_PLANE_LOCATION
替换以下内容:
CLUSTER_NAME
:第一个集群的名称。CLUSTER2_NAME
:第二个集群的名称。CONTROL_PLANE_LOCATION
:集群控制平面的位置。
停用映像流式传输
如果您使用 GKE Autopilot,则无法在单个集群上停用映像流式传输。您可以停用 Container File System API,这会对整个项目停用映像流式传输。
如果您使用 GKE Standard 集群,则可以在单个集群或特定节点池上停用映像流式传输,如以下部分所述。
在 GKE Standard 集群上停用映像流式传输
您可以使用 gcloud CLI 或Google Cloud 控制台在现有 GKE Standard 集群上停用映像流式传输。
gcloud
如需在现有集群上停用映像流式传输,请运行以下命令:
gcloud container clusters update CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION \
--no-enable-image-streaming
替换以下内容:
CLUSTER_NAME
:您的集群的名称。CONTROL_PLANE_LOCATION
:集群控制平面的位置。
控制台
前往 Google Cloud 控制台中的 Google Kubernetes Engine 页面。
点击要修改的集群的名称。
在集群页面的功能下,点击映像流式传输旁边的 edit。
在修改映像流式传输对话框中,清除启用映像流式传输复选框。
点击保存更改。
在集群级层更新时,更改映像流式传输设置会遵循维护可用性,但在节点池级层更新时则不会。
此更改需要重新创建节点,这可能会导致正在运行的工作负载中断。如需详细了解此特定更改,请在使用节点升级策略并遵循维护政策重新创建节点的手动更改表格中找到相应的行。如需详细了解节点更新,请参阅规划节点更新中断。
在新节点池上
如需在创建新节点池时停用映像流式传输,请指定 --no-enable-image-streaming
标志,如以下命令所示:
gcloud container node-pools create NODE_POOL_NAME \
--cluster=CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION \
--no-enable-image-streaming
在现有节点池上
如需在现有节点池上停用映像流式传输,请运行以下命令:
gcloud container node-pools update NODE_POOL_NAME \
--cluster=CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION \
--no-enable-image-streaming
替换以下内容:
NODE_POOL_NAME
:节点池的名称。CLUSTER_NAME
:节点池的集群名称。CONTROL_PLANE_LOCATION
:集群控制平面的位置。
在集群级层更新时,更改映像流式传输设置会遵循维护可用性,但在节点池级层更新时则不会。
此更改需要重新创建节点,这可能会导致正在运行的工作负载中断。如需详细了解此特定更改,请在使用节点升级策略(而不遵循维护政策)重新创建节点的手动更改表格中找到相应的行。如需详细了解节点更新,请参阅规划节点更新中断。
为映像流式传输预留内存
除了为节点系统组件预留的内存之外,GKE 还会为映像流式传输预留内存资源。 GKE 不会为映像流式传输预留额外的 CPU 资源。在 GKE Standard 集群中,此预留会更改您可以在 Pod 中请求的内存资源。在 GKE Autopilot 中,GKE 会管理系统分配,因此调度工作负载没有任何影响。
如需详细了解 GKE 为节点组件预留的内存,请参阅标准集群架构。
在使用映像流式传输的节点中,GKE 会为新预留预留以下额外的内存:
- 内存不足 1 GiB 的机器无额外内存
- 前 4 GiB 内存的 1%
- 接下来 4 GiB 内存(最多 8 GiB)的 0.8%
- 接下来 8 GiB 内存(最多 16 GiB)的 0.4%
- 接下来 112 GiB 内存(最多 128 GiB)的 0.24%
- 128 GiB 以上任何内存的 0.08%
问题排查
以下部分提供了有关排查映像流式传输问题的建议。如需获取有关排查标准映像拉取问题的建议,请参阅排查映像拉取问题。
GKE 不使用映像流式传输文件系统
如果您的 GKE 事件日志未显示映像流式传输事件,则您的映像不受远程文件系统支持。如果 GKE 之前在节点上拉取映像,则这是预期行为,因为 GKE 使用映像的本地缓存进行后续拉取,而不是使用映像流式传输。如需验证这一点,您可以在 Pod Pulled
事件的 Message
字段中查找 Container image IMAGE_NAME already present on machine
。
如果您在节点上首次拉取映像时没有看到映像流式传输事件,请确保满足映像流式传输的要求。如果满足要求,您可以通过检查映像流式传输服务(名为 gcfsd
)的日志来诊断问题:
前往 Google Cloud 控制台中的 Logs Explorer 页面:
在查询字段中,指定以下查询:
logName="projects/PROJECT_ID/logs/gcfsd" resource.labels.cluster_name="CLUSTER_NAME"
请替换以下内容:
PROJECT_ID
:您的项目的名称。CLUSTER_NAME
:您的集群的名称。
点击运行查询。
您还可以使用 Logs Explorer 检查 gcfsd
日志:
在 Google Cloud 控制台中前往 Logs Explorer:
在查询字段中,指定以下查询:
logName="projects/PROJECT_ID/logs/gcfsd"
将
PROJECT_ID
替换为您的 Google Cloud 项目 ID。
PermissionDenied
如果 gcfsd
日志显示类似于以下内容的错误消息,则表示节点没有正确的 API 范围。GKE 会拉取容器映像,而不使用映像流式传输。
level=fatal msg="Failed to create a Container File System client: rpc error:
code = PermissionDenied desc = failed to probe endpoint: rpc error: code = PermissionDenied
desc = Request had insufficient authentication scopes."
您可以通过向节点授予正确的范围以允许其使用映像流式传输来解决此问题。将 devstorage.read_only
范围添加到集群或节点池,类似于以下命令:
gcloud container node-pools create NODE_POOL_NAME \
--cluster=CLUSTER_NAME \
--location=CONTROL_PLANE_LOCATION \
--image-type="COS_CONTAINERD" \
--enable-image-streaming \
--scopes="https://www.googleapis.com/auth/devstorage.read_only"
FailedPrecondition
如果您发现 code = FailedPrecondition
错误消息,则映像未导入映像流式传输远程文件系统。
如果您尝试使用现有节点池进行映像流式传输,则可能会注意到此错误。如果节点池中的节点已有磁盘上的容器映像,则 GKE 会使用本地映像,而不是使用映像流式传输来获取映像。
如需解决此问题,请尝试以下操作:
- 等待几分钟,然后再次尝试部署工作负载。
- 添加新节点或新节点池,并在这些节点上安排工作负载。
InvalidArgument
如果您发现 code=InvalidArgument
错误消息,则您的工作负载使用的容器映像不符合映像流式传输的条件。确保映像满足要求。如果您的映像不在 Artifact Registry 上,请尝试迁移到 Artifact Registry。
backend.FileContent failed
在启用图片串流的情况下读取容器文件时,可能会出现以下错误:
level=error msg="backend.FileContent failed" error="rpc error: code = ResourceExhausted desc = Quota exceeded for quota metric 'Content requests per project per region' and limit 'Content requests per project per region per minute per region' of service 'containerfilesystem.googleapis.com' for consumer 'project_number:PROJECT_NUMBER'." layer_id="sha256:1234567890" module=gcfs_backend offset=0 path=etc/passwd size=4096
此错误表示项目超出了从远程容器文件系统服务读取文件所需的配额。如需解决此问题,请申请调整配额,以提高以下配额值:
- 每个区域每个项目每分钟的内容请求数
- 每个项目每个区域的内容请求数
GKE 会下载映像,但不进行数据流式传输
使用客户管理的加密密钥 (CMEK) 的容器映像仅符合 GKE 1.25.3-gke.1000 或更高版本的映像流式传输的条件。具有重复层的容器映像不符合映像流式传输的条件。如需了解详情,请参阅限制。
检查是否存在空层或重复层
如需检查容器映像是否存在空层或重复层,请运行以下命令:
docker inspect IMAGE_NAME
将 IMAGE_NAME
替换为容器映像的名称。
在该命令的输出中,检查 "Layers"
下的条目。
如果其中一个条目与以下 "sha256"
输出完全匹配,则容器映像具有空层,不符合映像流式传输的条件。
"Layers": [ ... "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4", ... ]
如果存在重复条目(如以下示例所示),则容器映像具有重复层,不符合映像流式传输的条件。
"Layers": [
"sha256:28699c71935fe3ffa56533db44ad93e5a30322639f7be70d5d614e06a1ae6d9b",
...
"sha256:28699c71935fe3ffa56533db44ad93e5a30322639f7be70d5d614e06a1ae6d9b",
...
]
对符号链接文件执行的 mv
命令和 renameat2
系统调用失败
对于运行 1.25 及更高版本的 GKE 节点,启用映像流式传输后,对容器映像中的符号链接文件执行的 mv
命令和 renameat2
系统调用可能会失败,并显示错误消息“没有此设备或地址”。该问题是由近期的 Linux 内核倒退造成的。
这些系统调用并不常见,因此大多数映像不受此问题的影响。应用准备运行和移动文件时,在容器初始化阶段通常会出现此问题。无法在本地测试映像,因此 GKE 建议在生产环境中使用映像之前,在测试环境中使用映像流式传输找出问题。
以下 GKE 补丁版本中包含此修复:
- 1.25:1.25.14-gke.1351000 及更高版本
- 1.26:1.26.9-gke.1345000 及更高版本
- 1.27:1.27.6-gke.100 及更高版本
- 1.28:1.28.1-gke.1157000 及更高版本
为了为受影响工作负载缓解此问题,您可以尝试替换导致 renameat2
系统调用的代码。如果您无法修改代码,则必须在节点池上停用映像流式传输来缓解问题。
后续步骤
- 了解如何使用辅助启动磁盘预加载数据或容器映像。
- 了解如何排查 GKE 问题。
- 了解 GKE 集群自动扩缩。