Mendesain tugas GPU yang berjalan lama dan tangguh

Tutorial ini menjelaskan cara mendesain dan men-deploy tugas Cloud Run yang tangguh dan didukung GPU yang berjalan hingga 12 jam.

Meskipun mendukung waktu tunggu tugas yang diperpanjang, Cloud Run tidak menawarkan SLA untuk eksekusi tanpa gangguan. Karena tugas yang mendukung GPU tidak dimigrasikan secara langsung, pemeliharaan mingguan rutin akan menghentikannya di tengah proses. Oleh karena itu, tugas yang diperpanjang diperkirakan akan terganggu setidaknya sekali. Untuk memastikan tugas Anda selesai dengan sukses tanpa membuang resource komputasi, rancang aplikasi Anda untuk melakukan checkpoint dan melanjutkan, bukan mengandalkan satu operasi yang tidak terputus.

Tutorial ini memandu Anda cara menerapkan checkpoint, menangani sinyal SIGTERM platform, dan mengonfigurasi percobaan ulang maksimum.

Tujuan

Dalam tutorial ini, Anda akan melakukan hal berikut:

  • Siapkan aplikasi Python yang menerapkan checkpoint dan menangani sinyal SIGTERM.
  • Membuat bucket Cloud Storage untuk mempertahankan checkpoint.
  • Bangun dan deploy tugas Cloud Run dengan GPU diaktifkan, waktu tunggu tugas 12 jam, dan kebijakan percobaan ulang yang dikonfigurasi.
  • Jalankan tugas dan pahami cara memantau peristiwa preemption di log.

Biaya

Dalam dokumen ini, Anda akan menggunakan komponen Google Cloudyang dapat ditagih berikut:

Untuk membuat perkiraan biaya berdasarkan proyeksi penggunaan Anda, gunakan kalkulator harga.

Pengguna Google Cloud baru mungkin memenuhi syarat untuk mendapatkan uji coba gratis.

Sebelum memulai

  1. Instal Google Cloud CLI.

  2. Konfigurasi gcloud CLI agar menggunakan identitas gabungan Anda.

    Untuk mengetahui informasi selengkapnya, lihat Login ke gcloud CLI dengan identitas gabungan Anda.

  3. Untuk melakukan inisialisasi gcloud CLI, jalankan perintah berikut:

    gcloud init
  4. Buat atau pilih project Google Cloud .

    Peran yang diperlukan untuk memilih atau membuat project

    • Memilih project: Memilih project tidak memerlukan peran IAM tertentu—Anda dapat memilih project apa pun yang perannya telah diberikan kepada Anda.
    • Membuat project: Untuk membuat project, Anda memerlukan peran Project Creator (roles/resourcemanager.projectCreator), yang berisi izin resourcemanager.projects.create. Pelajari cara memberikan peran.
    • Buat project Google Cloud :

      gcloud projects create PROJECT_ID

      Ganti PROJECT_ID dengan nama untuk Google Cloud project yang Anda buat.

    • Pilih project Google Cloud yang Anda buat:

      gcloud config set project PROJECT_ID

      Ganti PROJECT_ID dengan nama project Google Cloud Anda.

  5. Pastikan penagihan diaktifkan untuk project Google Cloud Anda.

  6. Aktifkan Cloud Run, Artifact Registry, Cloud Build, dan Cloud Storage API, jika belum diaktifkan:

    Peran yang diperlukan untuk mengaktifkan API

    Untuk mengaktifkan API, Anda memerlukan izin serviceusage.services.enable. Jika Anda membuat project, kemungkinan Anda sudah memiliki izin ini melalui peran Pemilik (roles/owner). Jika tidak, Anda bisa mendapatkan izin ini melalui peran Service Usage Admin (roles/serviceusage.serviceUsageAdmin). Pelajari cara memberikan peran.

    gcloud services enable run.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com storage.googleapis.com
  7. Tetapkan region Anda sebagai variabel lingkungan:
    export REGION=REGION
  8. Buat akun layanan untuk tugas:
    gcloud iam service-accounts create gpu-job-sa
  9. Pastikan Anda memiliki [kuota GPU yang cukup](/run/docs/configuring/jobs/gpu#request-quota) (misalnya, Nvidia L4) di region yang Anda pilih.

Menyiapkan aplikasi Anda

Agar tugas yang berjalan lama menjadi tangguh, aplikasi Anda harus:

  1. Simpan progres secara berkala (checkpointing) ke lokasi persisten, seperti bucket Cloud Storage yang terpasang.

    Anda memiliki waktu sekitar 10 detik setelah SIGTERM sebelum tugas dihentikan. Waktu ini tidak cukup untuk menulis checkpoint model yang besar. Perlakukan pengendali SIGTERM sebagai flush upaya terbaik untuk status kecil saja, dan andalkan checkpointing berkala sebagai perlindungan utama Anda. Pilih interval checkpoint berdasarkan seberapa banyak pekerjaan yang dapat Anda korbankan, dengan mengingat bahwa checkpoint yang lebih sering berarti lebih banyak waktu yang tidak dihabiskan untuk melakukan pekerjaan yang berguna. Tujuannya adalah untuk mencapai keseimbangan yang tepat untuk kasus penggunaan Anda.

  2. Pulihkan status dari checkpoint terakhir saat memulai.

  3. Dengarkan sinyal SIGTERM, yang dikirim Cloud Run 10 detik sebelum proses pemeliharaan, dan coba simpan checkpoint akhir sebelum keluar.

Contoh berikut menunjukkan cara menerapkan fitur ini.

Membuat kode aplikasi

  1. Buat direktori untuk project Anda:

    mkdir gc-run-gpu-resilience
    cd gc-run-gpu-resilience
    
  2. Buat file bernama task.py, dan tempelkan skrip berikut untuk menyimulasikan proses pelatihan atau batch processing yang mendukung checkpoint dan penanganan sinyal:

    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)
    
  3. Buat Dockerfile untuk memasukkan aplikasi ke dalam container:

Lihat contoh ini untuk mengetahui penerapan yang lebih mendetail dan realistis.

Membuat bucket Cloud Storage untuk checkpoint

Buat bucket Cloud Storage untuk menyimpan file checkpoint, dan beri izin akun layanan tugas Anda untuk mengaksesnya.

  1. Buat bucket:

    gcloud storage buckets create gs://gpu-checkpoints-PROJECT_ID \
        --location REGION
    
  2. Berikan peran Storage Object Admin ke akun layanan tugas:

    gcloud storage buckets add-iam-policy-binding gs://gpu-checkpoints-PROJECT_ID \
        --member="serviceAccount:gpu-job-sa@PROJECT_ID." \
        --role="roles/storage.objectAdmin"
    

Men-deploy tugas

Men-deploy tugas ke 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. \
    --add-volume=name=checkpoint-volume,type=cloud-storage,bucket=gpu-checkpoints-PROJECT_ID \
    --add-volume-mount=volume=checkpoint-volume,mount-path=/checkpoints

Perhatikan flag penting berikut:

  • --task-timeout 168h: Memungkinkan tugas berjalan hingga 12 jam.
  • --max-retries 3: Untuk tugas GPU dengan waktu tunggu lebih dari 1 jam, sebaiknya tetapkan konfigurasi default 3 percobaan ulang. Untuk mencegah kegagalan senyap selama pemeliharaan platform, sebaiknya jangan menetapkan 0 percobaan ulang. Terakhir, sebaiknya anggarkan setidaknya 1 percobaan ulang untuk kegagalan terkait pemeliharaan serta percobaan ulang tambahan untuk kegagalan aplikasi selama periode eksekusi 12 jam.
  • --add-volume dan --add-volume-mount: Memasang bucket Cloud Storage ke /checkpoints sehingga aplikasi dapat mempertahankan status di seluruh percobaan ulang tugas.

Menjalankan dan memantau tugas

  1. Jalankan tugas:

    gcloud run jobs execute gpu-resilient-job --region REGION
    

    Perintah ini menampilkan pesan yang mirip dengan berikut ini:

    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
    

    String gpu-resilient-job-abcde adalah ID unik yang dibuat otomatis untuk upaya eksekusi spesifik ini. Anda dapat menggunakannya untuk memantau atau membatalkan operasi tertentu ini. Output juga menyertakan link langsung ke halaman Logs Explorer di konsol Google Cloud untuk melihat output atau error dari tugas Anda.

  2. Pantau log. Jika terjadi peristiwa pemeliharaan, Cloud Run akan mencatat peringatan ke dalam log. Anda akan melihat:

    • Log aplikasi Anda: Received SIGTERM signal from platform. Initiating graceful shutdown... diikuti dengan Saving checkpoint....
    • Log sistem yang menunjukkan preemption: Container instance preemption initiated by the platform due to underlying hardware maintenance. dengan alasan INSTANCE_PREEMPTED.
    • Cloud Run akan otomatis memulai ulang tugas.
    • Log aplikasi Anda setelah dimulai ulang: Resuming from checkpointed step X..

Pembersihan

Agar akun Google Cloud Anda tidak dikenai biaya tambahan, hapus semua resource yang Anda deploy dengan panduan memulai ini.

Menghapus repositori Anda

Cloud Run hanya mengenakan biaya untuk waktu eksekusi tugas Anda. Namun, Anda mungkin tetap dikenai biaya atas penyimpanan image container di Artifact Registry. Untuk menghapus repositori Artifact Registry, ikuti langkah-langkah di bagian Menghapus repositori dalam dokumentasi Artifact Registry.

Menghapus tugas Anda

Tugas Cloud Run hanya dikenai biaya saat tugas dijalankan. Untuk menghapus tugas Cloud Run, ikuti salah satu langkah berikut:

Konsol

Untuk menghapus tugas:

  1. Di konsol Google Cloud , buka Cloud Run:

    Buka Cloud Run

  2. Temukan tugas yang ingin Anda hapus dalam daftar tugas, lalu klik kotak centang tugas tersebut untuk memilihnya.

  3. Klik Hapus. Tindakan ini akan menghentikan semua eksekusi tugas yang sedang berlangsung dan semua instance container yang sedang berjalan.

gcloud

Untuk menghapus tugas, jalankan perintah berikut:

gcloud run jobs delete JOB_NAME

Ganti JOB_NAME dengan nama tugas.

Menghapus project pengujian Anda

Menghapus project Google Cloud Anda akan menghentikan penagihan untuk semua resource dalam project tersebut. Untuk merilis semua resource Google Cloud dalam project Anda, ikuti langkah-langkah berikut:

    Menghapus project Google Cloud :

    gcloud projects delete PROJECT_ID

Hapus bucket Cloud Storage:

gcloud storage buckets delete gs://gpu-checkpoints-PROJECT_ID

Langkah berikutnya