SSD Nodes Learn 8GB RAM — yılda $66
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-08-01

Docker Compose Açılışta Otomatik Başlatma

Docker Compose hizmetlerini yeniden başlatma sonrası çalıştırın: restart politikaları, on-failure neden tek başına yetmez ve systemd unit ne zaman gereklidir.

Kısa yanıt

Docker Compose hizmetleri, iki koşul aynı anda sağlandığında sistem açılışında başlar. Docker daemon bir sistem hizmeti olarak etkinleştirilmiş olmalıdır ve dosyadaki her hizmette unless-stopped veya always yeniden başlatma ilkelerinden biri bulunmalıdır. Her hizmete restart: unless-stopped ekleyin, bir kez docker compose up -d çalıştırın; yeniden başlatmanın ardından container'lar kendiliğinden yeniden başlar. Yaygın kullanım senaryosu için başka bir işlem gerekmez.

Sıralamanın önemli olduğu durumlarda systemd unit gerekir. Örneğin stack, Docker daemon başlatıldığı sırada henüz hazır olmayan bağlı bir diske, VPN arayüzüne veya ağ paylaşımına bağlı olabilir. Bu durum gerçektir ve bu kılavuzun ikinci yarısında ele alınır. Hizmet tanımları ve volume'lar konusunda hâlâ yolunuzu bulmaya çalışıyorsanız VPS üzerinde Docker Compose temelleri ile başlayıp ardından buraya dönün.

compose.yaml dosyasında yeniden başlatma politikasını ayarlama

Politika, her hizmet için bir satırdan oluşur. Genel bir anahtar yoktur. Bu nedenle unuttuğunuz bir hizmet yeniden başlatma sonrasında çalışmaz, yığının geri kalanı ise başlatılır.

services:
  app:
    image: nginx:1.27
    restart: unless-stopped
    ports:
      - "8080:80"
  db:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: change-me
    volumes:
      - dbdata:/var/lib/postgresql/data

volumes:
  dbdata:

Politikayı uygulayın ve ardından çalışan container üzerinden politikayı yeniden okuyun:

docker compose up -d
docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app)

Bu komut unless-stopped çıktısını verir. no çıktısını veriyorsa dosya düzenlenmiş, ancak container yeniden oluşturulmamıştır.

En yaygın hata budur. Yeniden başlatma politikası YAML dosyasında değil, container üzerinde saklanır. compose.yaml dosyasının düzenlenmesi mevcut bir container'ın yapılandırmasını değiştirmez. docker compose restart de yardımcı olmaz, çünkü aynı container nesnesini durdurup yeniden başlatır ve yapılandırmasına dokunmaz. Yalnızca docker compose up -d dosyayı çalışan container'larla karşılaştırır, politikanın değiştiğini fark eder ve container'ları yeniden oluşturur.

Şimdilik yeniden oluşturmak istemediğiniz bir container için politikayı yerinde değiştirin:

docker update --restart unless-stopped my-container

YAML dosyasını da düzenleyin. docker update çalışan container'ı değiştirir. Sonraki docker compose up -d dosyayı okur ve eski değeri geri yükler.

Her yeniden başlatma değerinin gerçekte yaptığı işlem

Docker dört değer tanımlar. Bu değerler arasındaki fark yalnızca makine yeniden başlatıldığında veya daemon yeniden başlatıldığında ortaya çıkar.

  • no varsayılan değerdir. Container, hiçbir koşulda otomatik olarak yeniden başlatılmaz.
  • always container durduğu her seferde yeniden başlatır. Container elle durdurulmuş olsa bile Docker daemon bir sonraki başlatıldığında yeniden çalışır. Bu durum çoğu zaman şaşırtıcıdır: geçen hafta bilerek durdurulan bir container, yeniden başlatma sonrasında tekrar çalışır.
  • unless-stopped, always gibi davranır. Ancak elle durdurulan bir container, daemon yeniden başlatıldığında durdurulmuş olarak kalır. Bakım için zaman zaman durdurulan bir servis için kullanılması gereken değer budur.
  • on-failure container yalnızca sıfır olmayan bir çıkış koduyla sonlandığında yeniden başlatır. Deneme sayısı restart: on-failure:3 örneğindeki gibi sınırlandırılabilir.

Sunucu çalıştığı sürece çalışır durumda olması gereken bir stack için unless-stopped doğru varsayılan değerdir. Durdurulmuş halde kalmasını engellemek istediğiniz bir container için yalnızca always seçilmelidir.

Neden yeniden başlatma: on-failure yeniden başlatma sonrasında geçerli olmaz

Birçok kişi dikkatli göründüğü için on-failure seçer, ardından ilk yeniden başlatmadan sonra tüm container'ların durduğunu görür. Bunun nedeni tanımındadır. on-failure yalnızca tek bir duruma tepki verir: container işleminin hata koduyla sonlanması.

Yeniden başlatma bir hata değildir. Ana makine kapatılırken systemd, docker.service işlemini durdurur ve daemon her container'ı kasıtlı olarak durdurur. Container başarısız olmadığı için politika tepki vermez. Sistem yeniden başlatıldığında daemon, devam ettirmesi gereken container'ları kontrol eder. Temiz şekilde durdurulmuş on-failure container bunlardan biri değildir. Container exited durumunda kalır.

Bunu doğrudan görebilirsiniz. Bir hizmette restart: on-failure değerini ayarlayın, docker compose up -d komutunu çalıştırın, sistemi yeniden başlatın ve ardından şunu çalıştırın:

docker compose ps -a

Hizmet, Exited durumuyla ve Exited (0) 2 minutes ago benzeri bir status ile listelenir. Hiçbir şey bozulmamıştır ve hiçbir şey hata olarak günlüğe kaydedilmez. Sorunun tanılanmasını zorlaştıran da budur. Politika, tanımında belirtildiği şekilde çalışmıştır.

on-failure yine de kullanışlıdır. İş çalıştıran ve çöken bir container için uygundur. Bu durumda sınırlı sayıda yeniden deneme istenir ve yeniden başlatma döngüsü istenmez. Uzun süre çalışan bir hizmeti yeniden başlatmalar arasında çalışır durumda tutmak için yanlış araçtır.

Yeniden başlatma ilkeleri yalnızca Docker hizmeti önyükleme sırasında başlarsa çalışır

Yeniden başlatma ilkeleri Docker daemon tarafından uygulanır. Daemon başlamazsa hiçbir şey uygulanmaz. Durumu kontrol edin:

systemctl is-enabled docker
systemctl is-enabled containerd

Her iki komut da enabled çıktısını vermelidir. Docker'ın resmi deposundaki paketler, kurulum sırasında bu hizmetleri etkinleştirir. Bu nedenle yeni bir sunucuda kontrol genellikle başarılı olur. Komutlardan biri disabled çıktısını verirse düzeltin:

sudo systemctl enable --now docker containerd

Burada anlaşılması gereken bir nokta vardır. Ubuntu, daemon'u ilk kez Docker API ile iletişim kurulduğunda isteğe bağlı olarak başlatan docker.socket paketini de sunar. docker.socket öğesinin etkin olduğunu gören bazı kişiler daemon'un güvence altında olduğunu varsayar ve bellek tasarrufu için docker.service öğesini devre dışı bırakır. Önyükleme sırasında API'yi çağıran hiçbir işlem olmaz. Bu nedenle sokete hiç erişilmez, daemon başlamaz ve ilk docker komutunu yazana kadar hiçbir container başlatılmaz. Soket etkinleştirme, docker.service öğesinin etkin olmasının yerine geçmez.

systemd unit dosyasının daha uygun olduğu durumlar

Yeniden başlatma ilkelerinde sistemin geri kalanına göre sıralama kavramı yoktur. Daemon başlar ve container'ları mümkün olan en kısa sürede çalıştırır. Stack ayrı bir volume'dan, bir NFS (network file system) paylaşımından veya şifrelenmiş bir diskten bir dizini bind-mount ediyorsa container'lar bu yol mevcut olmadan başlayabilir. Docker, mount noktasında boş bir dizin oluşturur ve container'ı bu dizinle çalıştırır. Veritabanınız da veri olmadan başlar.

Aşağıdaki durumlardan herhangi biri geçerliyse bir systemd unit yazılmalıdır. Stack'in önce bir mount'un, bir VPN arayüzünün veya başka bir unit'in hazır olmasına ihtiyacı vardır. systemctl stop myapp ve systemctl start myapp değerlerinin sistemdeki diğer tüm servislerde olduğu gibi çalışması istenir. Ya da daemon ile birlikte sonlandırılmak yerine, kapatma sırasında stack'in düzgün biçimde durdurulması istenir. systemd unit'leri yeniyse, systemd service ve timer yazma dosya biçimini daha ayrıntılı olarak açıklar.

systemd biriminin yazılması

Yığını bir home dizininin dışında, sabit bir yola yerleştirin. /srv/myapp iyi bir seçimdir, çünkü herhangi biri oturum açmadan önce çalışan bir birimin /home okuması gerekmez.

/etc/systemd/system/myapp.service dosyasını oluşturun:

[Unit]
Description=myapp docker compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
RequiresMountsFor=/srv/myapp/data

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/srv/myapp
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0

[Install]
WantedBy=multi-user.target

Birimi etkinleştirin ve başlatın:

sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.service

Sağlıklı birim Active: active (exited) durumunu gösterir. Bu durumu ilk gördüğünüzde yanlış görünebilir. Doğrudur: Type=oneshot ve RemainAfterExit=yes, birimin komutunu çalıştırdığı, komutun tamamlandığı ve systemd'nin birimi etkin olarak işaretlemeye devam ettiği anlamına gelir. Böylece ExecStop kapanış sırasında çalışır.

Her satırın bir amacı vardır. Requires=docker.service, birimin ölü bir soket üzerinde docker compose çalıştırmak yerine hemen başarısız olmasını sağlar. After= başlatma sırasını belirler; çünkü Requires= tek başına bunu yapmaz. RequiresMountsFor=, systemd'nin bu yol için mount birimini dahil etmesini ve onun hazır olmasını beklemesini sağlar. Bir yeniden başlatma ilkesi yerine birim kullanılmasının temel nedeni budur. TimeoutStartSec=0, büyük bir imaj hâlâ çekilirken systemd'nin başlatma işini sonlandırmasını önler.

İki mekanizmanın birlikte kullanılması hakkında: Docker belgeleri, restart ilkelerinin bir host process manager ile birlikte kullanılmamasını önerir. Bu uyarı, container sürecinin kendisini denetleyen ve daemon aynı işi yapmaya çalışırken süreci yeniden başlatan bir process manager ile ilgilidir. Bir Type=oneshot birimi hiçbir şeyi denetlemez. Bu nedenle restart: unless-stopped değerini compose dosyasında bu birimle birlikte tutmak uygundur ve istenen yapı budur. systemd açılış sırasını yönetir; daemon ise sabaha karşı çöken bir container'ı yönetir.

Gerçek bir yeniden başlatma ile doğrulama

Gerçek testin yerini hiçbir şey tutmaz. systemctl restart docker bağlama sırasını test etmez; docker compose down ardından docker compose up -d çalıştırılması da önyükleme ile ilgili hiçbir şeyi test etmez.

sudo reboot

Bekleyin, yeniden bağlanın ve şu sırayla kontrol edin:

uptime
systemctl is-active docker
docker compose ps

uptime, gerçekten yeniden başlatılmış bir makineyi incelediğinizi doğrular. Yığın dizininden çalıştırılan docker compose ps, her hizmeti running durumunda ve makinenin çalışma süresine yakın bir çalışma süresiyle listelemelidir. Exited gösteren hizmet incelenmelidir.

Bir şey başlatılmadıysa daemon günlüğü önyükleme aralığını kapsar:

journalctl -u docker.service -b --no-pager | tail -50

Bir unit tarafından yönetilen bir yığın için journalctl -u myapp.service -b --no-pager, önyükleme sırasında alınan tam docker compose çıktısını gösterir. Buna başarısız bir image çekme işlemi veya eksik bir .env dosyası da dahildir.

Otomatik başlatmayı sessizce bozan durumlar

docker compose run ile oluşturulan container'lar, dosyada tanımlanan yeniden başlatma politikasını almaz. Compose bunları tek seferlik container olarak değerlendirir. Bir service kendi politikasını yok sayıyor gibi görünüyorsa, up yerine run ile başlatılıp başlatılmadığını kontrol edin.

Bir volume içindeki veya env_file girdisindeki göreli yol, compose dosyasının bulunduğu dizine göre çözümlenir. Bu işlem shell üzerinden çalışır. WorkingDirectory tanımlayan bir unit üzerinden de çalışır. Ancak WorkingDirectory tanımlamayan bir unit üzerinden başarısız olur. Çünkü bu durumda çalışma dizini / olur.

Rootless Docker farklı bir durumdur. Daemon, kullanıcı service'i olarak çalışır. Kullanıcı service'i, o kullanıcıya ait son oturum sona erdiğinde durur. Kullanıcı için etkinleştirin ve oturum açmış kullanıcı olmadığında çalışmaya devam etmesine izin verin:

systemctl --user enable docker
sudo loginctl enable-linger $USER

enable-linger olmadan rootless daemon, oturum kapatıldığında kapanır. Container'lar da onunla birlikte durur. Bu durum, bozuk bir yeniden başlatma politikasıyla tamamen aynı şekilde görünür.

Son bir nokta. Otomatik güvenlik güncellemeleri bir server'ı sabit bir saatte yeniden başlatabilir. Bu yalnızca stack'in kendiliğinden yeniden başlaması durumunda yararlıdır. Yeni bir makinede bunun yapılandırılması, yeni bir VPS üzerindeki ilk on dakika kapsamındaki diğer ilk saat işlemleriyle birlikte yapılmalıdır.

FAQ

restart: always ile restart: unless-stopped arasındaki fark nedir?

Her ikisi de kapsayıcı kendiliğinden durduğunda yeniden başlatır. Kapsayıcı elle durdurulduktan sonraki davranışları farklıdır. always kullanıldığında, Docker daemon bir sonraki kez başladığında kapsayıcı yeniden başlar. Bu nedenle yeniden başlatma, elle durdurma işlemini geçersiz kılar. unless-stopped kullanıldığında daemon, kapsayıcının bilerek durdurulduğunu hatırlar ve kapsayıcıyı çalıştırmaz. Kapsayıcının durdurulduktan sonra yeniden çalışmamasını özellikle istiyorsanız unless-stopped kullanılır.

restart: unless-stopped ekledim, ancak kapsayıcı yeniden başlatmanın ardından hâlâ başlamıyor. Neden?

Politika dosyada değil, kapsayıcı üzerinde tutulur. Mevcut bir kapsayıcı, YAML dosyasını düzenlemekle güncellenmez. Compose'un kapsayıcıyı yeniden oluşturması için docker compose up -d çalıştırılır, ardından docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app) ile doğrulama yapılır. Bu komut no çıktısını verirse kapsayıcı, yaptığınız düzenlemeden önce oluşturulmuştur. Diğer yaygın neden, docker.service özelliğinin etkin olmamasıdır. Bu durum systemctl is-enabled docker ile denetlenebilir.

Restart policy kullanıyorsam systemd unit gerekli midir?

Genellikle gerekli değildir. Yalnızca ağa ihtiyaç duyan bir stack için restart policy yeterlidir. Stack'lerin çoğu bu kapsamdadır. Kapsayıcılar, Docker daemon başladığında henüz hazır olmayan bir bileşene bağlıysa unit eklenir. Buna harici disk, şifrelenmiş volume, NFS paylaşımı veya VPN arayüzü örnek verilebilir. Unit, restart policy ile ifade edilemeyen sıralamayı After= ve RequiresMountsFor= üzerinden sağlar.

Bir stack'in sonraki yeniden başlatmada geri gelmesini engelleyerek kalıcı olarak nasıl durdurabilirim?

unless-stopped kullanıldığında docker compose stop yeterlidir. Çünkü elle durdurulan kapsayıcı, daemon yeniden başladığında yeniden başlatılmaz. always kullanıldığında durdurma işlemi yeterli değildir ve kapsayıcı yeniden başlatmanın ardından geri gelir. Bunun yerine, kapsayıcıları kaldıran docker compose down çalıştırılır veya önce politika docker update --restart no my-container ile değiştirilir. Stack'i bir systemd unit yönetiyorsa sudo systemctl disable myapp.service da çalıştırılmalıdır. Aksi takdirde unit stack'i yeniden başlatır.