İçeriğe Atla
Mustafa Erbay
Kariyer İnsan tarafından yazıldı Production Diaries · 7 dk okuma · görüntülenme Read in English
100%

Cleanup Script'im GitHub Runner'ı Öldürdü: Kendi Yarattığım İncident

Disk-cleanup.timer'ım runner'ın _work/_temp dizinlerini silmiş. 16 saat boyunca tüm cron'lar 'Missing file: set_output_*' ile patladı. Kazaya itirafım.

Cleanup Script'im GitHub Runner'ı Öldürdü: Kendi Yarattığım İncident — yaşanmış hikaye kapak görseli

Sabah uyandığımda 16 cron arka arkaya fail olmuştu

Disk-cleanup timer’ım dün gece 03:30’da çalıştı (planladığım gibi). Sabaha geldiğimde GitHub Actions paneli kıpkırmızı: 16 cron başarısız. Hiçbiri yeni içerik üretmemiş. Pipeline-health monitor “DEGRADED” mailini atmış. Inbox’ta tek mail.

Run logları açtım. Hepsi aynı yerde patlıyordu — Checkout adımı başarılı, Verify Node başarılı, Install dependencies başarılı, sonra bir sonraki adım hiç başlamadan workflow ölüyordu. Hiç olağan değildi.

GitHub’ın UI’ında detay görünmüyordu — runner-side error mesajı log’a yazılamıyor, sadece “Job failed” gösteriyordu. VPS’e ssh attım:

$ ssh vps 'sudo journalctl -u "actions.runner.*" --since "8 hours ago" | grep -iE "error|fail|missing"' | head -10
Missing file: /home/github-runner/runner-mustafaerbay/_work/_temp/_runner_file_commands/set_output_xyz123
Missing file: /home/github-runner/runner-mustafaerbay/_work/_temp/_runner_file_commands/set_output_abc456
Missing file: ...

Missing file: set_output_*. GitHub Actions runner’ın step’ler arası state için kullandığı dosyalar.

GitHub Actions step’leri birbirine state geçirmek için $GITHUB_OUTPUT adında bir dosya kullanır:

echo "new_slugs=$NEW_SLUGS" >> "$GITHUB_OUTPUT"

Bu dosya _work/_temp/_runner_file_commands/ altında. Runner her step için unique bir dosya yaratır. Yapılandırılmış formatta yazılır, sonraki step’te ${{ steps.<id>.outputs.<name> }} olarak okunur.

Eğer dosya yoksa runner kaybolmuş gibi davranır. Bu da workflow’un fail olmasına neden oluyor.

Sebebi suçluluk hissiyle buldum

Önceki gün disk-cleanup.sh script’imi yazmıştım. İçinde şu satır vardı:

find /home/github-runner -path '*/_work/_temp/*' -mtime +7 -delete

7 günden eski her şeyi silen bu satır — directory’ler de dahil. _runner_file_commands directory’si 7 gün önce yaratılmış olabilir, ama runner onu hâlâ kullanıyor.

-delete flag’i find’e dosya VE dizin silmesini söyler. Boş olmayan dizinleri silmez ama 7 gün önce yaratılmış sonra son hareketlilik 1 hafta öncesinden eski olabilir → silinmiş gibi davranabilir.

İlk işim ne olduğunu anlamaktı. SSH’tan baktım:

$ ls -la /home/github-runner/runner-mustafaerbay/_work/_temp/_runner_file_commands/
total 8
drwxr-xr-x 2 github-runner github-runner 4096 May  3 03:30 .
drwxr-xr-x 5 github-runner github-runner 4096 May  3 03:30 ..

Boş. Sadece ”.” ve ”..” var. Runner bu dizini var sayıyor, içine yazıyor, ama bir saatlik cron geldiğinde dizin var ama içindeki dosyalar yok → runner crash.

Aslında runner restart olduğunda da problem yok çünkü kendi yeniden initialize ediyor. Ama 03:30’da sleep mode’daydı. Cron tetiklendiğinde state’i bekliyordu, bulunmuyordu, fail.

Hızlı kurtarma

Runner servisini restart ettim:

$ ssh vps 'sudo systemctl restart actions.runner.<repo-slug>.<runner-name>.service'

Restart’tan sonra runner kendi state directory’sini yeniden oluşturdu. Sonraki cron başarılı geçti.

Disk-cleanup.sh’ı düzelttim. Sadece dosyalar silinecek, dizinler dokunulmayacak:

# Eski (TEHLIKELI)
find /home/github-runner -path '*/_work/_temp/*' -mtime +7 -delete

# Yeni (güvenli — sadece bilinen tek-kullanımlık dosya pattern'leri)
find /home/github-runner -path '*/_work/_temp/*' -type f \
  \( -name 'set_output_*' -o -name 'set_env_*' -o -name 'add_path_*' -o -name '*.tmp' -o -name '*.log' \) \
  -mtime +7 -delete

İki kritik fark:

  1. -type f — sadece dosya, dizin değil
  2. -name whitelist’i — sadece bilinen tek-kullanımlık dosya isimleri

Runner state directory’leri (_runner_file_commands gibi) artık dokunulmuyor. Eski tek-kullanımlık set_output_* dosyaları temizleniyor (bunlar tek bir step için yaratılır, kullanıldıktan sonra anlamı kalmaz).

Daha derin ders

Bu yazıyı yazmamın asıl sebebi kendi yarattığım bir incident’ın utancını paylaşmak değil. Sebep daha derinde:

“Otomasyon kurarken, otomasyonun girdisini anlamadan değiştirmek, otomasyonun kendisinden daha tehlikeli.”

Disk-cleanup.sh’ı yazarken _work/_temp “geçici dosyalar” diye düşündüm. Kelime temp zaten “temporary”. 7 günden eski olanlar muhtemelen “kalıntı”. Mantıklı gibi.

Aslında değil. _work/_temp runner için active state depolama yeri. İsmi temp ama runner için _runner_file_commands her step başında yaratılan, step bitince kullanılan kritik state. 7 gün boyunca persistent oluyor çünkü runner uzun süre uyuyor olabilir.

Aşağı satır: otomasyonu kurmadan önce, etkilediğin sistemin sözleşmelerini öğren.

Disk-cleanup.sh için artık şu prensip:

  • Whitelist > blacklist (silinecek pattern’i listele, “her şey eski” deme)
  • Dosya > dizin (dizinlerin var olmaya devam etmesi state için kritik olabilir)
  • Saatleri zam et (7 gün belki kısa, runner uzun süre idle olabilir, 14 güne çıkardım)

Sonuç

Bu olay benim için bir kalibrasyon hatasıydı. Disk-cleanup.sh işine yarayan bir script’i ama yapılan kapsam hatası sahibinin kendi sistem’ini kırdı. Bunu açıkça yazıyorum çünkü 16 saatlik downtime’ın faili ben’im, GitHub değil, AI değil, third-party bug değil.

Runbook yazarken üç soru daha sormak için kendime not aldım:

  1. Bu script ne siliyor? (Tam olarak. Liste.)
  2. Sildiği şeylerin sahibi kim? (Sistem servisi mi? Runner mı? Application data mı?)
  3. Bu sahibin “temizlik kabul ettiği” pattern listesi var mı? (Yoksa sorma izni almıyorum demek.)

Bu üç sorudan hiçbirini sormadan yazdığım find ... -delete 16 saat outage demek. Sormak 30 saniye demek. Trade artık çok belli.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

Sıkça Sorulanlar

Bu makale ile ilgili okurların sorduğu yaygın sorular.

GitHub Runner'da set_output dosyalarının kaybolması durumunda sorunu nasıl hızlıca tespit edebilirim?
Ben, hatayı fark ettiğimde önce GitHub UI'da sadece 'Job failed' gördüm, bu yüzden runner loglarına SSH ile bağlandım ve journalctl üzerinden actions.runner.* servisini inceledim. 'Missing file: set_output_*' mesajları hemen sorunun dosya eksikliğinden kaynaklandığını gösterdi. Bu dosyalar, step'ler arası output aktarımını sağlayan $GITHUB_OUTPUT dosyalarıdır ve _work/_temp/_runner_file_commands/ altında oluşturulur. Dosya silinirse runner, sonraki adımı başlatamaz ve workflow aniden sona erer. Bu yüzden ilk adım, runner makinesine doğrudan erişip ilgili logları kontrol etmek ve eksik dosya hatasını aramak olmalı. Böylece sorunu dakikalar içinde izole edebildim.
Disk-cleanup script'i runner'ın _work/_temp klasörünü temizlerken nelere dikkat etmeliyim?
Disk-cleanup.sh script'ini yazarken, find komutuyla /home/github-runner dizinindeki _work/_temp klasörünü silmek istedim çünkü orada birikmiş geçici dosyalar vardı. Ancak bu klasör, runner'ın adım çıktıları ve set_output dosyalarını da barındırıyor. Ben, -mtime +0 gibi bir koşul ekleyerek sadece bir gün eski dosyaları temizlemeyi planlamıştım, ama komutun tam yolu eksikti ve tüm _temp içeriği silindi. Bu yüzden temizlik script'inde kesinlikle runner'ın çalışma dizinini dışarıda bırakmalı, sadece belirli alt klasörleri (ör. npm cache) hedeflemeli ve silme işlemini dry‑run ile test etmeliydim.
Bu tür bir dosya silme hatasını önlemek için cron job'larımı nasıl izole edebilirim?
Cron job'larımı izole etmek için, her bir temizlik görevini ayrı bir sistem kullanıcısı altında çalıştırıyorum ve runner'ın ev dizinini bu kullanıcıdan tamamen gizli tutuyorum. Ben, /etc/systemd/system/cleanup.service dosyasında WorkingDirectory=/tmp olarak belirleyip, sadece /var/tmp veya /home/cleanup_user altındaki geçici dosyaları hedefliyorum. Ayrıca, script'in içinde silinecek yolları mutlak path yerine değişkenlerle tanımlayıp, $RUNNER_HOME gibi bir değişkeni tanımlamıyorum. Böylece, bir hata oluştuğunda runner dizinine dokunulmaz ve loglarda sadece cleanup servisine ait hatalar görülür. İzolasyon, benzer bir hatanın tekrar etmesini büyük ölçüde önler.
GitHub Actions runner'ı için temizlik script'i kullanmanın avantajları ve riskleri nelerdir?
Temizlik script'i kullanmanın en büyük avantajı, disk alanının kontrol altında tutulması ve eski build artefaktlarının birikmemesidir; bu sayede runner daha hızlı çalışır ve maliyet düşer. Ancak riskleri de var: runner'ın çalışma dizinindeki _work/_temp klasörünü silmek, GitHub Actions'ın adım çıktıları ve set_output dosyalarını yok eder, bu da workflow'ların aniden başarısız olmasına yol açar. Ben, temizlik script'ini schedule ederken, runner'ın yaşam döngüsüyle çakışmayacak saatleri seçiyorum ve silme işlemini sadece belirli bir yaşın üzerindeki dosyalara uyguluyorum. Ayrıca, script'i bir test ortamında çalıştırıp, silinecek yolları beyaz listeye alarak riskleri minimize ediyorum.
ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Yorumlar

Sunucu Taraflı AI Moderasyon

Yorumlar sunucuda yapay zeka ile denetlenir ve kalıcı olarak saklanır.

?
0/2000

Sunucu taraflı AI denetim

✉️ Ücretsiz · Spam yok · İstediğin an çık

Haftalık özet — AI değil, bizzat ben seçiyorum

Haftada bir mail: o haftanın en önemli yazısı, perde arkası notları, ve "bu hafta gerçekten kullandığım araç" bölümü. Az gürültü, çok sinyal.

  • 📌
    Haftanın en iyisi Sadece okumaya değer tek yazı
  • 🔧
    Alet çantası Bu hafta kullandığım araçlar
  • 🧠
    Perde arkası Blog'a girmeyen notlar

Spam yapmıyoruz. İstediğiniz zaman ayrılabilirsiniz. · Sadece Umami (self-hosted, Google yok) ile takip.

Okuma İstatistikleriniz

0

Yazı Okundu

0dk

Okuma Süresi

0

Gün Serisi

-

Favori Kategori

İlgili Yazılar