从第三方注册表迁移容器

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

此外,您还可以利用其他功能,包括使用漏洞扫描保护您的软件供应链,以及通过 Binary Authorization 强制执行部署政策。

选择注册表

Artifact Registry 是推荐用于在 Google Cloud 中存储和管理容器映像和其他构建工件的服务。

  • 如果您不使用 Container Registry,请改为将映像迁移到 Artifact Registry。Artifact Registry 提供了更高的灵活性和更强的控制性(包括将映像存储在单区域位置而非多区域位置),更精细的访问权限控制,并支持其他工件格式。
  • 如果您使用的是 Container Registry,则可以改换为 Artifact Registry

迁移概览

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

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

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

准备工作

  1. 验证您的权限。在要将映像迁移到 Container Registry 的项目中,您必须具有 Owner 或 Editor IAM 角色。
  2. 转到项目选择器页面

    1. 选择要在其中使用 Container Registry 的 Google Cloud 项目
    2. 在 Google Cloud 控制台中,前往 Cloud Shell
    3. 查找您的项目 ID 并在 Cloud Shell 中进行设置。将 YOUR_PROJECT_ID 替换为您的项目 ID。

      gcloud config set project YOUR_PROJECT_ID
      
  3. 导出以下环境变量:

      export PROJECT=$(gcloud config get-value project)
    
  4. 使用以下命令启用 BigQuery、Container Registry 和 Cloud Monitoring API:

    gcloud services enable \
    containerregistry.googleapis.com \
    stackdriver.googleapis.com \
    logging.googleapis.com \
    monitoring.googleapis.com
    
  5. 验证是否已安装 Go 版本 1.13 或更高版本。

    • 使用以下命令查看现有的 Go 安装版本:

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

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

以下说明适用于 Logging 预览界面

  1. 转到日志浏览器

  2. 选择 Google Cloud 项目。

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

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

    映像

  5. 点击运行查询

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

  7. 在接收器列表中,选择 BigQuery 数据集,然后点击下一步

  8. 在“修改接收器”面板中,执行以下步骤:

    • 接收器名称字段中,输入 image_pull_logs
    • 接收器目标位置字段中,创建新数据集或在另一个项目中选择目标数据集。
  9. 点击创建接收器

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

  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 列中,您可以查看未存储在 Container Registry 或 Artifact Registry 中的映像的拉取频率。

映像

将映像复制到 Container Registry

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

  1. 在 Cloud Shell 中使用您识别的映像名称创建一个文本文件 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 "${GCR_PROJECT}" ]
    then
        echo ERROR: GCR_PROJECT must be set before running this
        exit 1
    fi
    
    for img in ${images}
    do
        gcrane cp ${img} gcr.io/${GCR_PROJECT}/${img}
    done
    

    让该脚本可执行:

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

    GCR_PROJECT=${PROJECT}
    ./copy_images.sh
    

验证权限

默认情况下,Google Cloud CI/CD 服务有权访问同一 Google Cloud 项目中的 Container Registry。

  • Cloud Build 可以推送和拉取映像
  • 运行时环境(如 GKE、Cloud Run、App Engine 柔性环境和 Compute Engine)可以拉取映像。

如果您需要跨项目推送或拉取映像,或者您使用的是流水线中需要访问 Container Registry 的第三方工具,请确保权限已正确配置,然后再更新和重新部署工作负载。

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

更新清单以引用 Container Registry

更新 Dockerfile 和清单,以引用 Container 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

此更新后的清单版本指向 Container 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: gcr.io/<GCR_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

所有新映像拉取都应从 Container Registry 拉取并包含字符串 gcr.io

(可选)禁止从第三方注册表拉取映像

对于使用 Binary Authorization 的 GKE 集群,您定义的政策会自动禁止从不受信任的来源拉取映像。通过将迁移的映像添加到豁免项列表,以确保这些映像未被政策禁止。这些说明介绍了如何为存储在项目的 Container Registry 中的所有映像指定豁免项。

首次更新政策时,请考虑启用“试运行模式”。Binary Authorization 不会阻止映像,而是创建审核日志条目,以便您能够从需要迁移到 Container Registry 的第三方注册表中识别未完成的映像。

如需详细了解如何配置部署政策,请参阅 Binary Authorization 文档

  1. 转到 Binary Authorization 页面
  2. 点击修改政策
  3. 项目默认规则下,启用试运行模式
  4. 不受部署规则约束的映像下,选中信任 Google 提供的所有系统映像
  5. 展开映像路径
  6. 将映像的路径添加为默认项目规则的豁免项:
    1. 在映像列表的底部,点击添加映像
    2. 输入 Google Cloud 项目的映像路径。例如,gcr.io/my-project/* 会排除项目 my-project 中的所有映像。
  7. 为包含您要部署的映像的其他项目重复上一步骤。

在 Logging 中查看用于部署的试运行事件。迁移您定期从第三方注册表中拉取的所有剩余映像。迁移完所有映像后,您可以修改政策以停用试运行模式并屏蔽来自不信任来源的映像。