Ubuntu’da Cron Job Kurulumu ve Yönetimi

Sunucu yönetiminde belki de en sık kullandığımız ama en az dikkat ettiğimiz araçlardan biri cron’dur. Veritabanı yedekleri, log rotasyonu, sistem temizliği, API çağrıları… Bunların hepsi arka planda sessiz sedasız cron sayesinde çalışır. Yeni başlayan sysadminlerin çoğu cron’u kurar, çalıştırır ve “tamam hallettim” der geçer. Ama sonra gece 2’de telefon çalar, yedek alınmamıştır, log dolmuştur ya da bir betik hata verip durmuştur. Bu yazıda cron’u sadece kurmayı değil, doğru yönetmeyi, hata ayıklamayı ve production ortamında güvenli kullanmayı konuşacağız.

Cron Nedir ve Nasıl Çalışır

Cron, Unix/Linux sistemlerinde zamanlanmış görevleri çalıştırmak için kullanılan daemon’dır. Ubuntu’da bu daemon cron servisi olarak çalışır ve sistem başladığında otomatik başlar. Her kullanıcının kendi crontab dosyası olabilir, bir de sistem genelinde geçerli olan /etc/crontab ve /etc/cron.d/ dizini vardır.

Cron her dakika uyanır, tanımlı görevlere bakar ve zamanı gelmiş olanları çalıştırır. Bu kadar basit. Ama bu basitlik bazen insanı yanıltır. Cron’un kendi ortamı (environment) vardır ve bu ortam senin terminal oturumundan çok farklıdır. Bu farkı anlamadan yazdığın betikler çalışır gibi görünür ama cron’da çalışmaz. Buna birazdan döneceğiz.

Ubuntu’da Cron Servisini Kontrol Etme

Önce cron’un çalışıp çalışmadığını kontrol edelim:

sudo systemctl status cron
sudo systemctl enable cron
sudo systemctl start cron

Ubuntu 20.04 ve sonrasında cron genellikle zaten kurulu ve aktif gelir. Ama minimal kurulumlar veya konteyner tabanlı ortamlarda olmayabilir. Yoksa kur:

sudo apt update
sudo apt install cron -y

Cron loglarını görmek için:

sudo journalctl -u cron -f
# Ya da klasik yöntemle:
sudo tail -f /var/log/syslog | grep CRON

Crontab Sözdizimi

Cron ifadelerini anlamak için beş alan var. Soldan sağa sıralamayla:

Dakika (0-59): Görevin kaçıncı dakikada çalışacağı Saat (0-23): Hangi saat Gün (1-31): Ayın kaçıncı günü Ay (1-12): Hangi ay Haftanın günü (0-7): 0 ve 7 Pazar’dır, 1 Pazartesi

Genel format: * komut

Sık kullanılan özel ifadeler:

  • *: Her değer için
  • ,: Birden fazla değer (1,15,30)
  • : Aralık (1-5)
  • /: Adım (*/5 her 5 dakikada bir)

Bazı örnekler:

# Her gün sabah 3:30'da çalıştır
30 3 * * * /usr/local/bin/backup.sh

# Her 5 dakikada bir çalıştır
*/5 * * * * /usr/local/bin/health-check.sh

# Her Pazartesi saat 08:00'de çalıştır
0 8 * * 1 /usr/local/bin/weekly-report.sh

# Her ayın 1'i ve 15'inde gece yarısı çalıştır
0 0 1,15 * * /usr/local/bin/billing-sync.sh

# Her iş günü (Pazartesi-Cuma) saat 17:00'de çalıştır
0 17 * * 1-5 /usr/local/bin/daily-summary.sh

Crontab ifadelerini test etmek için [crontab.guru](https://crontab.guru) sitesini öneririm. Yazarken orada kontrol etmek çok işe yarıyor.

Crontab Düzenleme

Kullanıcı Crontab’ı

Her kullanıcı kendi crontab’ını yönetebilir:

# Kendi crontab'ını düzenle
crontab -e

# Mevcut crontab'ı listele
crontab -l

# Crontab'ı sil (dikkatli ol!)
crontab -r

# Başka bir kullanıcının crontab'ını düzenle (root gerektirir)
sudo crontab -u www-data -e

İlk crontab -e komutunu çalıştırdığında editör seçmen istenir. Ben nano’yu öneririm başlangıç için, vim biliyorsan zaten seçersin.

Sistem Geneli Crontab

/etc/crontab dosyasına bak. Burada standart kullanıcı crontab’ından farklı olarak kullanıcı adı da belirtilir:

# /etc/crontab formatı: dakika saat gün ay haftanın-günü kullanıcı komut
30 3 * * * root /usr/local/bin/system-backup.sh
0 */6 * * * www-data /var/www/scripts/cache-clear.php

/etc/cron.d/ dizinine de dosya ekleyebilirsin. Bu dizindeki her dosya sistem crontab’ı gibi davranır ve paketler tarafından sıklıkla kullanılır.

Hazır Dizinler

Ubuntu’da şu dizinler var ve buradaki betikler otomatik çalıştırılır:

  • /etc/cron.hourly/: Her saat başı
  • /etc/cron.daily/: Her gün
  • /etc/cron.weekly/: Her hafta
  • /etc/cron.monthly/: Her ay

Bu dizinlere script koyarken dikkat et: Dosya adında nokta (.) olmamalı, executable olmalı ve shebang satırı olmalı.

sudo cp /usr/local/bin/my-daily-script.sh /etc/cron.daily/my-daily-script
sudo chmod +x /etc/cron.daily/my-daily-script

Gerçek Dünya Senaryo 1: Veritabanı Yedekleme

Production ortamında en kritik cron görevi veritabanı yedeklemesidir. İşte bir MySQL/MariaDB yedekleme betiği:

#!/bin/bash
# /usr/local/bin/db-backup.sh

set -euo pipefail

BACKUP_DIR="/var/backups/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
DB_USER="backup_user"
DB_PASS="güçlü_şifre_buraya"
RETENTION_DAYS=7
LOG_FILE="/var/log/db-backup.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

mkdir -p "$BACKUP_DIR"

log "Yedekleme başladı"

databases=$(mysql -u"$DB_USER" -p"$DB_PASS" -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|sys)")

for db in $databases; do
    log "Yedekleniyor: $db"
    mysqldump -u"$DB_USER" -p"$DB_PASS" 
        --single-transaction 
        --routines 
        --triggers 
        "$db" | gzip > "$BACKUP_DIR/${db}_${DATE}.sql.gz"
    log "$db tamamlandı: $(du -sh ${BACKUP_DIR}/${db}_${DATE}.sql.gz | cut -f1)"
done

# Eski yedekleri temizle
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
log "Eski yedekler temizlendi ($RETENTION_DAYS günden eski)"

log "Yedekleme tamamlandı"

Bu betiği crontab’a ekle:

# Her gece 2:00'de çalıştır
0 2 * * * /usr/local/bin/db-backup.sh

Gerçek Dünya Senaryo 2: Disk Doluluk Uyarısı

Disk dolduğunda her şey durur. Bunu önceden öğrenmek için basit bir monitoring betiği:

#!/bin/bash
# /usr/local/bin/disk-monitor.sh

THRESHOLD=85
ADMIN_EMAIL="[email protected]"
HOSTNAME=$(hostname)

df -h | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{print $5 " " $6}' | while read output; do
    usage=$(echo $output | awk '{print $1}' | sed 's/%//')
    partition=$(echo $output | awk '{print $2}')

    if [ "$usage" -ge "$THRESHOLD" ]; then
        MESSAGE="UYARI: $HOSTNAME sunucusunda $partition bölümü %$usage dolu!"
        echo "$MESSAGE" | mail -s "Disk Doluluk Uyarısı - $HOSTNAME" "$ADMIN_EMAIL"
        logger -t disk-monitor "$MESSAGE"
    fi
done

Crontab’a ekle, her 30 dakikada bir çalıştır:

*/30 * * * * /usr/local/bin/disk-monitor.sh

Cron’da Environment Sorunu

Bu konu çok kritik ve çoğu insanın kafasını karıştırır. Terminalde çalışan bir komut cron’da çalışmayabilir. Neden? Çünkü cron’un PATH’i senin PATH’inden çok farklıdır.

Terminalinde echo $PATH yaz, sonra cron’a şunu ekle:

* * * * * echo $PATH >> /tmp/cron-path.log

Birkaç dakika sonra /tmp/cron-path.log‘a bak. Cron’un PATH’i genellikle /usr/bin:/bin gibi çok minimal bir şeydir.

Çözüm yöntemleri:

1. Betiklerde tam yol kullan:

#!/bin/bash
# Kötü:
python3 script.py

# İyi:
/usr/bin/python3 /home/ubuntu/scripts/script.py

2. Crontab’ın başına PATH tanımla:

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
SHELL=/bin/bash
[email protected]

0 3 * * * /usr/local/bin/backup.sh
*/5 * * * * /usr/local/bin/monitor.sh

3. Betik içinde environment’ı yükle:

#!/bin/bash
source /etc/environment
source /home/ubuntu/.bashrc
# Geri kalan komutlar...

Cron Çıktısını Yönetmek

Varsayılan olarak cron, görevlerin çıktısını kullanıcıya mail olarak gönderir. Büyük sunucularda bu çok fazla mail oluşturur. Yönetim seçenekleri:

# Tüm çıktıyı sustur
0 3 * * * /usr/local/bin/backup.sh > /dev/null 2>&1

# Sadece hataları sakla, stdout'u sustur
0 3 * * * /usr/local/bin/backup.sh > /dev/null 2>> /var/log/backup-errors.log

# Her şeyi log dosyasına yaz
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

# Timestamp'li log
0 3 * * * echo "--- $(date) ---" >> /var/log/backup.log && /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

Benim tercihim: Her betik kendi içinde logging yapsın, cron seviyesinde de bir log dosyasına yönlendir. > /dev/null 2>&1 kullanmaktan kaçın, hataları kaybediyorsun.

Log Rotasyonu

Cron logları şişebilir. Logrotate ile yönet:

# /etc/logrotate.d/my-cron-jobs dosyasını oluştur
sudo nano /etc/logrotate.d/my-cron-jobs
/var/log/backup.log
/var/log/db-backup.log
/var/log/disk-monitor.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 640 root adm
}

Gerçek Dünya Senaryo 3: Web Uygulaması Bakım Görevi

Bir Laravel uygulaması çalıştırdığını düşün. Scheduled task’lar için:

# Laravel schedule:run her dakika çalışmalı
* * * * * cd /var/www/my-app && /usr/bin/php artisan schedule:run >> /var/log/laravel-cron.log 2>&1

# Queue worker'ı her dakika kontrol et, çalışmıyorsa başlat
* * * * * /usr/local/bin/ensure-queue-worker.sh

# Günlük log temizliği
0 4 * * * cd /var/www/my-app && /usr/bin/php artisan log:clear >> /dev/null 2>&1

www-data kullanıcısıyla çalıştırman gerekebilir:

sudo crontab -u www-data -e

Cron Job Güvenliği

Production ortamında güvenliği göz ardı etme:

# Betiklerin doğru izinleri olsun
chmod 750 /usr/local/bin/backup.sh
chown root:root /usr/local/bin/backup.sh

# Yedek dizini sadece root'a açık olsun
chmod 700 /var/backups/mysql

# Şifreleri betik içine yazma, config dosyası kullan
# /etc/db-backup.conf
DB_USER="backup_user"
DB_PASS="güçlü_şifre"

# Betik içinde:
source /etc/db-backup.conf
chmod 600 /etc/db-backup.conf

/etc/cron.allow ve /etc/cron.deny dosyalarıyla hangi kullanıcıların cron kullanabileceğini kontrol edebilirsin:

# Sadece belirli kullanıcılar cron kullanabilsin
echo "ubuntu" | sudo tee /etc/cron.allow
echo "deploy" | sudo tee -a /etc/cron.allow

Hata Ayıklama

Cron çalışmıyor ama neden? Sırasıyla kontrol et:

1. Cron daemon çalışıyor mu?

sudo systemctl status cron
sudo journalctl -u cron --since "1 hour ago"

2. Syslog’a bak:

grep CRON /var/log/syslog | tail -50

3. Betiği elle çalıştır:

sudo -u www-data /usr/local/bin/my-script.sh

4. Cron ortamını simüle et:

# Cron'un environment'ında betiği test et
env -i HOME=/root LOGNAME=root PATH=/usr/bin:/bin SHELL=/bin/bash /usr/local/bin/my-script.sh

5. Basit test cron’u ekle:

# 1 dakika sonrasını ayarla ve bekle
* * * * * echo "Cron çalışıyor: $(date)" >> /tmp/cron-test.log 2>&1

Sık karşılaşılan sorunlar ve çözümleri:

  • Komut bulunamıyor: Tam yol kullan veya PATH tanımla
  • İzin hatası: Dosya izinlerini kontrol et, sudo crontab -u kullanici -e kullan
  • Betik çalışmıyor: Shebang satırı var mı? chmod +x yapıldı mı?
  • Mail gelmiyor: /var/mail/kullanici dosyasına bak
  • Saat yanlış: timedatectl ile timezone kontrol et

Systemd Timer Alternatifi

Ubuntu’da artık cron yerine systemd timer kullanmak da mümkün ve bazı avantajları var. Daha iyi log yönetimi, bağımlılık tanımlama ve daha esnek zamanlama imkanı sunar. Ama cron hala çok daha yaygın ve basit. Ağır görevler için systemd timer’ı araştırabilirsin, ama çoğu senaryo için cron yeterlidir.

Crontab Yedekleme

Son olarak çok önemli bir şey: Crontab’ını yedekle! Sistemi yeniden kurduğunda veya bir şeyler ters gittiğinde crontab’ını kaybedebilirsin.

# Manuel yedek
crontab -l > ~/crontab-backup-$(date +%Y%m%d).txt

# Otomatik yedek (cron ile, evet cron'u cron ile yedekle)
0 2 * * * crontab -l > /var/backups/crontab-$(whoami)-$(date +%Y%m%d).txt

# Tüm kullanıcıların crontab'larını yedekle
0 2 * * * for user in $(cut -f1 -d: /etc/passwd); do crontab -l -u $user 2>/dev/null > /var/backups/crontab-${user}-$(date +%Y%m%d).txt; done

Sonuç

Cron basit bir araç ama doğru kullanmak için dikkat gerektiriyor. En sık düşülen hatalar şunlar: Environment sorunları, eksik log yönetimi, güvenliği göz ardı etmek ve yedek almamak. Bu yazıdaki pratikleri uygularsan production ortamında çok daha az sürprizle karşılaşırsın.

Özellikle şu alışkanlıkları edin: Betiklerinde mutlaka logging yap, cron çıktısını asla > /dev/null 2>&1 ile tamamen susturma (en azından hataları yakala), önemli cron görevlerini belgelendir ve crontab’larını düzenli yedekle. Gece 2’de uyandıran o telefonu almak istemiyorsan, cron’unu ciddiye al.

Yorum yapın