Bir Pod Running Olabilir ve Yine de Hiçbir Yere Gitmiyor Olabilir
LiteLLM local'de çalıştı, sonra e2-small GKE node'larımda ne kadar az yer kaldığını tam olarak ortaya çıkardı.
LiteLLM laptop’ımda sorunsuzdu.
Proxy’i ekledim, ajanları ona yönlendirdim, fallback davranışını test ettim ve devam ettim. İlginç kısım, aynı kurulumu GKE’ye deploy ettiğimde başladı.
LiteLLM pod’u healthy olmadı. İlk başta bunu bir container konfigürasyon sorunu gibi ele aldım. Değildi.
İlk işe yarayan sayı %97’ydi
kubectl describe memory sorunu gösterdi, ben de LiteLLM limitini artırdım. Bu sadece hata modunu değiştirdi: öldürülmek yerine pod Pending’de kaldı.
Sonra container yerine node’a baktım.
e2-small node’lardan biri zaten yaklaşık %97 memory tahsisindeydi. Her node’un başlangıçta zaten sadece yaklaşık 2 GB RAM’i vardı ve bu memory; API, UI, Kubernetes sistem bileşenleri ve bilerek ucuz tutulan bu cluster’a sıkıştırdığım her şey tarafından paylaşılıyordu.
Var olmayan bir memory’i yaratabilecek akıllıca bir YAML ayarı yoktu.
API request’ini 256Mi’den 128Mi’ye, sonra 64Mi’ye düşürdüm, çoğunlukla kurulumu ne kadar zorlayabileceğimi görmek için. LiteLLM sonunda schedule edildi.
Hâlâ healthy değildi.
“Running” olmak, hazır olmakla aynı şey değildi
Bir noktada API container’ı iyiydi ama pod’un LiteLLM tarafı 1/2 Running’de takılı kalıyordu. İşe yarar log yoktu. Health probe’lar başarısız oldu. Port-forwarding bağlandı ama boş bir cevap döndürdü.
İmajı ayrıca ayağa kaldırdım ve yol boyunca başka bir sorun buldum: command’ı, imajın entrypoint’i yokmuş gibi override etmiştim.
Command’ım fiilen şuna dönüşüyordu:
litellm litellm --config ...
Gerçek binary path’ini kullanmak bu hatayı düzeltti:
/app/.venv/bin/litellm
Bu gerçek bir bug’dı, ama yine de ana kısıt değildi.
LiteLLM’i ayrı bir Deployment olarak tutmak yerine API container’ının yanına koyduğum sidecar yolunu da denedim. Bu topolojiyi değiştirdi, node’daki RAM miktarını değil. Pod hâlâ node’un verebileceğinden daha fazla memory isteyebiliyordu.
Aynı debug oturumu sırasında bir spot node preempt edildi ve NotReady’e düştü, bu da başka bir gürültü katmanı ekledi. Bir pod, artık agent’ı bulunmayan bir node’a takılı kaldı. Onu silip Kubernetes’in yeniden schedule etmesine izin vermek bu semptomu düzeltti.
Bu denemelerin hiçbiri temel aritmetiği değiştirmedi.
Local’deki başarı kısıtı gizliyordu
Local’de LiteLLM’e hiçbir zaman sıkı bir container memory limiti vermemiştim. Host’ta ne varsa onu kullanabiliyordu.
GKE’de her request ve limit önemliydi çünkü cluster bilerek küçük tutulmuştu.
Bu fark, local ortamı production davranışı için kötü bir öngörücü yaptı.
Şüphem, LiteLLM’in startup sürecinin steady state’inden daha fazla memory’e ihtiyaç duyduğuydu—model metadata’sı, cost map’leri, router state’i ve ilgili kurulumu yüklerken. Zaten kapasitesine yakın bir node’da, kısa süreli bir spike bile startup’ı güvenilmez kılmaya yetiyordu.
Cluster’ı hemen büyütmek yerine durdurdum.
Bu proje için doğru karar buydu. Trafik neredeyse yoktu ve CairnOps’un tüm amacı sıfır maliyet ya da çok düşük maliyet kısıtı içinde öğrenmekti. Sadece bir bileşeni rahat ettirmek için daha büyük node’lara para ödemek, anlamaya çalıştığım mimari trade-off’u gizlerdi.
Hata ilk başta bir LiteLLM sorunu gibi görünüyordu.
Sonunda LiteLLM şeklinde bir semptomu olan bir kapasite planlama sorunu olduğu ortaya çıktı.