Kubernetes マニフェストでのコンテナ イメージ ダイジェストの使用

このチュートリアルでは、Kubernetes にコンテナをデプロイするデベロッパーとオペレーターを対象に、コンテナ イメージ ダイジェストを使用してコンテナ イメージを識別する方法について説明します。コンテナ イメージ ダイジェストはコンテナ イメージを一意かつ不変的に識別します。

イメージ ダイジェストを使用してコンテナ イメージをデプロイすると、イメージタグを使用する場合と比べていくつかのメリットがあります。イメージ ダイジェストの詳細については、このチュートリアルに進む前に、コンテナ イメージ ダイジェストの使用についての付属ドキュメントをご覧ください。

Kubernetes Pod 仕様のコンテナの image 引数は、ダイジェスト付きのイメージを受け入れます。この引数は、Deployment、StatefulSet、DaemonSet、ReplicaSet、Job リソースの template セクションなど、Pod の仕様を使用するすべての場所に適用されます。

ダイジェストを使用してイメージをデプロイするには、イメージ名に続けて @sha256: とダイジェスト値を指定します。次に、ダイジェスト付きのイメージを使用する Deployment リソースの例を示します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-deployment
spec:
  selector:
    matchLabels:
      app: echo
  template:
    metadata:
      labels:
        app: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
        ports:
        - containerPort: 8080

イメージ ダイジェストを使用するデメリットの 1 つは、イメージをレジストリに公開するまでダイジェスト値がわからないことです。新しいイメージをビルドすると、ダイジェスト値が変わるため、デプロイのたびに Kubernetes マニフェストを更新しなければなりません。

このチュートリアルでは、Skaffoldkptdigesterkustomizegke-deploykoBazel などのツールを利用して、マニフェストでイメージ ダイジェストを使用する方法について説明します。

推奨事項

このドキュメントでは、Kubernetes Deployment でイメージ ダイジェストを使用する方法をいくつか説明します。このドキュメントで説明するツールは、他のツールと組み合わせて使用します。たとえば、さまざまな環境のバリアントを作成するために kustomize で kpt 関数の出力を使用できます。Skaffold では、kpt や kustomize を使用してイメージを Kubernetes クラスタにデプロイするために、Bazel を使用してイメージをビルドできます。

これらのツールが補完的な関係にあるのは、これらのツールが Kubernetes リソースモデル(KRM)に基づいて構造化された編集を行うためです。このモデルではツールがプラグイン可能なため、これらのツールを活用して、アプリやサービスのデプロイに役立つプロセスとパイプラインを構築できます。

最初の段階では、既存のツールとプロセスに最適なアプローチをおすすめします。

  • Kubernetes クラスタで、変更用アドミッション Webhook として digester ツールを使用すると、コンテナ イメージの現在のビルドとデプロイのプロセスへの影響を最小限に抑えながら、すべてのデプロイメントにダイジェストを追加できます。また、digester Webhook では、Namespace にラベルを追加することのみが必要とされ、Binary Authorization の導入も簡素化されます。

  • Kubernetes マニフェストを操作する柔軟なツールが必要な場合、kpt は優れたオプションです。ダイジェスト ツールは、kpt パイプラインでクライアント側の KRM 関数として使用できます。

  • Skaffold は、イメージ参照にダイジェストを追加するために使用できます。この機能は、構成に小さな変更を加えて有効にします。Skaffold を採用すると、さまざまなツールがコンテナ イメージをビルドしてデプロイする仕組みを抽象化するなど、追加のメリットがあります。

  • すでに kustomize を使用して環境間で Kubernetes マニフェストを管理している場合は、イメージ トランスフォーマーを利用して、ダイジェストによってイメージをデプロイすることをおすすめします。

  • Go アプリのイメージをビルドして公開する場合は ko が最適です。これは、KnativeTektonsigstore などのオープンソース プロジェクトで使用されています。

  • すでに Bazel を使用してアプリを作成している場合は、rules_docker ルールセットを追加してイメージをビルドし、rules_k8s ルールセットを使用して Kubernetes マニフェストにイメージ ダイジェストを挿入することをおすすめします。

このドキュメントで説明するツールを使用していない場合は、Skaffold と digester Webhook から使い始めることをおすすめします。Skaffold は、デベロッパー チームとリリースチームの双方でよく使用されているツールで、このチュートリアルで説明する他のツールと統合されて機能します。こうした統合の選択肢は、要件の変化に合わせて活用できます。Kubernetes の digester Webhook は、組織全体に対してダイジェスト ベースのデプロイを有効にすることで、Skaffold を補完します。

目標

  • Skaffold を使用してイメージのビルドと push を行い、イメージ名とダイジェストを Kubernetes マニフェストに挿入する。
  • kpt セッターを使用して、Kubernetes マニフェストのイメージタグをイメージ ダイジェストに置き換える。
  • digester クライアント側関数と変更用アドミッション Webhook を使用して、Kubernetes Pod と Pod テンプレートのイメージにダイジェストを追加する。
  • kustomize を使用して、イメージ ダイジェストを含む Kubernetes マニフェストを生成する。
  • gke-deploy を使用して、Kubernetes マニフェストでイメージタグをダイジェストに変更する。
  • ko を使用してイメージのビルドと push を行い、Kubernetes マニフェストにイメージとダイジェストを挿入する。
  • Bazel を使用してイメージのビルドと push を行い、Kubernetes マニフェストにイメージとダイジェストを挿入する。

費用

このチュートリアルでは、課金対象である次の Google Cloud コンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このチュートリアルを終了した後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

  1. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  2. Cloud プロジェクトに対して課金が有効になっていることを確認します。プロジェクトに対して課金が有効になっていることを確認する方法を学習する

  3. Container Registry API を有効にします。

    API を有効にする

  4. Cloud Console で、Cloud Shell をアクティブにします。

    Cloud Shell をアクティブにする

Skaffold の使用

Skaffold は、Kubernetes クラスタに対するアプリケーションの継続的な開発とデプロイを行うためのコマンドライン ツールです。

Skaffold を使用してイメージを作成し、そのイメージを Container Registry に push します。Kubernetes マニフェスト テンプレートの image プレースホルダ値を、push されたイメージの名前、タグとダイジェストで置き換えます。

  1. Cloud Shell で、このセクションで作成したファイルを保存するディレクトリを作成し、そのディレクトリに移動します。

    mkdir -p ~/container-image-digests-tutorial/skaffold
    cd ~/container-image-digests-tutorial/skaffold
    
  2. Skaffold Git リポジトリのクローンを作成します。

    git clone https://github.com/GoogleContainerTools/skaffold.git
    
  3. getting-started のサンプルのあるディレクトリに移動します。

    cd skaffold/examples/getting-started
    
  4. Skaffold のバージョンと一致する Git タグをチェックアウトします。

    git checkout $(skaffold version)
    
  5. skaffold.yaml 構成ファイルを表示します。

    cat skaffold.yaml
    

    ファイルは、次のような形式です。

    apiVersion: skaffold/v2beta26
    kind: Config
    build:
      artifacts:
      - image: skaffold-example
    deploy:
      kubectl:
        manifests:
          - k8s-*
    

    build.artifacts セクションには、イメージのコンテキスト(この場合はプレースホルダ名)が含まれています。Skaffold は、入力のマニフェスト ファイルで、このプレースホルダを検索します。このセクションでは、Skaffold がイメージのビルドに使用するコンテキスト ディレクトリも定義します。デフォルトでは、Skaffold はビルド コンテキストとして現在のディレクトリを使用します。

    deploy セクションでは、現在のディレクトリで名前が k8s-* パターンに一致する入力マニフェストを読み取り、レンダリングされたマニフェストを kubectl apply でデプロイすることを Skaffold に指示しています。

    使用可能なすべてのオプションの概要については、skaffold.yaml リファレンス ドキュメントをご覧ください。

  6. Kubernetes マニフェスト テンプレートを表示します。

    cat k8s-pod.yaml
    

    次のようなファイルが表示されます。

    apiVersion: v1
    kind: Pod
    metadata:
      name: getting-started
    spec:
      containers:
      - name: getting-started
        image: skaffold-example
    

    image フィールドの skaffold-example プレースホルダ値は、skaffold.yaml ファイル内の image フィールドの値と一致します。このプレースホルダ値は、レンダリングされた出力の完全なイメージ名とダイジェストで置き換えられます。

  7. イメージをビルドし、Container Registry に push します。

    skaffold build \
        --default-repo=gcr.io/$(gcloud config get-value core/project) \
        --file-output=artifacts.json \
        --interactive=false \
        --push=true \
        --update-check=false
    

    このコマンドは、次のフラグを使用しています。

    • --file-output フラグは、ビルドされたイメージに関する情報(ダイジェスト値など)を保存するファイルを指定します。
    • --push フラグは、ビルドされたイメージを --default-repo フラグで指定されたコンテナ イメージ レジストリに push するように Skaffold に指示します。
    • --interactive フラグと --update-check フラグはどちらも false に設定されています。ビルド パイプラインなど、インタラクティブでない環境では、これらのフラグを false に設定しますが、ローカル開発ではデフォルト値(両方のフラグでは true)のままにします。

    Google Cloud Deploy を使用して GKE にデプロイする場合は、リリースを作成する際に--file-outputフラグを--build-artifactsフラグの数値として使用してください。

  8. 前の手順のコンテナ イメージの名前、タグ、ダイジェストを使用して、拡張された Kubernetes マニフェストをレンダリングします。

    skaffold render \
        --build-artifacts=artifacts.json \
        --digest-source=none \
        --interactive=false \
        --offline=true \
        --output=rendered.yaml \
        --update-check=false
    

    このコマンドは、次のフラグを使用しています。

    • --build-artifacts フラグは、前のステップの skaffold build コマンドからの出力ファイルを参照します。
    • --digest-source=none フラグは、Container Registry からのダイジェストを解決する代わりに、--build-artifacts フラグで提供されるファイルのダイジェスト値を使用することを意味します。
    • --offline=true フラグを使用すると、Kubernetes クラスタにアクセスせずにコマンドを実行できます。
    • --output フラグには、レンダリングされたマニフェストの出力ファイルを指定します。
  9. レンダリングされたマニフェストを表示します。

    cat rendered.yaml
    

    出力は次のようになります。

    apiVersion: v1
    kind: Pod
    metadata:
      name: getting-started
    spec:
      containers:
      - image: gcr.io/YOUR_PROJECT_ID/skaffold-example:TAG@sha256:DIGEST
        name: getting-started
    

    この出力には次の値が含まれています。

    • YOUR_PROJECT_ID: 実際の Cloud プロジェクトの ID
    • TAG: Skaffold がイメージに割り当てるタグ。
    • DIGEST: イメージ ダイジェストの値

kpt セッターの使用

kpt は、Kubernetes リソース マニフェストを管理、操作、カスタマイズ、適用するためのコマンドライン ツールです。

新しいイメージをビルドするときに kpt 関数カタログcreate-setters および apply-setters KRM 関数を使用することで、Kubernetes マニフェストのイメージ ダイジェストを更新できます。

  1. Cloud Shell で、このセクションで作成したファイルを保存するディレクトリを作成し、そのディレクトリに移動します。

    mkdir -p ~/container-image-digests-tutorial/kpt
    cd ~/container-image-digests-tutorial/kpt
    
  2. kpt をダウンロードします。

    mkdir -p ${HOME}/bin
    curl -L https://github.com/GoogleContainerTools/kpt/releases/download/v1.0.0-beta.1/kpt_linux_amd64 --output ${HOME}/bin/kpt
    chmod +x ${HOME}/bin/kpt
    export PATH=${HOME}/bin:${PATH}
    
  3. 現在のディレクトリに kpt パッケージを作成します。

    kpt pkg init --description "Container image digest tutorial"
    
  4. イメージ gcr.io/google-containers/echoserver を参照する Kubernetes Pod マニフェストを、タグ 1.10 を使用して作成します。

    cat << EOF > pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.10
        ports:
        - containerPort: 8080
    EOF
    
  5. kpt を使用して、そのマニフェスト フィールド用に echoimage という名前のセッターを作成します。ここで、既存の値は gcr.io/google-containers/echoserver:1.10 です。

    kpt fn eval . \
        --image gcr.io/kpt-fn/create-setters:v0.1@sha256:0220cc87f29ff9abfa3a3b5643aa50f18d355d5e9dc9e1f518119633ddc4895c \
        -- "echoimage=gcr.io/google-containers/echoserver:1.10"
    
  6. マニフェストを確認します。

    cat pod.yaml
    

    次のようなファイルが表示されます。

    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.10 # kpt-set: ${echoimage}
        ports:
        - containerPort: 8080
    
  7. コンテナ イメージのダイジェストの値を取得します。

    DIGEST=$(gcloud container images describe \
        gcr.io/google-containers/echoserver:1.10 \
        --format='value(image_summary.digest)')
    
  8. 新しいフィールド値を設定します。

    kpt fn eval . \
        --image gcr.io/kpt-fn/apply-setters:v0.2@sha256:4d4295727183396f0c3c6a75d2560254c2f9041a39e95dc1e5beffeb49cc1a12 \
        -- "echoimage=gcr.io/google-containers/echoserver:1.10@$DIGEST"
    

    このコマンドを実行すると、kpt はマニフェスト内の image フィールド値のインプレース置換を実行します。

  9. 更新されたマニフェストを表示します。

    cat pod.yaml
    

    次のようなファイルが表示されます。

    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.10@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229 # kpt-set: ${echoimage}
        ports:
        - containerPort: 8080
    

digester の使用

digester は、Kubernetes Pod と Pod テンプレートの仕様のコンテナ イメージと init コンテナ イメージにダイジェストを追加します。タグを使用するコンテナ イメージの参照が、digester によって置き換えられます。

spec:
  containers:
  - image: gcr.io/google-containers/echoserver:1.10

イメージのダイジェストを使用する参照は、次のようになります。

spec:
  containers:
  - image: gcr.io/google-containers/echoserver:1.10@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229

digester は、Kubernetes クラスタで変更用アドミッション Webhook として実行するか、kpt や kustomize コマンドライン ツールを使用してクライアント側の KRM 関数として実行できます。

digester KRM 関数の使用

  1. Cloud Shell で、このセクションで作成したファイルを保存するディレクトリを作成し、そのディレクトリに移動します。

    mkdir -p ~/container-image-digests-tutorial/digester-fn
    cd ~/container-image-digests-tutorial/digester-fn
    
  2. digester バイナリをダウンロードします。

    DIGESTER_VERSION=v0.1.7
    mkdir -p ${HOME}/bin
    curl -L "https://github.com/google/k8s-digester/releases/download/${DIGESTER_VERSION}/digester_$(uname -s)_$(uname -m)" --output ${HOME}/bin/digester
    chmod +x ${HOME}/bin/digester
    export PATH=${HOME}/bin:${PATH}
    
  3. イメージ gcr.io/google-containers/echoserver を参照する Kubernetes Pod マニフェストを、タグ 1.10 を使用して作成します。

    cat << EOF > pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.10
        ports:
        - containerPort: 8080
    EOF
    
  4. kpt を使用して digester の KRM 関数を実行します(現在のディレクトリ(.)にあります)。

    kpt fn eval . --exec digester
    

    このコマンドを実行すると、kpt は現在のディレクトリでマニフェストのインプレース更新を行います。マニフェスト ファイルは変更せずに、kpt による更新後のマニフェストをコンソールに表示する場合は、--output unwrap フラグを追加します。

  5. 更新されたマニフェストを表示します。

    cat pod.yaml
    

    次のようなファイルが表示されます。

    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
        - name: echoserver
          image: gcr.io/google-containers/echoserver:1.10@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
          ports:
            - containerPort: 8080
    

digester アドミッション Webhook を使用する

  1. Cloud Shell で、このセクションで作成したファイルを保存するディレクトリを作成し、そのディレクトリに移動します。

    mkdir -p ~/container-image-digests-tutorial/digester-webhook
    cd ~/container-image-digests-tutorial/digester-webhook
    
  2. kind をダウンロードします。

    KIND_VERSION=v0.11.1
    mkdir -p ${HOME}/bin
    curl -L "https://github.com/kubernetes-sigs/kind/releases/download/${KIND_VERSION}/kind-linux-amd64" --output ${HOME}/bin/kind
    chmod +x ${HOME}/bin/kind
    export PATH=${HOME}/bin:${PATH}
    

    kind は、Docker を使用してローカルの Kubernetes クラスタを実行するためのコマンドライン ツールです。

  3. ローカルの Kubernetes クラスタを作成します。

    kind create cluster
    
  4. digester Webhook kpt パッケージをダウンロードし、manifests という名前のディレクトリに保存します。

    DIGESTER_VERSION=v0.1.7
    kpt pkg get https://github.com/google/k8s-digester.git/manifests@${DIGESTER_VERSION} manifests
    
  5. digester Webhook をデプロイします。

    kpt live init manifests
    kpt live apply manifests --reconcile-timeout=3m --output=table
    
  6. kind クラスタに digester-demo という Kubernetes Namespace を作成します。

    kubectl create namespace digester-demo
    
  7. digest-resolution: enabled ラベルを digester-demo Namespace に追加します。

    kubectl label namespace digester-demo digest-resolution=enabled
    

    digester Webhook は、このラベルを持つ名前空間の Pod にダイジェストを追加します。

  8. イメージ gcr.io/google-containers/echoserver を参照する Kubernetes Deployment マニフェストをタグ 1.10 を使用して作成します。

    cat << EOF > deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: echo-deployment
    spec:
      selector:
        matchLabels:
          app: echo
      template:
        metadata:
          labels:
            app: echo
        spec:
          containers:
          - name: echoserver
            image: gcr.io/google-containers/echoserver:1.10
            ports:
            - containerPort: 8080
    EOF
    
  9. digester-demo Namespace にマニフェストを適用します。

    kubectl apply --filename deployment.yaml --namespace digester-demo \
        --output jsonpath='{.spec.template.spec.containers[].image}{"\n"}'
    

    --output フラグは、kubectl にイメージ名をコンソールに出力するように指示します。次のような出力が表示されます。

    gcr.io/google-containers/echoserver:1.10@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
    

    この出力は、digester Webhook がイメージのダイジェストを Deployment リソースの Pod テンプレート仕様に追加したことを示しています。

  10. kind クラスタを削除して、Cloud Shell セッション内のリソースを解放します。

    kind delete cluster
    

Kustomize イメージ トランスフォーマーの使用

kustomize は、オーバーレイ、パッチ、トランスフォーマーを使用して Kubernetes マニフェストをカスタマイズできるコマンドライン ツールです。

kustomize イメージ トランスフォーマーを使用すると、既存のマニフェストに含まれているイメージ名、タグ、ダイジェストを更新できます。

次の kustomization.yaml スニペットは、Pod 仕様の image 値がトランスフォーマーの name 値と一致するイメージにトランスフォーマーの digest 値を使用するように、イメージ トランスフォーマーを構成します。

images:
- name: gcr.io/google-containers/echoserver
  digest: sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229

kustomize イメージ トランスフォーマーでイメージ ダイジェストを使用するには、次の操作を行います。

  1. Cloud Shell で、このセクションで作成したファイルを保存するディレクトリを作成し、そのディレクトリに移動します。

    mkdir -p ~/container-image-digests-tutorial/kustomize
    cd ~/container-image-digests-tutorial/kustomize
    
  2. kustomization.yaml ファイルを作成します。

    kustomize init
    
  3. タグ 1.10 を使用して、イメージ gcr.io/google-containers/echoserver を参照する Pod 仕様を含む Kubernetes マニフェストを作成します。

    cat << EOF > pod.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.10
        ports:
        - containerPort: 8080
    EOF
    
  4. kustomization.yaml ファイルで、リソースとしてマニフェストを追加します。

    kustomize edit add resource pod.yaml
    
  5. イメージ トランスフォーマーを使用して、イメージのダイジェストを更新します。

    kustomize edit set image \
        gcr.io/google-containers/echoserver@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
    
  6. kustomization.yaml ファイルでイメージ トランスフォーマーを表示します。

    cat kustomization.yaml
    

    次のようなファイルが表示されます。

    apiVersion: kustomize.config.k8s.io/v1beta1
    kind: Kustomization
    resources:
    - pod.yaml
    images:
    - digest: sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
      name: gcr.io/google-containers/echoserver
    
  7. 作成されたマニフェストを表示します。

    kustomize build .
    

    次のような出力が表示されます。

    apiVersion: v1
    kind: Pod
    metadata:
      name: echo
    spec:
      containers:
      - image: gcr.io/google-containers/echoserver@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
        name: echoserver
        ports:
        - containerPort: 8080
    
  8. 作成されたマニフェストを Kubernetes クラスタに適用するには、--kustomize フラグを指定した kubectl apply を使います。

    kubectl apply --kustomize .
    

    出力を後で適用する場合は、kustomize build コマンドの出力をファイルにリダイレクトします。kustomize には、このドキュメントでは範囲外の他の機能も備わっています。詳細については、kustomize のドキュメントをご覧ください。また、kustomize は、Cloud Build コミュニティ ビルダー イメージとしても利用できます。

gke-deploy の使用

gke-deploy は、Google Kubernetes Engine(GKE)とともに使用するコマンドライン ツールです。gke-deploy は、kubectl コマンドライン ツールをラップし、Google が推奨する方法に従って作成するリソースを変更できます。

gke-deploy のサブコマンド(prepare または run)を使用すると、gke-deploy はイメージタグの代わりにダイジェストを使用し、イメージ ダイジェストで拡張したマニフェストをデフォルトで output/expanded/aggregated-resources.yaml ファイルに保存します。

gke-deploy run を使用すると、イメージタグをダイジェストに置き換え、拡張されたマニフェストを GKE クラスタに適用できます。このコマンドは便利ですが、デプロイ時にイメージタグが置換されます。タグに関連付けられたイメージが実際にデプロイされるまでに変更されていると、予期しないイメージがデプロイされる場合があります。本番環境のデプロイでは、マニフェストの生成と適用は別の手順で行うことをおすすめします。

Kubernetes Deployment マニフェストのイメージタグをイメージ ダイジェストに置き換えるには、次の操作を行います。

  1. Cloud Shell で、このセクションで作成したファイルを保存するディレクトリを作成し、そのディレクトリに移動します。

    mkdir -p ~/container-image-digests-tutorial/gke-deploy
    cd ~/container-image-digests-tutorial/gke-deploy
    
  2. gke-deploy をインストールします。

    go install github.com/GoogleCloudPlatform/cloud-builders/gke-deploy@latest
    
  3. イメージ gcr.io/google-containers/echoserver を参照する Kubernetes Deployment マニフェストをタグ 1.10 を使用して作成します。

    cat << EOF > deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: echo-deployment
    spec:
      selector:
        matchLabels:
          app: echo
      template:
        metadata:
          labels:
            app: echo
        spec:
          containers:
          - name: echoserver
            image: gcr.io/google-containers/echoserver:1.10
            ports:
            - containerPort: 8080
    EOF
    
  4. deployment.yaml マニフェストに基づいて拡張されたマニフェストを生成します。

    gke-deploy prepare \
        --filename deployment.yaml \
        --image gcr.io/google-containers/echoserver:1.10 \
        --version 1.10
    
  5. 拡張されたマニフェストを表示します。

    cat output/expanded/aggregated-resources.yaml
    

    次のような出力が表示されます。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app.kubernetes.io/managed-by: gcp-cloud-build-deploy
        app.kubernetes.io/version: "1.10"
      name: echo-deployment
      namespace: default
    spec:
      selector:
        matchLabels:
          app: echo
      template:
        metadata:
          labels:
            app: echo
            app.kubernetes.io/managed-by: gcp-cloud-build-deploy
            app.kubernetes.io/version: "1.10"
        spec:
          containers:
          - image: gcr.io/google-containers/echoserver@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
            name: echoserver
            ports:
            - containerPort: 8080
    

    拡張されたマニフェストでは、イメージタグがダイジェストに置き換えられます。

    gke-deploy コマンドで使用した --version 引数により、デプロイで推奨される app.kubernetes.io/version ラベルと拡張されたマニフェストの Pod テンプレートのメタデータの値が設定されます。

    gke-deploy ツールは、Cloud Build のビルド済みイメージとしても利用できます。Cloud Build で gke-deploy を使用する方法については、Cloud Build のドキュメントで gke-deploy をご覧ください。

ko の使用

ko は、Go コンテナ イメージをビルドして Kubernetes クラスタにデプロイするコマンドライン ツールです。ko は、Docker デーモンを使用せずにイメージをビルドするため、Docker をインストールできない環境でもイメージを使用できます。

ko サブコマンド publish は、イメージをビルドして、Container Registry に公開するか、ローカルの Docker デーモンにロードします。

ko サブコマンド resolve は、次の処理を行います。

  • --filename 引数に指定した Kubernetes マニフェストの image フィールドでプレースホルダを検索し、ビルドするイメージを確認します。
  • イメージをビルドして公開します。
  • image 値のプレースホルダを、ビルドされたイメージの名前とダイジェストに置き換えます。
  • 拡張されたマニフェストを出力します。

ko サブコマンドの applycreaterun は、resolve と同じ手順を実行した後、拡張されたマニフェストを使用して kubectl applycreate、または run を実行します。

Go ソースコードからイメージをビルドし、イメージのダイジェストを Kubernetes Deployment マニフェストに追加するには、次の操作を行います。

  1. Cloud Shell で、このセクションで作成したファイルを保存するディレクトリを作成し、そのディレクトリに移動します。

    mkdir -p ~/container-image-digests-tutorial/ko
    cd ~/container-image-digests-tutorial/ko
    
  2. ko をダウンロードして PATH に追加します。

    mkdir -p ${HOME}/bin
    curl -L https://github.com/google/ko/releases/download/v0.9.3/ko_0.9.3_$(uname -s)_$(uname -m).tar.gz | tar -zxC ${HOME}/bin ko
    export PATH=${HOME}/bin:${PATH}
    
  3. app と呼ばれる新しいディレクトリに、example.com/hello-world というモジュール名で Go アプリを作成します。

    mkdir -p app/cmd/ko-example
    
    cd app
    
    go mod init example.com/hello-world
    
    cat << EOF > cmd/ko-example/main.go
    package main
    
    import "fmt"
    
    func main() {
        fmt.Println("hello world")
    }
    EOF
    
  4. ko がイメージの公開に使用するイメージ リポジトリを定義します。

    export KO_DOCKER_REPO=gcr.io/$(gcloud config get-value core/project)
    

    このサンプルでは Container Registry を使用しますが、別のレジストリを使用することもできます。

  5. アプリのイメージをビルドして公開するには、次のいずれかの手順を行います。

    • Go メイン パッケージのパスを指定してアプリのイメージをビルドし、公開します。

      ko publish --base-import-paths ./cmd/ko-example
      

      オプションの引数 --base-import-paths を使用すると、ko はイメージ名としてメイン パッケージ ディレクトリの短縮名を使用します。

      ko は、イメージ名とダイジェストを stdout に次の形式で出力します。

      gcr.io/YOUR_PROJECT_ID/ko-example@sha256:DIGEST_VALUE
      

      この出力で:

      • YOUR_PROJECT_ID: 実際の Cloud プロジェクトの ID
      • DIGEST_VALUE: イメージ ダイジェストの値
    • ko を使用して、マニフェストのプレースホルダを、ビルドして公開するイメージの名前とダイジェストに置き換えます。

      1. Kubernetes Pod マニフェストを作成します。このマニフェストでは、image フィールドの値としてプレースホルダ ko://IMPORT_PATH_OF_YOUR_MAIN_PACKAGE を使用します。

        cat << EOF > ko-pod.yaml
        apiVersion: v1
        kind: Pod
        metadata:
          name: ko-example
        spec:
          containers:
          - name: hello-world
            image: ko://example.com/hello-world/cmd/ko-example
        EOF
        
      2. ko resolve を使用してアプリのイメージをビルドして公開し、マニフェストのプレースホルダをイメージ名とダイジェストに置き換えます。

        ko resolve --base-import-paths --filename ko-pod.yaml
        

        ko は、イメージ名とダイジェストを含むマニフェストを stdout に出力します。

        apiVersion: v1
        kind: Pod
        metadata:
          name: ko-example
        spec:
          containers:
          - name: hello-world
            image: gcr.io/YOUR_PROJECT_ID/ko-example@sha256:DIGEST
        

        この出力で:

        • YOUR_PROJECT_ID: 実際の Cloud プロジェクトの ID
        • DIGEST: イメージ ダイジェストの値

Bazel の使用

Bazel は、Google の内部 Blaze ビルドシステムをベースとしたオープンソースの多言語ビルドツールです。

rules_docker は、コンテナ イメージをビルドして push するための Bazel ルールセットです。このルールにより、Docker デーモンを使用せずに再現可能なイメージをビルドできます。Bazel のキャッシュを使用することで、イメージのビルドとレジストリへの push の両方が高速化されます。

rules_k8s は、Kubernetes マニフェストとクラスタで動作する Bazel ルールセットです。

イメージをビルドして push し、イメージ ダイジェストを含む Kubernetes マニフェストを挿入するには、次の操作を行います。

  1. Cloud Shell で、このセクションで作成したファイルを保存するディレクトリを作成し、そのディレクトリに移動します。

    mkdir -p ~/container-image-digests-tutorial/bazel
    cd ~/container-image-digests-tutorial/bazel
    
  2. rules_k8s Git リポジトリのクローンを作成する

    git clone https://github.com/bazelbuild/rules_k8s.git
    
  3. Git リポジトリのディレクトリに移動します。

    cd rules_k8s
    
  4. Git タグをチェックアウトします。

    git checkout v0.6
    
  5. WORKSPACE ファイルで、Bazel がイメージを push するベースイメージ リポジトリ名を、イメージの push 権限のあるリポジトリに置き換えます。

    sed -i~ "s/image_chroot.*/image_chroot = \"gcr.io\/$(gcloud config get-value core\/project)\",/" WORKSPACE
    

    このサンプルでは Container Registry を使用しますが、別のレジストリを使用することもできます。

  6. ビルドで使用する Bazel のバージョンをインストールします。

    sudo apt-get install -y bazel-$(cat .bazelversion)
    
  7. Kubernetes Deployment マニフェスト テンプレートのサンプルで apiVersion フィールドを修正します。

    sed -i~ 's/v1beta1/v1/' examples/hellohttp/deployment.yaml
    
  8. Kubernetes Deployment マニフェスト テンプレートを表示します。

    cat examples/hellohttp/deployment.yaml
    

    次のようなファイルが表示されます。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-http-staging
    spec:
      replicas: 1
      template:
        metadata:
          labels:
            app: hello-http-staging
        spec:
          containers:
          - name: hello-http
            image: hello-http-image:latest
            imagePullPolicy: Always
            ports:
            - containerPort: 8080
    
  9. hellohttp サンプルの Java イメージをビルドして Container Registry に push します。Kubernetes Deployment マニフェスト テンプレートの image 値を、push されたイメージの名前とダイジェストに置き換えます。stdout 出力をリダイレクトして、拡張されたマニフェストを deployment.yaml.out という新しいファイルにキャプチャします。

    bazel --output_user_root=/tmp/bazel \
        run //examples/hellohttp/java:staging > deployment.yaml.out
    

    このコマンドを初めて実行する場合、数分かかります。これは、ルールセット、コンパイラ、依存関係がダウンロードされるためです。

    --output_user_root 引数により、ホーム ディレクトリ外の一時ディレクトリをディスクベースのキャッシュに使用することを Bazel に指示します。この一時ディレクトリは、Cloud Shell でホーム ディレクトリ ボリュームの占有を防ぐために必要になります。

  10. 拡張されたマニフェストを表示します。

    cat deployment.yaml.out
    

    ファイルは、次のような形式です。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-http-staging
    spec:
      replicas: 1
      template:
        metadata:
          labels:
            app: hello-http-staging
        spec:
          containers:
          - image: gcr.io/YOUR_PROJECT_ID/hello-http-image@sha256:b9d0a4643e9f11efe7cd300dd219ad691077ddfaccc118144cd83b7c472a8e86
            imagePullPolicy: Always
            name: hello-http
            ports:
            - containerPort: 8080
    
  11. Bazel が Container Registry に push したイメージを確認します。

    gcloud container images describe \
        gcr.io/$(gcloud config get-value core/project)/hello-http-image
    

クリーンアップ

課金を停止する最も簡単な方法は、チュートリアル用に作成した Cloud プロジェクトを削除することです。また、リソースを個別に削除することもできます。

プロジェクトの削除

  1. Cloud Console で [リソースの管理] ページに移動します。

    [リソースの管理] に移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

リソースの削除

このチュートリアルで使用した Cloud プロジェクトを保持する場合は、個々のリソースを削除します。

  1. Container Registry 内のイメージを削除します。

    for IMG in hello-http-image ko-example skaffold-example ; do \
        gcloud container images list-tags \
            gcr.io/$(gcloud config get-value core/project)/$IMG \
            --format 'value(digest)' | xargs -I {} gcloud container images \
            delete --force-delete-tags --quiet \
            gcr.io/$(gcloud config get-value core/project)/$IMG@sha256:{}
    done
    
  2. このチュートリアルで作成したファイルを削除します。

    cd
    rm -rf ~/container-image-digests-tutorial
    

次のステップ