Mert Özen Her Satırda Daha İleri
DevOps GitHub Actions — #14

GitHub Actions Runner'ları: Hosted Image'lar, ubuntu-latest Geçişi, ARM, Larger Runner ve Self-Hosted

Mert Özen 8 Kas 2026 9 dk 4 görüntülenme
GitHub Actions Runner'ları: Hosted Image'lar, ubuntu-latest Geçişi, ARM, Larger Runner ve Self-Hosted

Release ve deploy pipeline'larında runner label'ını pin'le: ubuntu-latest 19 Ekim–19 Kasım 2026 arasında 24.04'ten 26.04'e geçiyor. Hosted image haritası, arm64 ve larger runner'lar, actionlint'in label kontrolü, act'te label'ın yalnızca bir Docker image eşlemesi olduğu, ephemeral self-hosted runner, minimum sürüm kuralı, ARC, 2026 fiyatları ve multi-cloud'un IP allowlist'e etkisi.

Sürüm notu: Bu yazıdaki örnekler act 0.2.97 (runner image'ı catthehacker/ubuntu:act-24.04, arm64), actionlint 1.7.12 ve Docker 29.2 ile denenmiştir. GitHub-hosted image'lar, self-hosted runner kaydı ve ARC (Actions Runner Controller) bu makinede çalıştırılmamıştır; label'lar, tarihler ve fiyatlar Kasım 2026 itibarıyla GitHub changelog'u ve dokümantasyonundan doğrulanmıştır.

Önce Tahmin Et

Bookstore'un CI (Continuous Integration) workflow'u Ekim başında yeşildi. Kasım'ın ilk haftası hiçbir commit atılmadan yeniden çalıştırılan aynı run kırmızıya dönüyor; hata, build sırasında çağrılan bir sistem aracının bulunamaması. Kodda, workflow'da ve bağımlılıklarda değişiklik yok. Ne değişti?

İkinci soru: maliyetten tasarruf etmek için ofisteki bir Linux makinesine self-hosted runner kurup public bir repository'ye bağladın. Bu runner'da kimlerin kodu çalışabilir?

runs-on ve Label'lar: Job Nereye Gider?

Her job bir runner'da çalışır ve hangi runner'ı istediğini runs-on ile söyler. Değer bir label veya label listesidir; liste verildiğinde runner'ın bütün label'lara sahip olması gerekir:

jobs:
  build:
    runs-on: ubuntu-24.04
  build-arm:
    runs-on: ubuntu-24.04-arm
  build-on-our-machine:
    runs-on: [self-hosted, linux, arm64, bookstore-build]
  build-large:
    runs-on:
      group: bookstore-large
      labels: [bookstore-linux-8core]

GitHub-hosted runner'larda label bir image'ı ve makine tipini seçer; job her seferinde temiz bir VM'de (virtual machine) başlar ve job bitince VM silinir. Self-hosted runner'da label'ları sen verirsin; self-hosted, işletim sistemi ve mimari label'ları otomatik eklenir. Larger runner'lar organization seviyesinde tanımlanır, adı ve label'ı admin'in seçtiği şeydir (actionlint için onu da configuration'a eklemen gerekir) ve runner group üzerinden hangi repository'lerin kullanabileceği sınırlanır.

actionlint bilinen hosted label'ları tanır ve geri kalanını yazım hatası sayar. Kendi runner label'ın için repository'de bir configuration dosyası gerekir:

self-hosted-runner:
  labels:
    - bookstore-build
    - bookstore-linux-8core
    - ubuntu-26.04
    - ubuntu-26.04-arm

Listede ubuntu-26.04'ün ne aradığına birazdan geleceğiz.

GitHub-Hosted Image'lar: Kasım 2026 Haritası

Hosted runner label'ları ve -latest'in bugün gösterdiği image'lar:

LabelImageNot
ubuntu-latestUbuntu 24.04 → 26.04Geçiş 19 Ekim – 19 Kasım 2026
ubuntu-24.04, ubuntu-26.04, ubuntu-22.04Sabit sürümlerarm64 için sonuna -arm
ubuntu-slimHafif Linux runner1 vCPU, 5 GB bellek
windows-latestWindows Server 2025Visual Studio 2026'lı windows-2025-vs2026 da var
windows-11-armWindows 11 arm64
macos-latestmacOS 26, arm64Intel için macos-26-intel

Standart Linux ve Windows runner'ları public repository'lerde 4 vCPU (sanal işlemci çekirdeği) ve 16 GB RAM (Random Access Memory), private repository'lerde 2 vCPU ve 8 GB RAM ile geliyor; ikisinde de 14 GB SSD (Solid State Drive) var. Aynı workflow'un public bir fork'ta neden daha hızlı koştuğunun cevabı bazen bu kadar basit.

arm64 ve Larger Runner'lar

arm64 runner'lar .NET için doğal bir seçenek: SDK (Software Development Kit) ve runtime arm64'ü tam destekliyor, Bookstore'un build ve test adımları hiçbir değişiklik olmadan koşuyor. Multi-arch container image'ı üretirken QEMU (Quick Emulator) emülasyonu yerine her mimarinin image'ını kendi runner'ında build edip manifest'te birleştirmek çok daha hızlı. Larger runner'lar ise daha fazla CPU (Central Processing Unit) çekirdeği, bellek, GPU (Graphics Processing Unit) veya sabit IP (Internet Protocol) adresi gerektiren işler için; Team ve Enterprise planlarında, dakika başı daha yüksek ücretle. Sabit IP, bir önceki yazıda konuştuğumuz "sunucuyu yalnızca CI'a aç" kısıtını mümkün kılan şey.

ubuntu-latest Geçişi ve Pin'lemek

Tahminin ilk sorusunun cevabı burada. Ubuntu 26.04 hosted runner'lar 17 Eylül 2026'da GA (General Availability) oldu ve ubuntu-latest 19 Ekim ile 19 Kasım 2026 arasında kademeli olarak 24.04'ten 26.04'e taşınıyor. Kademeli demek, aynı hafta içinde bir run'ın 24.04'te, bir sonrakinin 26.04'te koşabilmesi demek. Yeni image Ubuntu 26.04.1 LTS (Long Term Support), 7.0 kernel ve systemd 259 ile geliyor; kurulu araçların listesi de değişiyor. Workflow'un bir sistem aracına veya belirli bir sürümüne dolaylı olarak bağlıysa, kod değişmeden kırılır. "Latest" bir sürüm değil, bir taahhütsüzlük.

Bu yüzden release ve deploy pipeline'larında label'ı pin'le: runs-on: ubuntu-24.04. Yeni image'ı kontrollü denemek için matrix'e bir satır ekle ve sonucu izle; hazır olduğunda pin'i bilinçli olarak ilerlet. -latest yalnızca "her zaman en yeni ortamda da çalışmalı" dediğin, kırılmasının bir sinyal olduğu job'lar için uygun.

Burada araçlar da bir adım geride. actionlint 1.7.12'ye ubuntu-26.04'ü sorduğumda tanımadı ve emekliye ayrılmış ubuntu-20.04'ü de doğru olarak reddetti:

.github/workflows/labels.yml:7:43: label "ubuntu-26.04" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2025-vs2026", "windows-2022", "windows-11-arm", "ubuntu-slim", "ubuntu-latest", ..., "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", ..., "macos-26", "macos-15-intel", ... if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file [runner-label]
.github/workflows/labels.yml:7:162: label "ubuntu-20.04" is unknown. ...
.github/workflows/labels.yml:12:42: label "bookstore-build" is unknown. ...

ubuntu-20.04 image'ı 15 Nisan 2025'te tamamen kaldırıldı; bu label'la kalan bir workflow GitHub'da çalışacak runner bulamaz. Yukarıdaki .github/actionlint.yaml dosyasıyla custom label ve henüz bilinmeyen yeni label'lar tanıtılınca lint temiz geçti. actionlint yeni sürümle 26.04'ü öğrendiğinde o iki satırı silmeyi unutma.

act'te Label Bir Image Eşlemesidir

act'te label'ın arkasında GitHub'ın image'ı yok; -P ile hangi Docker image'ını verdiysen o var. Aynı image'ı iki label'a eşleyip şu workflow'u koştum:

name: runner-info

on: workflow_dispatch

jobs:
  info:
    strategy:
      matrix:
        os: [ubuntu-24.04, ubuntu-26.04]
    runs-on: ${{ matrix.os }}
    steps:
      - name: Describe the runner
        run: |
          . /etc/os-release
          echo "label=${{ matrix.os }} os=$PRETTY_NAME arch=$RUNNER_ARCH"
          echo "ImageOS=${ImageOS:-unset} ImageVersion=${ImageVersion:-unset}"
          echo "cpus=$(nproc) mem=$(free -g | awk '/Mem:/{print $2}')G"
          dotnet --list-sdks | tail -1 || echo "no dotnet"
act workflow_dispatch -W .github/workflows/runner-info.yml -P ubuntu-26.04=catthehacker/ubuntu:act-24.04

[runner-info/info-2]   | label=ubuntu-26.04 os=Ubuntu 24.04.4 LTS arch=ARM64
[runner-info/info-2]   | ImageOS=ubuntu26 ImageVersion=unset
[runner-info/info-1]   | label=ubuntu-24.04 os=Ubuntu 24.04.4 LTS arch=ARM64
[runner-info/info-1]   | ImageOS=ubuntu26 ImageVersion=unset
[runner-info/info-2]   | cpus=10 mem=7G
[runner-info/info-1]   | /var/run/act/workflow/0: line 6: dotnet: command not found
[runner-info/info-1]   | cpus=10 mem=7G
[runner-info/info-2]   | /var/run/act/workflow/0: line 6: dotnet: command not found

Dört ders var. ubuntu-26.04 label'lı job aslında Ubuntu 24.04'te koştu, çünkü image'ı ben öyle eşledim. ImageOS değişkeni ikisinde de ubuntu26; act'teki bu değer gerçeği yansıtmıyor, ImageVersion ise hiç yok. CPU ve bellek Docker Desktop VM'inin değerleri, hosted runner'ınkiler değil. Ve hosted image'larda kurulu gelen .NET SDK burada yok; 10. yazıda az için gördüğümüz aynı fark. act, workflow mantığını test etmek için harika; image'a bağlı davranışı test etmek için değil. Image'a bağlı bir sorunu ancak GitHub'ın kendi runner'ında, veya runner-images deposundaki image tanımlarına bakarak doğrulayabilirsin.

Self-Hosted Runner: Ne Zaman, Nasıl, Nerede Değil

Self-hosted runner, GitHub'ın runner uygulamasını kendi makinende çalıştırmak. Gerekçeler genellikle şunlar: iç ağdaki bir kaynağa erişim (veritabanı, artifact deposu, deploy hedefi), özel donanım, büyük cache'leri makinede tutmak veya maliyet. Kurulum, repository veya organization ayarlarından alınan kısa ömürlü bir registration token ile yapılır:

./config.sh --url https://github.com/octo-org/bookstore --token "$REGISTRATION_TOKEN" \
  --name build-01 --labels bookstore-build --ephemeral --unattended
./run.sh

Token gerektirdiği için bu komutları çalıştırmadım. --ephemeral en önemli bayrak: runner tek bir job alır ve ardından kaydını otomatik olarak siler. Kalıcı bir runner'da bir job'ın bıraktığı dosyalar, process'ler, Docker image'ları ve credential'lar bir sonraki job'a kalır; ephemeral runner'ı her seferinde temiz bir VM veya container'da yeniden başlatan bir otomasyonla birlikte kullanırsın.

Tahminin ikinci sorusunun cevabı GitHub'ın kendi uyarısında: self-hosted runner'ı public repository'lerde kullanma. Herkes bir fork'tan PR (pull request) açabilir ve PR'daki kod senin makinende, senin ağında çalışır; runner'ın job'lar arasında temizlendiğinin garantisi yoktur. 13. yazıdaki her saldırı yüzeyi burada fiziksel bir makineye dönüşüyor.

Bir de bakım yükü var. 2026'dan itibaren GitHub self-hosted runner'lar için minimum sürüm uyguluyor: kayıt için en az 2.329.0 gerekiyor ve bir runner, yeni bir sürüm yayınlandıktan sonra 30 gün içinde güncellenmezse job almayı bırakıyor; Enterprise Cloud'da bu uygulama 29 Eylül 2026'da başladı. Node 24 ile çalışan action'lar (checkout@v5 ve sonrası) zaten en az 2.327.1 istiyor. Otomatik güncellemeyi kapattıysan bunu bir bakım takvimine bağla.

Kubernetes'te ARC ve Scale Set Client

Self-hosted runner'ları ölçeklemenin yerleşik yolu ARC: Kubernetes'te çalışan, runner scale set'leri yöneten ve bekleyen job sayısına göre ephemeral runner pod'ları açıp kapatan bir controller. Workflow tarafında scale set'in adını runs-on'a yazarsın. Eylül 2026'da çıkan ARC 0.15.0, yerinde patch yükseltmeleri ve ayarlanabilir sonlandırma süresi getirdi. Kubernetes kullanmayanlar için Şubat 2026'dan beri public preview'da olan scale set client, aynı ölçekleme API'sini (Application Programming Interface) bağımsız bir Go modülü olarak sunuyor; kendi VM otomasyonunu yazmak isteyenler için. Kubernetes'in kendisini ilerideki Kubernetes serisinde ele alacağız.

Maliyet: 2026 Fiyatları ve Multi-Cloud

1 Ocak 2026'da hosted runner fiyatları makine tipine göre yüzde 39'a varan oranlarda düştü; Linux 2 core dakikası 0,006 dolar ve yeni fiyatlara dakika başı 0,002 dolarlık bir platform ücreti dahil. Aynı ücretin self-hosted runner dakikalarına da 1 Mart 2026'da uygulanması planlanmıştı; GitHub bunu 15 Aralık 2025'te yeni bir tarih vermeden erteledi, dolayısıyla self-hosted dakikalar şu an ücretsiz. Planlara dahil aylık kullanım: Free 12 dolar (yaklaşık 2.000 Linux dakikası), Pro ve Team 18 dolar (yaklaşık 3.000), Enterprise Cloud 300 dolar (yaklaşık 50.000). Public repository'lerde standart hosted runner'lar ücretsiz.

Ekim 2026'nın sonunda bir değişiklik daha geldi: uygun standart 2 ve 4 core Linux runner'ları artık Azure'un yanında AWS (Amazon Web Services) üzerinde de çalışabiliyor. Free, Pro ve Team'de varsayılan olarak açık, Enterprise Cloud'da opt-in. Doğrudan etkisi IP allowlist'lerinde: sunucuna veya veritabanına yalnızca Azure veya Microsoft IP aralıklarından erişim veriyorsan, AWS'de koşan bir runner kapıda kalır. Allowlist'i https://api.github.com/meta adresindeki actions listesinden senkronize et ya da sabit IP'li larger runner kullan.

Üretimde Dikkat

Runner'ı kod gibi pin'le. Deploy pipeline'ları belirli bir image sürümünde koşsun; image yükseltmesi bir PR ile, matrix'te denenerek yapılsın.

Image'a güvenme, kurulumu kendin yap. .NET SDK'yı image'dan değil setup-dotnet ve global.json'dan al; Node'u setup-node'dan. Image'daki araçlar her geçişte değişebilir, senin pin'lediğin sürüm değişmez.

Self-hosted runner'ı ephemeral ve izole çalıştır. Kalıcı runner'da Docker socket'ini job'lara açmak, makinenin root'unu açmak demek.

Maliyeti ölç. Billing ekranındaki dakika kullanımı makine tipine göre ayrışıyor; macOS ve larger runner dakikaları Linux'tan katlarca pahalı. Hangi job'ın gerçekten macOS veya 8 core istediğini sorgula. Ölçme ve hız tarafını bir sonraki yazıda ayrıntılı konuşacağız.

Sık Düşülen Tuzaklar

ubuntu-latest'e güvenip kırılan build. Ekim–Kasım 2026'da tam olarak bu oluyor; release pipeline'larını pin'le.

Emekliye ayrılmış bir label'da kalmak. ubuntu-20.04 veya windows-2019 ile yazılmış bir workflow artık çalışacak bir hosted runner bulamaz; actionlint bunu YAML (YAML Ain't Markup Language) dosyasını yazarken yakalar.

Public repository'de self-hosted runner. Fork'tan gelen PR'ın kodu senin ağında çalışır.

act çıktısını image kanıtı saymak. act'te label yalnızca senin seçtiğin Docker image'ına bir isim.

IP allowlist'ini bir kez yazıp unutmak. GitHub'ın runner IP aralıkları değişiyor ve artık birden fazla cloud'a yayılıyor.

Self-hosted runner'ı güncellemeyi kapatıp unutmak. 30 günlük pencere dolunca runner sessizce job almayı bırakır ve job'lar kuyrukta bekler.

Küçük Bir Deneme

★☆☆ Kendi public test repository'nde runner-info workflow'unu ubuntu-latest, ubuntu-24.04 ve ubuntu-26.04 ile çalıştır; ImageOS, ImageVersion ve dotnet --list-sdks çıktılarını act'teki sonuçla karşılaştır.

★★☆ Bookstore'un API CI'ını ubuntu-24.04 ve ubuntu-24.04-arm matrix'inde koş ve iki mimarideki build ve test sürelerini job summary'ye yaz.

★★★ Bir Docker container'ında ephemeral bir self-hosted runner'ı başlatan, job bitince container'ı silen ve yenisini açan küçük bir script yaz (registration token'ı yalnızca kendi test repository'n için, kısa ömürlü olarak al). Runner'ın job sonrasında kaydını gerçekten sildiğini repository ayarlarından doğrula.

Runner'ın nerede koştuğunu ve neye mal olduğunu gördük. Bir sonraki yazıda aynı pipeline'ı hızlandırmaya ve hata ayıklamaya bakıyoruz: debug logging, act'in yerelde nerede işe yaradığı, cache key tasarımı, artifact retention ve billing ekranını okumak.