本教學課程說明如何設計及部署具備韌性、啟用 GPU 的 Cloud Run 工作,執行時間最長可達 12 小時。
雖然 Cloud Run 支援延長工作逾時時間,但並未提供不中斷執行的服務水準協議。由於啟用 GPU 的工作不會即時遷移,因此每週例行維護作業會在執行期間終止這些工作。因此,任何長時間執行的工作都應預期至少會中斷一次。為確保工作順利完成,且不浪費運算資源,請將應用程式設計為可設定檢查點並繼續執行,而非依賴單一不中斷的執行作業。
本教學課程將引導您實作檢查點、處理平台 SIGTERM 信號,以及設定重試次數上限。
目標
在本教學課程中,您將執行下列操作:
- 準備 Python 應用程式,實作檢查點功能並處理
SIGTERM信號。 - 建立 Cloud Storage bucket 來保留檢查點。
- 建構及部署 Cloud Run 工作,並啟用 GPU、設定 12 小時的工作逾時時間,以及重試政策。
- 執行工作,並瞭解如何監控記錄中的先占事件。
費用
在本文件中,您將使用下列 Google Cloud計費元件:
您可以使用 Pricing Calculator,根據預測用量估算費用。
事前準備
- 登入 Google Cloud 帳戶。如果您未曾使用過 Google Cloud,歡迎 建立帳戶,親自體驗實際使用我們產品的成效。新客戶還能獲得價值 $300 美元的免費抵免額,用於執行、測試及部署工作負載。
-
安裝 Google Cloud CLI。
-
若您採用的是外部識別資訊提供者 (IdP),請先 使用聯合身分登入 gcloud CLI。
-
執行下列指令,初始化 gcloud CLI:
gcloud init -
選取或建立專案所需的角色
- 選取專案:選取專案時,不需具備特定 IAM 角色,只要您已獲派某個專案的角色,即可選取該專案。
-
建立專案:如要建立專案,您必須具備專案建立者角色 (
roles/resourcemanager.projectCreator),其中包含resourcemanager.projects.create權限。瞭解如何授予角色。
-
建立 Google Cloud 專案:
gcloud projects create PROJECT_ID
將
PROJECT_ID替換為您要建立的 Google Cloud 專案名稱。 -
選取您建立的 Google Cloud 專案:
gcloud config set project PROJECT_ID
將
PROJECT_ID替換為 Google Cloud 專案名稱。
-
安裝 Google Cloud CLI。
-
若您採用的是外部識別資訊提供者 (IdP),請先 使用聯合身分登入 gcloud CLI。
-
執行下列指令,初始化 gcloud CLI:
gcloud init -
選取或建立專案所需的角色
- 選取專案:選取專案時,不需具備特定 IAM 角色,只要您已獲派某個專案的角色,即可選取該專案。
-
建立專案:如要建立專案,您必須具備專案建立者角色 (
roles/resourcemanager.projectCreator),其中包含resourcemanager.projects.create權限。瞭解如何授予角色。
-
建立 Google Cloud 專案:
gcloud projects create PROJECT_ID
將
PROJECT_ID替換為您要建立的 Google Cloud 專案名稱。 -
選取您建立的 Google Cloud 專案:
gcloud config set project PROJECT_ID
將
PROJECT_ID替換為 Google Cloud 專案名稱。
啟用 Cloud Run、Artifact Registry、Cloud Build 和 Cloud Storage API (如有尚未啟用的 API):
啟用 API 所需的角色
您必須具備
serviceusage.services.enable權限,才能啟用 API。如果您建立了專案,可能已透過「擁有者」角色 (roles/owner) 取得這項權限。否則,您可以透過「Service Usage 管理員」角色 (roles/serviceusage.serviceUsageAdmin) 取得這項權限。瞭解如何授予角色。gcloud services enable run.googleapis.com
cloudbuild.googleapis.com artifactregistry.googleapis.com storage.googleapis.com - 將區域設為環境變數:
export REGION=REGION
- 為工作建立服務帳戶:
gcloud iam service-accounts create gpu-job-sa
- 確認所選區域有 [足夠的 GPU 配額](/run/docs/configuring/jobs/gpu#request-quota) (例如 NVIDIA L4)。
準備應用程式
如要讓長時間執行的工作具有彈性,應用程式必須:
定期將進度儲存 (檢查點) 至永久位置,例如掛接的 Cloud Storage bucket。
SIGTERM之後,您有大約 10 秒的時間,工作就會終止。這段時間不足以寫入大型模型檢查點。請將SIGTERM處理常式視為僅盡力清除小型狀態,並以定期檢查點做為主要保護措施。請根據您能承受的工作損失量,選擇檢查點間隔,但請注意,檢查點越頻繁,代表未進行有用工作的時間越多。目標是根據您的用途,達到適當的平衡。啟動時從上一個檢查點還原狀態。
Cloud Run 會在維護程序開始前 10 秒傳送
SIGTERM信號,請監聽這個信號,並在結束前嘗試儲存最終檢查點。
以下範例說明如何實作這些功能。
建立應用程式程式碼
為專案建立目錄:
mkdir gc-run-gpu-resilience cd gc-run-gpu-resilience建立名為
task.py的檔案,並貼上以下指令碼,模擬支援檢查點和信號處理的訓練或批次處理程序:import os import sys import time import signal # The checkpoint directory will be mounted to this path CHECKPOINT_DIR = "/checkpoints" # Cloud Run sets these variables automatically JOB_NAME = os.environ.get("CLOUD_RUN_JOB", "local-job") TASK_INDEX = os.environ.get("CLOUD_RUN_TASK_INDEX", "0") CHECKPOINT_FILE = os.path.join( CHECKPOINT_DIR, f"{JOB_NAME}-task-{TASK_INDEX}-checkpoint.txt") TOTAL_STEPS = 100 current_step = 0 is_exiting = False def save_checkpoint(step): print(f"Saving checkpoint at step {step} to {CHECKPOINT_FILE}...") try: # Write to a temp file and rename to ensure atomicity temp_file = CHECKPOINT_FILE + ".tmp" with open(temp_file, "w") as f: f.write(str(step)) os.rename(temp_file, CHECKPOINT_FILE) print("Checkpoint saved successfully.") except Exception as e: print(f"Failed to save checkpoint: {e}") def load_checkpoint(): print(f"Looking for a checkpoint at {CHECKPOINT_FILE}...") global current_step if os.path.exists(CHECKPOINT_FILE): try: with open(CHECKPOINT_FILE, "r") as f: current_step = int(f.read().strip()) print(f"Resuming from checkpointed step {current_step}.") except Exception as e: print(f"Failed to load checkpoint: {e}. Starting from scratch.") else: print("No checkpoint found. Starting from scratch.") def sigterm_handler(signum, frame): global is_exiting print("Received SIGTERM signal from platform. Initiating graceful shutdown...") is_exiting = True # Register the signal handler for SIGTERM signal.signal(signal.SIGTERM, sigterm_handler) # Load existing checkpoint if any to resume work load_checkpoint() # Simulate work loop while current_step < TOTAL_STEPS and not is_exiting: print(f"Processing step {current_step}/{TOTAL_STEPS}...") # Simulate heavy GPU computation time.sleep(1) current_step += 1 # Periodically save checkpoint (e.g., every 5 steps) if current_step % 5 == 0: save_checkpoint(current_step) if is_exiting: # Save final state before exiting due to preemption # Best-effort only: with ~10s before SIGKILL this will not complete for # large state. Periodic checkpointing (above) is what actually protects # you. save_checkpoint(current_step) # Note that save_checkpoint already writes-then-renames for atomicity, # which is good, but the reason it matters here is that a truncated # checkpoint from an interrupted final save must not clobber the last # good one. print("Graceful shutdown complete. Exiting with error code to trigger retry.") # Exit with a non-zero code to signal to Cloud Run that the task # was interrupted and needs to be retried from the checkpoint. sys.exit(143) # Note that this statement deliberately consumes of the configured retry # attempts. print("Task completed successfully.") sys.exit(0)建立
Dockerfile,將應用程式容器化:
如需更詳細、實際的實作範例,請參閱這個範例。
建立 Cloud Storage bucket 來存放檢查點
建立 Cloud Storage bucket 來儲存檢查點檔案,並授予工作服務帳戶存取權限。
建立 bucket:
gcloud storage buckets create gs://gpu-checkpoints-PROJECT_ID \ --location REGION將 Storage 物件管理員角色授予工作的服務帳戶:
gcloud storage buckets add-iam-policy-binding gs://gpu-checkpoints-PROJECT_ID \ --member="serviceAccount:gpu-job-sa@PROJECT_ID.iam.gserviceaccount.com" \ --role="roles/storage.objectAdmin"
部署工作
將工作部署至 Cloud Run:
gcloud beta run jobs deploy gpu-resilient-job \
--source=. \
--region REGION \
--gpu 1 \
--gpu-type nvidia-l4 \
--no-gpu-zonal-redundancy \
--task-timeout 168h \
--max-retries 3 \
--service-account gpu-job-sa@PROJECT_ID.iam.gserviceaccount.com \
--add-volume=name=checkpoint-volume,type=cloud-storage,bucket=gpu-checkpoints-PROJECT_ID \
--add-volume-mount=volume=checkpoint-volume,mount-path=/checkpoints
請注意下列重要標記:
--task-timeout 168h:允許工作執行最多 12 小時。--max-retries 3:如果 GPU 工作的逾時時間超過 1 小時,建議將預設設定設為重試 3 次。為避免平台維護期間發生無訊息失敗,建議不要將重試次數設為 0。最後,建議您預留至少 1 次重試的預算,以因應維護相關失敗,並預留額外重試的預算,以因應 12 小時執行期間內的應用程式失敗。--add-volume和--add-volume-mount:將 Cloud Storage bucket 掛接至/checkpoints,讓應用程式在重試工作時能保留狀態。
執行及監控工作
執行工作:
gcloud run jobs execute gpu-resilient-job --region REGION這個指令會傳回類似以下的訊息:
Execution [gpu-resilient-job-abcde] has been successfully started. View details about this execution by running `gcloud run jobs executions describe gpu-resilient-job-abcde`. See logs for this execution at: https://console.cloud.google.com/logs/viewer?project=YOUR_PROJECT_ID&resource=cloud_run_job/job_name/my-job/location/my-region/execution_id/gpu-resilient-job-abcde字串
gpu-resilient-job-abcde是系統為這項特定執行嘗試自動生成的專屬 ID。您可以使用這個 ID 監控或取消這項特定執行作業。輸出內容也包含 Google Cloud 控制台中 Logs Explorer 頁面的直接連結,方便您查看工作任務的輸出內容或錯誤。監控記錄。如果發生維護事件,Cloud Run 會記錄警告。您會看到:
- 應用程式記錄:
Received SIGTERM signal from platform. Initiating graceful shutdown...,後面接著Saving checkpoint...。 - 系統記錄指出預先分配:
Container instance preemption initiated by the platform due to underlying hardware maintenance.,原因:INSTANCE_PREEMPTED。 - Cloud Run 會自動重新啟動工作。
- 重新啟動時的應用程式記錄:
Resuming from checkpointed step X.。
- 應用程式記錄:
清除所用資源
為避免系統向您的 Google Cloud 帳戶收取額外費用,請刪除您透過本快速入門導覽課程部署的所有資源。
刪除存放區
Cloud Run 只會依據工作執行時間收費。不過,您可能仍須支付在 Artifact Registry 儲存容器映像檔的費用。如要刪除 Artifact Registry 存放區,請按照 Artifact Registry 說明文件中的「刪除存放區」步驟操作。
刪除工作
Cloud Run 工作只有在執行工作任務時才會產生費用。如要刪除 Cloud Run 工作,請按照下列任一步驟操作:
控制台
如要刪除工作:
前往 Google Cloud 控制台的「Cloud Run」頁面:
在工作清單中找到要刪除的工作,然後勾選核取方塊。
按一下「Delete」(刪除)。這會終止所有執行中的工作和容器執行個體。
gcloud
如要刪除工作,請執行下列指令:
gcloud run jobs delete JOB_NAME
將 JOB_NAME 替換為工作名稱。
刪除測試專案
刪除 Google Cloud 專案後,系統會停止向該專案中的所有資源計費。如要釋出專案中的所有 Google Cloud 資源,請按照下列步驟操作:
刪除 Google Cloud 專案:
gcloud projects delete PROJECT_ID
刪除 Cloud Storage bucket:
gcloud storage buckets delete gs://gpu-checkpoints-PROJECT_ID
後續步驟
- 進一步瞭解工作重試和檢查點。
- 請參閱 GPU 效能最佳做法。