Menghosting runner GitHub dengan kumpulan pekerja Cloud Run

Tutorial ini memandu Anda menggunakan runner GitHub yang dihosting sendiri di kumpulan pekerja untuk menjalankan alur kerja yang ditentukan di repositori GitHub Anda.

Anda akan men-deploy kumpulan pekerja Cloud Run untuk menangani beban kerja ini, dan secara opsional men-deploy Cloud Run Function untuk mendukung penskalaan kumpulan pekerja.

Tentang runner GitHub yang dihosting sendiri

Dalam alur kerja GitHub Actions, runner adalah mesin yang menjalankan tugas. Misalnya, pelari dapat meng-clone repositori Anda secara lokal, menginstal software pengujian, lalu menjalankan perintah yang mengevaluasi kode Anda.

Anda dapat menggunakan runner yang dihosting sendiri untuk menjalankan GitHub Actions di instance kumpulan pekerja Cloud Run. Tutorial ini menunjukkan cara menskalakan kumpulan pelari secara otomatis berdasarkan jumlah tugas yang sedang berjalan dan tidak terjadwal, bahkan menskalakan kumpulan ke nol saat tidak ada tugas.

Tujuan

Dalam tutorial ini, Anda akan:

  • Deploy kumpulan pekerja Cloud Run ke Cloud Run.
  • Deploy fungsi Cloud Run untuk mendukung penskalaan kumpulan pekerja.
  • Buat secret Secret Manager untuk menyimpan token dan secret dengan aman.
  • Deploy runner GitHub yang dihosting sendiri untuk mendukung repositori GitHub.

Biaya

Di 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. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  5. Verify that billing is enabled for your Google Cloud project.

  6. Enable the Cloud Run, Secret Manager, Artifact Registry, and Cloud Build APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  7. Peran yang diperlukan

    Untuk mendapatkan izin yang Anda perlukan untuk menyelesaikan tutorial, minta administrator Anda untuk memberi Anda peran IAM berikut di project Anda:

    Untuk mengetahui informasi selengkapnya tentang pemberian peran, lihat Mengelola akses ke project, folder, dan organisasi.

    Anda mungkin juga bisa mendapatkan izin yang diperlukan melalui peran khusus atau peran bawaan lainnya.

    Anda memerlukan izin untuk mengedit setelan di repositori GitHub guna mengonfigurasi runner yang dihosting sendiri. Repositori dapat dimiliki pengguna, atau repositori yang dimiliki organisasi.

Mengambil contoh kode

Untuk mengambil contoh kode agar dapat digunakan:

  1. Clone repositori contoh ke komputer lokal Anda:

    git clone https://github.com/GoogleCloudPlatform/cloud-run-samples
    
  2. Ubah ke direktori yang memuat kode contoh Cloud Run:

    cd cloud-run-samples/github-runner
    

Memahami kode inti

Contoh ini diimplementasikan sebagai kumpulan worker dan penskala otomatis, yang dijelaskan berikutnya.

Kumpulan pekerja

Kumpulan pekerja dikonfigurasi dengan Dockerfile yang didasarkan pada image actions/runner yang dibuat GitHub.

Semua logika terkandung dalam gambar ini, terlepas dari skrip helper kecil.

FROM ghcr.io/actions/actions-runner:2.329.0

# Add scripts with right permissions.
USER root
# hadolint ignore=DL3045
COPY start.sh start.sh
RUN chmod +x start.sh

# Add start entrypoint with right permissions.
USER runner
ENTRYPOINT ["./start.sh"]

Skrip helper ini berjalan saat container dimulai, mendaftarkan dirinya ke repositori yang dikonfigurasi sebagai instance sementara, menggunakan token yang akan Anda buat. Skrip juga menentukan tindakan yang harus dilakukan saat container di-scale down.

# Configure the current runner instance with URL, token and name.
mkdir /home/docker/actions-runner && cd /home/docker/actions-runner
echo "GitHub Repo: ${GITHUB_REPO_URL} for ${RUNNER_PREFIX}-${RUNNER_SUFFIX}"
./config.sh --unattended --url ${GITHUB_REPO_URL} --pat ${GH_TOKEN} --name ${RUNNER_NAME}

# Function to cleanup and remove runner from Github.
cleanup() {
   echo "Removing runner..."
   ./config.sh remove --unattended --pat ${GH_TOKEN}
}

# Trap signals.
trap 'cleanup; exit 130' INT
trap 'cleanup; exit 143' TERM

# Run the runner.
./run.sh & wait $!

Autoscaler

Autoscaler adalah fungsi yang meningkatkan skala kumpulan pekerja saat ada tugas baru dalam antrean, atau menurunkan skala saat tugas selesai. Proses ini menggunakan Cloud Run API untuk memeriksa jumlah pekerja saat ini dalam kumpulan, dan menyesuaikan nilai tersebut sesuai kebutuhan.

try:
    current_instance_count = get_current_worker_pool_instance_count()
except ValueError as e:
    return f"Could not retrieve instance count: {e}", 500

# Scale Up: If a job is queued and we have available capacity
if action == "queued" and job_status == "queued":
    print(f"Job '{job_name}' is queued.")

    if current_instance_count < MAX_RUNNERS:
        new_instance_count = current_instance_count + 1
        try:
            update_runner_instance_count(new_instance_count)
            print(f"Successfully scaled up to {new_instance_count} instances.")
        except ValueError as e:
            return f"Error scaling up instances: {e}", 500
    else:
        print(f"Max runners ({MAX_RUNNERS}) reached.")

# Scale Down: If a job is completed, check to see if there are any more pending
# or in progress jobs and scale accordingly.
elif action == "completed" and job_status == "completed":
    print(f"Job '{job_name}' completed.")

    current_queued_actions, current_running_actions = get_current_actions()
    current_actions = current_queued_actions + current_running_actions

    if current_queued_actions >= 1:
        print(
            f"GitHub says {current_queued_actions} are still pending."
            f"Won't change scaling ({current_instance_count})."
        )
    elif current_queued_actions == 0 and current_running_actions >= 1:
        print(
            f"GitHub says no queued actions, but {current_running_actions} running actions."
            f"Won't change scaling ({current_instance_count})."
        )
    elif current_actions == 0:
        print(f"GitHub says no pending actions. Scaling to zero.")
        update_runner_instance_count(0)
        print(f"Successfully scaled down to zero.")
    else:
        print(
            f"Detected an unhandled state: {current_queued_actions=}, {current_running_actions=}"
        )
else:
    print(
        f"Workflow job event for '{job_name}' with action '{action}' and "
        f"status '{job_status}' did not trigger a scaling action."
    )

Mengonfigurasi IAM

Tutorial ini menggunakan akun layanan kustom dengan izin minimum yang diperlukan untuk menggunakan resource yang disediakan. Untuk menyiapkan akun layanan, lakukan hal berikut:

  1. Tetapkan project ID Anda di gcloud:

    gcloud config set project PROJECT_ID
    

    Ganti PROJECT_ID dengan project ID Anda.

  2. Buat akun layanan Identity and Access Management baru:

    gcloud iam service-accounts create gh-runners
    

  3. Beri akun layanan izin untuk bertindak sebagai akun layanan di project Anda:

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member "serviceAccount:gh-runners@PROJECT_ID.iam.gserviceaccount.com" \
      --role=roles/iam.serviceAccountUser
    

    Ganti PROJECT_ID dengan project ID Anda.

Mengambil informasi GitHub

Dokumentasi GitHub untuk menambahkan runner yang dihosting sendiri menyarankan untuk menambahkan runner melalui situs GitHub, yang kemudian memberikan token tertentu untuk digunakan dalam autentikasi.

Tutorial ini akan menambahkan dan menghapus pelari secara dinamis, dan memerlukan token GitHub statis untuk melakukannya.

Untuk menyelesaikan tutorial ini, Anda perlu membuat token GitHub dengan akses untuk berinteraksi dengan repositori yang Anda pilih.

Mengidentifikasi repositori GitHub

Dalam tutorial ini, variabel GITHUB_REPO mewakili nama repositori. Ini adalah bagian dari nama repositori GitHub yang setelah nama domain, baik untuk repositori pengguna pribadi maupun repositori organisasi.

Anda akan mereferensikan nama repositori yang muncul setelah nama domain untuk repositori milik pengguna dan milik organisasi.

Dalam tutorial ini:

  • Untuk https://github.com/myuser/myrepo, GITHUB_REPO adalah myuser/myrepo.
  • Untuk https://github.com/mycompany/ourrepo, GITHUB_REPO adalah mycompany/ourrepo.

Buat token akses

Anda harus membuat token akses di GitHub, dan menyimpannya dengan aman di Secret Manager:

  1. Pastikan Anda login ke akun GitHub Anda.
  2. Buka halaman Settings > Developer Settings > Personal Access Tokens di GitHub.
  3. Klik Buat token baru, lalu pilih Buat token baru (klasik).
  4. Buat token baru dengan cakupan "repo".
  5. Klik Generate Token.
  6. Salin token yang dihasilkan.

Buat nilai secret

Ambil token rahasia yang baru saja Anda buat, lalu simpan di Secret Manager, dan tetapkan izin akses.

  1. Buat secret di Secret Manager:

    echo -n "GITHUB_TOKEN" | gcloud secrets create github_runner_token --data-file=-
    

    Ganti GITHUB_TOKEN dengan nilai yang Anda salin dari GitHub.

  2. Berikan akses ke rahasia yang baru dibuat:

    gcloud secrets add-iam-policy-binding github_runner_token \
      --member "serviceAccount:gh-runners@PROJECT_ID.iam.gserviceaccount.com" \
      --role "roles/secretmanager.secretAccessor"
    

Men-deploy Kumpulan Pekerja

Buat kumpulan pekerja Cloud Run untuk memproses tindakan GitHub. Pool ini akan menggunakan image berdasarkan image actions/runner yang dibuat GitHub.

Menyiapkan kumpulan pekerja Cloud Run

  1. Buka kode contoh untuk kumpulan pekerja:

    cd worker-pool-container
    
  2. Deploy kumpulan pekerja:

    gcloud beta run worker-pools deploy WORKER_POOL_NAME \
      --region WORKER_POOL_LOCATION \
      --source . \
      --scaling 1 \
      --set-env-vars GITHUB_REPO=GITHUB_REPO \
      --set-secrets GITHUB_TOKEN=github_runner_token:latest \
      --service-account gh-runners@PROJECT_ID.iam.gserviceaccount.com \
      --memory 2Gi \
      --cpu 4
    

    Ganti kode berikut:

    Jika ini pertama kalinya Anda menggunakan deployment sumber Cloud Run di project ini, Anda akan diminta untuk membuat repositori Artifact Registry default.

Menggunakan kumpulan pekerja

Sekarang Anda memiliki satu instance di kumpulan pekerja, yang siap menerima tugas dari GitHub Actions.

Untuk memverifikasi bahwa Anda telah menyelesaikan penyiapan runner yang dihosting sendiri, panggil tindakan GitHub di repositori Anda.

Agar tindakan Anda menggunakan runner yang dihosting sendiri, Anda perlu mengubah job tindakan GitHub. Dalam tugas, ubah nilai runs-on menjadi self-hosted.

Jika repo Anda belum memiliki tindakan apa pun, Anda dapat mengikuti Mulai Cepat untuk GitHub Actions.

Setelah Anda mengonfigurasi tindakan untuk menggunakan runner yang dihosting sendiri, jalankan tindakan tersebut.

Konfirmasi bahwa tindakan berhasil diselesaikan di antarmuka GitHub.

Men-deploy Penskala Otomatis GitHub Runner

Anda men-deploy satu pekerja di pool asli, yang akan memungkinkan pemrosesan satu tindakan dalam satu waktu. Bergantung pada penggunaan CI, Anda mungkin perlu menskalakan pool untuk menangani lonjakan pekerjaan yang harus dilakukan.

Setelah men-deploy kumpulan pekerja dengan runner GitHub yang aktif, konfigurasi penskalaan otomatis untuk menyediakan instance pekerja berdasarkan status tugas dalam antrean tindakan.

Implementasi ini memproses peristiwa workflow_job. Saat tugas alur kerja dibuat, tugas tersebut akan menskalakan pool pekerja, dan setelah tugas selesai, tugas tersebut akan menskalakannya kembali. Penskalaan tidak akan melampaui jumlah maksimum instance yang dikonfigurasi, dan akan diskalakan ke nol saat semua tugas yang sedang berjalan telah selesai.

Anda dapat menyesuaikan autoscaler ini berdasarkan workload Anda.

Buat nilai rahasia webhook

Untuk membuat nilai rahasia untuk webhook, lakukan hal berikut:

  1. Buat secret Secret Manager yang berisi nilai string arbitrer.

    echo -n "WEBHOOK_SECRET" | gcloud secrets create github_webhook_secret --data-file=-
    

    Ganti WEBHOOK_SECRET dengan nilai string arbitrer.

  2. Berikan akses ke secret untuk akun layanan penskala otomatis:

    gcloud secrets add-iam-policy-binding github_webhook_secret \
      --member "serviceAccount:gh-runners@PROJECT_ID.iam.gserviceaccount.com" \
      --role "roles/secretmanager.secretAccessor"
    

Men-deploy fungsi untuk menerima permintaan webhook

Untuk men-deploy fungsi guna menerima permintaan webhook, lakukan hal berikut:

  1. Buka kode contoh untuk webhook:

    cd ../autoscaler
    
  2. Deploy fungsi Cloud Run:

    gcloud run deploy github-runner-autoscaler \
      --function github_webhook_handler \
      --region WORKER_POOL_LOCATION \
      --source . \
      --set-env-vars GITHUB_REPO=GITHUB_REPO \
      --set-env-vars WORKER_POOL_NAME=WORKER_POOL_NAME \
      --set-env-vars WORKER_POOL_LOCATION=WORKER_POOL_LOCATION \
      --set-env-vars MAX_RUNNERS=5 \
      --set-secrets GITHUB_TOKEN=github_runner_token:latest \
      --set-secrets WEBHOOK_SECRET=github_webhook_secret:latest \
      --service-account gh-runners@PROJECT_ID.iam.gserviceaccount.com \
      --allow-unauthenticated
    

    Ganti kode berikut:

    • GITHUB_REPO bagian nama repositori GitHub Anda setelah nama domain
    • WORKER_POOL_NAME nama kumpulan pekerja
    • WORKER_POOL_LOCATION region kumpulan pekerja
    • REPOSITORY_NAME nama repositori GitHub
  3. Catat URL tempat layanan Anda di-deploy. Anda akan menggunakan nilai ini pada langkah selanjutnya.

  4. Beri akun layanan izin untuk mengupdate kumpulan pekerja Anda:

    gcloud alpha run worker-pools add-iam-policy-binding WORKER_POOL_NAME \
      --member "serviceAccount:gh-runners@PROJECT_ID.iam.gserviceaccount.com" \
      --role=roles/run.developer
    

    Ganti PROJECT_ID dengan project ID Anda.

Membuat webhook GitHub

Untuk membuat webhook GitHub, ikuti langkah-langkah berikut:

  1. Pastikan Anda login ke akun GitHub Anda.
  2. Buka repositori GitHub Anda.
  3. Klik Setelan.
  4. Di bagian "Kode dan otomatisasi", klik Webhook.
  5. Klik Tambahkan webhook.
  6. Masukkan:

    1. Di Payload URL, masukkan URL fungsi Cloud Run yang Anda deploy sebelumnya.

      URL akan terlihat seperti: https://github-runner-autoscaler-PROJECTNUM.REGION.run.app, dengan PROJECTNUM adalah ID numerik unik project Anda, dan REGION adalah region tempat Anda men-deploy layanan.

    2. Untuk Jenis konten, pilih application/json.

    3. Untuk Secret, masukkan nilai WEBHOOK_SECRET yang Anda buat sebelumnya.

    4. Untuk SSL verification, pilih Enable SSL verification.

    5. Untuk "Peristiwa mana yang ingin Anda gunakan untuk memicu webhook ini?", pilih Izinkan saya memilih peristiwa satu per satu.

    6. Di pilihan acara, pilih Tugas alur kerja. Batalkan pilihan opsi lainnya.

    7. Klik Tambahkan webhook.

Menurunkan skala kumpulan pekerja

Webhook kini sudah tersedia, jadi Anda tidak perlu memiliki pekerja persisten di kumpulan. Hal ini juga akan memastikan Anda tidak memiliki pekerja yang sedang berjalan saat tidak ada pekerjaan yang harus dilakukan, sehingga mengurangi biaya.

  • Sesuaikan pool Anda agar diskalakan ke nol:

    gcloud beta run worker-pools update WORKER_POOL_NAME \
      --region WORKER_POOL_LOCATION \
      --scaling 0
    

Menggunakan pelari penskalaan otomatis

Untuk memverifikasi bahwa pelari penskalaan otomatis Anda berfungsi dengan benar, jalankan tindakan yang sebelumnya Anda konfigurasi ke runs-on: self-hosted.

Anda dapat melacak progres GitHub Actions di tab "Actions" repositori Anda.

Anda dapat memeriksa eksekusi fungsi webhook dan kumpulan pekerja dengan memeriksa tab Logs dari fungsi Cloud Run dan kumpulan pekerja Cloud Run.

Pembersihan

Agar tidak menimbulkan biaya tambahan pada akun Google Cloud Anda, hapus semua resource yang Anda deploy dengan tutorial ini.

Menghapus project

Jika Anda membuat project baru untuk tutorial ini, hapus project tersebut. Jika Anda menggunakan project yang ada dan perlu mempertahankannya tanpa perubahan yang Anda tambahkan dalam tutorial ini, hapus resource yang Anda buat untuk tutorial.

Cara termudah untuk menghilangkan penagihan adalah dengan menghapus project yang Anda buat untuk tutorial.

Untuk menghapus project:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Menghapus resource tutorial

  1. Hapus layanan Cloud Run yang Anda deploy dalam tutorial ini. Layanan Cloud Run tidak menimbulkan biaya hingga menerima permintaan.

    Untuk menghapus layanan Cloud Run, jalankan perintah berikut:

    gcloud run services delete SERVICE-NAME

    Ganti SERVICE-NAME dengan nama layanan Anda.

    Anda juga dapat menghapus layanan Cloud Run dari Google Cloud console.

  2. Hapus konfigurasi region default gcloud yang Anda tambahkan selama penyiapan tutorial:

     gcloud config unset run/region
    
  3. Hapus konfigurasi project:

     gcloud config unset project
    
  4. Hapus resource Google Cloud lain yang dibuat dalam tutorial ini:

Langkah berikutnya