Uygulama geliştirme ve dağıtım süreçleri, günümüzün hızlı tempolu yazılım dünyasında sürekli evrim geçiriyor. Geleneksel yöntemlerle yapılan uygulama dağıtımları genellikle yavaş, hatalara açık ve tekrarlayan manuel adımlarla dolu olabilir. Özellikle küçük hatalar bile büyük aksaklıklara yol açarken, her yeni sürümde aynı adımları tekrarlamak geliştiriciler ve operasyon ekipleri için ciddi bir zaman kaybı anlamına gelir. Peki, bu süreci nasıl daha verimli, daha güvenilir ve daha hızlı hale getirebiliriz? İşte tam da bu noktada, Docker ve otomasyon betiklerinin gücü devreye giriyor.
Otomatik Docker dağıtımı, bu zorlukların üstesinden gelmek için güçlü bir çözüm sunar. Uygulamalarınızı Docker konteynerlerine taşıyarak, “bir kez yaz, her yerde çalıştır” felsefesini benimseyebilir ve dağıtım ortamınız ne olursa olsun tutarlı bir çalışma garantisi elde edersiniz. Ancak Docker’ı kullanmak sadece bir başlangıçtır; asıl verimlilik, dağıtım sürecini otomatikleştirmekle sağlanır. Otomatik dağıtım betikleri sayesinde, bir butona basarak veya bir kod değişikliği algılandığında uygulamanızın üretim ortamına sorunsuz bir şekilde taşınmasını sağlayabilirsiniz. Bu makale, bu heyecan verici dünyaya ilk adımını atmak isteyenler için kapsamlı bir rehber niteliğindedir. Sıfırdan başlayarak, Docker’ı ve otomasyon betiklerini temel seviyede anlayacak, kendi otomatik dağıtım betiğinizi oluşturacak ve hatta ileri düzey ipuçlarıyla bilginizi pekiştireceksiniz. Hazırsanız, uygulama dağıtım süreçlerinizi dönüştürmeye başlayalım!
Temel Kavramlar: Docker ve Betik Tabanlı Otomasyon Nedir?
Otomatik Docker dağıtım betikleri oluşturmaya başlamadan önce, temel taşları iyi anlamak kritik öneme sahiptir. Bu bölümde, Docker’ın ne olduğunu ve neden bu kadar popüler olduğunu, otomasyon betiklerinin genel mantığını ve bu yolculuğa başlamak için hangi temel gereksinimlere ihtiyaç duyduğumuzu ele alacağız. Bu kavramları sağlam bir şekilde kavradığınızda, karmaşık görünen süreçlerin aslında ne kadar mantıklı olduğunu göreceksiniz.
Docker Nedir ve Neden Kullanılır?
Docker, uygulamaları ve bağımlılıklarını izole edilmiş, hafif ve taşınabilir birimler olan “konteynerler” içinde paketlemeyi sağlayan açık kaynaklı bir platformdur. Geleneksel sanal makinelerden (VM) farklı olarak, Docker konteynerleri işletim sistemi kernelini paylaşır ve bu sayede çok daha hızlı başlar, daha az kaynak tüketir ve daha verimlidir. Bir Docker konteyneri, uygulamanızın çalışması için gereken tüm kodları, çalışma zamanını, sistem araçlarını, sistem kütüphanelerini ve ayarları içerir. Bu, geliştirme, test ve üretim ortamları arasında tutarlılık sağlamak için kritik bir özelliktir. Artık “benim makinemde çalışıyordu” gibi sorunlarla karşılaşma olasılığınız minimuma iner.
Docker’ın temelini oluşturan iki ana bileşen vardır: Docker İmajları ve Docker Konteynerleri. Docker İmajı, bir uygulamanın çalışması için gerekli her şeyi içeren statik, salt okunur bir şablondur. Bir imaj, bir veya daha fazla konteyneri başlatmak için kullanılan bir “yapı planı” gibidir. Docker Konteyneri ise bu imajın çalışan bir örneğidir. İmajlar bir kez oluşturulur ve yüzlerce kez çalıştırılabilir. Bu izolasyon ve taşınabilirlik özellikleri, modern yazılım geliştirme ve dağıtım süreçlerinin vazgeçilmez bir parçası haline gelmiştir. Docker sayesinde, uygulamalarınızı herhangi bir bulut sağlayıcısında, yerel sunucunuzda veya geliştirme ortamınızda aynı tutarlılıkla çalıştırabilirsiniz. Uygulama dağıtımı artık karmaşık bağımlılık sorunlarıyla uğraşmak yerine, standart bir format üzerinden çok daha basit hale gelir.
Otomasyon Betikleri Ne İşe Yarar?
Otomasyon betikleri, belirli görevleri otomatik olarak gerçekleştirmek için yazılan komut dizileridir. Genellikle Shell betikleri (Bash, Zsh gibi) veya Python gibi betik dilleriyle oluşturulurlar. Bu betikler, tekrarlayan ve zaman alıcı manuel görevleri ortadan kaldırarak yazılım geliştirme yaşam döngüsüne muazzam bir değer katarlar. Uygulama derleme, test çalıştırma, sunuculara dosya kopyalama, hizmetleri yeniden başlatma ve tabii ki uygulama dağıtımı gibi birçok alanda kullanılabilirler. Bir kez doğru şekilde yazıldığında, bir otomasyon betiği her seferinde aynı adımları, aynı tutarlılıkla ve insan hatası riski olmadan gerçekleştirir.
Örneğin, bir uygulamanın Docker imajını oluşturmak, bu imajı bir kayıt defterine göndermek, mevcut konteyneri durdurup kaldırmak ve yeni bir konteyneri başlatmak gibi adımlar, elle yapıldığında her biri ayrı ayrı komutlarla girilir. Bu süreçte bir yazım hatası veya unutulan bir adım, dağıtımın başarısız olmasına yol açabilir. Ancak tüm bu adımları tek bir betik altında topladığınızda, tek bir komutla tüm süreci tetikleyebilir ve sonuçtan emin olabilirsiniz. Bu, hem zaman tasarrufu sağlar hem de dağıtımın güvenilirliğini artırır. Ayrıca, betikler sürüm kontrol sistemlerinde (Git gibi) saklanabilir, bu da değişikliklerin izlenebilir olmasını ve ekip üyeleri arasında kolayca paylaşılmasını sağlar. Bu sayede, DevOps prensiplerinin temelini oluşturan “kod olarak altyapı” yaklaşımına da yaklaşmış olursunuz.
Gereksinimler: Başlamak İçin Ne Lazım?
Bu rehberdeki adımları takip etmek için birkaç temel şeye ihtiyacınız olacak:
- Docker Engine veya Docker Desktop: Docker konteynerlerini yerel makinenizde çalıştırabilmeniz için bu araçlardan birinin kurulu olması gerekmektedir. Eğer Linux kullanıyorsanız Docker Engine, macOS veya Windows kullanıyorsanız Docker Desktop tercih edebilirsiniz.
- Bir Metin Düzenleyici/IDE: Kod ve betik dosyalarını yazmak için Visual Studio Code, Sublime Text, Atom gibi bir metin düzenleyiciye veya IDE’ye ihtiyacınız olacak. Bu araçlar, sözdizimi vurgulama ve otomasyon özellikleri ile işinizi kolaylaştıracaktır.
- Temel Komut Satırı (CLI) Bilgisi: Linux/Unix tabanlı sistemlerde kullanılan
cd,ls,mkdir,echogibi temel komutlara ve Shell betikleri çalıştırmaya aşina olmanız beklenmektedir. Bu, betiklerle daha rahat çalışmanızı sağlayacaktır. - Biraz Sabır ve Öğrenme İsteği: Yeni bir teknolojiye adapte olmak zaman ve çaba gerektirir. Karşılaşacağınız sorunlara karşı sabırlı olun ve her hatayı bir öğrenme fırsatı olarak görün.
Bu gereksinimleri karşıladığınız sürece, otomatik Docker dağıtım betikleri oluşturma yolculuğuna hazırsınız demektir. Unutmayın, pratik yapmak en iyi öğrenme yöntemidir.
Adım Adım İlk Docker Uygulamanızı Hazırlama: Bir Örnek Uygulama
Otomatik dağıtım betiği oluşturmaya başlamadan önce, dağıtacağımız bir Docker uygulamasını hazır etmemiz gerekiyor. Bu bölümde, basit bir Python Flask web uygulamasını ele alacağız, bu uygulamayı bir Docker imajına dönüştürecek bir Dockerfile yazacak ve son olarak imajı derleyip bir konteyner içinde nasıl çalıştıracağımızı adım adım göreceğiz. Bu pratik örnek, Docker’ın temel işleyişini anlamanıza yardımcı olacak ve sonraki adımlarda otomasyon betiklerini inşa etmek için sağlam bir zemin oluşturacaktır.
Basit Bir Web Uygulaması Oluşturma (Python/Flask Örneği)
Öncelikle, dağıtmak istediğimiz çok basit bir web uygulaması oluşturalım. Bu örnek için Python ve Flask framework’ünü kullanacağız, ancak bu konseptler herhangi bir programlama dili veya framework ile kolayca uyarlanabilir. Çalışma dizininizde my-docker-app adında bir klasör oluşturun ve içine aşağıdaki iki dosyayı ekleyin:
app.py dosyası:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Merhaba Docker Dünyası!
Uygulamamız sorunsuz çalışıyor.
"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
Bu Python kodu, Flask kullanarak 5000 numaralı portta çalışan basit bir web sunucusu oluşturur. Ana sayfaya yapılan bir istekte "Merhaba Docker Dünyası!" mesajını döndürür.
requirements.txt dosyası:
Flask==2.0.2
Bu dosya, Python uygulamasının ihtiyaç duyduğu bağımlılıkları (bu durumda sadece Flask) listeler. Docker, bu dosyayı kullanarak konteyner içinde gerekli kütüphaneleri kuracaktır.
Bu iki dosya, uygulamanızın temelini oluşturur. Şimdi bu uygulamayı Dockerize etme zamanı.
Dockerfile Yazımı: Uygulamanızı Kapsayıcı Hale Getirme
Uygulamanızı bir Docker imajına dönüştürmek için bir Dockerfile oluşturmanız gerekir. Bu dosya, Docker'ın imajı nasıl oluşturacağını adım adım anlatan bir talimat listesidir. app.py ve requirements.txt dosyalarının bulunduğu dizine Dockerfile adında bir dosya oluşturun ve içine aşağıdaki içeriği ekleyin:
# Python 3.9 tabanlı resmi bir imajı başlangıç noktası olarak kullan
FROM python:3.9-slim-buster
# Çalışma dizinini /app olarak ayarla
WORKDIR /app
# requirements.txt dosyasını çalışma dizinine kopyala
COPY requirements.txt .
# Gerekli Python bağımlılıklarını yükle
RUN pip install -r requirements.txt
# Uygulama kodunu çalışma dizinine kopyala
COPY . .
# Uygulamanın 5000 numaralı portu kullanacağını Docker'a bildir
EXPOSE 5000
# Konteyner başlatıldığında çalıştırılacak komut
CMD ["python", "app.py"]
Bu Dockerfile aşağıdaki adımları gerçekleştirir:
FROM python:3.9-slim-buster: Python 3.9'un hafif bir sürümünü içeren resmi Docker imajını temel alır. Bu, imaj boyutunu küçük tutar.WORKDIR /app: Konteyner içinde çalışacağımız dizini/appolarak belirler. Sonraki tüm komutlar bu dizin içinde yürütülür.COPY requirements.txt .: Yerelrequirements.txtdosyasını konteynerin/appdizinine kopyalar.RUN pip install -r requirements.txt: Kopyalananrequirements.txtdosyasındaki bağımlılıkları yükler.COPY . .: Uygulamanızın tüm kodunu (bu durumdaapp.py) konteynerin/appdizinine kopyalar.EXPOSE 5000: Uygulamanın 5000 numaralı port üzerinden hizmet vereceğini belirtir. Bu sadece bir dokümantasyondur, gerçek port eşlemesinidocker runkomutuyla yaparız.CMD ["python", "app.py"]: Konteyner başlatıldığında çalıştırılacak ana komutu tanımlar. Bu, Flask uygulamanızı başlatır.
Ayrıca, gereksiz dosyaların (örneğin .git klasörü, __pycache__) Docker imajına kopyalanmasını engellemek için Dockerfile ile aynı dizine bir .dockerignore dosyası ekleyebilirsiniz. Bu, imaj boyutunu optimize eder ve güvenlik açıklarını azaltır. Örneğin:
.git
__pycache__/
*.pyc
*.log
.vscode/
Docker İmajı Oluşturma ve Çalıştırma
Şimdi Dockerfile'ı kullanarak bir Docker imajı oluşturalım ve uygulamamızı bir konteyner içinde çalıştıralım. Komut satırınızı açın ve Dockerfile ile app.py dosyalarının bulunduğu my-docker-app dizinine gidin.
- Docker İmajını Oluşturma:
Aşağıdaki komutla imajınızı derleyin.
-tparametresi imaja bir etiket (isim ve isteğe bağlı sürüm) verir..ise Dockerfile'ın mevcut dizinde olduğunu belirtir.docker build -t my-flask-app:1.0 .Bu komut çalıştıktan sonra, tüm adımları tek tek göreceksiniz. İşlem tamamlandığında,
my-flask-app:1.0adında yeni bir Docker imajınız olacak. - Docker Konteynerini Çalıştırma:
İmajdan bir konteyner başlatmak için aşağıdaki komutu kullanın:
docker run -d -p 5000:5000 --name my-running-app my-flask-app:1.0-d: Konteyneri arka planda (detached mode) çalıştırır.-p 5000:5000: Konteynerin 5000 numaralı portunu yerel makinenizin 5000 numaralı portuna eşler. Böylece uygulamanıza tarayıcınızdan erişebilirsiniz.--name my-running-app: Konteynera okunabilir bir isim verir.my-flask-app:1.0: Hangi imajın kullanılacağını belirtir.
- Uygulamayı Kontrol Etme:
Tarayıcınızı açın ve http://localhost:5000 adresine gidin. "Merhaba Docker Dünyası!" mesajını görmelisiniz. Bu, uygulamanızın Docker konteyneri içinde başarıyla çalıştığını gösterir.
Tebrikler! İlk Docker uygulamanızı başarıyla hazırladınız ve çalıştırdınız. Artık bu adımları otomatikleştirecek bir betik oluşturmaya hazırız.
Otomatik Dağıtım Betiği Oluşturma: İlk Adımlarınız Neler Olmalı?
Önceki bölümde Docker uygulamanızı manuel olarak hazırlayıp çalıştırdınız. Ancak her değişiklikte bu komutları tek tek girmek hem sıkıcı hem de hataya açık bir süreçtir. İşte bu noktada otomasyon betikleri devreye giriyor. Bu bölümde, tüm bu adımları tek bir çalıştırılabilir dosyada toplayacak basit bir Shell betiği oluşturacağız. Bu betik, Docker imajınızı derleyecek, eski konteyneri durdurup kaldıracak ve uygulamanızın yeni sürümünü sorunsuz bir şekilde başlatacaktır.
Neden Bir Betik Yazmalıyız?
Manuel dağıtım süreçlerinin birkaç temel dezavantajı vardır:
- İnsan Hatası Riski: Komutları elle girerken yapılan küçük bir yazım hatası veya unutulan bir parametre, dağıtımın başarısız olmasına yol açabilir.
- Tekrarlanabilirlik Eksikliği: Her dağıtım, farklı bir kişi tarafından veya farklı bir sırayla yapıldığında, sonuçlar tutarlı olmayabilir.
- Zaman Kaybı: Her seferinde aynı uzun komut dizilerini yazmak veya kopyalayıp yapıştırmak önemli bir zaman kaybına neden olur.
- Bilgi Silosu: Dağıtım süreci hakkında bilgi, sadece onu yapan kişinin zihninde kalabilir, bu da ekip içinde paylaşımı zorlaştırır.
Bir dağıtım betiği yazarak bu sorunların üstesinden gelebiliriz. Betik, tüm adımları önceden tanımlanmış bir sırayla ve hatasız bir şekilde gerçekleştiren "tek kaynaklı bir doğruluk" sağlar. Bu, özellikle sürekli entegrasyon/sürekli teslimat (CI/CD) boru hatlarına entegrasyon için hayati önem taşır, çünkü otomatik sistemler her zaman aynı betiği kullanarak tutarlı sonuçlar elde edebilirler.
Betiğin Temel Yapısı: Shell Script Örneği
Şimdi my-docker-app dizininizin kökünde deploy.sh adında bir dosya oluşturalım ve içine aşağıdaki Shell betiğini ekleyelim. Bu betik, daha önce manuel olarak yaptığınız adımları otomatikleştirecektir:
#!/bin/bash
# Hata durumunda betiği durdur
set -e
# Uygulamanın adı ve versiyonu
APP_NAME=my-flask-app
APP_VERSION=1.0 # İleride bunu dinamik hale getirebiliriz
CONTAINER_NAME=my-running-app
PORT=5000
echo "[ADIM 1/4] Docker imajı oluşturuluyor..."
docker build -t ${APP_NAME}:${APP_VERSION} .
echo "[ADIM 2/4] Mevcut konteyner kontrol ediliyor ve durduruluyor (varsa)..."
# Konteynerin var olup olmadığını kontrol et
if docker ps -a --format '{{.Names}}' | grep -q ${CONTAINER_NAME}; then
echo "Mevcut '${CONTAINER_NAME}' konteyneri bulunuyor. Durduruluyor ve kaldırılıyor..."
docker stop ${CONTAINER_NAME}
docker rm ${CONTAINER_NAME}
else
echo "Mevcut '${CONTAINER_NAME}' konteyneri bulunamadı."
fi
echo "[ADIM 3/4] Yeni Docker konteyneri başlatılıyor..."
docker run -d -p ${PORT}:${PORT} --name ${CONTAINER_NAME} ${APP_NAME}:${APP_VERSION}
echo "[ADIM 4/4] Uygulama dağıtımı tamamlandı! Kontrol etmek için: http://localhost:${PORT}"
echo "Çalışan Docker konteynerleri:"
docker ps
Bu betikteki önemli noktalar:
#!/bin/bash: Betiğin hangi Shell yorumlayıcısı ile çalıştırılacağını belirtir.set -e: Bu komut, betik içindeki herhangi bir komut hata verdiğinde (sıfırdan farklı bir çıkış kodu döndürdüğünde) betiğin derhal durmasını sağlar. Bu, dağıtım sürecinde bir hata oluştuğunda betiğin tutarsız bir durumda devam etmesini engeller.- Değişkenler:
APP_NAME,APP_VERSION,CONTAINER_NAME,PORTgibi değişkenler kullanarak betiği daha okunabilir ve yönetilebilir hale getirdik. Değişiklik yapmak istediğinizde sadece bu değişkenleri güncellemeniz yeterlidir. - Mevcut Konteyner Yönetimi:
docker ps -akomutuyla mevcut konteynerin var olup olmadığını kontrol ederiz. Eğer aynı isimde bir konteyner çalışıyorsa veya durdurulmuş bir şekilde varsa,docker stopile durdurupdocker rmile kaldırırız. Bu, yeni sürümü sorunsuz bir şekilde dağıtmak için eski sürümün temizlenmesini sağlar. - Bilgilendirme Mesajları:
echokomutlarıyla betiğin hangi adımda olduğunu belirten mesajlar eklemek, süreci takip etmeyi kolaylaştırır.
Betiği çalıştırılabilir yapmak için şu komutu kullanın:
chmod +x deploy.sh
Şimdi betiği çalıştırabilirsiniz:
./deploy.sh
Bu komut, tüm dağıtım sürecini otomatik olarak başlatacak ve uygulamanızın güncel sürümünü çalışır duruma getirecektir. Tarayıcınızdan http://localhost:5000 adresini kontrol ederek uygulamanızın çalıştığından emin olabilirsiniz.
set -e kullanmaya özen gösterin. Bu, beklenmedik hataların tüm dağıtım sürecini bozmasını engeller ve daha güvenilir otomasyon sağlar. Ayrıca, betiklerinizi git gibi sürüm kontrol sistemlerinde saklayarak değişiklikleri takip edebilir ve ekibinizle kolayca paylaşabilirsiniz.
Ortam Değişkenleri ve Güvenlik: Hassas Bilgileri Nasıl Yönetiriz?
Yukarıdaki betiğimizde bazı bilgileri (uygulama adı, port) doğrudan betiğin içine yazdık. Ancak veritabanı şifreleri, API anahtarları veya diğer hassas bilgiler gibi kritik veriler söz konusu olduğunda, bunları doğrudan betik içine yazmak veya sürüm kontrol sistemine yüklemek ciddi bir güvenlik riski oluşturur. Bu tür bilgileri yönetmenin en iyi yolu, ortam değişkenlerini veya özel gizli yönetim araçlarını kullanmaktır.
Ortam Değişkenleri Kullanımı:
Dağıtım betiklerinizde hassas bilgileri ortam değişkenleri aracılığıyla sağlamak oldukça yaygın ve güvenli bir yöntemdir. Örneğin, deploy.sh betiğinizden önce export DB_PASSWORD="secret" gibi bir komutla ortam değişkenini ayarlayabilir, ardından betik içinde $DB_PASSWORD olarak bu değere erişebilirsiniz. Daha düzenli bir yaklaşım için, .env adında bir dosya oluşturup içine değişkenlerinizi yazabilirsiniz:
.env dosyası:
DB_PASSWORD=cokgizlisifrem
API_KEY=benim-api-anahtarim-123
Daha sonra deploy.sh betiğinizde bu .env dosyasını kaynak olarak gösterebilirsiniz:
#!/bin/bash
set -e
# .env dosyasını oku ve ortam değişkenlerini yükle (varsa)
if [ -f .env ]; then
source .env
fi
# Örnek kullanım
echo "Veritabanı şifresi: ${DB_PASSWORD}"
echo "API anahtarı: ${API_KEY}"
# ... dağıtım komutları devam eder ...
Önemli Not: .env dosyasını asla sürüm kontrol sisteminize (Git) dahil etmeyin! Bu dosyayı .gitignore'a ekleyerek hassas bilgilerin yanlışlıkla herkese açık hale gelmesini engelleyin. Ortam değişkenleri, CI/CD araçları tarafından veya sunucuda el ile ayarlanarak güvenli bir şekilde sağlanabilir. Bu yöntem, betiklerinizin esnekliğini artırırken, güvenlik standartlarını da yükseltir.
Gelişmiş Dağıtım Senaryoları ve En İyi Uygulamalar: Betiğinizi Güçlendirin
Basit bir Docker uygulamasını otomatikleştirmeyi öğrendiniz. Ancak gerçek dünya uygulamaları genellikle birden fazla servisten oluşur (web sunucusu, veritabanı, önbellek gibi) ve daha karmaşık dağıtım senaryoları gerektirir. Bu bölümde, betiğinizi daha güçlü hale getirecek gelişmiş teknikleri, en iyi uygulamaları ve modern DevOps yaklaşımlarını keşfedeceğiz. Böylece sadece tek bir konteyneri değil, tüm uygulama yığınını etkili bir şekilde yönetebileceksiniz.
Docker Compose ile Çok Kapsayıcılı Uygulamaları Yönetme
Tek bir konteyner dağıtmak kolaydır, ancak çoğu modern uygulama genellikle birkaç farklı servisten oluşur. Örneğin, bir web uygulaması genellikle bir veritabanına, belki bir önbellek sunucusuna ve hatta bir arka plan görev işleyicisine ihtiyaç duyar. Bu farklı servislerin her birini ayrı Docker konteynerlerinde çalıştırmak ve birbirleriyle iletişim kurmalarını sağlamak karmaşık olabilir. İşte bu noktada Docker Compose devreye girer.
Docker Compose, çok kapsayıcılı Docker uygulamalarını tanımlamak ve çalıştırmak için bir araçtır. Tek bir docker-compose.yml dosyası kullanarak uygulamanızın tüm servislerini, ağlarını ve depolama birimlerini yapılandırabilirsiniz. Bu dosya, tüm uygulama yığınınızın "kod olarak altyapı" tanımını içerir. docker-compose.yml dosyası genellikle uygulamanızın kök dizininde bulunur ve YAML formatında yazılır.
Örnek docker-compose.yml dosyası:
version: '3.8'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/app # Geliştirme için canlı kod eşleştirme
environment:
FLASK_ENV: development
depends_on:
- db
db:
image: postgres:13
environment:
POSTGRES_DB: mydatabase
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
Bu örnek, bir Flask web uygulamasını (web servisi) ve bir PostgreSQL veritabanını (db servisi) tanımlar. Web servisi, mevcut dizindeki Dockerfile'dan oluşturulur ve 5000 numaralı portu dışarıya açar. Veritabanı servisi ise resmi PostgreSQL imajını kullanır. volumes ve environment gibi bölümlerle depolama ve ortam değişkenlerini yapılandırabilirsiniz. depends_on ile servisler arası bağımlılıkları tanımlamak, servislerin doğru sırada başlatılmasını sağlar.
Dağıtım betiğinizi Docker Compose ile entegre etmek oldukça basittir. Betiğinizde docker build ve docker run yerine, uygulamanızın kök dizininde aşağıdaki komutları kullanırsınız:
# Mevcut servisleri durdur ve kaldır
docker-compose down
# Servisleri oluştur ve arka planda çalıştır
docker-compose up -d --build
Bu komutlar, docker-compose.yml dosyanızdaki tanımlara göre tüm servislerinizi derleyecek, eski konteynerleri kaldıracak ve yeni sürümleri başlatacaktır. Docker Compose'un kullanımı, özellikle çoklu servis mimarilerinde dağıtım sürecini büyük ölçüde basitleştirir ve otomasyon betiklerinizin gücünü artırır.
Sürüm Kontrolü ve Etiketleme Stratejileri: Uygulamalarınızı Nasıl Takip Edersiniz?
Otomatik dağıtımın en önemli yönlerinden biri, uygulamanızın farklı sürümlerini etkili bir şekilde yönetebilmektir. Docker imajlarınızı doğru bir şekilde etiketlemek, hangi imajın hangi koda karşılık geldiğini izlemenizi, sorunlu bir sürümü hızlıca geri almanızı (rollback) ve farklı ortamlar için belirli sürümleri kullanmanızı sağlar. En iyi etiketleme uygulamaları şunları içerir:
- Semantik Versiyonlama:
v1.0.0,v1.0.1,v2.0.0gibi anlamlı sürüm numaraları kullanın. Bu, değişikliklerin türünü (majör, minör, yama) belirtir. - Git Commit Hash: Her Git commit'inin kısa hash'ini (örn.
a1b2c3d) etiket olarak kullanmak, imajı doğrudan belirli bir kod sürümüne bağlamanın en kesin yoludur. Bu, özellikle hata ayıklama ve denetlenebilirlik için çok değerlidir. latestEtiketi: Genellikle en son kararlı sürümü işaret etmek için kullanılır. Ancak üretim ortamında belirli bir sürüm etiketini kullanmak,latestetiketinin aniden değişme riskine karşı daha güvenlidir.- Ortama Özel Etiketler: Geliştirme (
dev), test (test), üretim (prod) gibi ortamlara özel etiketler kullanmak, her ortam için uygun imajın kullanılmasını sağlar.
Dağıtım betiklerinizde, bu etiketleme stratejilerini dinamik olarak uygulayabilirsiniz. Örneğin, Git commit hash'ini otomatik olarak alıp Docker imajı etiketinde kullanabilirsiniz:
#!/bin/bash
set -e
APP_NAME=my-flask-app
GIT_COMMIT_HASH=$(git rev-parse --short HEAD) # Git commit hash'ini al
APP_VERSION=${GIT_COMMIT_HASH} # Etiket olarak kullan
echo "[ADIM 1/4] Docker imajı oluşturuluyor (Etiket: ${APP_NAME}:${APP_VERSION})..."
docker build -t ${APP_NAME}:${APP_VERSION} .
docker tag ${APP_NAME}:${APP_VERSION} ${APP_NAME}:latest # latest etiketini de ekle
# ... diğer dağıtım adımları ...
Bu şekilde, her dağıtımınız otomatik olarak doğru Git commit'iyle ilişkilendirilir, bu da izlenebilirliği büyük ölçüde artırır.
Otomatik Güncelleme ve Geri Alma (Rollback) Mekanizmaları
Otomatik dağıtım sadece yeni sürümleri yüklemekle kalmaz, aynı zamanda sorunlu güncellemeler durumunda hızlı ve güvenli geri alma yeteneğini de içermelidir. Dağıtım betiklerinizde, yeni bir sürümü dağıtırken eski konteyneri durdurup yenisini başlatırsınız. Ancak geri alma, eski, bilinen iyi bir imaja hızla geri dönebilme yeteneği anlamına gelir. Etiketleme stratejiniz burada kritik rol oynar.
Geri alma işlemini kolaylaştırmak için, betiğinizin yeni bir sürümü dağıtırken önceki çalışan imajın etiketini bir kenara not etmesi veya bir dağıtım geçmişi tutması faydalı olabilir. Bir sorun tespit edildiğinde, basit bir komutla (örneğin rollback.sh v1.0.0) belirlenen eski bir imajın tekrar çalıştırılmasını sağlayabilirsiniz. Modern CI/CD araçları genellikle bu tür geri alma yeteneklerini yerleşik olarak sunar.
Kesinti süresini (downtime) azaltmak için "mavi/yeşil dağıtım" veya "kanarya dağıtımı" gibi daha gelişmiş stratejiler de mevcuttur. Mavi/yeşil dağıtımda, uygulamanın yeni sürümü (yeşil) eski sürümle (mavi) aynı anda ayrı bir ortamda çalıştırılır. Yeni sürüm test edildikten sonra, trafik tamamen yeni sürüme yönlendirilir ve eski sürüm kapatılır. Bu, neredeyse sıfır kesinti süresi sağlar. Kanarya dağıtımında ise, yeni sürüm trafiğin küçük bir yüzdesine yönlendirilir ve sorun yaşanmazsa kademeli olarak daha fazla kullanıcıya açılır.
Sürekli Entegrasyon ve Sürekli Teslimat (CI/CD) Entegrasyonu
Otomatik dağıtım betikleriniz, modern CI/CD boru hatlarının kalbinde yer alır. Sürekli Entegrasyon (CI), geliştiricilerin kodlarını sık sık bir ana depoya birleştirmesi ve her birleştirmenin otomatik olarak test edilmesidir. Sürekli Teslimat (CD), CI'ın bir uzantısıdır; başarılı testlerden geçen kod değişikliklerinin otomatik olarak bir test veya üretim ortamına dağıtılabileceği anlamına gelir.
Dağıtım betikleriniz, GitLab CI/CD, GitHub Actions, Jenkins, CircleCI gibi popüler CI/CD araçları tarafından otomatik olarak tetiklenebilir. Örneğin, her kod gönderiminde (push), CI/CD boru hattı otomatik olarak tetiklenir:
- Kod çekilir.
- Unit ve entegrasyon testleri çalıştırılır.
- Testler başarılı olursa, Docker imajı derlenir.
- İmaj bir Docker kayıt defterine (Docker Hub, GitLab Registry vb.) gönderilir.
- Son olarak, bizim
deploy.shbetiğimiz çalıştırılarak uygulama bir sunucuya veya Kubernetes kümesine dağıtılır.
Bu entegrasyon, yazılım geliştirme sürecini son derece hızlandırır, hataları erken yakalar ve yeni özelliklerin kullanıcılara çok daha hızlı ulaşmasını sağlar. Otomatik dağıtım betikleriniz, bu sorunsuz iş akışının temel yapı taşıdır.
Vaka Analizi: Küçük Bir Proje İçin Otomatik Dağıtım Betiği
Şimdiye kadar teorik bilgileri ve temel örnekleri ele aldık. Gelin, öğrendiklerimizi gerçekçi bir senaryoda uygulayalım: Basit bir blog uygulamasının (daha önce oluşturduğumuz Flask uygulamasını genişlettiğimizi varsayalım) uzak bir sunucuya otomatik olarak dağıtılması. Amacımız, geliştiricinin her kod değişikliğinden sonra SSH ile sunucuya bağlanıp manuel komutlar çalıştırma yükünden kurtulmaktır. Bunun yerine, yerel makineden çalıştırılan tek bir betik, tüm dağıtım sürecini halledecektir.
Senaryo: Uzak Sunucuya Otomatik Dağıtım
Hayal edelim ki my-flask-app adlı blog uygulamamız var ve bu uygulama uzak bir Linux sunucusunda çalışıyor. Her yeni özellik veya hata düzeltmesi eklendiğinde, bu güncellemeleri uzak sunucuya dağıtmak istiyoruz. Dağıtım sürecini otomatikleştirmek için aşağıdaki adımları izleyeceğiz:
- Yerel makinemizde uygulamanın Docker imajını derleyeceğiz.
- Bu imajı Docker Hub gibi bir genel veya özel Docker kayıt defterine göndereceğiz.
- SSH üzerinden uzak sunucuya bağlanacağız.
- Uzak sunucuda mevcut çalışan konteyneri durdurup kaldıracağız.
- Yeni imajı Docker kayıt defterinden uzak sunucuya çekeceğiz.
- Yeni imajdan bir Docker konteyneri başlatacağız.
Bu senaryo, üretim ortamına dağıtım yaparken yaygın olarak kullanılan bir modeli temsil eder. Güvenliği sağlamak için SSH anahtarlarının kullanıldığını ve uzak sunucuda Docker'ın kurulu olduğunu varsayıyoruz.
Örnek Uzak Dağıtım Betiği (remote_deploy.sh)
Aşağıdaki betik, yukarıdaki adımları otomatik olarak gerçekleştirecektir. Bu betiği my-docker-app dizininizin kökünde remote_deploy.sh adıyla kaydedin.
#!/bin/bash
set -e
# --- Ayarlanabilir Değişkenler ---
APP_NAME=my-flask-app
# İmaj etiketini dinamik olarak almak için Git commit hash'ini kullanabiliriz
# Ya da parametre olarak alabiliriz. Şimdilik sabit bir sürüm kullanalım.
# GIT_COMMIT_HASH=$(git rev-parse --short HEAD)
# IMAGE_TAG=${GIT_COMMIT_HASH}
IMAGE_TAG=1.0 # Manuel olarak belirlenmiş imaj etiketi
DOCKER_HUB_USERNAME=kullaniciadiniz # Docker Hub kullanıcı adınız
REMOTE_USER=ubuntu
REMOTE_HOST=54.123.45.67 # Uzak sunucunuzun IP adresi veya hostname
REMOTE_PORT=5000 # Uygulamanın uzak sunucuda çalışacağı port
CONTAINER_NAME=my-running-app_prod # Uzak sunucudaki konteyner adı
# --- Doğrulama ---
if [ -z "$DOCKER_HUB_USERNAME" ] || [ "$DOCKER_HUB_USERNAME" == "kullaniciadiniz" ]; then
echo "HATA: Lütfen DOCKER_HUB_USERNAME değişkenini Docker Hub kullanıcı adınızla güncelleyin."
exit 1
fi
if [ -z "$REMOTE_HOST" ] || [ "$REMOTE_HOST" == "54.123.45.67" ]; then
echo "HATA: Lütfen REMOTE_HOST değişkenini uzak sunucunuzun IP adresi veya hostname'i ile güncelleyin."
exit 1
fi
# --- ADIM 1: Yerel Docker İmajını Oluştur ---
echo "[ADIM 1/6] Yerel Docker imajı oluşturuluyor: ${APP_NAME}:${IMAGE_TAG}"
docker build -t ${APP_NAME}:${IMAGE_TAG} .
# --- ADIM 2: İmajı Docker Hub'a Gönder ---
echo "[ADIM 2/6] Docker Hub'a giriş yapılıyor ve imaj gönderiliyor..."
# Eğer daha önce giriş yapmadıysanız docker login komutunu manuel çalıştırmanız gerekebilir.
# Ya da CI/CD ortamında DOCKER_PASSWORD ortam değişkeni ile otomatik giriş sağlanabilir.
docker tag ${APP_NAME}:${IMAGE_TAG} ${DOCKER_HUB_USERNAME}/${APP_NAME}:${IMAGE_TAG}
docker push ${DOCKER_HUB_USERNAME}/${APP_NAME}:${IMAGE_TAG}
echo "[ADIM 3/6] Uzak sunucuya SSH üzerinden bağlanılıyor ve dağıtım başlatılıyor..."
# SSH üzerinden uzak sunucuda komutları çalıştır
ssh ${REMOTE_USER}@${REMOTE_HOST} "
set -e
echo "Uzak sunucuda: Mevcut '${CONTAINER_NAME}' konteyneri kontrol ediliyor ve durduruluyor (varsa)..."
if docker ps -a --format '{{.Names}}' | grep -q ${CONTAINER_NAME}; then
docker stop ${CONTAINER_NAME}
docker rm ${CONTAINER_NAME}
else
echo "Uzak sunucuda: Mevcut '${CONTAINER_NAME}' konteyneri bulunamadı."
fi
echo "Uzak sunucuda: Yeni Docker imajı çekiliyor: ${DOCKER_HUB_USERNAME}/${APP_NAME}:${IMAGE_TAG}"
docker pull ${DOCKER_HUB_USERNAME}/${APP_NAME}:${IMAGE_TAG}
echo "Uzak sunucuda: Yeni Docker konteyneri başlatılıyor..."
docker run -d -p ${REMOTE_PORT}:${REMOTE_PORT} --name ${CONTAINER_NAME} ${DOCKER_HUB_USERNAME}/${APP_NAME}:${IMAGE_TAG}
echo "Uzak sunucuda: Uygulama başarıyla başlatıldı!"
docker ps
"
echo "[ADIM 6/6] Dağıtım tamamlandı! Uygulamayı kontrol etmek için: http://${REMOTE_HOST}:${REMOTE_PORT}"
Bu betiği kullanmadan önce dikkat etmeniz gerekenler:
DOCKER_HUB_USERNAME,REMOTE_USERveREMOTE_HOSTdeğişkenlerini kendi bilgilerinizle güncelleyin.- Uzak sunucunuzda Docker kurulu ve
dockerkomutlarını çalıştırabilen bir kullanıcınız (REMOTE_USER) olmalı. - Yerel makinenizden uzak sunucuya parola girmeden SSH bağlantısı kurabilmek için SSH anahtarları kurmanız önerilir. Aksi takdirde, her SSH komutunda parola girmeniz istenecektir.
- Eğer Docker Hub'a daha önce giriş yapmadıysanız,
docker pushkomutundan önce yerel makinenizdedocker loginkomutunu çalıştırmanız gerekebilir. CI/CD ortamlarında bu genellikle ortam değişkenleri aracılığıyla halledilir.
Betiği çalıştırılabilir yapmak için chmod +x remote_deploy.sh komutunu kullanın ve ardından ./remote_deploy.sh ile çalıştırın. Bu betik, lokaldeki imajı derleyecek, Docker Hub'a gönderecek ve ardından SSH üzerinden uzak sunucunuzda yeni imajı çekip uygulamanızı yeniden başlatacaktır. Bu sayede, tek bir komutla uygulamanızı üretim ortamına dağıtabileceksiniz. Bu vaka analizi, otomatik dağıtım betiklerinin ne kadar güçlü ve zaman tasarrufu sağlayan araçlar olabileceğini açıkça göstermektedir.
Sonuç: Otomatik Docker Dağıtımında Ustalaşmak ve Sıkça Sorulan Sorular
Bu kapsamlı rehber boyunca, manuel uygulama dağıtımının zorluklarından, Docker'ın sunduğu çözümlere ve nihayetinde otomatik dağıtım betiklerinin nasıl oluşturulacağına kadar geniş bir yelpazeyi ele aldık. Temel Docker kavramlarını anladık, basit bir Flask uygulamasını Dockerize ettik ve bu süreci otomatikleştiren bir Shell betiği yazdık. Ayrıca, Docker Compose ile çok servisli uygulamaların yönetiminden, sürüm kontrolü ve etiketleme stratejilerine, hatta CI/CD entegrasyonuna kadar ileri düzey konulara da değindik. Bir vaka analiziyle, uzak bir sunucuya otomatik dağıtımın nasıl yapılabileceğini pratik bir örnekle gösterdik.
Otomatik Docker dağıtımı, yazılım geliştirme süreçlerinizi kökten değiştirebilecek güçlü bir araçtır. Daha hızlı, daha güvenilir ve daha tutarlı dağıtımlar sayesinde, geliştirme ekipleri daha az operasyonel yükle karşılaşır ve daha çok yenilik yapmaya odaklanabilirler. İnsan hatası riski azalırken, üretim ortamındaki kesinti süreleri minimuma iner. Bu yetenekler, modern DevOps kültürünün temelini oluşturur ve günümüzün rekabetçi teknoloji dünyasında vazgeçilmez bir avantaj sağlar.
Bu makale, otomatik Docker dağıtımına başlamak için size sağlam bir temel sunsa da, bu alan sürekli gelişmektedir. Bir sonraki adım olarak, farklı CI/CD araçlarını (Jenkins, GitLab CI, GitHub Actions) keşfedebilir, Kubernetes gibi konteyner orkestrasyon araçlarını inceleyebilir ve daha karmaşık dağıtım stratejilerini (mavi/yeşil, kanarya) derinlemesine araştırabilirsiniz. Unutmayın, pratik yapmak ve sürekli öğrenmek, bu alanda ustalaşmanın anahtarıdır. Başarılar dileriz!
Sıkça Sorulan Sorular (SSS):
-
S: Dağıtım betiklerimi nerede saklamalıyım?
C: Genellikle dağıtım betiklerinizi, ilişkili oldukları uygulamanın kaynak koduyla birlikte Git gibi bir sürüm kontrol sisteminde saklamalısınız. Bu, betiklerin uygulamanın kod tabanıyla birlikte versiyonlanmasını sağlar, değişikliklerin izlenebilirliğini artırır ve ekip üyeleri arasında işbirliğini kolaylaştırır. Ancak hassas bilgileri (API anahtarları, şifreler) betik içinde tutmak yerine ortam değişkenleri,
.envdosyaları (veya bulut sağlayıcılarının gizli yönetim hizmetleri) kullanarak güvenliği sağlamalısınız..envdosyasını ise.gitignore'a ekleyerek asla sürüm kontrolüne dahil etmeyin. -
S: Betiğim neden çalışmıyor? Hata ayıklama ipuçları nelerdir?
C: Betiklerin çalışmamasının en yaygın nedenleri sözdizimi hataları, dosya izinleri veya eksik bağımlılıklardır. İlk olarak, betiğin çalıştırılabilir olduğundan emin olun (
chmod +x script.sh). Hata ayıklama için betiğibash -x deploy.shkomutuyla çalıştırın.-xparametresi, Shell'in her komutu yürütmeden önce ekrana yazdırmasını sağlar, bu da sorunun nerede olduğunu anlamanıza yardımcı olur. Ayrıca, her komutun dönüş kodunu (echo $?) kontrol etmek, hangi komutun başarısız olduğunu anlamak için önemlidir. Genellikle betiğin başındaset -ekullanmak, hata durumunda betiğin durmasını sağlayarak sorunu daha erken fark etmenize yardımcı olur. -
S: Farklı ortamlar (geliştirme, test, üretim) için aynı betiği kullanabilir miyim?
C: Evet, kesinlikle! Bu, otomatik dağıtımın en büyük avantajlarından biridir ve DevOps felsefesinin temel prensiplerindendir. Betiğinizin içine koşullu mantık (
if-elseyapıları) ekleyebilir veya ortam değişkenleri (export ENVIRONMENT=production) kullanarak farklı ortamlar için özelleştirmeler yapabilirsiniz. Örneğin,REMOTE_HOSTveyaIMAGE_TAGgibi değişkenleri betiği çalıştırırken parametre olarak veya ortam değişkenleri olarak ileterek farklı hedefler için aynı betiği kullanabilirsiniz. Bu yaklaşım, tüm ortamlar arasında tutarlılığı artırır ve "çalışan" bir çözümün her ortamda aynı şekilde çalıştığını garanti eder. -
S: Docker imajlarımı ne sıklıkla güncellemeli ve etiketlemeliyim?
C: Her yeni özellik, hata düzeltmesi veya önemli bir kod değişikliği için yeni bir Docker imajı oluşturmalı ve bu imajı benzersiz bir etiketle işaretlemelisiniz. Semantik versiyonlama (
v1.2.3), Git commit hash'leri (a1b2c3d) veya her ikisinin bir kombinasyonu (v1.2.3-a1b2c3d) bu etiketleme için iyi yöntemlerdir.latestetiketini sadece en son kararlı sürümü belirtmek için kullanmak iyi bir uygulama olsa da, üretim ortamında dağıtım yaparken spesifik, versiyonlu etiketleri kullanmak geri alma (rollback) işlemlerini çok daha güvenli ve öngörülebilir hale getirir. Bu, hangi kodun hangi imaja karşılık geldiğini her zaman bilmenizi sağlar.