Veri Bilimi Okulu

Kubernetes ve Airflow ile "Cloud-Native" Düşünmek: Bir Pull Request Reddi Beni Nasıl Aydınlattı?
Kubernetes ve Airflow ile “Cloud-Native” Düşünmek: Bir Pull Request Reddi Beni Nasıl Aydınlattı?
kubernetes_airflow_isolation_kapak_960x640

Loading

Her şeyin yolunda gittiğini düşündüğün bir an vardır. Yeni ELT projesi için yazdığın Airflow DAG’ı tıkır tıkır çalışıyor, veriler akıyor, testler başarılı. Gururla kodunu ekibin görmesi için Pull Request’e (PR) dönüştürüyorsun. ✨

Kısa bir süre sonra o bildirim gelir. Takım liderin bir yorum bırakmış:

“We cannot except this. No isolation airflow dag and ingestion pyhton code. Please think cloud native way.” 🤔

İlk tepkim bir anlık duraksama ve hayal kırıklığı oldu. “Ama kodum çalışıyor, görevler başarılı oluyor, sorun ne ki?” diye düşündüm. Kodumda KubernetesPodOperator bile kullanmıştım, daha ne kadar “cloud-native” olabilirdim ki?

Bu yorumun aslında bir eleştiri değil, modern veri mühendisliğine bir davet olduğunu anlamam biraz zaman aldı. 💡Bu makale, o daveti anlama, kabul etme ve sonunda “işte şimdi oldu!” deme yolculuğumun hikayesidir.

Eski Alışkanlıklar – Neden “Sadece Çalışması” Yeterli Değil?

İlk bakışta DAG dosyam oldukça standart görünüyordu. Tarih kontrolü yapan, konfigürasyon hazırlayan ve asıl veri çekme işini KubernetesPodOperator ile izole bir ortamda başlatan bir yapı kurmuştum. Sorun da tam olarak bu “hibrit” yapıda saklıymış. Takım liderimin “izolasyon yok” derken kastettiği şey, DAG’ın bütünsel olarak izole olmamasıydı.

ÖNCEKİ YAPI (Problemli Yaklaşım):
# ...
# PythonOperator: Airflow Worker üzerinde çalışan görev
validate_date_task = PythonOperator(
    task_id='validate_execution_date',
    python_callable=check_date_validity,  # Bu fonksiyon Worker'da çalışır
    dag=dag,
)

# KubernetesPodOperator: İzole bir Pod'da çalışan görev
run_ingestion_task = KubernetesPodOperator(
    task_id='run_data_ingestion',
    name='nyc-taxi-data-ingestion',
    image='nyc-taxi-ingestion:latest',  # Kendi izole ortamı var
    # ...
    dag=dag,
)

validate_date_task >> run_ingestion_task

Gördüğünüz gibi, validate_date_task bir PythonOperator kullanıyor. Bu, check_date_validity fonksiyonunun, Airflow’un kendi Worker’ı üzerinde çalıştığı anlamına gelir. Bu, çift ortam yönetimi, bağımlılık çakışmaları ve en önemlisi, uygulamanın mantığının bir kısmının Airflow ortamına “sızması” demekti. 🌪️

Gerçek İzolasyon – Mantığı Uygulamanın İçinde Tutmak

Çözüm, Airflow’u bir görev çalıştırıcı olarak değil, bir orkestratör olarak görmeyi gerektiriyordu. PythonOperator‘dan tamamen kurtulup tüm adımları KubernetesPodOperator ile kendi konteynerinde çalışacak şekilde tasarladık.

SONRAKİ YAPI (Cloud-Native Yaklaşım): ✅
# ...
# Artık PythonOperator yok! Tarih kontrolü de uygulamamızın bir parçası.
validate_date_task = KubernetesPodOperator(
    task_id='validate_execution_date',
    name='nyc-taxi-date-validation',
    image='nyc-taxi-ingestion:latest',  # Aynı uygulama imajı!
    cmds=['python', '-m', 'src.cli'],
    arguments=['validate-date', '--date', '{{ ds }}'],
    # ...
    dag=dag,
)

# Asıl veri çekme görevi de aynı imajı kullanıyor.
run_ingestion_task = KubernetesPodOperator(
    task_id='run_data_ingestion',
    name='nyc-taxi-data-ingestion',
    image='nyc-taxi-ingestion:latest',  # Aynı tutarlı ortam!
    cmds=['python', '-m', 'src.cli'],
    arguments=['single-date', '--date', '{{ ds }}'],
    # ...
    dag=dag,
)

validate_date_task >> run_ingestion_task

Bir Saniye… İşlemi Yapan DAG Dosyası mı, Python Dosyası mı?

Bu noktada aklınıza haklı bir soru takılmış olabilir: “İyi de, şimdi işi .py dosyası mı yapıyor, yoksa KubernetesPodOperator mü? Hangisi doğru?”

Cevap, bu ikisinin rakip değil, birbirini tamamlayan bir operasyon gücü olduğudur. Gelin bu teknik ilişkiyi Türk Hava Kuvvetleri’nden bir operasyon analojisiyle ele alalım:

Görev Pilotu (ayrı bir .py dosyası) 👨‍✈️

Sizin ingestion.py dosyanız, tüm eğitimini tamamlamış, görev brifingini almış, her türlü manevra ve uygulama tekniklerini (kodun mantığını) bilen deneyimli bir görev pilotudur. Görevi, hedefe kilitlenip verilen uçuş planını kusursuzca yerine getirmektir.

Savaş Uçağı (Docker İmajı) ✈️

Bu görev pilotunu, pilot kabinine oturttuğumuz son teknoloji bir savaş uçağı olarak düşünün. Bu uçak (bizim Docker imajımız), pilotun görevi için ihtiyaç duyduğu her şeyi barındırır: yakıt sistemleri, silah sistemleri, aviyonikler, yaşam destek ünitesi. Uçak, pilotu dış tehditlerden tamamen izole eder ve ona görevini yapması için maksimum performansı sunar. Pilot ve uçak, artık tek bir “görev paketi” haline gelmiştir.

Hava Harekat Merkezi (DAG Dosyası) 🏛️

İşte sizin Airflow DAG dosyanız, üssün derinliklerindeki korumalı merkezde bulunan Hava Harekat Merkezi’dir. Harekat Merkezi personeli asla uçak uçurmaz. Onların önünde tüm harekat alanının stratejik haritası (iş akışı) vardır ve tek işleri, doğru zamanda doğru pilota doğru görevi vererek “Kalkışa izin!” emrini vermektir.

Uçak Gemisi ve Güverte Mürettebatı (Kubernetes) 🚢

KubernetesPodOperator ise Hava Harekat Merkezi’nin, uçak gemisinin uçuş kontrolüne gönderdiği bir “görev emri” mesajıdır. Harekat Merkezi emri verdiğinde, devasa uçak gemisi (yani Kubernetes), güvertedeki mürettebatı (planlamacı, düğümler) harekete geçirir. Mancınık fırlatma sistemi (kube-scheduler), pilotun içinde olduğu uçağı (Pod’u) güverteden (node) fırlatır, pilot görevini icra eder ve dönüşte uçağın güverteye güvenle apona etmesini sağlar.

Operasyonel Özet:

Hava Harekat Merkezi (DAG dosyası), KubernetesPodOperator aracılığıyla, Uçak Gemisi’ne (Kubernetes), içinde Görev Pilotu’nun (.py dosyası) bulunduğu Savaş Uçağı’nı (Docker İmajı) fırlatma talimatını verir.

Asıl görevi, yani karmaşık manevraları, hedef tespitini, CPU ve bellek yönetimini her zaman uçağın içindeki Pilot yapar. Hava Harekat Merkezi (DAG) ise sadece doğru görevin, doğru zamanda ve doğru müdahale kurallarıyla başlamasını sağlayan stratejik zekadır. Bu sorumluluk ayrımı, “cloud-native” yaklaşımın temelini oluşturur.

Kısa Bir Not: Packaging ve Configuration

Bu yapının çalışması için iki temel “cloud-native” pratiği hayati önem taşır:

Packaging (Dockerfile): Uygulamanız ve onun Python dependencies’i (requirements.txt), bir Dockerfile aracılığıyla self-contained bir image haline getirilmelidir.

Configuration (Secrets & ConfigMaps): Kodun içine asla credentials gibi sensitive bilgileri yazmayın. Bu bilgiler Kubernetes Secrets ve ConfigMaps ile yönetilir.

Neden Bu Kadar Zahmete Değdi? Kazanımlarımız

Başta gereksiz bir iş gibi görünen bu dönüşüm, aslında projenin geleceği için yapılmış en iyi yatırımlardan biriydi. En önemli kazanımımız gerçek ve tam izolasyon oldu – artık Airflow Worker’larımızın ortamı ile uygulamamızın ortamı arasında sıfır etkileşim var. Bu sayede sürecin her parçası, birebir aynı Docker imajı içinde, aynı kütüphane sürümleriyle çalışır hale geldi ve tutarlı bir çalışma ortamı elde ettik. Airflow mimarimiz de önemli ölçüde basitleşti. Worker’larımız artık hafif birer orkestratöre dönüştü ve gereksiz kompleksiteden kurtulduk. nyc-taxi-ingestion:latest imajımız atomik ve taşınabilir bir mantık haline geldi – artık kendi kendine yeten, her yerde çalıştırılabilir bir araç. Son olarak, hassas kaynak yönetimi imkanı kazandık ve artık her adım için özel kaynak (CPU/RAM) atayabiliyoruz. 📈

Sonuç: Zihniyet Değişikliğinin Gücü

Geriye dönüp baktığımda, takım liderimin o kısa yorumunun ne kadar değerli olduğunu anlıyorum. “Cloud-native” düşünmek, sadece havalı araçlar kullanmak değil; asıl mesele, sorumlulukları ayrıştırma, izolasyonu kutsal sayma ve her bir bileşeni bağımsız birimler olarak tasarlama disiplinidir. Reddedilen o PR, bana sadece daha iyi bir DAG yazmayı değil, daha iyi bir mühendislik bakış açısı kazanmayı öğretti. 🌟 Umarım bu keşif yolculuğu, sizin de bir sonraki projenizde daha sağlam, ölçeklenebilir ve geleceğe dönük sistemler kurmanıza ilham verir.

Kaynaklar

0

Bir yanıt yazın

Password Requirements:

  • At least 8 characters
  • At least 1 lowercase letter
  • At least 1 uppercase letter
  • At least 1 numerical number
  • At least 1 special character