Docker ve Kubernetes'te Cron Job Kapsamlı Rehberi

DevOpsYayın: Güncellendi: 10 dk okumaHazırlayan: cronjob.com.tr Editörleri

Docker içindeki bir betiğin terminalden çalışması, zamanında ve doğru ortamda çalışacağını göstermez. Cron farklı bir kullanıcıyla başlayabilir, loglar container içinde kalabilir veya yeniden oluşturulan container üzerindeki elle girilmiş zamanlama kaybolabilir. Bu rehber, zamanlayıcının nerede duracağına karar vermenizi ve ilk çalışmayı doğrulamanızı sağlar.

Örnekler Linux container kullanan geliştiriciler ve sunucu yöneticileri içindir. Önce küçük bir disk kullanım raporu oluşturacak, ardından aynı işi host cron, Compose veya Kubernetes ile zamanlayacaksınız. Cron job kavramını biliyorsanız doğrudan kuruluma geçebilirsiniz; Docker Desktop kullanırken host crontab örneklerinin Linux sunucuyu hedeflediğini dikkate alın.

Zamanlayıcı Nerede Çalışmalı?

Tek Linux sunucuda zaten cron yönetiyorsanız host üzerinden kısa ömürlü container başlatmak kolay denetlenir. Taşınabilir bir zamanlama paketi istiyorsanız ayrı bir cron container kullanabilirsiniz. Mevcut Kubernetes kümesinde ise CronJob kaynağı, zamanlama ile Pod yaşam döngüsünü birlikte yönetir. Yalnızca birkaç görev için yeni bir küme kurmanız gerekmez.

YöntemUygun ihtiyaçKontrol etmeniz gereken
Host cron ve docker runTek sunucuda bağımsız toplu işlemDocker yetkisi, host logları ve kilit
Ayrı cron containerİmajla birlikte taşınan zamanlamaOrtam, log yönlendirmesi ve tek kopya
Kubernetes CronJobKümede zamanlanmış PodJob süresi, tekrar deneme ve kalıcı veri

Docker, container başına bir sorumluluğu ayırmayı önerir; bu, mutlaka yalnızca bir işletim sistemi süreci bulunacağı anlamına gelmez. Web sunucusuyla cron'u aynı kabuk komutunda başlatmak yerine ayrı servisler kullanmanız kapanışları ve hata teşhisini kolaylaştırır. Süreç yönetimi ayrıntıları Docker süreç belgelerinde açıklanır.

Zamanlayıcıyı kendi sunucunuzda işletmek yerine yönetilen bir hizmete bırakacaksanız hedef türü belirleyicidir: AWS EventBridge ve ECS zamanlaması, Azure Functions Timer Trigger kurulumu veya Google Cloud Scheduler ile HTTP hedefleri farklı çalıştırma modelleri sunar. Bu seçeneklerde container imajı kadar kimlik yetkileri, zaman aşımı ve başarısız çalışmaların nasıl izleneceği de karşılaştırılmalıdır.

Uygulamanın çalışma zamanı da mimariyi etkiler. Go'da goroutine ve cron paketleriyle zamanlama uzun ömürlü bir süreç isterken, Node.js zamanlanmış görev seçenekleri uygulama sürecinin yaşam döngüsüne bağlıdır. Django tarafında veritabanından yönetilen periyotlar için Django Celery Beat ve DatabaseScheduler yaklaşımı, beat ile worker süreçlerinin birlikte çalışmasını gerektirir; container yeniden başlatma politikası bu süreçleri kapsamalıdır.

Görev bir sunucu servisinden çok depo bakımı yapıyorsa CI zamanlayıcıları daha uygun olabilir. GitHub Actions schedule tetikleyicisi ve GitLab pipeline schedule yapılandırması, Docker imajını bir runner üzerinde çalıştırırken depo erişimini iş akışı yetkileriyle ilişkilendirir. Üretim veritabanına erişen işlerde token kapsamını ve çalışma süresini ayrıca sınırlayın.

Yedekleme görevlerinde zamanlayıcı seçimi tek başına yeterli değildir; dump dosyasının kalıcı ve erişimi kısıtlı bir depoya yazılması gerekir. Cron ile veritabanı yedekleme ve geri yükleme sınaması adımlarını uygulayarak container silindiğinde kaybolmayan bir saklama alanı seçin ve yedeğin açılabildiğini ayrı bir ortamda doğrulayın.

Adım Adım: Ayrı Cron Container Kurulumu

Aşağıdaki örnek Debian tabanlı imaj içindir; Alpine üzerindeki BusyBox crond farklı seçenekler ve dosya konumları kullanır. Aynı dizinde üç dosya hazırlayın. Zamanlama dosyasını UTF-8 ve LF satır sonuyla kaydedin, son satırın sonunda yeni satır bırakın.

  1. task.py oluşturun. Betik bağlı veri dizininin disk kullanımını JSON olarak kaydeder. Geçici dosya ve yeniden adlandırma, okuyucunun yarım rapor görmesini önler.
  2. app-cron oluşturun. Bu örnek /etc/cron.d biçimidir; beş zaman alanından sonra kullanıcı adı bulunur.
  3. Dockerfile oluşturun. Cron ön planda çalışır. İmaj oluşturulurken cron başlatılmaz; gerçek çalışma container açıldığında başlar.
  4. İmajı oluşturup deneyin. Önce betiği doğrudan çalıştırın, ardından zamanlayıcıyı başlatıp bir dakika bekleyin ve logu inceleyin.
# task.py
import json
import shutil
from datetime import datetime, timezone
from pathlib import Path

def run_report():
    target = Path("/data")
    target.mkdir(parents=True, exist_ok=True)
    usage = shutil.disk_usage(target)
    report = {
        "at": datetime.now(timezone.utc).isoformat(),
        "total_bytes": usage.total,
        "free_bytes": usage.free,
    }
    temporary = target / "disk.json.tmp"
    temporary.write_text(json.dumps(report), encoding="utf-8")
    temporary.replace(target / "disk.json")
    print(json.dumps(report), flush=True)

if __name__ == "__main__":
    run_report()
# app-cron
SHELL=/bin/sh
PATH=/usr/local/bin:/usr/bin:/bin
* * * * * root /usr/local/bin/python /app/task.py >/proc/1/fd/1 2>/proc/1/fd/2
FROM python:3.12-slim-bookworm
RUN apt-get update && apt-get install -y --no-install-recommends cron \
    && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY task.py /app/task.py
COPY app-cron /etc/cron.d/app-cron
RUN chmod 0644 /etc/cron.d/app-cron
CMD ["cron", "-f"]
docker build -t disk-report:local .
docker volume create cron-data
docker run --rm -v cron-data:/data disk-report:local python /app/task.py
docker run -d --name disk-cron -v cron-data:/data disk-report:local
docker logs --tail 20 disk-cron
docker exec disk-cron cat /data/disk.json

Burada sistem zamanlama dosyasını ayrıca crontab komutuyla yüklemeyin. Kullanıcı crontab'ında kullanıcı sütunu yoktur; iki biçimi birleştirmek yanlış komut yorumlanmasına veya çift çalışmaya yol açar. Dosya biçimi ve izinler için Debian crontab kılavuzunu esas alın. Gerçek sunucuda imaj etiketinizi veya digest değerini sabitleyin ve güvenlik güncellemelerini planlayın.

Host Cron ve Docker Compose ile Çalıştırma

Host cron tercih ederseniz yukarıdaki sürekli çalışan disk-cron container'ını aynı iş için açık bırakmayın. Aksi halde iki ayrı zamanlayıcı raporu yazar. Önce host üzerinde docker ve flock konumlarını kontrol edin; aşağıdaki yollar Linux dağıtımınıza göre değişebilir. Log ve kilit dosyasının dizinleri cron kullanıcısına yazılabilir olmalıdır.

# Linux host kullanıcısının crontab -e kaydı; kullanıcı sütunu yoktur
*/5 * * * * /usr/bin/flock -n /home/ops/disk-report.lock /usr/bin/docker run --rm -v cron-data:/data disk-report:local python /app/task.py >>/home/ops/disk-report.log 2>&1

flock aynı host üzerindeki bu kayıtları çakıştırmaz; farklı makinelerdeki işleri kilitlemez. docker run -d kullanmayın: komut arka plana geçerse host kilidi iş bitmeden bırakılır. Mevcut bir container'a bağımlı docker exec yaklaşımıysa uygulama yeniden başlarken görev kaçırabilir. Linux tarafındaki kullanıcı ve ortam ayrıntılarını Linux cron kurulumu rehberinde bulabilirsiniz.

# compose.yaml
services:
  report:
    image: disk-report:local
    volumes:
      - cron-data:/data
volumes:
  cron-data:
    external: true
docker compose -f /opt/reports/compose.yaml run --rm -T report python /app/task.py

Compose örneği önceden oluşturduğunuz aynı volume'u kullanır; cron satırında docker run yerine bu komutu koyabilirsiniz. -T terminal ayırmayı kapatır. Veritabanına bağlanan gerçek işlerinizde yalnızca başlatma sırasına güvenmeyin: sağlık kontrolü ve bağlantı için sınırlı tekrar deneme ekleyin. Compose başlangıç sırası belgesi, çalışıyor durumuyla hazır olma arasındaki farkı açıklar.

Kubernetes CronJob Manifesti ve Doğrulama

Kümede ilk deneme için uygulama bağımlılığı olmayan bu manifesti kullanın. UTC zamanını her beş dakikada bir loglar. Disk raporunu taşırken erişilebilir bir uygulama imajı ve ihtiyacınıza uygun PersistentVolumeClaim ekleyin; boş bir Pod dosya sistemi kalıcı rapor deposu değildir.

apiVersion: batch/v1
kind: CronJob
metadata:
  name: zaman-kontrol
spec:
  schedule: "*/5 * * * *"
  timeZone: "Europe/Istanbul"
  concurrencyPolicy: Forbid
  startingDeadlineSeconds: 120
  successfulJobsHistoryLimit: 2
  failedJobsHistoryLimit: 2
  jobTemplate:
    spec:
      backoffLimit: 1
      activeDeadlineSeconds: 240
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: kontrol
              image: busybox:1.36
              command: ["/bin/sh", "-c", "date -u"]
              resources:
                requests:
                  cpu: "10m"
                  memory: "16Mi"
                limits:
                  cpu: "100m"
                  memory: "32Mi"
kubectl apply -f cronjob.yaml
kubectl get cronjobs
kubectl create job --from=cronjob/zaman-kontrol zaman-kontrol-deneme
kubectl logs job/zaman-kontrol-deneme
kubectl describe cronjob zaman-kontrol
kubectl get jobs

Forbid yalnızca aynı CronJob'un oluşturduğu işler arasındaki eşzamanlılığı sınırlar; elle oluşturduğunuz deneme Job'u ayrı değerlendirin. Başlatma gecikme sınırı ile toplam çalışma süresi farklıdır. timeZone alanı Kubernetes 1.27'den itibaren kararlıdır; belirtilmezse denetleyicinin yerel saat dilimi kullanılır, otomatik olarak UTC varsaymayın. Kubernetes tam bir kez çalıştırma garantisi vermez. Bu davranışlar resmî CronJob belgesinde anlatılır.

Loglar, Ortam ve Güvenli Çalışma

Örnekte root görev çıktısını PID 1'in standart çıktı ve hata akışlarına gönderir. Yalnızca /var/log altına yazılan dosya, docker logs ekranında kendiliğinden görünmez. Başlangıç ve bitiş zamanını, iş kimliğini, işlenen kayıt sayısını ve hata durumunu kaydedin; erişim token'ını yazmayın. Docker log belgesi standart akışların rolünü açıklar.

Cron ortamının interaktif terminalinizle aynı olduğunu varsaymayın. Betikte mutlak yollar kullanın; hassas ayarları erişimi kısıtlı dosyalardan okuyun. Bütün ortamı herkese okunabilir bir dosyaya dökmeyin. /proc yönlendirmesini farklı kullanıcıyla kullanacaksanız erişimini ayrıca sınayın. Docker soketini bir HTTP servisine bağlamak yerine yalnızca gerekli işlevi uygulama içinde sunun.

Gerçek Senaryolar: Rapor ve Dosya Temizliği

Disk doluluğu raporu: Yukarıdaki görevi beş dakikada bir çalıştırarak yedeklerin yazıldığı volume üzerindeki boş alanı kaydedebilirsiniz. Kontrol ettiğiniz dosya sisteminin gerçekten yedek deposu olduğundan emin olun. JSON raporunun güncellenmesi depolamaya yazılabildiğini gösterir; tek başına uyarı göndermez. Eşik aşımını izleyen uygulamanız raporun tarihini de kontrol etmelidir.

Geçici dışa aktarımların temizlenmesi: Her gece 03:00'te yalnızca uygulamaya ayrılmış /data/exports dizinindeki süresi geçmiş dosyaları seçin. Önce silmeden aday listesini kaydedin, sonra işaretlenen kayıtların hâlâ kullanılmadığını doğrulayın. Kullanıcı yüklemeleriyle geçici raporları aynı klasörde tutmayın. Tekrar çalışan temizlik zaten kaldırılmış dosyayı güvenle atlamalı; devam eden dışa aktarımı silmemelidir.

Sık Hatalar ve Çözümleri

/bin/sh: 1: root: not found

Sistem crontab'ındaki kullanıcı sütununu kullanıcı crontab'ına aktarmış olabilirsiniz. Kaydın nereden yüklendiğini belirleyin. /etc/cron.d altında root sütununu tutun; crontab -e içinde kaldırın. Aynı kaydın iki yerde bulunmadığını da kontrol edin.

Permission denied veya python: not found

İlk hata dosya veya dizin erişimini, ikincisi çalıştırılabilir program yolunu işaret edebilir. İlgili kullanıcıyla veri dizinine yazmayı deneyin ve Python yolunu container içinde doğrulayın. Çözüm olarak bütün dizine sınırsız izin vermeyin; gereken kullanıcıya gereken dizin erişimini tanımlayın.

Container çalışıyor ama log boş

Cron'un açık olması işin başarıyla çalıştığını kanıtlamaz. Zamanlama dosyasının adını, 0644 iznini, LF satır sonunu ve son yeni satırını kontrol edin. Betiği elle çalıştırıp çıktıyı doğrulayın; ardından cron zamanını bekleyin. Genel kontrol sırası için cron çalışmıyor rehberini kullanabilirsiniz.

Cannot connect to the Docker daemon

Host cron kullanıcısı Docker daemon'a erişemiyor veya daemon çalışmıyor olabilir. Aynı kullanıcıyla docker info çalıştırın. Yetki modelini sunucu politikanıza göre düzeltin; Docker soketini herkese yazılabilir yapmak güvenli bir çözüm değildir.

Kubernetes'te ImagePullBackOff veya işler üst üste biniyor

ImagePullBackOff durumunda Pod olaylarından imaj adı, registry erişimi ve çekme yetkisini inceleyin. Çakışmada birden fazla CronJob veya elle oluşturulan Job arayın. İşin bitiş süresini ölçün; zamanlayıcı kilidine ek olarak iş sonucuna benzersiz bir dönem anahtarı koyun.

cronjob.com.tr ile HTTP Tabanlı Alternatif

Uygulamanız dışarıdan erişilebilir HTTPS uç noktası sunuyorsa host crontab yerine HTTP tetikleme kullanabilirsiniz. Aşağıdaki server.py aynı disk raporunu sabit bir POST yoluyla çalıştırır; Docker daemon komutu kabul etmez. Bu temel örneği üretimde HTTPS sağlayan ters vekil arkasında, yalnızca ihtiyaç duyulan veri volume'una erişen uygulama kullanıcısıyla çalıştırın.

# server.py; task.py ile aynı dizinde
import hmac
import os
from http.server import BaseHTTPRequestHandler, HTTPServer
from task import run_report

TOKEN = os.environ["CRON_HTTP_TOKEN"]
if not TOKEN:
    raise RuntimeError("CRON_HTTP_TOKEN boş olamaz")

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path != "/internal/disk-report":
            self.send_error(404)
            return
        supplied = self.headers.get("X-Cron-Token", "")
        if not hmac.compare_digest(
            supplied.encode("utf-8"), TOKEN.encode("utf-8")
        ):
            self.send_error(403)
            return
        try:
            run_report()
        except Exception:
            self.send_error(500)
            return
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b'{"status":"completed"}')

HTTPServer(("0.0.0.0", 8080), Handler).serve_forever()
  1. server.py dosyasını HTTP uygulama imajınıza ekleyin; sunucu ortamında uzun, rastgele CRON_HTTP_TOKEN tanımlayın. Gizli değeri imaja veya URL'ye koymayın.
  2. Panelde HTTPS URL'nizi, POST metodunu ve X-Cron-Token özel header'ını girin. Beş dakikalık hazır aralığı ve iş saat dilimini seçin.
  3. Önce yanlış token ile 403, doğru token ile 200 döndüğünü doğrulayın; sonra panelden manuel çalıştırın. Bu işin diğer zamanlayıcısını kapatın.

cronjob.com.tr yerel veya özel ağ adreslerine erişmez ve HTTPS sertifikasını doğrular. Hazır bir dakikalık aralıkta bekleme 55 saniye, beş dakika ve üzerindeki aralıklarda ve cron ifadeli işlerde 290 saniyedir. Uzun işlemleri kuyruğa devrediyorsanız 202 yalnızca kabulü ifade eder; tamamlanmayı uygulamada izleyin.

Bağlantı hatası olmadan HTTP 200–399 başarı sayılır. Ardışık hata eşiği varsayılan 3 olup 1–20 arasında ayarlanabilir; eşik aşılınca erişim sorunu, düzelince kesinti süresiyle düzeldi e-postası gönderilir. Aynı işte bildirimler arasında en az 60 dakika vardır. Çalışma kayıtları 7 gün saklanır; kuyrukta sonradan oluşan hata HTTP başarısına yansımaz.

Sıkça Sorulan Sorular (SSS)

Cron dosyasını neden crontab komutuyla yüklemiyoruz?

Bu örnek /etc/cron.d sistem biçimini kullanır ve kullanıcı sütunu içerir. Kullanıcı crontab biçimi farklıdır; dosyayı iki yöntemle birden kurmak yanlış yorumlamaya veya çift çalışmaya neden olabilir.

docker logs neden görev çıktısını göstermiyor?

Görev yalnızca container içindeki bir dosyaya yazıyorsa çıktı standart akışlara ulaşmaz. Uygun izinlerle stdout ve stderr yönlendirmesi yapın veya kullandığınız log toplama sistemine dosyayı açıkça tanıtın.

Container yeniden oluşturulunca raporlar kaybolur mu?

Yalnızca container dosya sistemine yazılan raporlara güvenmeyin. Örnekteki gibi kalıcı volume kullanın ve volume için ayrıca yedekleme politikası belirleyin; volume kullanmak tek başına yedek almak değildir.

Forbid aynı işin yalnızca bir kez çalışmasını garanti eder mi?

Hayır. Forbid aynı CronJob kaynağının eşzamanlı Job'larını sınırlar. Elle başlatılan işler, başka zamanlayıcılar ve tekrar denemeler için uygulamanızda ayrıca benzersiz iş anahtarı veya ortak kilit kullanmanız gerekir.

HTTP Görevinizi Zamanlayın

cronjob.com.tr ile HTTPS uç noktanızı ücretsiz zamanlayın. Kayıtta kredi kartı istenmez.

Ücretsiz Başla →

İlgili Rehberler