从第三方注册表迁移容器映像

如果直接从第三方注册表中拉取某些容器映像以部署到 Google Cloud 环境(例如 Google Kubernetes Engine),则映像拉取或第三方服务中断的速率限制可能会中断您的构建和部署。本页面介绍了如何识别这些映像并将其复制到 Artifact Registry,以便集中、一致地管理容器映像。

Artifact Registry 不会监控第三方注册表,以检测您复制到 Artifact Registry 的映像的更新情况。如果您想将映像的较新版本纳入流水线中,则必须将其推送到 Artifact Registry。

迁移概览

容器映像的迁移包括以下步骤:

  1. 设置前提条件。
  2. 识别要迁移的映像。
    • 搜索 Dockerfile 文件和部署清单,查找第三方注册表的引用
    • 使用 Cloud Logging 和 BigQuery 确定从第三方注册表拉取映像的频率。
  3. 将识别的映像复制到 Artifact Registry。
  4. 验证注册表的权限是否已正确配置,尤其是在 Artifact Registry 和您的 Google Cloud部署环境位于不同项目中的情况下。
  5. 更新部署的清单。
  6. 重新部署您的工作负载。

准备工作

  1. 安装 Google Cloud CLI。

  2. 配置 gcloud CLI 以使用您的联合身份。

    如需了解详情,请参阅使用联合身份登录 gcloud CLI。

  3. 如需初始化 gcloud CLI,请运行以下命令:

    gcloud init
  4. 创建或选择 Google Cloud 项目。

    选择或创建项目所需的角色

    • 选择项目:选择项目不需要特定的 IAM 角色,您可以选择已获授角色的任何项目。
    • 创建项目:如需创建项目,您需要拥有 Project Creator 角色 (roles/resourcemanager.projectCreator),该角色包含 resourcemanager.projects.create 权限。了解如何授予角色。
    • 创建 Google Cloud 项目:

      gcloud projects create PROJECT_ID

      将 PROJECT_ID 替换为您要创建的 Google Cloud 项目的名称。

    • 选择您创建的 Google Cloud 项目:

      gcloud config set project PROJECT_ID

      将 PROJECT_ID 替换为您的 Google Cloud 项目名称。

  5. 验证是否已为您的 Google Cloud 项目启用结算功能。

  6. 如果尚未启用 Artifact Registry API,请启用该 API:

    启用 API 所需的角色

    如需启用 API,您需要拥有 serviceusage.services.enable 权限。如果您创建了项目,则可能已经通过 Owner 角色 (roles/owner) 获得了此权限。否则,您可以通过 Service Usage Admin 角色 (roles/serviceusage.serviceUsageAdmin) 获得此权限。了解如何授予角色。

    gcloud services enable artifactregistry.googleapis.com
  7. 如果您没有 Artifact Registry 代码库,请创建代码库并为需要访问该代码库的第三方客户端配置身份验证。
  8. 验证您的权限。您必须对要将映像迁移到 Artifact Registry 的项目拥有 Owner 或 Editor IAM 角色。
  9. 导出以下环境变量:
    export PROJECT=$(gcloud config get-value project)
  10. 验证是否已安装 Go 1.13 版或更高版本。
    go version
    如果您需要安装或更新 Go,请参阅 Go 安装文档。

费用

本指南使用 Google Cloud的以下收费组件:

识别要迁移的映像

搜索用于构建和部署容器映像的文件,以查找第三方注册表的引用,然后检查映像的拉取频率。

识别 Dockerfile 中的引用

在存储 Dockerfile 的位置执行此步骤。这可能是您的代码在本地签出的位置。

在包含 Dockerfile 的目录中,运行以下命令:

grep -inr -H --include Dockerfile\* "FROM" . | grep -i -v -E 'docker.pkg.dev'

输出类似于以下示例:

./code/build/baseimage/Dockerfile:1:FROM debian:stretch
./code/build/ubuntubase/Dockerfile:1:FROM ubuntu:latest
./code/build/pythonbase/Dockerfile:1:FROM python:3.5-buster

此命令会搜索目录中的所有 Dockerfile,并标识 "FROM" 行。根据需要调整命令,以匹配 Dockerfile 的存储方式。

识别清单中的引用

在存储 GKE 清单的位置执行这些步骤。这可能是您的代码在本地签出的位置。
  1. 在包含 GKE 清单的目录中,运行以下命令:
    grep -inr -H --include \*.yaml "image:" . | grep -i -v -E 'docker.pkg.dev'
    输出类似以下内容:
        ./code/deploy/k8s/ubuntu16-04.yaml:63: image: busybox:1.31
        
    此命令会查看您目录中的所有 YAML 文件,并识别 image: 行。根据需要调整命令,以适应清单的存储方式
  2. 如需列出集群上运行的映像,请运行以下命令:
    kubectl get all --all-namespaces -o yaml | grep image: | grep -i -v -E 'docker.pkg.dev'
    此命令会返回所选 Kubernetes 集群中运行的所有对象,并获取这些对象的映像名称。 输出类似以下内容:
        - image: nginx
          image: nginx:latest
            - image: nginx
            - image: nginx
        

针对所有Google Cloud 项目中的所有 GKE 集群运行上述命令,以实现全面覆盖。

识别从第三方注册表拉取映像的频率

在从第三方注册表拉取映像的项目中,使用映像拉取频率相关信息来确定您的用量是否接近或超过第三方注册表强制执行的速率限制。

收集日志数据

创建日志接收器,以将数据导出到 BigQuery。日志接收器包含目标位置以及用于选择要导出的日志条目的查询。您可以通过查询各个项目来创建接收器,也可以使用脚本来跨项目收集数据。

如需为单个项目创建接收器,请执行以下操作:

  1. 在 Google Cloud 控制台中,前往 Logs Explorer 页面:

    前往 Logs Explorer

    如果您使用搜索栏查找此页面,请选择子标题为 Logging 的结果。

  2. 选择一个 Google Cloud 项目。

  3. 在查询构建器标签页中,输入以下查询:

      resource.type="k8s_pod"
      jsonPayload.reason="Pulling"
    
  4. 将更改历史记录过滤条件从过去 1 小时更改为过去 7 天。

  5. 点击 Run Query。

  6. 验证结果正确显示后,点击操作 > 创建接收器。

  7. 在接收器详情对话框中,完成以下操作:

    1. 在接收器名称字段中,输入 image_pull_logs。
    2. 在接收器说明中,输入接收器的说明。
  8. 点击下一步。

  9. 在接收器目标位置对话框中,选择以下值:

    1. 在选择接收器服务字段中,选择 BigQuery 数据集。
    2. 在选择 BigQuery 数据集字段中,选择创建新的 BigQuery 数据集,然后在打开的对话框中填写所需信息。如需详细了解如何创建 BigQuery 数据集,请参阅创建数据集。
    3. 点击创建数据集。
  10. 点击下一步。

    在选择要包含在接收器中的日志部分中,查询与您在查询构建器标签页中运行的查询相匹配。

  11. 点击下一步。

  12. 可选:选择要从接收器中过滤掉的日志。如需详细了解如何查询和过滤 Cloud Logging 数据,请参阅日志记录查询语言。

  13. 点击创建接收器。

    日志接收器已创建。

如需为多个项目创建接收器,请执行以下操作:

  1. 打开 Cloud Shell。

  2. 在 Cloud Shell 中运行以下命令:

    PROJECTS="PROJECT-LIST"
    DESTINATION_PROJECT="DATASET-PROJECT"
    DATASET="DATASET-NAME"
    
    for source_project in $PROJECTS
    do
      gcloud logging --project="${source_project}" sinks create image_pull_logs bigquery.googleapis.com/projects/${DESTINATION_PROJECT}/datasets/${DATASET} --log-filter='resource.type="k8s_pod" jsonPayload.reason="Pulling"'
    done
    

    其中

    • PROJECT-LIST 是以空格分隔的 Google Cloud 项目 ID 列表。例如:project1 project2 project3。
    • DATASET-PROJECT 是您要存储数据集的项目。
    • DATASET-NAME 是数据集的名称,例如 image_pull_logs。

创建接收器后,数据需要一些时间才能流向 BigQuery 表,具体取决于映像的拉取频率。

查询拉取频率

获得构建创建的映像拉取的代表性样本后,运行查询以获取拉取频率。

  1. 转到 BigQuery 控制台。

  2. 请运行以下查询:

    SELECT
      REGEXP_EXTRACT(jsonPayload.message, r'"(.*?)"') AS imageName,
      COUNT(*) AS numberOfPulls
    FROM
          `DATASET-PROJECT.DATASET-NAME.events_*`
    GROUP BY
          imageName
    ORDER BY
          numberOfPulls DESC
    

    其中

    • DATASET-PROJECT 是包含您的数据集的项目。
    • DATASET-NAME 是数据集的名称。

将映像复制到 Artifact Registry

通过第三方注册表确定映像后,就可以将它们复制到 Artifact Registry 中了。gcrane 工具可以帮助您执行复制过程。

  1. 创建一个文本文件 images.txt,其中包含您识别出的图片名称。例如:

    ubuntu:18.04
    debian:buster
    hello-world:latest
    redis:buster
    jupyter/tensorflow-notebook
    
  2. 下载 gcrane。

      GO111MODULE=on go get github.com/google/go-containerregistry/cmd/gcrane
    
  3. 创建一个名为 copy_images.sh 的脚本以复制文件列表。

    #!/bin/bash
    
    images=$(cat images.txt)
    
    if [ -z "${AR_PROJECT}" ]
    then
        echo ERROR: AR_PROJECT must be set before running this
        exit 1
    fi
    
    for img in ${images}
    do
        gcrane cp ${img} LOCATION-docker.pkg.dev/${AR_PROJECT}/${img}
    done
    

    将 LOCATION 替换为相应制品库的区域位置。

    让该脚本可执行:

      chmod +x copy_images.sh
    
  4. 运行该脚本以复制文件:

    AR_PROJECT=${PROJECT}
    ./copy_images.sh
    

验证权限

在更新和重新部署工作负载之前,请确保权限已正确配置。

如需了解详情,请参阅访问权限控制文档。

更新清单以引用 Artifact Registry

更新 Dockerfile 和清单,以引用 Artifact Registry 而不是第三方注册表。

以下示例展示了引用第三方注册表的清单:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

此更新后的清单版本指向 us-docker.pkg.dev 上的映像。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: us-docker.pkg.dev/<AR_PROJECT>/nginx:1.14.2
        ports:
        - containerPort: 80

对于大量清单,请使用 sed 或其他可处理多个文本文件更新的工具。

重新部署工作负载

使用更新后的清单重新部署工作负载。

通过在 BigQuery 控制台中运行以下查询,来跟踪新映像拉取:

SELECT`

FORMAT_TIMESTAMP("%D %R", timestamp) as timeOfImagePull,
REGEXP_EXTRACT(jsonPayload.message, r'"(.*?)"') AS imageName,
COUNT(*) AS numberOfPulls
FROM
  `image_pull_logs.events_*`
GROUP BY
  timeOfImagePull,
  imageName
ORDER BY
  timeOfImagePull DESC,
  numberOfPulls DESC

所有新映像拉取都应从 Artifact Registry 拉取并包含字符串 docker.pkg.dev。