使用映像流式传输拉取容器映像


本页面介绍了如何在 Google Kubernetes Engine (GKE) 中使用映像流式传输,以通过流式传输应用所需的映像数据来拉取容器映像。

运行 GKE 1.25.5-gke.1000 版及更高版本的新 Autopilot 集群会自动使用映像流式传输来拉取符合条件的映像。本页面中的说明仅适用于 Standard 集群。

概览

映像流式传输是一种拉取容器映像的方法,在这种方法中,GKE 会按照您的应用的要求从符合条件的映像中流式传输数据。您可以使用映像流式传输来允许工作负载初始化,而无需等待整个映像下载,这会显著缩短初始化时间。缩短拉取时间具有以下优势:

  • 更快的自动扩缩
  • 缩短了拉取大型映像时的延迟时间
  • 加快了 Pod 启动速度

如果使用映像流式传输,GKE 会将远程文件系统用作使用符合条件的容器映像的任何容器的根文件系统。GKE 会根据您的工作负载需要从远程文件系统流式传输映像数据。如果不使用映像流式传输,GKE 会将整个容器映像下载到每个节点上,并将其用作工作负载的根文件系统。

在流式传输映像数据时,GKE 会将整个容器映像下载到后台当地硬盘并缓存。然后,GKE 会传送来自缓存映像的未来数据读取请求。

当您部署需要读取容器映像中的特定文件的工作负载时,映像流式传输后端仅传送这些请求的文件。

要求

您必须满足以下要求才能在 GKE Autopilot 和 Standard 集群中使用映像流式传输:

  • 您必须启用 Container File System API。

    启用 Container File System API

  • 新的 Autopilot 集群必须运行 GKE 1.25.5-gke.1000 版或更高版本,才能自动启用映像流式传输。如需查看相关说明,请参阅设置新的 Autopilot 集群的版本和发布渠道

  • 新的和现有的 GKE Standard 集群必须运行 1.18.6-gke.4801 版或更高版本。

  • 您必须将 Container-Optimized OS 与 containerd 节点映像搭配使用。 Autopilot 节点始终使用此节点映像。

  • 您的容器映像必须存储在 Artifact Registry 中。

  • 如果您使用专用集群,则必须在子网上启用专用 Google 访问通道,这样节点才能访问映像流式传输 Service。

  • 如果 VPC Service Controls 在保护您的容器映像,并且您使用了映像流式传输,则还必须在服务边界内添加 Image Streaming API (containerfilesystem.googleapis.com)。

  • 如果集群中的 GKE 节点不使用默认服务账号,您必须确保自定义服务账号在托管容器映像的项目中具有 Service Usage Consumer (roles/serviceusage.serviceUsageConsumer) IAM 角色。

限制

  • 1.23.5-gke.1900 之前的 GKE 版本不支持使用 Secret 拉取容器映像
  • 使用 V2 映像清单,架构版本 1 的容器映像不符合条件。
  • 使用客户管理的加密密钥 (CMEK) 加密的容器映像符合 GKE 1.25.3-gke.1000 或更高版本的映像流式传输的条件。在以前的版本中,GKE 会下载这些映像,但不会流式传输数据。您仍然可以使用 CMEK 来保护使用映像流式传输的集群中的挂接永久性磁盘自定义启动磁盘
  • 不支持具有重复层的容器映像。GKE 下载这些映像,但不流式传输数据。检查容器映像是否存在空层或重复层
  • Artifact Registry 代码库必须与您的 GKE 节点位于同一区域中,或者位于与您的节点运行的区域相对应的多区域中。例如:
    • 如果您的节点位于 us-east1,则映像流式传输可用于 us-east1 区域或 us 多区域的代码库,因为 GKE 和 Artifact Registry 都在美国境内的数据中心位置运行。
    • 如果您的节点位于 northamerica-northeast1 区域,则这些节点在加拿大运行。在这种情况下,映像流式传输仅适用于同一区域中的代码库。
  • 如果您的工作负载在初始化期间读取映像中的许多文件,您可能会注意到初始化时间增加,因为远程文件读取导致的延迟。
  • 在符合条件的映像首次拉取期间,您可能不会注意到映像流式传输的优势。但是,在映像流缓存映像后,将来的映像将受益于任何映像流式传输。
  • GKE Standard 集群使用集群级配置来确定是否在使用节点自动预配功能创建的新节点池上启用映像流式传输。但是,如果在集群级层停用映像流式传输,您无法使用工作负载分离来创建启用了映像流式传输的节点池。
  • GKE 1.22.6-gke.300 版及更高版本的映像流式传输支持 Linux 文件功能,例如 CAP_NET_RAW。对于以前的 GKE 版本,当流处理映像文件或将映像保存到本地磁盘时,这些功能不可用。为避免潜在的中断,请勿在 1.22.6-gke.300 之前的 GKE 版本中对具有这些功能的容器使用映像流式传输。 如果您的容器依赖于 Linux 文件功能,则在启用映像流式传输功能的情况下运行时,它可能无法启动并发出没有权限错误。

准备工作

在开始之前,请确保您已执行以下任务:

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行 gcloud components update 以获取最新版本。

在集群上启用映像流式传输

您可以使用 gcloud CLI --enable-image-streaming 标志或使用 Google Cloud 控制台在新的或现有的 Standard 集群上启用映像流式传输。默认情况下,集群中的节点池会继承集群级层的映像流式传输设置。您可以通过在集群中的节点池上启用或停用映像流式传输来更改此行为。

运行 GKE 1.25.5-gke.1000 版及更高版本的所有新 Autopilot 集群都使用映像流式传输来拉取符合条件的映像。如需查看相关说明,请参阅设置新的 Autopilot 集群的版本和发布渠道。以下说明仅适用于 GKE Standard 集群。

在新集群上

您可以使用 gcloud CLI 或 Google Cloud 控制台在新集群上启用映像流式传输。

gcloud

如需创建启用了映像流式传输的新集群,请运行以下命令:

gcloud container clusters create CLUSTER_NAME \
    --zone=COMPUTE_ZONE \
    --image-type="COS_CONTAINERD" \
    --enable-image-streaming

替换以下内容:

  • CLUSTER_NAME:新集群的名称。
  • COMPUTE_ZONE:新集群的 Compute Engine 区域。对于区域级集群,请改用 --region=COMPUTE_REGION 标志。确保该地区或区域位于同一映像或包含映像的 Artifact Registry 代码库的多区域内。

控制台

  1. 转到 Google Cloud 控制台中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 点击 创建

  3. GKE Standard 部分中,点击配置

  4. 在导航窗格的集群下,点击功能

  5. 其他部分中,选中启用映像流式传输复选框。

  6. 根据需要配置集群,然后点击创建

在现有集群上

您可以使用 gcloud CLI 或 Google Cloud 控制台在满足要求的现有集群上启用映像流式传输。

gcloud

如需更新现有集群以使用映像流式传输,请使用 gcloud CLI 运行以下命令:

gcloud container clusters update CLUSTER_NAME \
    --enable-image-streaming

控制台

  1. 转到 Google Cloud 控制台中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 点击要修改的集群的名称。

  3. 集群页面的功能部分中,点击映像流式传输旁边的

  4. 修改映像流式传输对话框中,选中启用映像流式传输复选框。

  5. 点击保存更改

修改集群后,默认情况下 GKE 会自动在现有节点池上启用映像流式传输。如果您在个别节点池上明确启用或停用了映像流式传输,则这些节点池不会继承对集群级层设置的更改。

验证集群上是否已启用映像流式传输

您可以使用 gcloud CLI 或 Google Cloud 控制台检查是否已在集群级层启用映像流式传输。

gcloud

运行以下命令:

gcloud container clusters describe CLUSTER_NAME \
    --flatten "nodePoolDefaults.nodeConfigDefaults"

如果输出类似于以下内容,则表示设置已启用:

gcfsConfig:
  enabled: true
...

如果输出类似于以下内容,则表示设置已停用:

gcfsConfig: {}
...

控制台

  1. 转到 Google Cloud 控制台中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 点击要检查的集群的名称。

  3. 集群页面的功能部分中,映像流式传输旁边会显示该设置是否已启用。

在节点池上启用映像流式传输

默认情况下,节点池会继承集群级层的映像流式传输设置。您可以使用 gcloud CLI 在特定节点池上启用或停用映像流式传输。

在新节点池上

如需创建启用了映像流式传输的新节点池,请运行以下命令:

gcloud container node-pools create NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --zone=COMPUTE_ZONE \
    --image-type="COS_CONTAINERD" \
    --enable-image-streaming

替换以下内容:

  • NODE_POOL_NAME:新节点池的名称。
  • CLUSTER_NAME:节点池的集群名称。
  • COMPUTE_ZONE:集群的 Compute Engine 可用区。对于区域级集群,请改用 --region=COMPUTE_REGION 标志。

在现有节点池上

您可以在满足要求的现有节点池上启用映像流式传输。

如需更新现有节点池以使用映像流式传输,请运行以下命令:

gcloud container node-pools update POOL_NAME \
    --cluster=CLUSTER_NAME \
    --enable-image-streaming

验证节点池上是否启用了映像流式传输

检查是否为节点池启用了映像流式传输:

gcloud container node-pools describe POOL_NAME \
    --cluster=CLUSTER_NAME \

如果输出类似于以下内容,则表示设置已启用:

gcfsConfig:
  enabled: true
...

如果输出类似于以下内容,则表示设置已停用:

gcfsConfig: {}
...

使用映像流式传输安排工作负载

在集群上启用映像流式传输后,GKE 会在从 Artifact Registry 中拉取符合条件的容器映像时自动使用映像流式传输,而无需进一步配置。

GKE 会向启用了映像流式传输的节点池中的节点添加 cloud.google.com/gke-image-streaming: "true" 标签。在 GKE Standard 中,如果您在特定节点池上启用或停用映像流式传输,以便集群混合使用映像流式传输的节点和不使用映像流式传输的节点,则可以在部署中使用节点选择器,以控制 GKE 是否在使用映像流式传输的节点上调度工作负载。

在以下示例中,您安排了在启用了映像流式传输的集群上使用大型容器映像的 Deployment。然后,您可以选择将性能与未启用映像流式传输的映像拉取进行比较

  1. 创建启用了映像流式传输的新集群:

    gcloud container clusters create CLUSTER_NAME \
        --zone=COMPUTE_ZONE \
        --enable-image-streaming \
        --image-type="COS_CONTAINERD"
    
  2. 获取集群的凭据:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --zone=COMPUTE_ZONE
    
  3. 将以下清单保存为 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。

  4. 将清单应用到您的集群:

    kubectl apply -f frontend-deployment.yaml
    
  5. 验证 GKE 是否已创建 Deployment:

    kubectl get pods -l app=guestbook
    

    输出内容类似如下:

    NAMESPACE    NAME                          READY    STATUS       RESTARTS    AGE
    default      frontend-64bcc69c4b-pgzgm     1/1      Completed    0           3s
    
  6. 获取 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 以比较映像流式传输的性能。

  1. 创建停用了映像流式传输的新集群:

    gcloud container clusters create CLUSTER2_NAME\
        --zone=COMPUTE_ZONE \
        --image-type="COS_CONTAINERD"
    
  2. 获取集群的凭据:

    gcloud container clusters get-credentials CLUSTER2_NAME \
        --zone=COMPUTE_ZONE
    
  3. 部署上一个示例中的 frontend Deployment:

    kubectl apply -f frontend-deployment.yaml
    
  4. 获取 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

停用映像流式传输

如果您使用 GKE Autopilot,则无法在单个集群上停用映像流式传输。您可以停用 Container File System API,这会对整个项目停用映像流式传输。

如果您使用 GKE Standard 集群,则可以在单个集群或特定节点池上停用映像流式传输,如以下部分所述。

在 GKE Standard 集群上停用映像流式传输

您可以使用 gcloud CLI 或 Google Cloud 控制台在现有 GKE Standard 集群上停用映像流式传输。

gcloud

如需在现有集群上停用映像流式传输,请运行以下命令:

gcloud container clusters update CLUSTER_NAME \
    --no-enable-image-streaming

控制台

  1. 转到 Google Cloud 控制台中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 点击要修改的集群的名称。

  3. 集群页面的功能下,点击映像流式传输旁边的

  4. 修改映像流式传输对话框中,清除启用映像流式传输复选框。

  5. 点击保存更改

在新节点池上

如需在创建新节点池时停用映像流式传输,请指定 --no-enable-image-streaming 标志,如以下命令所示:

gcloud container node-pools create NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --zone=COMPUTE_ZONE \
    --no-enable-image-streaming

在现有节点池上

如需在现有节点池上停用映像流式传输,请运行以下命令:

gcloud container node-pools update NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --no-enable-image-streaming

为映像流式传输预留内存

除了为节点系统组件预留的内存之外,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)的日志来诊断问题:

  1. 进入 Google Cloud 控制台中的 Logs Explorer 页面。

    进入 Logs Explorer

  2. 查询字段中,指定以下查询:

    logName="projects/PROJECT_ID/logs/gcfsd"
    resource.labels.cluster_name="CLUSTER_NAME"
    

    请替换以下内容:

    • PROJECT_ID:您的项目的名称。
    • CLUSTER_NAME:您的集群的名称。
  3. 点击运行查询

您还可以使用 Logs Explorer 检查 gcfsd 日志:

  1. 转到 Google Cloud 控制台中的 Logs Explorer

    进入 Logs Explorer

  2. 查询字段中,指定以下查询:

    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 \
    --zone=COMPUTE_ZONE \
    --image-type="COS_CONTAINERD" \
    --enable-image-streaming \
    --scope="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 系统调用的代码。如果您无法修改代码,则必须在节点池上停用映像流式传输来缓解问题。