Jenkins'in eklenti yönetimi ve bellek iştahı fazla geliyor, GitHub Actions ise kodunu dışarı taşıdığı için tercih etmiyorsan aradaki boşluğu Drone CI dolduruyor. Drone CI kurulumu iki konteynerden ibarettir — bir server, bir runner — ve tüm pipeline adımları konteyner içinde çalışır. Yapılandırma deponun kökündeki .drone.yml dosyasında yaşar, arayüz sade ve az kaynakla çalışır.
Bu rehberde Drone'u sıfırdan kuracağız. Önce server–runner mimarisini netleştireceğim, çünkü ikisini tek bir şey sanmak kurulumdaki en yaygın kafa karışıklığı. Sonra Git sağlayıcısı tarafında OAuth uygulamasını oluşturacağız, Docker Compose ile iki servisi ayağa kaldıracağız, çalışan bir .drone.yml yazacağız ve gizli bilgileri güvenli biçimde saklayacağız. Sonda da üretimde en çok vakit kaybettiren tuzaklar var.
Mimari: Server ve Runner Ayrı Şeylerdir#
Drone iki bileşenden oluşur ve bu ayrım kurulumu anlamanın anahtarıdır. Server, web arayüzünü sunar, Git sağlayıcısıyla (GitHub, GitLab, Gitea, Bitbucket) konuşur, webhook'ları karşılar ve derleme kuyruğunu tutar. Hiçbir zaman derleme yapmaz. Runner, server'a bağlanır, kuyruktan iş alır ve pipeline adımlarını gerçekten çalıştırır.
İkisi arasındaki güven, paylaşılan bir sırla (DRONE_RPC_SECRET) kurulur. Aynı değeri iki tarafa da vermezsen runner bağlanamaz ve arayüzde derlemeler sonsuza kadar "pending" durumunda bekler — bu, kurulumdaki bir numaralı sorundur ve hata mesajı runner log'unda saklıdır.
| Bileşen | Görevi | Nerede çalışır |
|---|---|---|
| Drone Server | Arayüz, webhook, kuyruk | Genellikle tek sunucu |
| Docker Runner | Adımları konteynerde çalıştırır | Aynı ya da ayrı sunucu |
| Exec Runner | Adımları doğrudan kabukta çalıştırır | Yalnızca güvenilen depolar için |
| Kubernetes Runner | Her adım bir pod | Zaten Kubernetes varsa |
Çoğu kurulumda server ve Docker runner aynı makinede yaşar; yük arttığında runner'ı ayrı bir sunucuya taşımak, server'a hiç dokunmadan yapılabilecek tek adımlık bir iştir. Docker'ın temel kavramları taze değilse Docker nedir yazısı buradaki her şeyi daha anlaşılır kılar.
Ön Hazırlık: OAuth Uygulaması#
Drone kimlik doğrulamayı kendisi yapmaz; Git sağlayıcının hesaplarını kullanır. Bu yüzden kurulumdan önce sağlayıcı tarafında bir OAuth uygulaması oluşturman gerekir. GitHub için Settings → Developer settings → OAuth Apps → New OAuth App yolunu izlersin. Doldurman gereken tek kritik alan geri dönüş adresidir:
Homepage URL: https://drone.firmaniz.com
Authorization callback URL: https://drone.firmaniz.com/login
Callback adresindeki /login yolunu unutmak, "redirect_uri mismatch" hatasının en sık sebebidir. Kendi Git sunucunu kullanıyorsan aynı adımı Gitea'nın Settings → Applications bölümünden yaparsın; Gitea kurulumu için Gitea ile kendi Git sunucunuz yazısına bakabilirsin.
Uygulamayı oluşturduğunda sana bir Client ID ve Client Secret verilir. Bir de RPC sırrı üretmen gerekiyor:
# Server ile runner arasındaki paylaşılan sır
openssl rand -hex 16
# Örnek çıktı: 9f2c4a1b7d6e3f508a1c2b3d4e5f6071
Bu değeri bir yere kaydet; hem server hem runner aynısını kullanacak. Rastgele ve güçlü değerler üretmek için şifre üretici aracımızı da kullanabilirsin.
Docker Compose ile Kurulum#
Şimdi iki servisi birlikte tanımlayalım. Aşağıdaki dosya GitHub entegrasyonlu bir kurulumdur; Gitea kullanıyorsan DRONE_GITHUB_* değişkenlerini DRONE_GITEA_* ile değiştirir ve DRONE_GITEA_SERVER adresini eklersin.
services:
drone-server:
image: drone/drone:2
restart: unless-stopped
ports:
- "127.0.0.1:8080:80" # ters vekil önünde duracak
volumes:
- drone-veri:/data # SQLite veritabanı burada
environment:
DRONE_GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID}
DRONE_GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET}
DRONE_RPC_SECRET: ${RPC_SECRET}
DRONE_SERVER_HOST: drone.firmaniz.com
DRONE_SERVER_PROTO: https # TLS'i ters vekil sonlandırıyor
DRONE_USER_CREATE: username:kullaniciadin,admin:true
DRONE_LOGS_TEXT: "true"
drone-runner:
image: drone/drone-runner-docker:1
restart: unless-stopped
depends_on: [drone-server]
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
DRONE_RPC_PROTO: http
DRONE_RPC_HOST: drone-server # Compose ağı içindeki servis adı
DRONE_RPC_SECRET: ${RPC_SECRET} # server ile AYNI değer
DRONE_RUNNER_CAPACITY: "2" # eşzamanlı derleme sayısı
DRONE_RUNNER_NAME: runner-1
volumes:
drone-veri:
Değerleri yanına koyacağın .env dosyasına yaz ve o dosyayı asla depoya ekleme:
# .env — depoya EKLENMEYECEK
GITHUB_CLIENT_ID=xxxxxxxxxxxx
GITHUB_CLIENT_SECRET=yyyyyyyyyyyy
RPC_SECRET=9f2c4a1b7d6e3f508a1c2b3d4e5f6071
# Başlat ve kontrol et
docker compose up -d
docker compose logs -f drone-runner | head -20
# Beklenen satır: "successfully pinged the remote server"
DRONE_USER_CREATE satırı ilk yönetici hesabını belirler; oraya Git sağlayıcındaki kullanıcı adını yazmalısın, e-posta adresini değil. Compose dosyalarının yapısı ve .env kullanımı konusunda derinleşmek istersen Docker Compose kullanımı yazısı iyi bir tamamlayıcı.
Son adım ters vekil ve TLS'tir. DRONE_SERVER_PROTO: https yazdığın için Drone tüm bağlantıları HTTPS üzerinden bekler; sertifikayı Nginx tarafında sonlandırıp X-Forwarded-Proto başlığını ilettiğinden emin ol.
İlk .drone.yml Dosyası#
Drone'da her adım bir konteynerdir ve adımlar aynı çalışma dizinini paylaşır. Bu, Compose'a alışkın biri için son derece tanıdık bir modeldir:
kind: pipeline
type: docker
name: varsayilan
steps:
- name: testler
image: node:22-alpine
commands:
- npm ci
- npm run lint
- npm test
- name: imaj
image: plugins/docker
settings:
registry: kayit.firmaniz.com
repo: kayit.firmaniz.com/api
tags:
- ${DRONE_COMMIT_SHA:0:8} # kısa commit sha'sı
- latest
username:
from_secret: kayit_kullanici
password:
from_secret: kayit_parola
when:
branch: [main] # yalnızca ana dalda
- name: dagitim
image: appleboy/drone-ssh
settings:
host: 185.12.34.56
username: deploy
key:
from_secret: ssh_anahtari
script:
- cd /srv/uygulama
- docker compose pull
- docker compose up -d --remove-orphans
when:
branch: [main]
event: [push]
trigger:
event: [push, pull_request]
Adımlar varsayılan olarak sırayla çalışır ve biri başarısız olursa sonrakiler atlanır. Paralel çalıştırmak istersen depends_on alanıyla bağımlılık grafiği kurarsın. Testlerin bir veritabanına ihtiyaç duyuyorsa services bölümü tam da bunun için var:
services:
- name: veritabani
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: test
POSTGRES_DB: testdb
Bu servis, pipeline boyunca ayakta kalır ve adımlardan veritabani:5432 adresiyle erişilir — servis adı doğrudan ana makine adı olur. Bu, Docker network yapılandırma yazısında anlattığım kullanıcı tanımlı ağ davranışının aynısıdır.
Gizli Bilgiler ve Güvenilen Depolar#
.drone.yml deponun içinde yaşadığı için parolaları oraya yazamazsın. Drone'un secret deposu depo ayarlarında Settings → Secrets yolundadır ve pipeline'da from_secret ile çağrılır. Üç davranışı bilmen gerekiyor:
- Secret'lar çekme isteklerinde varsayılan olarak paylaşılmaz. Dış katkı alan bir depoda bu doğru davranıştır; kötü niyetli bir PR,
.drone.ymldosyasını değiştirerek secret'ı dışarı yazdıramaz. İhtiyacın varsa secret'ı açıkça "pull request" olaylarına açman gerekir ve bunu yalnızca kapalı depolarda yapmalısın. - Trusted (güvenilen) bayrağı ayrı bir yetkidir. Bir depo trusted işaretlenmediği sürece pipeline'ı ayrıcalıklı konteyner çalıştıramaz, ana makine yolunu bağlayamaz ve ana makine ağını kullanamaz. Bu bayrağı yalnızca yönetici verebilir ve gerçekten gerekmedikçe verilmemelidir.
- Secret adları küçük harf ve alt çizgi ile yazılır.
KAYIT_PAROLAyerinekayit_parola. Yanlış yazılan bir ad hata vermez, sadece değer boş gelir ve adım anlaşılmaz biçimde düşer.
Kimlik bilgilerinin depoya sızmasının maliyetini merak ediyorsan .git klasörü ve .env dosyası ifşası yazısındaki örnekler net bir fikir verir.
Koşullar, Önbellek ve Kaynak Sınırları#
Drone'da koşullar when bloğuyla ifade edilir ve oldukça okunabilirdir:
when:
branch:
include: [main, "surum/*"]
exclude: [deneme]
event: [push, tag]
status: [success] # önceki adımlar başarılıysa
Bir adımın başarısızlıkta bile çalışmasını istiyorsan status: [success, failure] yazarsın; bildirim adımları için tipik kullanım budur.
Önbellek konusunda Drone, GitHub Actions kadar hazır çözüm sunmaz. İki pratik yol var. Birincisi, ana makinedeki bir dizini bağlamak — ama bu depo için trusted yetkisi gerektirir ve paylaşımlı bir sunucuda risklidir. İkincisi ve tercih edilmesi gereken yol, önbelleği bir nesne deposuna gönderen eklentileri kullanmaktır. Küçük kurulumlarda üçüncü bir seçenek daha var: bağımlılıkları temel imaja gömmek. Kendi node-tabani imajını haftada bir derleyip kayıt defterine göndermek, her derlemede yüzlerce paketi indirmekten çok daha hızlıdır; bu yaklaşımın nasıl kurulacağını Dockerfile en iyi pratikler yazısında anlattım.
Runner'ın kaynak tüketimini de sınırlamayı unutma. DRONE_RUNNER_CAPACITY eşzamanlı derleme sayısını belirler; sunucun 4 çekirdekliyse bunu 2'de tutmak, derlemelerin birbirini boğmasını engeller. Ayrıca adım başına bellek ve CPU sınırı koyabilirsin:
DRONE_LIMIT_MEM: "1073741824" # adım başına 1 GB
DRONE_LIMIT_CPU: "1000000000" # yaklaşık 1 çekirdek
Sık Yapılan Hatalar ve Tuzaklar#
RPC sırrını iki tarafta farklı yazmak. Derlemeler kuyrukta bekliyor ve hiç başlamıyorsa ilk bakılacak yer budur. docker compose logs drone-runner çıktısında kimlik doğrulama hatası görürsün.
Callback adresini yanlış girmek. OAuth uygulamasındaki geri dönüş adresi tam olarak https://alan-adin/login olmalıdır. Sondaki eğik çizgi ya da eksik /login yolu girişte hataya yol açar.
DRONE_SERVER_PROTO ile gerçek protokolü uyumsuz bırakmak. https yazıp ters vekilde TLS kurmadıysan giriş döngüye girer; http yazıp HTTPS üzerinden servis ediyorsan webhook adresleri yanlış üretilir.
Docker soketini gereksiz yerlere bağlamak. Runner'ın /var/run/docker.sock erişimine ihtiyacı vardır, ama bunu pipeline adımlarına da vermek, depoya push yetkisi olan herkese sunucuda root yetkisi vermek demektir. Neden böyle olduğunu Docker daemon socket permission denied yazısında ayrıntılandırdım.
Disk temizliğini ihmal etmek. Her derleme yeni imaj katmanları ve geçici hacimler bırakır. Sunucuda haftalık bir temizlik görevi kur:
# Kullanılmayan imaj, ağ ve hacimleri temizle (haftalık cron için uygun)
docker system prune -af --filter "until=168h"
SQLite ile büyük ekip yönetmek. Varsayılan kurulum SQLite kullanır ve küçük ekipler için fazlasıyla yeterlidir. Onlarca eşzamanlı derleme yapan bir kurulumda PostgreSQL'e geçmek daha sağlıklıdır; geçiş DRONE_DATABASE_DRIVER ve DRONE_DATABASE_DATASOURCE değişkenleriyle yapılır.
Sıkça Sorulan Sorular#
Drone CI ücretsiz mi#
Drone'un kaynak kodu açıktır ancak lisansı kullanım ölçeğine göre koşullar içerir; küçük ekipler ve kişisel kullanım için ücretsiz kullanılabilirken belirli bir kurumsal ölçeğin üzerinde ticari lisans gerekir. Tamamen özgür lisanslı bir alternatif arıyorsan Drone'un topluluk çatalı olan Woodpecker CI neredeyse aynı yapılandırma modelini kullanır ve tam açık kaynaktır.
Derlemeler neden pending durumunda kalıyor#
Neredeyse her zaman runner server'a bağlanamıyordur. Sırayla şunları kontrol et: iki tarafta DRONE_RPC_SECRET birebir aynı mı, runner'ın DRONE_RPC_HOST değeri server'a erişebiliyor mu ve DRONE_RPC_PROTO doğru mu? Runner log'unda başarılı bağlantı "successfully pinged the remote server" satırıyla görünür; o satır yoksa iş kuyruktan alınamaz.
Drone için ne kadar sunucu kaynağı gerekir#
Server bileşeni çok hafiftir; birkaç yüz megabayt bellek yeter. Asıl kaynağı runner ve çalıştırdığı adımlar tüketir. Küçük bir ekip için 2 çekirdek ve 4 GB bellekli bir sunucu rahatça idare eder; derlemeler ağırsa DRONE_RUNNER_CAPACITY değerini düşük tutup gerektiğinde ikinci bir runner sunucusu eklemek daha öngörülebilir bir yol.
GitHub Actions yerine neden Drone kullanayım#
Üç sebep: kodun ve derleme çıktıların kendi sunucunda kalır, dakika kotası yoktur ve özel ağdaki kaynaklara ek tünel kurmadan erişebilirsin. Buna karşılık sunucunun bakımı, güncellemeleri ve yedeği sende olur. Kodun zaten GitHub'daysa ve bu üç gereksinim yoksa GitHub Actions daha az iş çıkarır.
.drone.yml dosyasını nasıl doğrularım#
Drone'un komut satırı istemcisi drone lint ile söz dizimini doğrular, drone exec ile de pipeline'ı yerel makinende çalıştırabilirsin. drone exec özellikle değerlidir: her denemede depoya commit atmadan adımları test edersin. Secret gerektiren adımları yerelde çalıştırırken değerleri --secret-file ile geçici bir dosyadan verirsin.
Birden fazla runner ekleyebilir miyim#
Evet ve yük arttığında yapman gereken şey tam olarak budur. Yeni sunucuya yalnızca runner konteynerini kurar, DRONE_RPC_HOST değerine server'ın adresini ve aynı RPC sırrını verirsin; runner kendini kaydeder ve kuyruktan iş almaya başlar. Farklı mimariler için ayrı runner'lar çalıştırıp pipeline'da platform alanıyla hedef seçebilirsin.
Kapanış#
Drone, kendi altyapında kalmak isteyen ekipler için kurulumu en hızlı CI seçeneklerinden biri: iki konteyner, bir OAuth uygulaması ve deponun içinde yaşayan bir .drone.yml. Sağlıklı bir kurulum için şu dördünü akılda tut — RPC sırrını iki tarafta aynı yaz, ters vekil ve TLS'i baştan kur, depoya trusted yetkisini yalnızca gerçekten gerektiğinde ver ve haftalık bir disk temizliği görevi tanımla.
Drone server ve runner'ını barındırmak için tam root erişimli VDS veya ihtiyaca göre büyüyen bulut sunucu paketlerimiz uygun bir zemin sunuyor; runner'ı ayrı makinede tutmak istersen sanal sunucu ekonomik bir başlangıç. Sunucunun kurulumu, güvenlik sıkılaştırması ve yedeklenmesiyle uğraşmak istemiyorsan sunucu yönetimi ve yedekleme hizmetlerimiz bu tarafı sizin yerinize üstlenir.