Container'larda FastAPI - Docker¶
🌐 Translation by AI and humans
This translation was made by AI guided by humans. 🤝
It could have mistakes of misunderstanding the original meaning, or looking unnatural, etc. 🤖
You can improve this translation by helping us guide the AI LLM better.
FastAPI uygulamalarını deploy ederken yaygın bir yaklaşım, bir Linux container image oluşturmaktır. Bu genellikle Docker kullanılarak yapılır. Ardından bu container image'ı birkaç farklı yöntemden biriyle deploy edebilirsiniz.
Linux container'ları kullanmanın güvenlik, tekrarlanabilirlik, basitlik gibi birçok avantajı vardır.
İpucu
Aceleniz var ve bunları zaten biliyor musunuz? Aşağıdaki Dockerfile'a atlayın 👇.
Dockerfile Önizleme 👀
FROM python:3.9
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
# If running behind a proxy like Nginx or Traefik add --proxy-headers
# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
Container Nedir¶
Container'lar (özellikle Linux container'ları), bir uygulamayı tüm bağımlılıkları ve gerekli dosyalarıyla birlikte paketlemenin, aynı sistemdeki diğer container'lardan (diğer uygulama ya da bileşenlerden) izole tutarken yapılan, çok hafif bir yoludur.
Linux container'ları, host'un (makine, sanal makine, cloud server vb.) aynı Linux kernel'ini kullanarak çalışır. Bu da, tüm bir işletim sistemini emüle eden tam sanal makinelere kıyasla çok daha hafif oldukları anlamına gelir.
Bu sayede container'lar az kaynak tüketir; süreçleri doğrudan çalıştırmaya benzer bir seviyede (bir sanal makine çok daha fazla tüketirdi).
Container'ların ayrıca kendi izole çalışan process'leri (çoğunlukla tek bir process), dosya sistemi ve ağı vardır. Bu da deployment, güvenlik, geliştirme vb. süreçleri kolaylaştırır.
Container Image Nedir¶
Bir container, bir container image'dan çalıştırılır.
Container image; bir container içinde bulunması gereken tüm dosyaların, environment variable'ların ve varsayılan komut/programın statik bir sürümüdür. Buradaki statik, container image'ının çalışmadığı, execute edilmediği; sadece paketlenmiş dosyalar ve metadata olduğu anlamına gelir.
Depolanmış statik içerik olan "container image"ın aksine, "container" normalde çalışan instance'ı, yani execute edilen şeyi ifade eder.
Container başlatılıp çalıştığında (bir container image'dan başlatılır), dosyalar oluşturabilir/değiştirebilir, environment variable'ları değiştirebilir vb. Bu değişiklikler sadece o container içinde kalır; alttaki container image'da kalıcı olmaz (diske kaydedilmez).
Bir container image, program dosyası ve içeriklerine benzetilebilir; örn. python ve main.py gibi bir dosya.
Ve container'ın kendisi (container image'a karşıt olarak) image'ın gerçek çalışan instance'ıdır; bir process'e benzer. Hatta bir container, yalnızca içinde çalışan bir process varken çalışır (ve genelde tek process olur). İçinde çalışan process kalmayınca container durur.
Container Image'lar¶
Docker, container image ve container oluşturup yönetmek için kullanılan başlıca araçlardan biri olmuştur.
Ayrıca birçok araç, ortam, veritabanı ve uygulama için önceden hazırlanmış resmi container image'ların bulunduğu herkese açık bir Docker Hub vardır.
Örneğin, resmi bir Python Image bulunur.
Ve veritabanları gibi farklı şeyler için de birçok image vardır; örneğin:
- PostgreSQL
- MySQL
- MongoDB
- Redis, vb.
Hazır bir container image kullanarak farklı araçları birleştirmek ve birlikte kullanmak çok kolaydır. Örneğin yeni bir veritabanını denemek için. Çoğu durumda resmi image'ları kullanıp sadece environment variable'lar ile yapılandırmanız yeterlidir.
Bu şekilde, çoğu zaman container'lar ve Docker hakkında öğrendiklerinizi farklı araç ve bileşenlerde tekrar kullanabilirsiniz.
Dolayısıyla; veritabanı, Python uygulaması, React frontend uygulaması olan bir web server gibi farklı şeyler için birden fazla container çalıştırır ve bunları internal network üzerinden birbirine bağlarsınız.
Docker veya Kubernetes gibi tüm container yönetim sistemlerinde bu ağ özellikleri entegre olarak bulunur.
Container'lar ve Process'ler¶
Bir container image normalde metadata içinde, container başlatıldığında çalıştırılacak varsayılan program/komutu ve o programa geçirilecek parametreleri içerir. Bu, komut satırında yazacağınız şeye çok benzer.
Bir container başlatıldığında bu komutu/programı çalıştırır (ancak isterseniz bunu override edip başka bir komut/program çalıştırabilirsiniz).
Bir container, ana process (komut/program) çalıştığı sürece çalışır.
Container'larda normalde tek bir process olur. Ancak ana process içinden subprocess'ler başlatmak da mümkündür; böylece aynı container içinde birden fazla process olur.
Ama en az bir çalışan process olmadan çalışan bir container olamaz. Ana process durursa container da durur.
FastAPI için Docker Image Oluşturalım¶
Tamam, şimdi bir şeyler inşa edelim! 🚀
Resmi Python image'ını temel alarak, FastAPI için sıfırdan bir Docker image nasıl oluşturulur göstereceğim.
Bu, örneğin şu durumlarda çoğu zaman yapmak isteyeceğiniz şeydir:
- Kubernetes veya benzeri araçlar kullanırken
- Raspberry Pi üzerinde çalıştırırken
- Container image'ınızı sizin için çalıştıran bir cloud servisi kullanırken, vb.
Paket Gereksinimleri¶
Uygulamanızın paket gereksinimleri genelde bir dosyada yer alır.
Bu, gereksinimleri yüklemek için kullandığınız araca göre değişir.
En yaygın yöntem, paket adları ve versiyonlarının satır satır yazıldığı bir requirements.txt dosyasına sahip olmaktır.
Versiyon aralıklarını belirlemek için elbette FastAPI sürümleri hakkında bölümünde okuduğunuz fikirleri kullanırsınız.
Örneğin requirements.txt şöyle görünebilir:
fastapi[standard]>=0.113.0,<0.114.0
pydantic>=2.7.0,<3.0.0
Ve bu bağımlılıkları normalde pip ile yüklersiniz, örneğin:
$ pip install -r requirements.txt
---> 100%
Successfully installed fastapi pydantic
Bilgi
Paket bağımlılıklarını tanımlamak ve yüklemek için başka formatlar ve araçlar da vardır.
FastAPI Kodunu Oluşturun¶
- Bir
appdizini oluşturun ve içine girin. - Boş bir
__init__.pydosyası oluşturun. - Aşağıdakilerle bir
main.pydosyası oluşturun:
from typing import Union
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
Dockerfile¶
Şimdi aynı proje dizininde Dockerfile adlı bir dosya oluşturun ve içine şunları yazın:
# (1)!
FROM python:3.9
# (2)!
WORKDIR /code
# (3)!
COPY ./requirements.txt /code/requirements.txt
# (4)!
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
# (5)!
COPY ./app /code/app
# (6)!
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
-
Resmi Python base image'ından başlayın.
-
Geçerli çalışma dizinini
/codeolarak ayarlayın.requirements.txtdosyasını veappdizinini buraya koyacağız. -
Gereksinimleri içeren dosyayı
/codedizinine kopyalayın.Önce kodun tamamını değil, sadece gereksinim dosyasını kopyalayın.
Bu dosya çok sık değişmediği için Docker bunu tespit eder ve bu adımda cache kullanır; böylece bir sonraki adım için de cache devreye girer.
-
Gereksinim dosyasındaki paket bağımlılıklarını yükleyin.
--no-cache-dirseçeneği, indirilen paketlerin yerel olarak kaydedilmemesinipip'e söyler. Bu kayıt,pipaynı paketleri tekrar yüklemek için yeniden çalıştırılacaksa işe yarar; ancak container'larla çalışırken genelde bu durum geçerli değildir.Not
--no-cache-diryalnızcapipile ilgilidir; Docker veya container'larla ilgili değildir.--upgradeseçeneği, paketler zaten yüklüysepip'e onları yükseltmesini söyler.Bir önceki adım (dosyayı kopyalama) Docker cache tarafından tespit edilebildiği için, bu adım da uygun olduğunda Docker cache'i kullanır.
Bu adımda cache kullanmak, geliştirme sırasında image'ı tekrar tekrar build ederken size çok zaman kazandırır; her seferinde bağımlılıkları indirip yüklemek zorunda kalmazsınız.
-
./appdizinini/codedizininin içine kopyalayın.Burada en sık değişen şey olan kodun tamamı bulunduğundan, bu adım (ve genelde bundan sonraki adımlar) için Docker cache'i kolay kolay kullanılamaz.
Bu yüzden, container image build sürelerini optimize etmek için bunu
Dockerfile'ın sonlarına yakın koymak önemlidir. -
Altta Uvicorn kullanan
fastapi runkomutunu command olarak ayarlayın.CMDbir string listesi alır; bu string'lerin her biri komut satırında boşlukla ayrılmış şekilde yazacağınız parçaları temsil eder.Bu komut, yukarıda
WORKDIR /codeile ayarladığınız/codedizininden çalıştırılır.
İpucu
Kod içindeki her numara balonuna tıklayarak her satırın ne yaptığını gözden geçirin. 👆
Uyarı
Aşağıda açıklandığı gibi CMD talimatının her zaman exec form'unu kullandığınızdan emin olun.
CMD Kullanımı - Exec Form¶
CMD Docker talimatı iki formda yazılabilir:
✅ Exec form:
# ✅ Do this
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
⛔️ Shell form:
# ⛔️ Don't do this
CMD fastapi run app/main.py --port 80
FastAPI'nin düzgün şekilde kapanabilmesi ve lifespan event'lerinin tetiklenmesi için her zaman exec formunu kullanın.
Detaylar için shell ve exec form için Docker dokümanlarına bakabilirsiniz.
Bu durum docker compose kullanırken oldukça belirgin olabilir. Daha teknik detaylar için şu Docker Compose FAQ bölümüne bakın: Why do my services take 10 seconds to recreate or stop?.
Dizin Yapısı¶
Artık dizin yapınız şöyle olmalı:
.
├── app
│ ├── __init__.py
│ └── main.py
├── Dockerfile
└── requirements.txt
TLS Termination Proxy Arkasında¶
Container'ınızı Nginx veya Traefik gibi bir TLS Termination Proxy (load balancer) arkasında çalıştırıyorsanız --proxy-headers seçeneğini ekleyin. Bu, Uvicorn'a (FastAPI CLI üzerinden) uygulamanın HTTPS arkasında çalıştığını söyleyen proxy header'larına güvenmesini söyler.
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
Docker Cache¶
Bu Dockerfile içinde önemli bir numara var: önce kodun geri kalanını değil, sadece bağımlılık dosyasını kopyalıyoruz. Nedenini anlatayım.
COPY ./requirements.txt /code/requirements.txt
Docker ve benzeri araçlar bu container image'larını artımlı (incremental) olarak build eder; Dockerfile'ın en üstünden başlayıp her talimatın oluşturduğu dosyaları ekleyerek katman katman (layer) ilerler.
Docker ve benzeri araçlar image build ederken ayrıca bir internal cache kullanır. Son build'den beri bir dosya değişmediyse, dosyayı tekrar kopyalayıp sıfırdan yeni bir layer oluşturmak yerine, daha önce oluşturulan aynı layer'ı yeniden kullanır.
Sadece dosya kopyalamayı azaltmak her zaman büyük fark yaratmaz. Ancak o adımda cache kullanıldığı için, bir sonraki adımda da cache kullanılabilir. Örneğin bağımlılıkları yükleyen şu talimat için:
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
Paket gereksinimleri dosyası sık sık değişmez. Bu yüzden sadece bu dosyayı kopyalayınca, Docker bu adımda cache kullanabilir.
Sonra Docker, bağımlılıkları indirip yükleyen bir sonraki adımda da cache kullanabilir. Asıl çok zaman kazandığımız yer de burasıdır. ✨ ...ve beklerken sıkılmayı engeller. 😪😆
Bağımlılıkları indirip yüklemek dakikalar sürebilir, fakat cache kullanmak en fazla saniyeler alır.
Geliştirme sırasında kod değişikliklerinizin çalıştığını kontrol etmek için container image'ı tekrar tekrar build edeceğinizden, bu ciddi birikimli zaman kazancı sağlar.
Sonra Dockerfile'ın sonlarına doğru tüm kodu kopyalarız. En sık değişen kısım bu olduğu için sona koyarız; çünkü neredeyse her zaman bu adımdan sonra gelen adımlar cache kullanamaz.
COPY ./app /code/app
Docker Image'ını Build Edin¶
Tüm dosyalar hazır olduğuna göre container image'ı build edelim.
- Proje dizinine gidin (
Dockerfile'ınızın olduğu veappdizininizi içeren dizin). - FastAPI image'ınızı build edin:
$ docker build -t myimage .
---> 100%
İpucu
Sondaki . ifadesine dikkat edin; ./ ile aynı anlama gelir ve Docker'a container image build etmek için hangi dizini kullanacağını söyler.
Bu örnekte, mevcut dizindir (.).
Docker Container'ını Başlatın¶
- Image'ınızdan bir container çalıştırın:
$ docker run -d --name mycontainer -p 80:80 myimage
Kontrol Edin¶
Docker container'ınızın URL'inden kontrol edebilmelisiniz. Örneğin: http://192.168.99.100/items/5?q=somequery veya http://127.0.0.1/items/5?q=somequery (ya da Docker host'unuzu kullanarak eşdeğeri).
Şuna benzer bir şey görürsünüz:
{"item_id": 5, "q": "somequery"}
Etkileşimli API Dokümanları¶
Şimdi http://192.168.99.100/docs veya http://127.0.0.1/docs adresine gidebilirsiniz (ya da Docker host'unuzla eşdeğeri).
Otomatik etkileşimli API dokümantasyonunu görürsünüz ( Swagger UI tarafından sağlanır):

Alternatif API Dokümanları¶
Ayrıca http://192.168.99.100/redoc veya http://127.0.0.1/redoc adresine de gidebilirsiniz (ya da Docker host'unuzla eşdeğeri).
Alternatif otomatik dokümantasyonu görürsünüz (ReDoc tarafından sağlanır):

Tek Dosyalık FastAPI ile Docker Image Oluşturma¶
FastAPI uygulamanız tek bir dosyaysa; örneğin ./app dizini olmadan sadece main.py varsa, dosya yapınız şöyle olabilir:
.
├── Dockerfile
├── main.py
└── requirements.txt
Bu durumda Dockerfile içinde dosyayı kopyaladığınız path'leri buna göre değiştirmeniz yeterlidir:
FROM python:3.9
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
# (1)!
COPY ./main.py /code/
# (2)!
CMD ["fastapi", "run", "main.py", "--port", "80"]
-
main.pydosyasını doğrudan/codedizinine kopyalayın (herhangi bir./appdizini olmadan). -
Tek dosya olan
main.pyiçindeki uygulamanızı sunmak içinfastapi runkullanın.
Dosyayı fastapi run'a verdiğinizde, bunun bir package'ın parçası değil tek bir dosya olduğunu otomatik olarak algılar; nasıl import edip FastAPI uygulamanızı nasıl serve edeceğini bilir. 😎
Deployment Kavramları¶
Aynı Deployment Kavramlarını bu kez container'lar açısından tekrar konuşalım.
Container'lar, bir uygulamayı build etme ve deploy etme sürecini basitleştiren bir araçtır. Ancak bu deployment kavramlarını ele almak için belirli bir yaklaşımı zorunlu kılmazlar; birkaç farklı strateji mümkündür.
İyi haber şu: Hangi stratejiyi seçerseniz seçin, deployment kavramlarının tamamını kapsayacak bir yol vardır. 🎉
Bu deployment kavramlarını container'lar açısından gözden geçirelim:
- HTTPS
- Startup'ta çalıştırma
- Restart'lar
- Replication (çalışan process sayısı)
- Memory
- Başlatmadan önceki adımlar
HTTPS¶
Bir FastAPI uygulamasının sadece container image'ına (ve sonra çalışan container'a) odaklanırsak, HTTPS genellikle haricen başka bir araçla ele alınır.
Örneğin Traefik kullanan başka bir container olabilir; HTTPS ve sertifikaların otomatik alınmasını o yönetebilir.
İpucu
Traefik; Docker, Kubernetes ve diğerleriyle entegre çalışır. Bu sayede container'larınız için HTTPS'i kurup yapılandırmak oldukça kolaydır.
Alternatif olarak HTTPS, bir cloud provider'ın sunduğu servislerden biri tarafından da yönetilebilir (uygulama yine container içinde çalışırken).
Startup'ta Çalıştırma ve Restart'lar¶
Container'ınızı başlatıp çalıştırmaktan sorumlu genellikle başka bir araç olur.
Bu; doğrudan Docker, Docker Compose, Kubernetes, bir cloud service vb. olabilir.
Çoğu (veya tüm) durumda, container'ı startup'ta çalıştırmayı ve hata durumlarında restart'ları etkinleştirmeyi sağlayan basit bir seçenek vardır. Örneğin Docker'da bu, --restart komut satırı seçeneğidir.
Container kullanmadan, uygulamaları startup'ta çalıştırmak ve restart mekanizması eklemek zahmetli ve zor olabilir. Ancak container'larla çalışırken çoğu zaman bu işlevler varsayılan olarak hazır gelir. ✨
Replication - Process Sayısı¶
Kubernetes, Docker Swarm Mode, Nomad veya benzeri, birden fazla makinede dağıtık container'ları yöneten karmaşık bir sistemle kurulmuş bir cluster'ınız varsa, replication'ı her container içinde bir process manager (ör. worker'lı Uvicorn) kullanarak yönetmek yerine, muhtemelen cluster seviyesinde ele almak istersiniz.
Kubernetes gibi dağıtık container yönetim sistemleri, gelen request'ler için load balancing desteği sunarken aynı zamanda container replication'ını yönetmek için entegre mekanizmalara sahiptir. Hepsi cluster seviyesinde.
Bu tür durumlarda, yukarıda anlatıldığı gibi bağımlılıkları yükleyip sıfırdan bir Docker image build etmek ve birden fazla Uvicorn worker kullanmak yerine tek bir Uvicorn process çalıştırmak istersiniz.
Load Balancer¶
Container'lar kullanırken, genellikle ana port'ta dinleyen bir bileşen olur. Bu, HTTPS'i ele almak için bir TLS Termination Proxy olan başka bir container da olabilir ya da benzeri bir araç olabilir.
Bu bileşen request'lerin yükünü alıp worker'lar arasında (umarım) dengeli şekilde dağıttığı için yaygın olarak Load Balancer diye de adlandırılır.
İpucu
HTTPS için kullanılan aynı TLS Termination Proxy bileşeni muhtemelen bir Load Balancer olarak da çalışır.
Container'larla çalışırken, onları başlatıp yönettiğiniz sistem; bu load balancer'dan (aynı zamanda TLS Termination Proxy de olabilir) uygulamanızın bulunduğu container(lar)a network communication'ı (ör. HTTP request'leri) iletmek için zaten dahili araçlar sunar.
Tek Load Balancer - Çoklu Worker Container¶
Kubernetes veya benzeri dağıtık container yönetim sistemleriyle çalışırken, dahili ağ mekanizmaları sayesinde ana port'u dinleyen tek bir load balancer, uygulamanızı çalıştıran muhtemelen birden fazla container'a request'leri iletebilir.
Uygulamanızı çalıştıran bu container'ların her birinde normalde tek bir process olur (ör. FastAPI uygulamanızı çalıştıran bir Uvicorn process). Hepsi aynı şeyi çalıştıran özdeş container'lardır; ancak her birinin kendi process'i, memory'si vb. vardır. Böylece CPU'nun farklı core'larında, hatta farklı makinelerde paralelleştirmeden yararlanırsınız.
Load balancer'lı dağıtık sistem, request'leri uygulamanızın bulunduğu container'ların her birine sırayla dağıtır. Böylece her request, uygulamanızın birden fazla replicated container'ından biri tarafından işlenebilir.
Ve bu load balancer normalde cluster'ınızdaki diğer uygulamalara giden request'leri de (ör. farklı bir domain ya da farklı bir URL path prefix altında) yönetebilir ve iletişimi o diğer uygulamanın doğru container'larına iletir.
Container Başına Tek Process¶
Bu senaryoda, replication'ı zaten cluster seviyesinde yaptığınız için, muhtemelen container başına tek bir (Uvicorn) process istersiniz.
Dolayısıyla bu durumda container içinde --workers gibi bir komut satırı seçeneğiyle çoklu worker istemezsiniz. Container başına sadece tek bir Uvicorn process istersiniz (ama muhtemelen birden fazla container).
Container içine ekstra bir process manager koymak (çoklu worker gibi) çoğu zaman zaten cluster sisteminizle çözdüğünüz şeye ek gereksiz karmaşıklık katar.
Birden Fazla Process'li Container'lar ve Özel Durumlar¶
Elbette bazı özel durumlarda bir container içinde birden fazla Uvicorn worker process çalıştırmak isteyebilirsiniz.
Bu durumlarda çalıştırmak istediğiniz worker sayısını --workers komut satırı seçeneğiyle ayarlayabilirsiniz:
FROM python:3.9
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
# (1)!
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
- Burada worker sayısını 4 yapmak için
--workerskomut satırı seçeneğini kullanıyoruz.
Bunun mantıklı olabileceği birkaç örnek:
Basit Bir Uygulama¶
Uygulamanız tek bir server üzerinde (cluster değil) çalışacak kadar basitse, container içinde bir process manager isteyebilirsiniz.
Docker Compose¶
Docker Compose ile tek bir server'a (cluster değil) deploy ediyor olabilirsiniz. Bu durumda, paylaşılan ağı ve load balancing'i koruyarak container replication'ını (Docker Compose ile) yönetmenin kolay bir yolu olmayabilir.
Bu durumda, tek bir container içinde bir process manager ile birden fazla worker process başlatmak isteyebilirsiniz.
Ana fikir şu: Bunların hiçbiri körü körüne uymanız gereken değişmez kurallar değildir. Bu fikirleri, kendi kullanım senaryonuzu değerlendirmek ve sisteminiz için en iyi yaklaşımı seçmek için kullanabilirsiniz. Şu kavramları nasıl yöneteceğinize bakarak karar verin:
- Güvenlik - HTTPS
- Startup'ta çalıştırma
- Restart'lar
- Replication (çalışan process sayısı)
- Memory
- Başlatmadan önceki adımlar
Memory¶
Container başına tek process çalıştırırsanız, her container'ın tüketeceği memory miktarı aşağı yukarı tanımlı, stabil ve sınırlı olur (replication varsa birden fazla container için).
Sonra aynı memory limit ve gereksinimlerini container yönetim sisteminizin (ör. Kubernetes) konfigürasyonlarında belirleyebilirsiniz. Böylece sistem; ihtiyaç duyulan memory miktarını ve cluster'daki makinelerde mevcut memory'yi dikkate alarak uygun makinelerde container'ları replicate edebilir.
Uygulamanız basitse, muhtemelen bu bir sorun olmaz ve katı memory limitleri belirlemeniz gerekmeyebilir. Ancak çok memory kullanıyorsanız (ör. machine learning modelleriyle), ne kadar memory tükettiğinizi kontrol edip her makinede çalışacak container sayısını ayarlamalısınız (ve gerekirse cluster'a daha fazla makine eklemelisiniz).
Container başına birden fazla process çalıştırırsanız, başlatılan process sayısının mevcut olandan fazla memory tüketmediğinden emin olmanız gerekir.
Başlatmadan Önceki Adımlar ve Container'lar¶
Container kullanıyorsanız (örn. Docker, Kubernetes), temelde iki yaklaşım vardır.
Birden Fazla Container¶
Birden fazla container'ınız varsa ve muhtemelen her biri tek process çalıştırıyorsa (ör. bir Kubernetes cluster'ında), replication yapılan worker container'lar çalışmadan önce, başlatmadan önceki adımların işini yapan ayrı bir container kullanmak isteyebilirsiniz (tek container, tek process).
Bilgi
Kubernetes kullanıyorsanız, bu muhtemelen bir Init Container olur.
Kullanım senaryonuzda bu adımları paralel olarak birden fazla kez çalıştırmak sorun değilse (örneğin veritabanı migration çalıştırmıyor, sadece veritabanı hazır mı diye kontrol ediyorsanız), o zaman her container'da ana process başlamadan hemen önce de çalıştırabilirsiniz.
Tek Container¶
Basit bir kurulumda; tek bir container olup onun içinde birden fazla worker process (ya da sadece bir process) başlatıyorsanız, bu adımları aynı container içinde, uygulama process'ini başlatmadan hemen önce çalıştırabilirsiniz.
Base Docker Image¶
Eskiden resmi bir FastAPI Docker image'ı vardı: tiangolo/uvicorn-gunicorn-fastapi. Ancak artık kullanımdan kaldırıldı (deprecated). ⛔️
Muhtemelen bu base Docker image'ını (veya benzeri başka bir image'ı) kullanmamalısınız.
Kubernetes (veya diğerleri) kullanıyor ve cluster seviyesinde birden fazla container ile replication ayarlıyorsanız, bu durumda yukarıda anlatıldığı gibi sıfırdan bir image build etmek daha iyi olur: FastAPI için Docker Image Oluşturalım.
Ve birden fazla worker gerekiyorsa, sadece --workers komut satırı seçeneğini kullanabilirsiniz.
Teknik Detaylar
Bu Docker image, Uvicorn dead worker'ları yönetmeyi ve yeniden başlatmayı desteklemediği dönemde oluşturulmuştu. Bu yüzden Uvicorn ile birlikte Gunicorn kullanmak gerekiyordu; sırf Gunicorn, Uvicorn worker process'lerini yönetip yeniden başlatsın diye oldukça fazla karmaşıklık ekleniyordu.
Ancak artık Uvicorn (ve fastapi komutu) --workers kullanımını desteklediğine göre, kendi image'ınızı build etmek yerine bir base Docker image kullanmanın bir nedeni kalmadı (kod miktarı da hemen hemen aynı 😅).
Container Image'ı Deploy Etme¶
Bir Container (Docker) Image'ınız olduktan sonra bunu deploy etmenin birkaç yolu vardır.
Örneğin:
- Tek bir server'da Docker Compose ile
- Bir Kubernetes cluster'ı ile
- Docker Swarm Mode cluster'ı ile
- Nomad gibi başka bir araçla
- Container image'ınızı alıp deploy eden bir cloud servisiyle
uv ile Docker Image¶
Projenizi yüklemek ve yönetmek için uv kullanıyorsanız, onların uv Docker rehberini takip edebilirsiniz.
Özet¶
Container sistemleri (örn. Docker ve Kubernetes ile) kullanınca tüm deployment kavramlarını ele almak oldukça kolaylaşır:
- HTTPS
- Startup'ta çalıştırma
- Restart'lar
- Replication (çalışan process sayısı)
- Memory
- Başlatmadan önceki adımlar
Çoğu durumda bir base image kullanmak istemezsiniz; bunun yerine resmi Python Docker image'ını temel alarak sıfırdan bir container image build edersiniz.
Dockerfile içindeki talimatların sırasına ve Docker cache'ine dikkat ederek build sürelerini minimize edebilir, üretkenliğinizi artırabilirsiniz (ve beklerken sıkılmayı önlersiniz). 😎