サードパーティ レジストリからコンテナ イメージを移行する

一部のコンテナ イメージをサードパーティのレジストリから直接 pull して、Google Kubernetes Engine や Cloud Run などの Google Cloud 環境にデプロイすると、イメージの pull やサードパーティの停止に対するレート制限がビルドとデプロイを中断することがあります。このページでは、それらのイメージを特定して、整合性のある統合されたコンテナ イメージ管理のために Artifact Registry にコピーする方法について説明します。

Artifact Registry は、Artifact Registry にコピーされたイメージの更新に関し、サードパーティのレジストリをモニタリングしません。新しいバージョンのイメージをパイプラインに組み込むには、Artifact Registry に push する必要があります。

移行の概要

コンテナ イメージの移行には次の手順が含まれます。

  1. 前提条件を設定する。
  2. 移行するイメージを特定する。
    • Dockerfile ファイルとデプロイメント マニフェストを検索して、サードパーティのレジストリへの参照を確認する
    • Cloud Logging と BigQuery を使用して、サードパーティのレジストリからイメージを pull する頻度を決定する
  3. 特定されたイメージを Artifact Registry にコピーする
  4. レジストリへの権限が正しく構成されていることを確認する(特に、Artifact Registry と Google Cloudのデプロイ環境が異なるプロジェクトに存在する場合)。
  5. デプロイのmanifestsを更新する。
  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 に移行するプロジェクトで、オーナーまたは編集者の IAM ロールが割り当てられている必要があります。
  16. 次の環境変数をエクスポートします。
    export PROJECT=$(gcloud config get-value project)
  17. Go バージョン 1.13 以降がインストールされていることを確認します。
    go version
    Go をインストールまたは更新する必要がある場合は、Go のインストールのドキュメントをご覧ください。

費用

このガイドでは、 Google Cloudの次の課金対象コンポーネントを使用します。

移行するイメージを特定する

サードパーティのレジストリの参照用としてコンテナ イメージのビルドとデプロイに使用するファイルを検索し、そのイメージを pull する頻度を確認します。

Dockerfile で参照を特定する

この手順は、Dockerfile が保存されている場所で実行します。これは、コードが局所的にチェックアウトされている場所の場合もあれば、ファイルが VM で利用可能な場合は 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 マニフェストが保存されている場所で実行してください。これは、コードが局所的にチェックアウトされている場所の場合もあれば、ファイルが VM で利用可能な場合は 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 クラスタに対して上記のコマンドを実行します。

サードパーティ レジストリから pull 頻度を特定する

サードパーティのレジストリから pull するプロジェクトでは、イメージの pull 頻度に関する情報を使用して、使用量がサードパーティのレジストリに適用されるレート制限と同等、または超過しているかを判断します。

ログデータを収集する

BigQuery にデータをエクスポートするログシンクを作成します。ログシンクに記述された宛先やクエリで、エクスポートするログエントリを選択します。個々のプロジェクトに対してクエリを実行してシンクを作成するか、スクリプトを使用してプロジェクト間でデータを収集できます。

単一のプロジェクトのシンクを作成するには:

  1. Google Cloud コンソールで、[ログ エクスプローラ] ページに移動します。

    [ログ エクスプローラ] に移動

    検索バーを使用してこのページを検索する場合は、小見出しが「Logging」の結果を選択します。

  2. Google Cloud プロジェクトを選択します。

  3. [クエリビルダー] タブに、次のクエリを入力します。

      resource.type="k8s_pod"
      jsonPayload.reason="Pulling"
    
  4. 履歴のフィルタを [過去 1 時間] から [過去 7 日間] に変更します。 画像

  5. [クエリを実行] をクリックします。

  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 テーブルにデータが流れるまでに時間がかかりますが、これはイメージを pull する頻度に応じて変わります。

pull 頻度のクエリ

ビルドが行うイメージ pull の代表サンプルを取得したら、pull 頻度のクエリを実行します。

  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 に保存されていないイメージの pull 頻度を確認できます。

画像

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 コンソールで次のクエリを実行して、新しいイメージの pull を追跡します。

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

新しいイメージの pull はすべて Artifact Registry から行われ、文字列 docker.pkg.dev が含まれている必要があります。