自動ロールバックの実装

スクリプトを使用して、リソース・マネージャで適用ジョブが失敗した場合に自動ロールバックを実装します。自動ロールバック・スクリプトには、ジョブ失敗の監視と、検証、カスタム・トリガーおよびアクションを含むロールバック・プロシージャの定義が含まれます。

本番環境では、堅牢で柔軟なデプロイメント戦略の確立が不可欠です。一般的なベスト・プラクティスは、OCI Resource Managerと継続的インテグレーション/継続的デリバリ(CI/CD)システムを統合して、自動ロールバックを含む完全なデプロイメント・ライフサイクルを管理することです。

Oracle Cloud Infrastructure(OCI)は、ネイティブでフル機能のCI/CDプラットフォームであるOCI DevOpsを提供します。このサービスは、デプロイメント、テスト、監視およびロールバック操作をシームレスに調整するために必要なツールおよびパイプラインを提供します。

自動ロールバック・スクリプト

開始に役立つように、OCI DevOpsデプロイメント・パイプラインで使用できる次のサンプルBashスクリプトが提供されています。このスクリプトは、デプロイメントが失敗した場合にOCIリソース・マネージャ・スタックを自動的にロールバックするメカニズムを示しています。

スクリプトは、特定の要件にあわせてカスタマイズできる開始点として機能し、デプロイメント・ワークフローの固有のニーズに確実に対応します。

スクリプト
version: 0.1
component: command
timeoutInSeconds: 600
shell: bash
steps:
  - type: Command
    name: "Deployment Runner Functionality"
    command: |
      # The STACK_OCID variable is externally injected and remains unescaped.
      STACK_OCID="${STACK_OCID}"

      echo "Starting Resource Manager Apply Job for Stack: ${STACK_OCID}"

      # 1. Create the Apply Job and capture its OCID.
      job_id=$(
        oci resource-manager job create-apply-job \
          --execution-plan-strategy AUTO_APPROVED \
          --display-name "DevOps-Apply-$(date +%s)" \
          --stack-id "${STACK_OCID}" \
          --wait-for-state 'ACCEPTED' \
          --query 'data.id' \
          --raw-output \
      )

      # Check if the job creation command returned a valid ID
      if [ -z "$job_id" ]; then
        echo "ERROR: Failed to create Resource Manager Apply job or command failed."
        exit 1
      fi

      echo "Resource Manager Job OCID: $job_id"

      # 2. Polling Loop to monitor job status
      max_poll_time_seconds=600 # 10 minutes maximum wait time
      poll_interval_seconds=10
      elapsed_time=0

      while [ $elapsed_time -le $max_poll_time_seconds ]; do

        # Get the current job status.
        status=$(
          oci resource-manager job get \
            --job-id "$job_id" \
            --query 'data."lifecycle-state"' \
            --raw-output \
        )

        echo "Time Elapsed: ${elapsed_time}s / ${max_poll_time_seconds}s - Current Job Status: $status"

        if [ "$status" == "SUCCEEDED" ]; then
          echo "Resource Manager Apply Job SUCCEEDED."
          exit 0 # Success exit code
        elif [ "$status" == "FAILED" ] || [ "$status" == "CANCELED" ]; then
          echo "Resource Manager Apply Job FAILED or CANCELED."

          # Check failure reason and conditionally trigger rollback
          if [ "$status" == "FAILED" ]; then
            # Fetch failure code
            failure_code=$(
              oci resource-manager job get \
                --job-id "$job_id" \
                --query 'data."failure-details".code' \
                --raw-output \
            )
            if [ -z "$failure_code" ]; then
              echo "No failure-details.code found in job output (field is empty or missing)"
              echo "==== Full job JSON output for debugging: ===="
              oci resource-manager job get \
                --job-id "$job_id" \
            else
              echo "Failure code: $failure_code"
            fi

            if [ "$failure_code" == "TERRAFORM_EXECUTION_ERROR" ]; then
              echo "Detected Terraform configuration error. Starting automatic rollback process..."

              # Define a rollback function
              automatic_rollback() {
                # List all jobs, filter for successful Apply jobs, sort by time-created desc, and get latest job OCID
                # Part 1: Fetch and count all succeeded APPLY jobs
                matched_jobs=$(
                  oci resource-manager job list \
                    --stack-id "$STACK_OCID" \
                    --query 'data[?operation==`APPLY` && "lifecycle-state"==`SUCCEEDED`] | sort_by(@, &`"time-created"`)' \
                )
                job_count=$(echo "$matched_jobs" | jq 'length')
                echo "Number of matching jobs found: $job_count"

                # Part 2: Extract and print first OCID if any
                last_succeeded_apply_job_ocid=$(echo "$matched_jobs" | jq -r '.[0].id // empty')

                if [ -n "$last_succeeded_apply_job_ocid" ]; then
                  echo "Last succeeded apply job OCID: $last_succeeded_apply_job_ocid"
                else
                  echo "No previous successful apply jobs found. Rollback skipped."
                  return 0
                fi
                
                echo "Invoking OCI CLI to create rollback job for OCID: $last_succeeded_apply_job_ocid"
                
                oci resource-manager job create \
                  --from-json "{\"stackId\":\"${STACK_OCID}\",\"displayName\":\"DevOps-Apply-Rollback-$(date +%s)\",\"jobOperationDetails\":{\"operation\":\"APPLY_ROLLBACK\",\"executionPlanRollbackStrategy\":\"AUTO_APPROVED\",\"targetRollbackJobId\":\"$last_succeeded_apply_job_ocid\"}}" \
                
                echo "======Apply Rollback Job Creation Complete========="
              }

              # Call the rollback function
              automatic_rollback
            fi
          fi
          exit 1 # Failure exit code
        fi

        # Wait before polling again
        sleep $poll_interval_seconds

        let "elapsed_time = elapsed_time + poll_interval_seconds"
      done

      # If the loop finished without SUCCEEDED or FAILED status
      echo "Error: Resource Manager Apply Job timed out after ${max_poll_time_seconds} seconds."
      exit 1

スクリプトに実装されている自動ロールバック・ロジックには、次のステップが含まれます。

  1. デプロイメントの開始: 更新されたTerraform構成をデプロイするための適用ジョブの作成
  2. デプロイメント・ステータスのモニター: 適用ジョブのステータスを継続的にモニターします。ジョブの詳細の取得を参照してください。
  3. 失敗の評価: 適用ジョブが失敗した場合は、事前定義された基準を評価して、自動ロールバックをトリガーするかどうかを決定します。
  4. 安定状態の識別: スタックの正常な適用ジョブを取得し、ロールバック先のターゲット・ジョブを決定します。ジョブのリストを参照してください。
  5. ロールバックのトリガー: 適用ロールバック・ジョブを作成して、スタックを以前の安定した状態にリストアします。