İçeriğe geç

EğitimlerKonteynerler ve Docker

Docker Compose temelleri: Linux sunucuda çok konteynerli uygulamalar

Linux sunucuda Docker Compose öğrenin: compose.yaml, .env değişkenleri, sağlık kontrolleri, yeniden başlatma, profiller, güncelleme, yedekleme ve çoklu proje.

  • Başlangıç
  • 35 dk okuma
  • Güncellendi

Denendiği sistemler: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12, Debian 13

Bu sayfada
  1. Ön koşullar
  2. Adım 1 — Bir proje klasörü oluşturun
  3. Adım 2 — Ayarları ve gizli bilgileri .env dosyasına koyun
  4. Adım 3 — compose.yaml dosyasını yazın
  5. Adım 4 — Servisleri sağlık kontrolleriyle doğru sırada başlatın
  6. Adım 5 — Yeniden başlatma politikalarını seçin ve portları gizli tutun
  7. Adım 6 — Stack'i kontrol edin, başlatın ve izleyin
  8. Adım 7 — İsteğe bağlı servisler için profilleri kullanın
  9. Adım 8 — Günlük komutlar ve down -v'nin sildikleri
  10. Adım 9 — Bir sunucuda birden fazla proje çalıştırın
  11. Compose stack'ini güncelleme
  12. Yedekleme ve geri yükleme
  13. Sorun giderme
  14. The "POSTGRES_USER" variable is not set. Defaulting to a blank string.
  15. dependency failed to start: container demo-db-1 is unhealthy
  16. Bind for 127.0.0.1:8080 failed: port is already allocated
  17. compose.yaml veya .env değişikliklerim etki etmiyor
  18. the attribute version is obsolete, it will be ignored
  19. ufw engellediği hâlde bir konteyner portuna internetten erişilebiliyor
  20. Sonraki adımlar

Docker Compose, bir uygulamanın tamamını, yani konteynerlerini, ağlarını, volume'larını ve ayarlarını tek bir YAML dosyasında tanımlar ve tek komutla başlatır. Bu kütüphanedeki uygulama rehberlerinin neredeyse hepsi bir Compose dosyasıyla gelir; biçimi bir kez öğrenmek her yerde işinize yarar. Bu rehber Linux sunucuda küçük ama gerçekçi bir stack kurar: bir web servisi, sağlık kontrolü olan bir PostgreSQL veritabanı ve bir profilin arkasında duran isteğe bağlı bir yönetim aracı. Bu sırada gizli bilgileri .env dosyasında tutar, portları yalnızca 127.0.0.1 üzerinde yayınlar, bir Compose projesini nasıl güncelleyeceğinizi, yedekleyeceğinizi ve geri yükleyeceğinizi, aynı sunucuda birden fazla projeyi nasıl çalıştıracağınızı öğrenirsiniz.

Ön koşullar

Compose'un kendisi küçük bir CLI eklentisidir ve Docker bunun için donanım gereksinimi yayınlamaz. İhtiyacınız çalıştıracağınız konteynerlere bağlıdır. Bu rehberdeki örnek stack (nginx ve PostgreSQL) için aşağıdaki değerler resmi bir rakam değil, temkinli bir başlangıç noktasıdır:

KaynakEn düşük (resmi)Önerilen başlangıç
CPUYayınlanmamış1 vCPU
RAMYayınlanmamış1 GB
DiskYayınlanmamışİmajlar, volume'lar ve yedekler için 10 GB boş alan

Adım 1 — Bir proje klasörü oluşturun

Bir Compose projesi, içinde compose.yaml dosyası bulunan bir klasördür. Varsayılan proje adı klasörün adıdır ve Compose oluşturduğu her şeyin başına bu adı ekler: ağ demo_default, volume demo_db_data, konteynerler demo-db-1 gibi adlar alır. Proje adlarında yalnızca küçük harf, rakam, tire ve alt çizgi kullanılabilir.

Bu kütüphanedeki ortak düzene uyarak projeyi /opt altında oluşturun ve sahipliğini kullanıcınıza verin:

Bash
sudo mkdir -p /opt/demo
sudo chown $USER:$USER /opt/demo
cd /opt/demo

Tüm docker compose komutlarını bu klasörden çalıştırın. Komutları docker compose --project-directory /opt/demo … ile başka bir yerden de çalıştırabilirsiniz, ancak klasörde kalmak daha basittir.

Adım 2 — Ayarları ve gizli bilgileri .env dosyasına koyun

Compose, proje klasöründeki .env adlı dosyayı kendiliğinden okur ve compose.yaml içinde ${DEGISKEN} yazdığınız her yere değerini yerleştirir. Böylece parolalar ve sunucuya özgü ayarlar Compose dosyasının dışında kalır; dosyayı gizli bilgi sızdırmadan paylaşabilir veya sürüm kontrolüne koyabilirsiniz.

Güçlü bir veritabanı parolası üretin ve .env dosyasını yazın:

Bash
openssl rand -hex 32
.env
# /opt/demo/.env
POSTGRES_USER=demo
POSTGRES_PASSWORD=paste-the-generated-value-here
POSTGRES_DB=demo
WEB_PORT=8080

Ardından dosyayı yalnızca sizin okuyabileceğiniz hale getirin:

Bash
chmod 600 /opt/demo/.env

Değişken yerleştirme sözdizimi varsayılan ve zorunlu değerleri destekler:

SözdizimiSonuç
${VAR}VAR değeri; tanımlı değilse uyarıyla birlikte boş metin
${VAR:-default}VAR tanımsız veya boşsa default
${VAR:?message}VAR tanımsız veya boşsa message ile durur
$$Compose'un konteynere olduğu gibi ilettiği düz bir $

Kabuğunuzda export edilen değişkenler .env dosyasını geçersiz kılar; --env-file ise onun yerine başka bir dosya kullanır. .env dosyası yalnızca değişken yerleştirme içindir; değişkenleri konteynere iletmek için yine de environment: altında listelemeniz (veya env_file: ile bir dosyayı göstermeniz) gerekir.

Adım 3 — compose.yaml dosyasını yazın

/opt/demo/compose.yaml dosyasını oluşturun. web servisi uygulamanızın yerini tutar, db bir PostgreSQL veritabanıdır, adminer ise yalnızca siz istediğinizde başlayan küçük bir veritabanı yönetim aracıdır:

YAML
services:
  web:
    image: nginx:stable
    restart: unless-stopped
    ports:
      - "127.0.0.1:${WEB_PORT:-8080}:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:18
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - db_data:/var/lib/postgresql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  adminer:
    image: adminer
    profiles: ["tools"]
    ports:
      - "127.0.0.1:8081:8080"
    depends_on:
      db:
        condition: service_healthy

volumes:
  db_data:

web için bir test sayfası oluşturun:

Bash
mkdir -p /opt/demo/html
echo "Hello from Compose" > /opt/demo/html/index.html

Her bölümün görevi:

  • services — her konteyner için bir kayıt. image çekilecek imajı belirtir; Compose imajı stack'i ilk başlattığınızda çeker.
  • volumes (en üst düzey) — Docker'ın /var/lib/docker/volumes/ altında sakladığı db_data adlı volume'u tanımlar. Konteyner yeniden oluşturulsa da korunur. web altındaki ./html kaydı ise bir bind mount'tur: ana makinedeki bir klasör konteynere bağlanır, burada salt okunurdur (:ro).
  • Ağlar — hiç ağ tanımlamadınız; bu yüzden Compose demo_default adlı tek bir ağ oluşturur ve tüm servisleri ona bağlar. Her servise diğerlerinden servis adıyla ulaşılır: bir uygulama veritabanına db adresi ve 5432 portu üzerinden bağlanır. Yayınlanan ana makine portunu yalnızca ağın dışından erişim için kullanın.
  • postgres:18 ve volume yolu — PostgreSQL 18'den itibaren resmi imaj verileri /var/lib/postgresql altında saklar; volume bu yüzden oraya bağlanır. PostgreSQL 17 ve öncesinde yol /var/lib/postgresql/data'dır; her zaman imajın belgelerini kontrol edin.

Dosyada version: satırı yoktur. Bu öğe kullanımdan kalkmıştır; Compose onu yok sayar ve varsa bir uyarı yazar.

Adım 4 — Servisleri sağlık kontrolleriyle doğru sırada başlatın

Yalın depends_on: [db] yalnızca veritabanı konteynerinin başlamasını bekler; PostgreSQL'in bağlantı kabul etmesini beklemez. condition: service_healthy içeren uzun biçim ise bağımlılığın sağlık kontrolü başarılı olana kadar bekler:

  • db üzerindeki healthcheck her 10 saniyede bir konteyner içinde pg_isready çalıştırır. start_period, hatalar sayılmaya başlamadan önce PostgreSQL'e ilk kurulum için 30 saniye verir; 5 başarısız kontrolden sonra konteyner unhealthy olarak işaretlenir.
  • $${POSTGRES_USER} ifadesi $$ ile kaçırılmıştır; böylece Compose onu değiştirmez, konteynerin içindeki kabuk değeri konteynerin kendi ortamından alır.
  • Diğer koşullar service_started (varsayılan) ve bir geçiş (migration) gibi tek seferlik bir işin 0 koduyla bitmesini bekleyen service_completed_successfully'dir.

Sağlık kontrolleri docker compose ps çıktısında da görünür; bu yüzden bağımlılık olmasa bile işe yararlar.

Adım 5 — Yeniden başlatma politikalarını seçin ve portları gizli tutun

Yeniden başlatma politikası, bir konteyner kapandığında veya sunucu yeniden başladığında ne olacağını belirler:

PolitikaDavranış
noVarsayılan. Hiçbir zaman kendiliğinden yeniden başlatılmaz
alwaysHer zaman yeniden başlatılır, sunucu açılışında da
on-failure[:N]Yalnızca sıfırdan farklı bir çıkış kodundan sonra, isteğe bağlı olarak en çok N kez yeniden başlatılır
unless-stoppedalways gibidir, ancak siz durdurduysanız durmuş olarak kalır

Uzun süre çalışan servisler için unless-stopped iyi bir varsayılandır. adminer aracının politikası yoktur; sunucu yeniden başladıktan sonra kapalı kalır.

Örnekteki her yayınlanan port 127.0.0.1 ile başlar. Docker belgelerine göre konteyner portlarını yayınlamak varsayılan olarak güvensizdir ve yayınlanan portlar ufw'yi atlar; çünkü Docker trafiği ufw kuralları kontrol edilmeden önce yönlendirir. "8080:80" olarak yazılan bir port, ufw 8080'i engellese bile internete açıktır. 127.0.0.1 ile yalnızca sunucunun kendisi bağlanabilir ve uygulamayı HTTPS üzerinden bir reverse proxy yayınlar: Caddy, Nginx ve Certbot veya Traefik rehberlerine bakın. 5432 gibi veritabanı portlarının hiç ports: kaydına ihtiyacı yoktur; diğer servisler onlara proje ağı üzerinden ulaşır.

Adım 6 — Stack'i kontrol edin, başlatın ve izleyin

Tüm değişkenlerin yerleştirildiği son yapılandırmayı görüntüleyin. YAML hataları veya eksik değişkenler, hiçbir şey başlamadan burada görünür:

Bash
docker compose config

Stack'i arka planda başlatın, ardından konteynerlerini listeleyin:

Bash
docker compose up -d
docker compose ps

up -d eksik imajları çeker, ağı ve volume'u oluşturur, db servisini başlatır, sağlıklı olmasını bekler ve ardından web servisini başlatır. docker compose ps çıktısında db satırının durum sütununda (healthy) görünmeli, web satırında ise 127.0.0.1:8080->80/tcp yazmalıdır. Web servisini sunucunun üzerinden test edin:

Bash
curl -I http://127.0.0.1:8080

HTTP/1.1 200 OK görmelisiniz. Tüm servislerin loglarını veya tek bir servisin son 100 satırını izleyin; izlemeyi Ctrl+C ile bırakın:

Bash
docker compose logs -f
docker compose logs -f --tail 100 db

Adım 7 — İsteğe bağlı servisler için profilleri kullanın

profiles: kaydı olan servisler yalnızca profilleri etkinleştirildiğinde başlar. Profili olmayan servisler her zaman başlar. Adminer'ı da çalıştırmak için stack'i tools profiliyle başlatın:

Bash
docker compose --profile tools up -d

Adminer 127.0.0.1:8081 üzerinde dinler; bu yüzden onu kendi bilgisayarınızdan bir SSH tüneliyle açın:

Bash
ssh -L 8081:127.0.0.1:8081 your-user@203.0.113.10

Ardından tarayıcıda http://localhost:8081 adresine gidin, PostgreSQL'i seçin, sunucu olarak db yazın ve .env dosyasındaki değerlerle giriş yapın. İşiniz bitince yalnızca aracı durdurup kaldırın:

Bash
docker compose --profile tools stop adminer
docker compose --profile tools rm -f adminer

Profilleri COMPOSE_PROFILES değişkeniyle de etkinleştirebilirsiniz; örneğin .env içine COMPOSE_PROFILES=tools yazarak. Yalın bir docker compose down komutunun yalnızca profili olmayan servisleri kaldırdığını unutmayın; profilli servisleri de kapsamak için --profile tools ekleyin.

Adım 8 — Günlük komutlar ve down -v'nin sildikleri

KomutNe yapar
docker compose up -dStack'i oluşturur veya günceller; yalnızca yapılandırması ya da imajı değişen konteynerleri yeniden oluşturur
docker compose stop / startKonteynerleri silmeden durdurur veya başlatır
docker compose restart webBir konteyneri yeniden başlatır; compose.yaml değişikliklerini uygulamaz
docker compose exec db psql -U demoÇalışan bir konteynerde komut çalıştırır
docker compose downKonteynerleri ve proje ağını kaldırır; volume'ları korur
docker compose down -vAdlandırılmış ve anonim volume'ları da siler
docker compose lsBu sunucuda çalışan Compose projelerini listeler

compose.yaml veya .env dosyasını düzenledikten sonra restart değil, yeniden docker compose up -d çalıştırın. Compose yeni yapılandırmayı çalışan konteynerlerle karşılaştırır ve yalnızca değişenleri yeniden oluşturur; volume'lardaki veriler korunur.

Adım 9 — Bir sunucuda birden fazla proje çalıştırın

Compose projeleri adlarıyla birbirinden yalıtır; bu yüzden birçok stack aynı sunucuyu paylaşabilir:

  • Her proje için bir klasör (/opt/n8n, /opt/uptime-kuma, …). Her biri kendiliğinden kendi ağ ve volume adlarını alır.
  • Benzersiz ana makine portları: iki proje aynı anda 127.0.0.1:8080 yayınlayamaz. Hangi uygulamanın hangi yerel portu kullandığını kısa bir listede tutun.
  • container_name: kullanmaktan kaçının; uygulamanın resmi dosyası gerektirmiyorsa. Konteyner adları tüm sunucuda benzersiz olmalıdır, Compose'un ürettiği adlar (proje-servis-1) ise hiçbir zaman çakışmaz.
  • Tüm uygulamalar için tek reverse proxy, 80 ve 443 numaralı portlarda. Caddy veya Nginx ana makinede çalışıyorsa her uygulama, kendi 127.0.0.1 portunu gösteren bir site bloğu alır. Konteynerde çalışan Traefik veya Nginx Proxy Manager kullanıyorsanız uygulamalar port yayınlamak yerine paylaşılan, external bir Docker ağına katılır.

Başka bir projenin oluşturduğu mevcut bir ağa katılmak için onu external olarak tanımlayın; Compose kendi ağını oluşturmak yerine onu kullanır:

YAML
networks:
  proxy:
    name: proxy
    external: true

Ağın önceden var olması gerekir (docker network create proxy); aksi halde up, external ağın bulunamadığını söyleyen bir hatayla durur.

Compose stack'ini güncelleme

Güncellemeden önce her uygulamanın sürüm notlarını okuyun, yedek alın (sonraki bölüm), ardından yeni imajları çekip değişen konteynerleri yeniden oluşturun:

Bash
cd /opt/demo
docker compose pull
docker compose up -d
docker compose ps
docker image prune

pull, compose.yaml içindeki etiketler için daha yeni imajları indirir; up -d yalnızca imajı değişen konteynerleri değiştirir ve volume'lar bağlı kalır. docker image prune artık kullanılmayan eski imaj katmanlarını siler. postgres:18 gibi bir etiket o ana sürümün yama sürümlerini izler. Yeni bir ana sürüme geçmek (örneğin PostgreSQL 18'den 19'a) etiketin bilinçli olarak değiştirilmesidir ve genellikle uygulamanın kendi yükseltme prosedürünü gerektirir; bir veritabanının ana sürümünü yalnızca etiketi düzenleyerek asla atlamayın.

Yedekleme ve geri yükleme

İmajlar yeniden çekilebilir; yedeklenmesi gereken şey durumdur:

  • compose.yaml, .env ve bind mount klasörleri (burada ./html) — hepsi /opt/demo içinde,
  • adlandırılmış volume'lar (burada db_data),
  • veritabanları için, veritabanı çalışırken de tutarlı olan, veritabanının kendi aracıyla alınmış mantıksal döküm.

Yedek klasörünü bir kez oluşturun, ardından veritabanının dökümünü alın ve proje klasörünü arşivleyin:

Bash
sudo mkdir -p /opt/backups
sudo chown $USER:$USER /opt/backups
cd /opt/demo
docker compose exec -T db sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB"' > /opt/backups/demo-db-$(date +%F).sql
tar czf /opt/backups/demo-files-$(date +%F).tar.gz -C /opt demo

Bir adlandırılmış volume'u dosya düzeyinde kopyalamak, veritabanı içermeyen volume'lar için asıl yöntemdir ve veritabanı dosyalarının ikinci bir kopyası olarak da işe yarar. Bunun için hiçbir şeyin yazmaması adına stack'i durdurun ve volume'u, Ubuntu'ya Docker kurulumu rehberinde gösterildiği gibi kısa ömürlü bir konteynerle arşivleyin:

Bash
docker compose stop
docker run --rm -v demo_db_data:/data -v /opt/backups:/backup ubuntu tar czf /backup/demo_db_data-$(date +%F).tar.gz -C /data .
docker compose start

Veritabanını yeni bir sunucuda geri yüklemek için proje klasörünü açın, yalnızca veritabanını başlatıp sağlıklı olmasını bekleyin, ardından dökümü yeni ve boş veritabanına yükleyin:

Bash
tar xzf /opt/backups/demo-files-2026-10-09.tar.gz -C /opt
cd /opt/demo
docker compose up -d --wait db
docker compose exec -T db sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB"' < /opt/backups/demo-db-2026-10-09.sql
docker compose up -d

Yedekleri sunucunun dışına da kopyalayın; örneğin rsync veya scp ile başka bir makineye. Böylece sunucuyu kaybetmek veriyi kaybetmek anlamına gelmez.

Sorun giderme

The "POSTGRES_USER" variable is not set. Defaulting to a blank string.

Compose değişkeni bulamadı. Ya .env dosyası yok, ya proje klasöründe değil ya da komutu başka bir klasörden çalıştırdınız. cd /opt/demo komutunu çalıştırın ve docker compose config çıktısını kontrol edin. POSTGRES_PASSWORD için kullanılan :? sözdizimi sayesinde Compose, parolasız bir veritabanı başlatmak yerine required variable POSTGRES_PASSWORD is missing a value hatasıyla durur.

dependency failed to start: container demo-db-1 is unhealthy

db servisinin sağlık kontrolü 5 kez başarısız oldu. Veritabanı logunu docker compose logs db ile okuyun. Sık nedenler sağlık kontrolündeki yanlış kullanıcı veya veritabanı adı, boş parola ya da volume'un PostgreSQL ana sürümü için yanlış yola bağlanmasıdır. docker inspect demo-db-1 çalıştırın ve son kontrollerin çıktısı için Health bölümüne bakın.

Bind for 127.0.0.1:8080 failed: port is already allocated

Bu ana makine portunu başka bir konteyner veya servis kullanıyor. sudo ss -tlpn 'sport = :8080' veya docker ps ile bulun, ardından .env içindeki WEB_PORT değerini değiştirip docker compose up -d komutunu yeniden çalıştırın.

compose.yaml veya .env değişikliklerim etki etmiyor

docker compose restart mevcut konteynerleri eski yapılandırmalarıyla yeniden başlatır. Compose'un değişen servisleri yeniden oluşturması için docker compose up -d çalıştırın. İmaj etiketi aynı kalıp daha yeni bir imaj yayımlandıysa önce docker compose pull çalıştırın.

the attribute version is obsolete, it will be ignored

Dosyada eski bir Compose biçiminden kalma, en üst düzeyde bir version: satırı var. Satırı silin; başka hiçbir şey değişmez.

ufw engellediği hâlde bir konteyner portuna internetten erişilebiliyor

Port, ana makine adresi belirtilmeden yayınlanmış; örneğin "8080:80". Bunu "127.0.0.1:8080:80" olarak değiştirin ve docker compose up -d çalıştırın. Başka bir makineden nc -vz sunucu-ip-adresiniz 8080 ile kontrol edin; bağlantı başarısız olmalıdır.

Sonraki adımlar

Sık sorulan sorular

docker-compose ile docker compose arasındaki fark nedir?

Tireli docker-compose, Python ile yazılmış ve artık desteklenmeyen ilk Compose sürümüdür (v1). Boşluklu docker compose ise Docker Engine ile docker-compose-plugin paketi olarak gelen Go eklentisidir (Compose v2, artık v5 olarak yayınlanıyor). Bu kütüphanedeki tüm rehberler docker compose kullanır.

Dosyanın adı compose.yaml mı olmalı, docker-compose.yml mi?

İkisi de çalışır. compose.yaml standart addır ve aynı klasörde iki dosya da varsa öncelik onundur; docker-compose.yml geriye dönük uyumluluk için hâlâ kabul edilir. Projenin resmi talimatları hangi adı kullanıyorsa onu koruyun.

Dosyanın başındaki version satırına hâlâ gerek var mı?

Hayır. En üst düzeydeki version öğesi kullanımdan kalkmıştır. Compose bu satırı yok sayar, dosyayı en güncel Compose Specification'a göre doğrular ve bir uyarı yazar; satırı silebilirsiniz.

docker compose down verilerimi siler mi?

Yalın down komutu projenin konteynerlerini ve ağlarını kaldırır, adlandırılmış volume'ları ve bind mount klasörlerini korur. down -v ise dosyada tanımlı adlandırılmış volume'ları ve anonim volume'ları da siler; bu genellikle veritabanlarınız demektir. External olarak işaretli volume'lar hiçbir zaman silinmez.

Bir sunucuda birden fazla Compose projesi çalıştırabilir miyim?

Evet. Her projeye kendi klasörünü verin; böylece her proje kendi proje adını, ağını ve volume adlarını alır. Her uygulamayı farklı bir 127.0.0.1 portunda yayınlayın ve hepsinin önüne tek bir reverse proxy koyun.

Kaynaklar

Şifre Oluştur

Lütfen onaylayın