Web uygulamalarının geliştirilmesi ve dağıtımı süreçleri, teknolojik gelişmelerle birlikte sürekli evrim geçirmektedir. Bu evrimin en önemli duraklarından biri şüphesiz Docker olmuştur. Docker, uygulamaları ve bağımlılıklarını tek bir taşınabilir birim olan kapsayıcılara (container) paketleyerek, “bir kez yaz, her yerde çalıştır” felsefesini gerçeğe dönüştürür. Bu yazımızda, Docker’ın web dağıtımındaki rolünü, temel kavramlarını ve adım adım bir web uygulamasını Docker ile nasıl dağıtabileceğinizi detaylıca inceleyeceğiz.
Geleneksel Dağıtımın Zorlukları ve Docker'ın Çözümü
Eski dönemlerde, bir web uygulamasını sunucuya dağıtmak genellikle karmaşık ve hatalara açık bir süreçti. "Benim bilgisayarımda çalışıyor!" sendromu, geliştirme, test ve üretim ortamları arasındaki uyumsuzluklardan kaynaklanıyordu. Bağımlılık çakışmaları, işletim sistemi farklılıkları ve manuel kurulum adımları, dağıtım süreçlerini kabusa çevirebiliyordu. Docker bu sorunlara radikal bir çözüm sunar:
Temel Docker Kavramları
Docker ile çalışırken anlamamız gereken birkaç temel terim bulunmaktadır:
* Docker Image (Docker Kalıbı): Bir uygulamanın çalışması için gerekli tüm bağımlılıkları, kodu ve yapılandırmayı içeren, salt okunur bir şablondur. Bir sınıfın taslağı gibi düşünebilirsiniz.
* Docker Container (Docker Kapsayıcısı): Bir Docker kalıbının çalışan bir örneğidir. Kalıptan oluşturulur ve izole bir ortamda uygulamanızı çalıştırır. Bir sınıftan oluşturulan nesneye benzer.
* Dockerfile: Bir Docker kalıbının nasıl oluşturulacağını adım adım tanımlayan metin tabanlı bir betiktir. Uygulamanız için özel bir ortam oluşturmanın tarifidir.
* Docker Hub: Docker kalıplarının depolandığı ve paylaşıldığı bulut tabanlı bir kayıt defteridir (registry). Ortak kalıpları buradan çekebilir veya kendi kalıplarınızı yayımlayabilirsiniz.
* Docker Compose: Çok servisli Docker uygulamalarını tanımlamak ve çalıştırmak için kullanılan bir araçtır. Tek bir YAML dosyası ile birden fazla kapsayıcıyı (örneğin, bir web uygulaması ve bir veritabanı) yönetmenizi sağlar.
Adım Adım Web Uygulaması Dağıtımı: Basit Bir Flask Uygulaması
Şimdi, basit bir Python Flask web uygulamasını Docker ile nasıl dağıtacağımıza bakalım. Uygulamamızın temel amacı, bir “Merhaba Docker!” mesajı göstermek olsun. Bu uygulamayı app.py ve requirements.txt dosyaları ile oluşturduğunuzu varsayalım.
1. Dockerfile Oluşturma
Proje dizininizde Dockerfile adında bir dosya oluşturun ve içine aşağıdaki komutları yazın:
Bu Dockerfile, uygulamanız için adım adım bir inşa süreci tanımlar. Her bir komut, yeni bir katman oluşturarak Docker imajınızı katmanlı bir yapıda inşa eder. Bu katmanlar, imaj boyutunu optimize etmeye ve önbellekleme yoluyla inşa sürelerini kısaltmaya yardımcı olur.
2. Docker İmajını Oluşturma
Terminali açın ve Dockerfile'ın bulunduğu dizine gidin. Aşağıdaki komutu çalıştırarak imajınızı oluşturun:
Burada:
* -t my-flask-app: Oluşturulan imaja 'my-flask-app' adını verir. Bu, imaja kolayca referans vermenizi sağlar.
* .: Dockerfile'ın ve uygulama dosyalarının mevcut dizinde olduğunu belirtir.
3. Docker Kapsayıcısını Çalıştırma
İmajınız başarıyla oluşturulduktan sonra, aşağıdaki komutla bir kapsayıcı başlatabilirsiniz:
Bu komut:
* -p 80:5000: Ana makinenizin 80. portunu (HTTP varsayılan portu) kapsayıcınızın 5000. portuna yönlendirir. Böylece tarayıcınızdan http://localhost adresine giderek uygulamanıza erişebilirsiniz.
* my-flask-app: Çalıştırılacak imajın adıdır.
Kapsayıcıyı arka planda çalıştırmak isterseniz -d (detached) parametresini kullanabilirsiniz:
4. Geliştirme Ortamında Volume Kullanımı
Geliştirme yaparken, her kod değişikliğinde imajı yeniden oluşturmak yerine, ana makinenizdeki kod dosyalarını kapsayıcıya bağlamak isteyebilirsiniz. Buna volume mounting denir:
* -v $(pwd):/app: Mevcut çalışma dizininizi ($(pwd)) kapsayıcının içindeki [/app] dizinine bağlar. Böylece kod değişiklikleri anında kapsayıcı içinde yansır.
Çok Servisli Uygulamalar için Docker Compose
Gerçek dünya uygulamaları genellikle birden fazla servisten oluşur; örneğin bir web sunucusu, bir veritabanı, bir önbellek servisi vb. Bu tür senaryoları yönetmek için Docker Compose devreye girer. Tek bir docker-compose.yml dosyası ile tüm servislerinizi tanımlayabilir ve tek bir komutla başlatıp durdurabilirsiniz.
Örnek bir docker-compose.yml dosyası (Flask uygulamamız ve bir PostgreSQL veritabanı için):
Bu dosya iki servis tanımlar:
* web: Mevcut dizinden bir imaj inşa eder (build: .), 80. portu 5000'e eşler ve kod değişiklikleri için volume kullanır. Ayrıca db servisine bağımlıdır (depends_on) ve veritabanı bağlantı bilgilerini environment değişkeni olarak sağlar.
* db: Resmi PostgreSQL 13 imajını kullanır, veritabanı kimlik bilgilerini ve adını ayarlar. Veritabanı verilerinin kalıcı olması için db_data adında bir volume kullanır.
Docker Compose ile Çalıştırma
docker-compose.yml dosyasının bulunduğu dizinde aşağıdaki komutu çalıştırın:
Bu komut, tüm servisleri arka planda (-d detached) başlatır, gerekli imajları çeker (veya inşa eder) ve kapsayıcıları ayağa kaldırır.
Servisleri durdurmak ve temizlemek için:
Üretim Ortamında Docker Kullanımı İçin İpuçları
Docker, geliştirme ortamındaki kolaylığının yanı sıra üretim ortamları için de güçlü çözümler sunar:
Sonuç
Docker, web uygulaması dağıtım süreçlerini basitleştiren, hızlandıran ve güvenilir hale getiren devrim niteliğinde bir teknolojidir. Uygulama izolasyonu, taşınabilirlik ve kaynak verimliliği gibi avantajlarıyla modern DevOps pratiklerinin vazgeçilmez bir parçası haline gelmiştir. Geliştiriciler ve sistem yöneticileri için öğrenilmesi gereken kritik bir beceridir.
Daha fazla bilgi ve güncel kaynaklar için Docker Resmi Belgeleri'ne göz atabilirsiniz.
Geleneksel Dağıtımın Zorlukları ve Docker'ın Çözümü
Eski dönemlerde, bir web uygulamasını sunucuya dağıtmak genellikle karmaşık ve hatalara açık bir süreçti. "Benim bilgisayarımda çalışıyor!" sendromu, geliştirme, test ve üretim ortamları arasındaki uyumsuzluklardan kaynaklanıyordu. Bağımlılık çakışmaları, işletim sistemi farklılıkları ve manuel kurulum adımları, dağıtım süreçlerini kabusa çevirebiliyordu. Docker bu sorunlara radikal bir çözüm sunar:
- Tutarlılık: Uygulamanız ve tüm bağımlılıkları, bir kapsayıcı içinde her ortamda aynı şekilde çalışır.
- İzolasyon: Her kapsayıcı izole bir ortamda çalışır, böylece farklı uygulamalar veya servisler birbirini etkilemez.
- Hızlı Dağıtım: Kapsayıcılar saniyeler içinde başlatılabilir, bu da dağıtım ve ölçeklendirme süreçlerini hızlandırır.
- Kaynak Verimliliği: Sanal makinelere göre çok daha hafif ve kaynak dostudur.
- Taşınabilirlik: Oluşturduğunuz Docker imajları, Docker kurulu herhangi bir sunucuda kolayca çalıştırılabilir.
Temel Docker Kavramları
Docker ile çalışırken anlamamız gereken birkaç temel terim bulunmaktadır:
* Docker Image (Docker Kalıbı): Bir uygulamanın çalışması için gerekli tüm bağımlılıkları, kodu ve yapılandırmayı içeren, salt okunur bir şablondur. Bir sınıfın taslağı gibi düşünebilirsiniz.
* Docker Container (Docker Kapsayıcısı): Bir Docker kalıbının çalışan bir örneğidir. Kalıptan oluşturulur ve izole bir ortamda uygulamanızı çalıştırır. Bir sınıftan oluşturulan nesneye benzer.
* Dockerfile: Bir Docker kalıbının nasıl oluşturulacağını adım adım tanımlayan metin tabanlı bir betiktir. Uygulamanız için özel bir ortam oluşturmanın tarifidir.
* Docker Hub: Docker kalıplarının depolandığı ve paylaşıldığı bulut tabanlı bir kayıt defteridir (registry). Ortak kalıpları buradan çekebilir veya kendi kalıplarınızı yayımlayabilirsiniz.
* Docker Compose: Çok servisli Docker uygulamalarını tanımlamak ve çalıştırmak için kullanılan bir araçtır. Tek bir YAML dosyası ile birden fazla kapsayıcıyı (örneğin, bir web uygulaması ve bir veritabanı) yönetmenizi sağlar.
Adım Adım Web Uygulaması Dağıtımı: Basit Bir Flask Uygulaması
Şimdi, basit bir Python Flask web uygulamasını Docker ile nasıl dağıtacağımıza bakalım. Uygulamamızın temel amacı, bir “Merhaba Docker!” mesajı göstermek olsun. Bu uygulamayı app.py ve requirements.txt dosyaları ile oluşturduğunuzu varsayalım.
Kod:
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Merhaba Docker! Bu bir Docker kapsayıcısından yayınlanıyor!'
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
# requirements.txt
Flask==2.0.2
1. Dockerfile Oluşturma
Proje dizininizde Dockerfile adında bir dosya oluşturun ve içine aşağıdaki komutları yazın:
Kod:
# Temel imaj olarak resmi Python imajını kullan
FROM python:3.9-slim-buster
# Çalışma dizinini /app olarak ayarla
WORKDIR /app
# Gerekli Python bağımlılıklarını kopyala ve kur
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Uygulama kodunu çalışma dizinine kopyala
COPY . .
# Uygulamanın çalışacağı portu belirt (sadece bilgi amaçlıdır)
EXPOSE 5000
# Kapsayıcı başlatıldığında çalıştırılacak komut
CMD ["python", "app.py"]
Bu Dockerfile, uygulamanız için adım adım bir inşa süreci tanımlar. Her bir komut, yeni bir katman oluşturarak Docker imajınızı katmanlı bir yapıda inşa eder. Bu katmanlar, imaj boyutunu optimize etmeye ve önbellekleme yoluyla inşa sürelerini kısaltmaya yardımcı olur.
2. Docker İmajını Oluşturma
Terminali açın ve Dockerfile'ın bulunduğu dizine gidin. Aşağıdaki komutu çalıştırarak imajınızı oluşturun:
Kod:
docker build -t my-flask-app .
Burada:
* -t my-flask-app: Oluşturulan imaja 'my-flask-app' adını verir. Bu, imaja kolayca referans vermenizi sağlar.
* .: Dockerfile'ın ve uygulama dosyalarının mevcut dizinde olduğunu belirtir.
3. Docker Kapsayıcısını Çalıştırma
İmajınız başarıyla oluşturulduktan sonra, aşağıdaki komutla bir kapsayıcı başlatabilirsiniz:
Kod:
docker run -p 80:5000 my-flask-app
Bu komut:
* -p 80:5000: Ana makinenizin 80. portunu (HTTP varsayılan portu) kapsayıcınızın 5000. portuna yönlendirir. Böylece tarayıcınızdan http://localhost adresine giderek uygulamanıza erişebilirsiniz.
* my-flask-app: Çalıştırılacak imajın adıdır.
Kapsayıcıyı arka planda çalıştırmak isterseniz -d (detached) parametresini kullanabilirsiniz:
Kod:
docker run -d -p 80:5000 my-flask-app
4. Geliştirme Ortamında Volume Kullanımı
Geliştirme yaparken, her kod değişikliğinde imajı yeniden oluşturmak yerine, ana makinenizdeki kod dosyalarını kapsayıcıya bağlamak isteyebilirsiniz. Buna volume mounting denir:
Kod:
docker run -p 80:5000 -v $(pwd):/app my-flask-app
* -v $(pwd):/app: Mevcut çalışma dizininizi ($(pwd)) kapsayıcının içindeki [/app] dizinine bağlar. Böylece kod değişiklikleri anında kapsayıcı içinde yansır.
Çok Servisli Uygulamalar için Docker Compose
Gerçek dünya uygulamaları genellikle birden fazla servisten oluşur; örneğin bir web sunucusu, bir veritabanı, bir önbellek servisi vb. Bu tür senaryoları yönetmek için Docker Compose devreye girer. Tek bir docker-compose.yml dosyası ile tüm servislerinizi tanımlayabilir ve tek bir komutla başlatıp durdurabilirsiniz.
Örnek bir docker-compose.yml dosyası (Flask uygulamamız ve bir PostgreSQL veritabanı için):
Kod:
version: '3.8'
services:
web:
build: .
ports:
- "80:5000"
volumes:
- .:/app
depends_on:
- db
environment:
DATABASE_URL: postgresql://myuser:mypassword@db:5432/mydatabase
db:
image: postgres:13
environment:
POSTGRES_DB: mydatabase
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Bu dosya iki servis tanımlar:
* web: Mevcut dizinden bir imaj inşa eder (build: .), 80. portu 5000'e eşler ve kod değişiklikleri için volume kullanır. Ayrıca db servisine bağımlıdır (depends_on) ve veritabanı bağlantı bilgilerini environment değişkeni olarak sağlar.
* db: Resmi PostgreSQL 13 imajını kullanır, veritabanı kimlik bilgilerini ve adını ayarlar. Veritabanı verilerinin kalıcı olması için db_data adında bir volume kullanır.
Docker Compose ile Çalıştırma
docker-compose.yml dosyasının bulunduğu dizinde aşağıdaki komutu çalıştırın:
Kod:
docker compose up -d
Bu komut, tüm servisleri arka planda (-d detached) başlatır, gerekli imajları çeker (veya inşa eder) ve kapsayıcıları ayağa kaldırır.
Servisleri durdurmak ve temizlemek için:
Kod:
docker compose down
Üretim Ortamında Docker Kullanımı İçin İpuçları
Docker, geliştirme ortamındaki kolaylığının yanı sıra üretim ortamları için de güçlü çözümler sunar:
- Güvenlik: Üretim imajlarınızı mümkün olduğunca küçük tutun (örneğin alpine tabanlı imajlar), root olmayan kullanıcılarla çalıştırın ve gereksiz bağımlılıkları dahil etmeyin.
- Ağ Yönetimi: Kapsayıcılar arasındaki iletişimi Docker'ın kendi ağ mekanizmalarıyla sağlayın. Harici erişim için bir ters proxy (Nginx, Traefik) kullanın.
- Loglama: Kapsayıcı loglarını merkezi bir loglama sistemine (ELK Stack, Grafana Loki) yönlendirin.
- Sürekli Entegrasyon/Sürekli Dağıtım (CI/CD): Gitlab CI/CD, Jenkins, Github Actions gibi araçlarla Docker imajlarının otomatik olarak inşa edilmesini ve dağıtılmasını otomatize edin.
- Orkestrasyon: Büyük ölçekli uygulamalar ve yüksek erişilebilirlik gereksinimleri için Kubernetes veya Docker Swarm gibi kapsayıcı orkestrasyon araçlarını değerlendirin.
"Docker, geliştirme ortamından üretime kadar tutarlı bir deneyim sunarak 'bir kez yaz, her yerde çalıştır' felsefesini gerçeğe dönüştürür. Bu sayede, yazılım geliştiriciler ve operasyon ekipleri arasındaki işbirliği daha sorunsuz hale gelir."
Sonuç
Docker, web uygulaması dağıtım süreçlerini basitleştiren, hızlandıran ve güvenilir hale getiren devrim niteliğinde bir teknolojidir. Uygulama izolasyonu, taşınabilirlik ve kaynak verimliliği gibi avantajlarıyla modern DevOps pratiklerinin vazgeçilmez bir parçası haline gelmiştir. Geliştiriciler ve sistem yöneticileri için öğrenilmesi gereken kritik bir beceridir.
Daha fazla bilgi ve güncel kaynaklar için Docker Resmi Belgeleri'ne göz atabilirsiniz.