🐳

Cloud Deploy用のcloudbuildでskaffold buildを使わない場合のサンプル

に公開

対象

  • manifest.yamlとかすでに動かせる
  • skaffold build使わないとき

前提

  • イメージ名server 想定
  • cacheFromを効かせる
  • Dockerfileは/deploy/Dockerfileに存在する
  • substitutionはCloudBuildTriggerの環境変数として渡される
  • cloudbuildリージョンは台湾
  • skaffold buildは使わず docker buildで代替したい

cloudbuild.yaml

steps:
  # ------------------------------------------------------------------------------------
  # STEP 1: Artifact Registryから"server"サービスの最新イメージのタグを取得する
  # ------------------------------------------------------------------------------------
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    id: 'Get Latest Image Tag'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        # Artifact Registryで"server"イメージの最新版(最終更新日時順)のタグを取得する
        gcloud artifacts docker images list $_ARTIFACT_REPOSITORY_PATH/server \
          --include-tags \
          --sort-by=~UPDATE_TIME \
          --limit=1 \
          --format='get(tags)' \
          | head -n 1 > /workspace/latest_image_tag.txt || echo "" > /workspace/latest_image_tag.txt

        echo "Latest tag found in Artifact Registry: $(cat /workspace/latest_image_tag.txt)"

  # ------------------------------------------------------------------------------------
  # STEP 2: Dockerイメージをビルドし、Artifact Registryにプッシュする
  # ------------------------------------------------------------------------------------
  - name: 'gcr.io/cloud-builders/docker'
    id: 'Docker Build and Push'
    secretEnv: ['TURBO_TOKEN', 'TIPTAP_PRO_TOKEN']
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        # STEP 1で取得した最新タグを読み込む
        LATEST_TAG_FROM_REPO=$(cat /workspace/latest_image_tag.txt)

        # 安定したフォールバックとして':latest'をキャッシュ元に指定
        CACHE_ARGS="--cache-from=$_ARTIFACT_REPOSITORY_PATH/server:latest"

        # もしArtifact Registryから最新タグが取得できていれば、それもキャッシュ元に追加
        if [[ -n "$$LATEST_TAG_FROM_REPO" ]]; then
          echo "✅ Caching from latest image in registry: $$LATEST_TAG_FROM_REPO"
          CACHE_ARGS="$$CACHE_ARGS --cache-from=$_ARTIFACT_REPOSITORY_PATH/server:$$LATEST_TAG_FROM_REPO"
        else
          echo "⚠️ No existing image found in registry. Caching from 'latest' only."
        fi

        # 動的に生成したキャッシュ引数を使ってビルドを実行
        docker build \
          --tag=$_ARTIFACT_REPOSITORY_PATH/server:$SHORT_SHA \
          $$CACHE_ARGS \
          --file=deploy/Dockerfile \
          .

        # ビルドしたイメージをプッシュ
        docker push $_ARTIFACT_REPOSITORY_PATH/server:$SHORT_SHA
    env:
      - 'DOCKER_BUILDKIT=1'

  # ------------------------------------------------------------------------------------
  # STEP 3: Cloud Deploy用のビルド成果物ファイル (artifacts.json) を手動で作成する
  # ------------------------------------------------------------------------------------
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    id: 'Generate Build Artifacts'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        # skaffold.yamlで定義されているイメージ名。STEP 2でビルドしたものと一致させる。
        IMAGE_NAME_IN_SKAFFOLD="${_ARTIFACT_REPOSITORY_PATH}/server"

        # 実際にプッシュしたイメージのフルパス付きタグ
        IMAGE_TAG_WITH_PATH="${_ARTIFACT_REPOSITORY_PATH}/server:$SHORT_SHA"

        # プッシュしたイメージのダイジェスト(一意なID)を取得
        # イメージ名はSTEP 2でビルド&プッシュした 'server' を使用
        DIGEST=$$(gcloud container images describe "$${IMAGE_TAG_WITH_PATH}" --format='get(image_summary.digest)')

        # ダイジェストを含む完全なイメージ参照を作成
        IMAGE_WITH_DIGEST="$${IMAGE_NAME_IN_SKAFFOLD}@$${DIGEST}"

        # Cloud Deployが要求する正しい形式でJSONファイルを作成
        # imageNameはskaffold.yamlで定義されているイメージ名と一致させる
        echo "{\"builds\":[{\"imageName\":\"server\",\"tag\":\"$${IMAGE_WITH_DIGEST}\"}]}" > /workspace/artifacts.json

        echo "✅ Generated /workspace/artifacts.json:"
        cat /workspace/artifacts.json

 
  # ------------------------------------------------------------------------------------
  # STEP 4: Cloud Deployを使って"Service"をデプロイする
  # ------------------------------------------------------------------------------------
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    id: 'Deploy Service'
    entrypoint: gcloud
    args:
      - 'deploy'
      - 'releases'
      - 'create'
      - 'rel-${SHORT_SHA}'
      - '--delivery-pipeline=${_CLOUD_DEPLOY_SERVICE_PIPELINE}'
      - '--region=${_REGION}'
      - '--annotations=commitSha=$SHORT_SHA'
      - '--source=.'
      - '--skaffold-file=apps/api/deploy/skaffold.yaml'
      - '--build-artifacts=/workspace/artifacts.json' # STEP 3で作成したファイルを参照
      - '--gcs-source-staging-dir=${_GCS_SOURCE_SERVICE_STAGING_DIR}'
      - '--impersonate-service-account=${_CLOUD_DEPLOY_SERVICE_RELEASER_EMAIL}'
    env:
      - 'IMAGE_TAG=$SHORT_SHA'

substitutions:
  _REGION: by-terraform
  _ARTIFACT_REPOSITORY_PATH: by-terraform
  _CLOUD_DEPLOY_JOB_PIPELINE: by-terraform
  _CLOUD_DEPLOY_SERVICE_PIPELINE: by-terraform
  _GCS_SOURCE_JOB_STAGING_DIR: by-terraform
  _GCS_SOURCE_SERVICE_STAGING_DIR: by-terraform
  _CLOUD_DEPLOY_JOB_RELEASER_EMAIL: by-terraform
  _CLOUD_DEPLOY_SERVICE_RELEASER_EMAIL: by-terraform

# https://cloud.google.com/build/docs/securing-builds/configure-user-specified-service-accounts?hl=ja#set_up_build_logs
# 設定しないとログエラーが発生する↓
# generic::invalid_argument: if 'build.service_account' is specified, the build must either (a) specify 'build.logs_bucket', (b) use the REGIONAL_USER_OWNED_BUCKET build.options.default_logs_bucket_behavior option, or (c) use either CLOUD_LOGGING_ONLY / NONE logging options
options:
  logging: CLOUD_LOGGING_ONLY

skaffold buildは使っていないのでbuildプロパティには不要なものもありそう
skaffold.yaml

apiVersion: skaffold/v3
kind: Config
metadata:
  name: hogehoge-server
build:
  tagPolicy:
    envTemplate:
      # テンプレートをサポートするフィールドは限られている
      # https://skaffold.dev/docs/environment/templating/#list-of-fields-that-support-templating
      template: '{{ .IMAGE_TAG }}' # 環境変数により置換される
  artifacts:
    - image: server
      context: .
      docker:
        dockerfile: deploy/Dockerfile
  local:
    useBuildkit: true
    push: true

deploy:
  cloudrun: {}

# マニフェストファイルの指定
manifests:
  rawYaml:
    - manifest.yaml

manifest.yaml

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: hogehoge-server
  annotations:
    run.googleapis.com/ingress: all
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/maxScale: '5' # from-param: ${max_scale}
        autoscaling.knative.dev/minScale: '0' # from-param: ${min_scale}
        run.googleapis.com/sessionAffinity: 'false'
    spec:
      containerConcurrency: 80
      timeoutSeconds: 300
      serviceAccountName: dummy # from-param: ${service_account_name}
      containers:
        - image: server # skaffold.yamlのnameにあわせる
          ports:
            - name: http1
              containerPort: 3000
          resources:
            limits:
              cpu: 1000m
              memory: 512Mi
          startupProbe:
            timeoutSeconds: 240
            periodSeconds: 240
            failureThreshold: 1
            tcpSocket:
              port: 3000

TRAPE(トラピ)

Discussion