Menghosting runner GitHub dengan kumpulan pekerja Cloud Run

Tutorial ini memandu Anda menggunakan runner GitHub yang dihosting sendiri di kumpulan pekerja untuk mengeksekusi 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 fungsi Cloud Run 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 yang tidak terjadwal, bahkan menskalakan kumpulan ke nol saat tidak ada tugas.

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." \
      --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 menyediakan 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." \
      --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. \
      --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 dapat 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 penskala 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." \
      --role "roles/secretmanager.secretAccessor"
    

Men-deploy fungsi untuk menerima permintaan webhook

Untuk men-deploy fungsi untuk 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. \
      --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 di 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." \
      --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 tugas 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.