Bu makalede9 bölüm
- Teknoloji
- Docker Engine, Docker Compose v2, Compose Specification, Nginx, PostgreSQL
- Konu
- Tek sunucuda Compose ile üretim yayını
- Seviye
- Orta–ileri
- Ön koşullar
- Docker Engine ve Compose eklentisi kurulu bir Linux sunucu
- Uygulamanın container imajı veya Dockerfile’ı
- Temel ağ ve reverse proxy bilgisi
Geliştiricinin dizüstünde çalışan compose dosyası üretime olduğu gibi taşındığında sorunlar sırayla gelir: latest etiketi bir gece başka sürüm çeker, dosyaya gömülü parola depoya girer, yayınlanan veritabanı portu güvenlik duvarını atlar, sınırsız json-file logları diski doldurur. Compose geliştirme için tasarlandı; yine de doğru yapılandırıldığında tek sunuculu üretim yayınında işini görür. Aşağıda üretimde verilmesi gereken kararlar sırayla ele alınıyor ve Compose’un yetmediği eşik açıkça tarif ediliyor.
Compose üretimde ne zaman yeterli
Compose bir orkestratör değildir. Tek bir Docker Engine’i yönetir, sunucu çökerse servisleri başka makineye taşımaz, güncellemelerde trafik geçişini yönetmez. Buna karşılık kurulumu basittir, öğrenme maliyeti düşüktür ve yığının tamamını tek dosyada tarif eder. Az parça, az arıza. Şu koşullarda üretim için makul bir seçimdir:
- Uygulama tek sunucuya sığıyor ve dikey büyüme (daha güçlü sunucu) yeterli.
- Sunucu arızasında kabul edilen kurtarma süresi, yedekten veya hazır bekleyen ikinci sunucudan yeniden kurulumla karşılanabiliyor.
- Güncellemeler sırasında kısa kesinti kabul edilebiliyor ya da reverse proxy düzeyinde ayrıca çözülüyor.
- Ekip Kubernetes gibi bir platformu işletecek kapasitede değil veya buna ihtiyaç duymuyor.
Örnek üretim compose dosyası
Aşağıdaki örnek; bir web uygulaması, PostgreSQL ve önde paylaşılan bir reverse proxy ağına bağlanan yapıyı gösterir. Sonraki bölümler her kararı ayrı ayrı açıklar.
name: shop
services:
app:
image: registry.example.com/shop/app:1.8.3
restart: unless-stopped
env_file: .env.production
environment:
DB_HOST: db
DB_PASSWORD_FILE: /run/secrets/db_password
secrets: [db_password]
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/healthz"]
interval: 30s
timeout: 5s
retries: 3
start_period: 40s
read_only: true
tmpfs: [/tmp]
security_opt: ["no-new-privileges:true"]
deploy:
resources:
limits:
cpus: "1.5"
memory: 768M
logging:
driver: json-file
options:
max-size: "20m"
max-file: "5"
networks: [proxy, backend]
db:
image: postgres:16.4
restart: unless-stopped
environment:
POSTGRES_DB: shop
POSTGRES_USER: shop
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets: [db_password]
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U shop -d shop"]
interval: 10s
timeout: 5s
retries: 5
networks: [backend]
secrets:
db_password:
file: ./secrets/db_password.txt
volumes:
db_data:
networks:
backend:
internal: true
proxy:
external: true
Yapılandırmayı uygulamadan önce docker compose config ile birleştirilmiş ve değişkenleri çözülmüş hali görüntüleyin; söz dizimi hataları ve beklenmeyen değişken değerleri burada ortaya çıkar. Healthcheck’te kullanılan wget veya curl’ün imajda bulunduğundan emin olun; minimal imajlarda bu araçlar yoktur ve kontrol her zaman başarısız görünür. Sürekli “unhealthy” görünen ama çalışan bir container’da ilk bakılacak yer burasıdır.
İmaj sürüm sabitleme ve derleme
latest veya yalnızca ana sürüm (postgres:16) etiketi, aynı compose dosyasının farklı günlerde farklı yazılım çalıştırmasına yol açar. Sunucu yeniden başlatıldığında ya da biri docker compose pull çalıştırdığında beklenmeyen bir sürüm devreye girebilir. Sürüm, karar verilerek değişmeli. Üretimde:
- Tam sürüm etiketi kullanın (
postgres:16.4). Daha sıkı kontrol için etiketle birlikte özet de sabitlenebilir:postgres:16.4@sha256:…; bu durumda etiket değişse bile aynı imaj çekilir. - Kendi uygulamanızın imajını sunucuda
build:ile derlemek yerine CI hattında derleyip bir registry’ye sürüm etiketiyle gönderin. Böylece sunucuda yalnızca test edilmiş imaj çalışır ve geri dönüş, etiketi bir önceki sürüme çevirmekten ibaret olur. Hattın kurulumu GitHub Actions ile CI/CD hattı rehberinde anlatılıyor. - Temel imajları güvenlik güncellemeleri için düzenli olarak yeniden derleyin; sabitleme, güncellemeyi bırakmak değil, güncellemeyi kontrollü yapmak demektir.
Ortam değişkenleri ve gizli bilgiler
Compose’da iki farklı “env” kavramı sık karıştırılır. Proje dizinindeki .env dosyası compose dosyasındaki ${DEGISKEN} ifadelerini doldurmak için okunur; env_file: ise değişkenleri container’ın içine aktarır. Ortama özgü ayarlar (alan adı, log seviyesi, dış servis adresleri) için env_file yeterlidir, ancak parola ve API anahtarları için zayıf bir seçimdir: ortam değişkenleri docker inspect çıktısında görünür, hata raporlarına ve alt süreçlere sızabilir.
Daha iyi yöntem Compose secrets tanımıdır. Dosya tabanlı bir secret container içinde /run/secrets/<ad> yolunda salt okunur dosya olarak görünür. Resmi PostgreSQL, MariaDB ve MySQL imajları _FILE sonekli değişkenlerle parolayı dosyadan okumayı destekler; kendi uygulamanızda da aynı deseni uygulayın. Kurallar:
secrets/dizini ve.env.productionsürüm kontrolüne girmez;.gitignoreve.dockerignoredosyalarına eklenir.- Dosya izinleri yalnızca dağıtım kullanıcısının okuyabileceği şekilde ayarlanır.
- Gizli bilgiler imaja hiçbir zaman
COPYveyaENVile gömülmez; imaj katmanları geri okunabilir.
Ağ yapısı ve port yayınlama
Örnekteki backend ağı internal: true olarak tanımlandığı için dış dünyaya çıkışı yoktur; veritabanı yalnızca uygulamadan erişilebilir. Uygulama ise önde çalışan reverse proxy ile önceden oluşturulmuş (docker network create proxy) ortak bir ağ üzerinden konuşur, bu yüzden hiçbir port yayınlamaz. Proxy yapılandırmasının ayrıntıları Nginx reverse proxy yapılandırması yazısında.
Port yayınlıyorsanız şu tuzağı bilin: Docker, yayınlanan portlar için kendi iptables kurallarını ekler ve bu kurallar UFW gibi ön yüz araçlarıyla tanımlanan kuralları atlayabilir. "5432:5432" yazılan bir veritabanı portu, güvenlik duvarında kapalı görünse bile internetten erişilebilir hale gelebilir. Yalnızca yerel erişim gerekiyorsa portu açıkça loopback adresine bağlayın: "127.0.0.1:8080:3000". Doğrulamayı sunucunun dışından bir port taramasıyla yapın; içeriden bakmak yanıltır.
Volume, yedek ve veri kalıcılığı
Container’lar geçicidir; kalıcı olması gereken her şey (veritabanı dosyaları, kullanıcı yüklemeleri) adlandırılmış volume’de veya bind mount’ta tutulmalıdır. docker compose down -v komutu adlandırılmış volume’leri de siler. Üretim sunucusunda bu komut operasyon kurallarında açıkça yasaklanmalı; tek bir alışkanlık hatası veritabanını götürür.
Volume’ün varlığı yedek demek değildir. Çalışan bir veritabanının dosyalarını tar ile kopyalamak tutarsız bir yedek üretebilir; veritabanının kendi aracını kullanın:
# Mantıksal yedek (PostgreSQL özel biçim)
docker compose exec -T db pg_dump -U shop -Fc shop > /backup/shop_$(date +%F).dump
# Yükleme dizini gibi statik veriler için volume arşivi
docker run --rm -v shop_uploads:/data:ro -v /backup:/backup alpine \
tar czf /backup/uploads_$(date +%F).tar.gz -C /data .
Compose, volume adlarının önüne proje adını ekler (shop_uploads gibi); docker volume ls ile gerçek adı doğrulayın. Yedekler sunucu dışına kopyalanmalı ve geri yükleme düzenli olarak boş bir ortamda denenmelidir. Test edilmemiş yedek, yedek değildir. Yedek saklama kurgusu için 3-2-1-1-0 yedekleme kuralı iyi bir çerçeve sunar.
Healthcheck, restart ve kaynak limitleri
| Ayar | Ne sağlar | Dikkat |
|---|---|---|
restart: unless-stopped |
Çöken süreç ve sunucu yeniden başlatmasında servis geri gelir | Sağlıksız ama çalışan container’ı yeniden başlatmaz |
healthcheck |
Servisin gerçekten yanıt verdiğini ölçer | Uç nokta ağır sorgu çalıştırmamalı |
depends_on: condition: service_healthy |
Uygulama, veritabanı hazır olmadan başlamaz | Yalnızca başlangıç sırası içindir |
deploy.resources.limits |
Bir servisin tüm belleği tüketmesini engeller | Bellek sınırı aşılırsa süreç OOM ile sonlandırılır |
logging seçenekleri |
Log dosyalarının diski doldurmasını önler | Varsayılan json-file sürücüsünde boyut sınırı yoktur |
Yayın sırasında docker compose up -d --wait kullanmak, komutun servisler sağlıklı duruma gelene kadar beklemesini ve aksi halde hata koduyla dönmesini sağlar; CI/CD hattında bir sonraki adımın sağlıksız bir yayının üzerine çalışmasını önler. Bellek limitini belirlerken uygulamanın çalışma zamanı ayarlarını da uyumlu hale getirin (örneğin Node.js’te --max-old-space-size, JVM’de yığın boyutu); aksi halde süreç limiti bilmeden büyür ve sonlandırılır.
Ek sertleştirme için örnekteki read_only: true kök dosya sistemini salt okunur yapar, no-new-privileges ise süreçlerin setuid ile yetki yükseltmesini engeller. Container içinde root yerine imajda tanımlı bir uygulama kullanıcısıyla çalışmak da aynı amaca hizmet eder.
Orkestratöre geçiş eşikleri
Kubernetes, Nomad veya Docker Swarm gibi bir orkestratöre geçiş moda değil, somut ihtiyaç kararıdır. Aşağıdakilerden biri ya da birkaçı ortaya çıktığında geçişi değerlendirin:
- Kesintisiz güncelleme bir iş gereksinimi haline geldi ve reverse proxy düzeyinde yapılan çözümler karmaşıklaşıyor; bu tekniklerin seçenekleri sıfır kesintili dağıtım yazısında karşılaştırılıyor.
- Tek sunucu arızasında kabul edilebilir kesinti süresi, yeniden kurulumla karşılanamayacak kadar kısa.
- Yük, yatay ölçekleme (birden çok sunucuya dağılma) gerektiriyor.
- Sunucu ve yığın sayısı arttı; her birinde ayrı compose dosyası, ayrı yedek betiği ve ayrı izleme yönetmek hata üretmeye başladı.
Bu eşiklere gelmeden orkestratör kurmak, küçük bir ekipte uygulamadan çok platformu işletmek anlamına gelir. Karmaşıklık da bir arıza kaynağıdır. Yayın mimarisi, imaj hattı ve geçiş kararı birlikte planlanmalıdır; bunu Docker ve container tabanlı yayın hizmetimiz kapsamında ele alıyoruz. Tüm alanların tanımı Compose file reference belgesindedir.
Sık sorulan sorular
docker-compose ile docker compose arasında fark var mı?
docker-compose, Python ile yazılmış eski bağımsız araçtır (Compose v1) ve artık geliştirilmiyor. Güncel sürüm, Docker CLI’ya eklenti olarak gelen docker compose komutudur (Compose v2). Dosyalardaki version alanı da artık dikkate alınmaz; yeni dosyalarda yazmaya gerek yoktur.
Healthcheck başarısız olan container’ı Docker otomatik yeniden başlatır mı?
Tek başına Docker Engine ve Compose’da hayır. Healthcheck durumu unhealthy olarak işaretlenir, depends_on koşullarında ve izlemede kullanılır; restart politikası ise yalnızca süreç sonlandığında devreye girer. Sağlıksız container’ı yeniden başlatmak için orkestratör, harici bir izleme betiği ya da uygulamanın kendini sonlandırması gerekir.
Compose ile yayında güncelleme sırasında kesinti olur mu?
Evet, kısa da olsa olur. docker compose up -d yeni imajla container’ı yeniden oluştururken eskisi durdurulur, yenisi başlar ve arada istekler karşılanmaz. Kesintiyi önlemek için reverse proxy arkasında iki ayrı yığınla blue-green geçiş gibi teknikler gerekir; Compose bunu kendiliğinden yapmaz.
Veritabanını da Compose içinde çalıştırmalı mıyım?
Tek sunuculu küçük ve orta yükteki projelerde mümkündür, ancak yedek, sürüm yükseltme ve izleme sorumluluğu size kalır. Yönetilen bir veritabanı hizmeti veya ayrı bir veritabanı sunucusu, uygulama yığınını yeniden kurarken veriyi riske atmamayı kolaylaştırır.
- Teknoloji
- Docker Engine, Docker Compose v2, Compose Specification, Nginx, PostgreSQL
- Konu
- Tek sunucuda Compose ile üretim yayını
- Seviye
- Orta–ileri
- Ön koşullar
- Docker Engine ve Compose eklentisi kurulu bir Linux sunucu
- Uygulamanın container imajı veya Dockerfile’ı
- Temel ağ ve reverse proxy bilgisi
Web Sunucuları ve DevOps