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

如果直接从第三方注册表中拉取某些容器映像以部署到 Google Cloud 环境(例如 Google Kubernetes Engine 或 Cloud Run),则映像拉取或第三方服务中断的速率限制可能会中断您的构建和部署。本页介绍如何识别这些映像并将其复制到 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. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.
  3. To use a federated identity with the gcloud CLI, you must first configure the tool to use a federated identity.

    For more information, see Browser-based sign-in with the gcloud CLI.

  4. To initialize the gcloud CLI, run the following command:

    gcloud init
  5. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  6. Make sure that billing is enabled for your Google Cloud project.

  7. Enable the Artifact Registry API:

    gcloud services enable artifactregistry.googleapis.com
  8. Install the Google Cloud CLI.
  9. To use a federated identity with the gcloud CLI, you must first configure the tool to use a federated identity.

    For more information, see Browser-based sign-in with the gcloud CLI.

  10. To initialize the gcloud CLI, run the following command:

    gcloud init
  11. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  12. Make sure that billing is enabled for your Google Cloud project.

  13. Enable the Artifact Registry API:

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

费用

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

识别要迁移的映像

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

识别 Dockerfile 中的引用

在 Dockerfile 的存储位置执行此步骤。该位置可能是在本地签出代码的位置或 Cloud Shell 中的位置(如果文件位于虚拟机)。

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

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

输出类似于以下示例:

./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 或 Cloud Run 清单的存储位置执行以下步骤。该位置可能是在本地签出代码的位置或 Cloud Shell 中的位置(如果文件位于虚拟机)。
  1. 在包含 GKE 或 Cloud Run 清单的目录中,运行以下命令:
    grep -inr -H --include \*.yaml "image:" . | grep -i -v -E 'docker.pkg.dev|gcr.io'
    输出类似以下内容:
        ./code/deploy/k8s/ubuntu16-04.yaml:63: image: busybox:1.31.1-uclibc
        ./code/deploy/k8s/master.yaml:26:      image: kubernetes/redis:v1
        
    此命令会查看目录中的所有 YAML 文件,并标识 image: 行。根据需要调整命令,以匹配清单的存储方式
  2. 如需列出在集群上运行的映像,请运行以下命令:
    kubectl get all --all-namespaces -o yaml | grep image: | grep -i -v -E 'docker.pkg.dev|gcr.io'
    此命令会返回所选 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 数据,请参阅 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 是数据集的名称。
以下示例展示了查询的输出。在 imageName 列中,您可以查看未存储在 Artifact Registry 或 Container Registry 中的映像的拉取频率。

映像

将映像复制到 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