Veritabanı Docker içinde mi yoksa host üzerinde mi?
PostgreSQL, MySQL veya Redis gibi veritabanlarını Docker içinde çalıştırmanın üretim ortamındaki risklerini keşfedin. Hatalı volume, yedekleme ve sürüm yönetimi detaylarını inceleyin.
Veritabanı Docker içinde mi yoksa host üzerinde mi çalışmalı?
Veritabanını Docker içinde çalıştırın. Tek bir VPS üzerinde tek bir uygulama yığını için container haline getirilmiş PostgreSQL, MySQL, MongoDB veya Redis standart bir üretim tercihidir; bu konuda yapılan tartışmalar genellikle yanlış bir zemine oturmaktadır. Bir container, etrafında namespace ve cgroup bulunan bir Linux sürecidir, sanal makine değildir; dolayısıyla veritabanı ile disk arasında bir hypervisor katmanı bulunmaz. Bind mount veya yerel bir named volume kullanıldığında, okuma ve yazma işlemleri, paket kurulumunun kullanacağı dosya sistemiyle aynı olan host dosya sistemine doğrudan ulaşır.
Asıl maliyet operasyoneldir. Bu kurulumun sorunsuz mu yoksa yavaş bir felaket mi olacağını dört unsur belirler: verinin nerede yaşadığı, o dizinin sahibinin kim olduğu, ana sürüm yükseltme işleminin nasıl gerçekleştiği ve daha önce hiç yedekten geri yükleme yapıp yapmadığınız. Bunları doğru yapılandırdığınızda container sadece bir detaydan ibarettir. Yanlış yapılandırdığınızda ise suçlayacağınız ilk şey container olacaktır.
Bu karar, sunucudaki her veritabanı için aynıdır. Aşağıdaki örneklerde PostgreSQL, MySQL, MongoDB ve Redis kullanılmıştır; ürüne özgü farklar, önem arz ettikleri noktalarda belirtilmiştir.
Bir container gerçekte neleri değiştirir
Bir volume mount ettiğiniz sürece depolama yolu değişmez. Aynı çekirdek, aynı sayfa önbelleği (page cache) ve aynı dosya sistemi kullanılır.
Performans açısından tek gerçek tuzak, hiçbir şey mount etmediğiniz durumdur. Bir volume olmadan veri dizini, imajın üzerine yığılan bir overlay dosya sistemi olan container'ın yazılabilir katmanına gider. Buradaki yazma işlemleri daha yavaştır ve container silindiğinde tüm katman yok olur. "Bu sabah veritabanım boştu" sorununun kaynağı budur.
Gerçekten değişenler şunlardır:
- Yaşam döngüsü.
docker compose downcontainer'ı yok eder. Volume içinde olmayan her şey onunla birlikte gider. - Sürüm. İmaj etiketi (tag) sürümdür. Bir veritabanı container'ı içinde, bir sonraki
docker compose pullişleminden sağ çıkacak birapt upgradebulunmaz. - Bellek yönetimi. Bir cgroup limiti, çekirdek tarafından uygulanan kesin bir sınırdır ve veritabanı bunun orada olduğundan haberdar değildir.
- Kullanıcı. Süreç, container içinde sayısal bir kullanıcı kimliği (UID) ile çalışır; bu kullanıcı ana makinenizde hiçbir şeye sahip olmayabilir.
Verilerin nerede tutulacağı her şeyi belirler
İki iyi seçenek ve bir yaygın hata bulunmaktadır.
- Adlandırılmış bir volume:
pgdata:/var/lib/postgresql/data. Docker, dizini/var/lib/docker/volumes/<project>_pgdata/_datakonumunda oluşturur ve image entrypoint'i ilk çalıştırmada sahiplik ayarlarını yapar. Bu varsayılan yöntemdir. - Bind mount:
/srv/appname/pg:/var/lib/postgresql/data. Yolu siz seçersiniz, bu nedenle izin sorunlarının sorumluluğu size aittir. - Hiç mount kullanmamak. Yukarıya bakın. Veriler container içinde kalır.
Bu konudaki tüm avantaj ve dezavantajlar ayrı bir başlık konusudur ve bind mount ile adlandırılmış volume karşılaştırması bu konuyu ele alır. Veritabanları için kısa özet şudur: Host üzerindeki yolu bilmenizi gerektiren özel bir nedeniniz yoksa adlandırılmış bir volume kullanın. Eğer bind mount kullanmanız gerekiyorsa, bunu proje dizini gibi bir git clean tarafından erişilebilecek yerler yerine /srv/appname/pg gibi kararlı bir konuma yerleştirin.
Kesin bir sınır: Veritabanı veri dizinini NFS (ağ dosya sistemi) veya kilitleme ve fsync davranışlarını test etmediğiniz herhangi bir ağ mount noktasına koymayın. Veritabanları, başarılı bir fsync işleminin verilerin kararlı depolama birimine yazıldığı anlamına geldiğini varsayar. Bu varsayım yanlış olduğunda, haftalar sonra ortaya çıkan veri bozulmalarıyla karşılaşırsınız.
Volume ismini sabitleyin, volume kaybolmadan önlem alın
Compose, bir volume ismini <project>_<volume> olarak belirler ve proje ismi varsayılan olarak dizin ismini alır. Bu nedenle volume kimliği, kullanıcıların üzerinde düşünmeden değiştirebildiği bir dizin ismine bağımlı hale gelir.
/srv/app dizinini /srv/app-old konumuna taşırsanız veya compose dosyasındaki pgdata anahtarını yeniden adlandırırsanız, bir sonraki docker compose up -d komutu yepyeni ve boş bir volume oluşturur. Postgres, bu yeni volume içinde temiz bir küme başlatır. Container sağlıklı görünür, uygulama başlar ancak tüm tablolar silinmiş olur. İyi haber şudur: Eski volume, eski ismiyle diskte durmaya devam eder.
docker volume ls
docker volume inspect app_pgdataBu durumun yaşanmaması için isimleri sabitleyin. Proje ismini ve volume ismini açıkça tanımlayın:
name: myapp
services:
db:
image: postgres:17
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
name: myapp_pgdataEğer verileriniz sahipsiz bir volume içinde kaldıysa, veritabanını durdurarak verileri yeni volume içine kopyalayın:
docker compose stop db
docker run --rm -v app_pgdata:/from -v myapp_pgdata:/to alpine sh -c 'cp -a /from/. /to/'
docker compose start dbVeritabanı çalışırken kopyalama yaparsanız, yazılmakta olan dosyaların tutarsız bir kopyasını alırsınız. Önce veritabanını durdurun.
Veri dizininin sahibi kimdir
Resmi Postgres, MySQL ve MongoDB imajları, sunucularını genellikle 999 olan yetkisiz bir kullanıcı kimliğiyle çalıştırır. Container root olarak başladığında, giriş noktası (entrypoint) veri dizininin sahipliğini bu kullanıcıya devreder ve ardından yetkilerini düşürür. Boş bir bind mount işleminin genellikle ilk denemede çalışmasının nedeni budur.
Compose dosyasında user: ayarını yaptığınız anda bu süreç bozulur, çünkü giriş noktasının herhangi bir şeyi düzeltmek için yetkisi kalmaz. Postgres bunu doğrudan belirtir:
initdb: error: could not change permissions of directory "/var/lib/postgresql/data": Operation not permittedYanlış mod ile var olan bir veri dizini farklı bir mesaj verir; bu mesajı tanımak önemlidir çünkü çözüm chmod değil, chown komutudur:
FATAL: data directory "/var/lib/postgresql/data" has invalid permissions
DETAIL: Permissions should be u=rwx (0700) or u=rwx,g=rx (0750).Root sahipli bir bind mount üzerinde çalışan MongoDB, kilit dosyasında (lock file) hata verir:
Unable to create/open the lock file: /data/db/mongod.lock (Permission denied). Ensure the user executing mongod is the owner of the lock file and has the appropriate permissions.Çözüm, ana makinedeki dizinin sahipliğini bir isme değil, sayısal kimliğe (numeric id) göre ls -ldn ile değiştirmektir:
sudo chown -R 999:999 /srv/appname/pg
sudo chmod 700 /srv/appname/pg
ls -ldn /srv/appname/pgls -ldn komutu isimler yerine sayıları yazdırır ve 999 999 değerini göstermelidir. Ana makinenizdeki postgres adlı hesap ile imajın içindeki postgres adlı hesap birbiriyle ilişkisizdir: çekirdek (kernel) sayıları karşılaştırır, isimler ise her iki tarafta ayrı ayrı çözümlenir. PUID ve PGID değerlerinin ana makine kullanıcılarını container içine nasıl eşlediği konusu bu eşlemeyi detaylıca açıklar. Rootless Docker veya kullanıcı isim alanı (user namespace) yeniden eşleme durumlarında sayılar tekrar değişecektir; bu nedenle 999 değerini varsaymak yerine kimlikleri çalışan container üzerinden okuyun.
Adlandırılmış birimler (named volumes) kullanıldığında, Docker boş bir dizin oluşturup giriş noktası da sahipliğini aldığı için bu bölümdeki sorunların tamamı ilk çalıştırmada ortadan kalkar.
Yükseltmeler: image etiketi değişikliği ile paket yükseltme
Ana makinede apt upgrade sizi bir alt sürüm boyunca ilerletir. Dağıtımınız, siz istemeden bir veritabanı ana sürümüne geçiş yapmaz; geçiş yapmaya karar verdiğinizde ise her iki ikili dosya seti aynı anda kurulabilir ki pg_upgrade tam olarak buna ihtiyaç duyar.
Container yapısında etiket sürümü temsil eder, bu nedenle yükseltme işlemi tek bir satırı düzenlemekten ibarettir. Bu durum alt sürüm yükseltmelerini önemsiz, ana sürüm yükseltmelerini ise bir prosedür haline getirir.
postgres:16 değerini postgres:17 ile değiştirin, docker compose up -d komutunu çalıştırın; container anında kapanacaktır:
PostgreSQL Database directory appears to contain a database; Skipping initialization
FATAL: database files are incompatible with server
DETAIL: The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.Hiçbir şey zarar görmez. Yeni ikili dosyalar, ana sürümler arasında değişen eski disk üzerindeki katalog düzenini okumayı reddeder. Etiketi tekrar postgres:16 değerine getirdiğinizde servis yeniden başlar. Bu geri alma imkanı, container yapısının sunduğu tek gerçek yükseltme avantajıdır.
Desteklenen yöntem dump ve restore işlemidir. PostgreSQL, dump işleminin daha yeni istemci tarafından alınmasını tercih eder; bu nedenle işlemi, compose ağı üzerinde hala çalışmakta olan eski sunucuya karşı yeni image üzerinden çalıştırın:
docker run --rm --network myapp_default -e PGPASSWORD="$POSTGRES_PASSWORD" \
postgres:17 pg_dumpall -h db -U postgres > /srv/backups/all.sql
ls -lh /srv/backups/all.sql
tail -n 2 /srv/backups/all.sqlDosya en azından onlarca kilobayt boyutunda olmalı ve PostgreSQL database cluster dump complete yazan bir satırla bitmelidir. Birkaç yüz baytlık bir dosya, dump işleminin başarısız olduğu ve boş yere bir volume silmek üzere olduğunuz anlamına gelir. Yalnızca bu kontrolden sonra:
docker compose down
docker volume rm myapp_pgdata
# edit the compose file: image: postgres:17
docker compose up -d db
docker compose exec -T db psql -U postgres -f /dev/stdin < /srv/backups/all.sqlDiğer motorlar farklılık gösterir:
- MySQL 8, kendi veri sözlüğünü başlangıçta yükseltir, bu nedenle alt sürüm etiketi değişikliği genellikle sadece bir yeniden başlatmadır. Sürüm serileri arasında geçiş yapmadan önce sürüm notlarını okuyun ve her iki durumda da önce bir dump alın.
- MariaDB, sunucu yeni sürümde ayağa kalktıktan sonra
mariadb-upgradekomutunun çalıştırılmasını bekler. - MongoDB her seferinde bir ana sürüm yükseltilmelidir; her adımdan sonra bir sonrakine geçmeden önce özellik uyumluluk sürümünü ayarlamanız gerekir. Bir sürümü atlamak,
mongodservisinin başlamayı reddetmesine ve loglardafeatureCompatibilityVersiondeğerini belirten birUPGRADE PROBLEMsatırı oluşmasına neden olur. MongoDB 7.0 sürümünden itibaren komut açık bir onay bayrağı gerektirir:db.adminCommand({ setFeatureCompatibilityVersion: "8.0", confirm: true }). - Redis eski snapshot dosyalarını sorunsuz yükler ancak daha yenilerini yüklemez; bu nedenle yükseltme bir yeniden başlatmadır ve sürüm düşürme verilerin yüklenememesine neden olabilir.
Genel kural şudur: Container sürüm düşürmeyi kolaylaştırır ancak yükseltmeyi daha kolay hale getirmez.
Veritabanı container'ım neden 137 hata koduyla kapanıyor?
Çünkü çekirdeğin bellek yetersizliği (OOM) sonlandırıcısı (killer) süreci sonlandırmıştır. 137 değeri, 128 ile 9 numaralı sinyalin toplamıdır.
docker compose ps
docker inspect myapp-db-1 | grep -i oomkilled
journalctl -k | tail -n 20docker compose ps komutu Exited (137) çıktısını veriyorsa, inspect satırı "OOMKilled": true şeklinde görünüyorsa ve çekirdek günlüğünde eşleşen bir kayıt varsa durum budur:
Memory cgroup out of memory: Killed process 4711 (postgres) total-vm:2170416kBMekanizma şu şekildedir ve genellikle şaşırtıcı bulunur. PostgreSQL ve MySQL, arabellek boyutlarını ana makinenin toplam bellek miktarına göre ayarlar. Bir cgroup sınırı, bu değeri onlar için değiştirmez. 16 GB belleğe sahip bir ana makinede 2 GB sınırınız varsa, veritabanı 16 GB belleği varmış gibi planlama yapar ve ana makine henüz hiçbir baskı altında değilken cgroup tarafından sonlandırılır. Bu nedenle, yalnızca bellek sınırı koymak yeterli değildir. Veritabanına sahip olduğu kaynakları açıkça belirtmeniz gerekir:
- PostgreSQL:
shared_buffersayarını yapılandırın vework_memdeğerine dikkat edin.work_mem, bağlantı başına her sıralama işlemi için ayrılır; bu nedenle cömert bir değerin elli bağlantıyla çarpılması, container'ın başlangıçta değil, yük altında ölmesinin yaygın nedenidir. - MySQL ve MariaDB: Varsayılan değeri 128M olan
innodb_buffer_pool_sizeayarını yapılandırın. Container içerisindeinnodb_dedicated_serverayarını kapalı tutun, çünkü bu ayarın temel işlevi makine belleğini algılayarak kendini boyutlandırmaktır. - MongoDB: WiredTiger önbellek boyutunu, ana makine belleğinden tahmin etmesine izin vermek yerine açıkça belirtin.
- Redis:
maxmemoryvarsayılan olarak sınırsızdır, bu nedenle Redis cgroup tarafından durdurulana kadar büyür.maxmemorydeğerini container sınırının güvenli bir miktarda altına ayarlayın ve birmaxmemory-policyseçin.
Postgres de bu olayı kendi tarafından raporlar; günlükte şu iki satırı göreceksiniz:
LOG: server process (PID 123) was terminated by signal 9: Killed
LOG: terminating any other active sessions due to crash of another server processBir arka uç (backend) sürecinin sonlandırılması, paylaşılan bellek tutarsız hale gelebileceği için diğer tüm arka uç süreçlerinin yeniden başlatılmasına neden olur. Bu durum, uygulamanız için sessiz bir olay değil, bir bağlantı fırtınasıdır. Docker Compose içinde bellek sınırlarını ayarlama konusu, sözdizimini ve mem_limit ile deploy.resources biçimi arasındaki farkı açıklar.
Bunların hiçbiri ana makinede yok olmaz, sadece yer değiştirir. Bir cgroup olmadan veritabanı, sunucudaki diğer her şeyle rekabet eder ve ana makine OOM sonlandırıcısı, sshd dahil herhangi bir süreci puanına göre kurban seçebilir. Veritabanını öngörülebilir şekilde sonlandıran bir sınır, sizi sistemden kilitleyen bir ana makine OOM durumundan daha yönetilebilirdir.
Yedekleme: içeride dump alın, dışarıda yedekleyin
Çalışan bir veritabanını veri dizinini kopyalayarak yedeklemeyin. Sunucu yazma işlemi yaparken alınan dosya seviyesindeki bir kopyalama işlemi "torn copy" (parçalı kopya) oluşturur ve bunu ancak geri yükleme aşamasında fark edersiniz.
İki güvenilir yöntem mevcuttur: veritabanı çalışırken kendi aracıyla dump almak ve bu dump dosyasını yedeklemek ya da container'ı durdurup volume dizinini soğuk yedeklemek.
docker compose exec -T db pg_dump -U postgres -Fc appdb > /srv/backups/appdb.dump
docker compose exec -T db mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --single-transaction --all-databases > /srv/backups/mysql.sql
docker compose exec -T db mongodump --archive --gzip --db appdb > /srv/backups/appdb.archive.gz
docker compose exec -T redis redis-cli BGSAVE-T parametresi önemlidir. Bu parametre olmadan docker compose exec komutu terminali sürece bağlayabilir ve terminal katmanı çıktı akışına satır başı karakterleri ekleyebilir. Bu durumda metin tabanlı dump dosyaları geri yüklenirken garip hatalar oluşur, ikili (binary) dump dosyaları ise doğrudan bozulur. Yedekleme sırasında sessizce başarısız olan bu durum, bir ay sonra geri yükleme yapmaya çalıştığınızda büyük sorunlara yol açar.
--single-transaction parametresi, mysqldump aracına tüm sunucuyu kilitlemeden InnoDB tablolarının tutarlı bir anlık görüntüsünü (snapshot) alma imkanı tanır.
Bu komutlar tek bir dosya oluşturur. Bunlar tek başlarına bir yedekleme sistemi değildir; saklama politikası (retention), sunucu dışına aktarım veya doğrulama mekanizmaları içermezler. Dump dizinini bu üç özelliği de sağlayan bir araca emanet edin; restic ile VPS yedekleme rehberinin amacı budur. /var/lib/docker/volumes değil, /srv/backups yedeğini alın.
Ardından geri yükleme işlemini test edin; çünkü daha önce geri yüklemediğiniz bir yedek, yedek sayılmaz:
docker compose exec -T db createdb -U postgres restore_test
docker compose exec -T db pg_restore -U postgres -d restore_test < /srv/backups/appdb.dump
docker compose exec -T db psql -U postgres -d restore_test -c '\dt'\dt komutu uygulamanızın tablolarını listelemelidir. Boş bir sonuç veya Did not find any relations. hatası, dump dosyasının beklediğiniz içerikte olmadığını gösterir. İşiniz bittiğinde restore_test veritabanını silin.
Her şeyi silen komut
docker compose down -v.
Basit down komutu, container'ları ve ağı kaldırır. -v komutu ise compose dosyasında tanımlanan tüm adlandırılmış volume'ları ve bu container'lara bağlı tüm anonim volume'ları da siler. Bu işlem için herhangi bir onay istenmez ve geri dönüşü yoktur. Self-hosted bir veritabanının yok edilmesinin en yaygın yolu budur; genellikle konuyla ilgisiz bir sorun giderme işlemi sırasında, bir forum yanıtında önerildiği için yanlışlıkla çalıştırılır.
Etki alanını daraltmak için şu dört yöntem uygulanmalıdır:
- Veritabanı volume'unu
external: trueolarak tanımlayın. Compose, kendi yönetmediği bir volume'u silmeyeceği için-vkomutu ona erişemez. Bu volume'udocker volume create myapp_pgdataile bir kez oluşturmanız yeterlidir. - Rutin yeniden başlatmalar için
docker compose stopvedocker compose startkomutlarını kullanın. Compose'da down ve stop arasındaki farklar belgesi, her bir komutun neleri kaldırdığını açıklar. - Veritabanı yedeklerini, compose tarafından yönetilen volume'ların dışında, host üzerinde bir dizinde tutun.
- Veri kaybı yaşamak istemediğiniz bir stack üzerinde, bir sorun giderme yanıtından kopyaladığınız
-vkomutunu asla çalıştırmayın.
Veritabanı portunu dış dünyaya açmayın
Bu satır, veritabanınızı genel internete açık hale getirir:
ports:
- "5432:5432"Bu yapılandırma, veritabanını tüm ağ arayüzlerine bağlar. Docker, bir portu yayınlarken paketin hedef adresini, güvenlik duvarınızın giriş kuralları devreye girmeden önce yeniden yazar. ufw kuralları ise giriş zincirinde (input chain) yer aldığından, ufw deny 5432 hiçbir işe yaramaz. Docker tarafından yayınlanan portların ufw'yi neden devre dışı bıraktığı bağlantısı, paketlerin zincir üzerindeki hareketini göstermektedir.
Aynı compose projesi içindeki bir uygulama, veritabanına compose ağı üzerinden servis adıyla erişebilir; bu nedenle dışarıya açılmış bir porta ihtiyaç duymaz. İlgili bloğu silin. Eğer ana makine (host) üzerinden bir istemci ile bağlanmak istiyorsanız, yalnızca loopback arayüzüne bağlayın:
ports:
- "127.0.0.1:5432:5432"Hangi servislerin dinlemede olduğunu kontrol edin:
sudo ss -ltnp | grep 5432İstediğiniz durum 127.0.0.1:5432 çıktısını görmektir. 0.0.0.0:5432 çıktısı, herkesin parolanızı deneyebileceği anlamına gelir.
Nerede ne çalıştırılmalı
Tek bir VPS üzerinde tek bir uygulama. Container kullanın. Sabitlenmiş bir isme sahip adlandırılmış bir volume, dışarıya açılmamış bir port, veritabanı ayarlarıyla uyumlu bir bellek sınırı ve restic tarafından toplanan, ana makine yoluna alınan günlük dökümler kullanın. VPS üzerinde temiz bir Docker kurulumu ile başlayın ve yığını commit ettiğiniz tek bir compose dosyasında tutun. Avantajı gerçektir: veritabanı sürümü, git üzerinde gözden geçirilebilir bir satır haline gelir.
Birden fazla servis çalıştıran bir ana makine. Her uygulama için bir veritabanı olacak şekilde container'lar kullanın; hepsini tek bir paylaşımlı sunucuya toplamayın. Paylaşımlı bir sunucu, her uygulamayı tek bir yükseltme takvimine bağlar ve tek bir hatalı sorgu herkesin kesintiye uğramasına neden olur. Her container'a kendi bellek sınırını atayın; böylece hatalı bir sorgu, sadece onu yazan uygulamayla sınırlı kalır. Birkaç küçük Postgres örneği, biraz daha fazla disk alanı harcar ancak koordinasyon yükünü ciddi oranda azaltır.
Veritabanı ürünün kendisidir. Veritabanını, sağlayıcının paket deposundan ana makine üzerinde çalıştırın veya yönetilen bir hizmet için ödeme yapın. pg_upgrade, ikili dosyaların her iki ana sürümünün de aynı anda yüklü olmasını gerektirir; paketler bunu sağlar ancak tek sürümlü bir imaj sağlamaz. Veritabanı makineye ve disklere tam hakim olduğunda, replikasyon ve WAL (write ahead log) arşivleme ile belirli bir ana geri dönüş (point in time recovery) işlemleri çok daha kolaydır. Sizi saat 03:00'te uyandıracak sistemler için her zaman en güvenilir ve standart yolu seçin.
Uygulama küçük ölçeklidir. Hiç sunucu tabanlı veritabanı çalıştırmamayı değerlendirin. Tek bir VPS üzerinde tek yazarlı bir web uygulaması için genellikle üretim ortamında SQLite kullanmak daha iyidir; bu yöntemde yedekleme tek bir dosyadan ibarettir ve yükseltme yolu bir kütüphane sürümünden geçer.
FAQ
Üretim ortamındaki bir veritabanını Docker üzerinde çalıştırmak güvenli midir?
Evet, tek sunuculu bir uygulama yığını için güvenlidir. Bir container, etrafında namespace ve cgroup bulunan bir Linux sürecidir; bu nedenle mount edilmiş bir volume ile veritabanı, paketten kurulmuş gibi aynı host dosya sistemine yazar. Riskler hızdan ziyade operasyoneldir: ismi sabitlenmemiş bir volume, yanlış kullanıcı kimliğine (UID) sahip bir bind mount, hiç test edilmemiş bir geri yükleme süreci ve docker compose down -v. Bu dört maddeyi çözdüğünüzde container sorunsuz çalışır. Veritabanı ana iş yükü haline geldiğinde ve pg_upgrade, replikasyon veya belirli bir ana geri dönüş (point in time recovery) özelliklerine ihtiyaç duyduğunuzda host kurulumuna geçiş yapın.
Veritabanı verileri için bind mount mu yoksa named volume mu kullanmalıyım?
Host üzerindeki yolu bilmenizi gerektiren özel bir neden yoksa named volume kullanın. Docker dizini oluşturur ve image entrypoint'i ilk başlatmada sahiplik ayarlarını yapar, böylece izin sorunları yaşanmaz. Volume'u açık bir name: ile sabitleyin veya external: true olarak işaretleyin; aksi takdirde proje dizinini yeniden adlandırmak, sessizce yeni ve boş bir volume ile boş bir veritabanı oluşturulmasına neden olur. Host dizinini, resmi Postgres, MySQL ve MongoDB image'larının kullandığı 999 numaralı kullanıcı kimliğine (chown ile) atarsanız bind mount da kullanılabilir. Bunu ls -ldn ile doğrulayın, çünkü ls -l bu numara için host'unuzdaki ismi gösterir ve bu isim container içinde anlamsızdır.
docker compose down -v komutu neleri siler?
Tıpkı basit bir down gibi container'ları ve ağı kaldırır; -v ise buna ek olarak o compose dosyasında tanımlanan tüm named volume'ları ve bu container'lara bağlı tüm anonim volume'ları siler. Buna veritabanı da dahildir. Onay istemi yoktur ve geri dönüşü mümkün değildir. external: true olarak işaretlenen volume'lar silinmez; bir veritabanı volume'unu external olarak işaretlemenin temel nedeni budur. Rutin yeniden başlatmalar için docker compose stop ve docker compose start kullanın.
Docker üzerinde PostgreSQL'i yeni bir ana sürüme nasıl yükseltirim?
Dump alıp geri yükleyerek. postgres:16 değerini postgres:17 ile değiştirip yeniden başlatmak, her iki sürümü de belirten bir DETAIL satırı içeren FATAL: database files are incompatible with server hatasına yol açar; çünkü yeni binary'ler eski katalog yapısını okuyamaz. Hiçbir şey zarar görmez: eski etiketi geri koyduğunuzda sistem çalışmaya devam eder. Çalışan eski container'a karşı yeni sürümün istemcisini kullanarak bir pg_dumpall alın, dosyanın PostgreSQL database cluster dump complete ile bittiğini doğrulayın, ardından yeni etiketi boş bir volume üzerinde ayağa kaldırıp dump dosyasını yükleyin. Aynı ana sürüm içindeki küçük güncellemeler için sadece pull ve restart yeterlidir.
Veritabanı container'ım neden 137 hata koduyla kapanıyor?
137, 128 artı 9 numaralı sinyaldir; yani bir süreç doğrudan öldürülmüştür. docker inspect <container> | grep -i oomkilled komutunu çalıştırın; true değeri, container'ın cgroup bellek sınırına ulaştığı anlamına gelir. Bunun yaygın nedeni, PostgreSQL ve MySQL'in toplam bellek miktarını host üzerinden okuması ve container sınırını görmemesidir; bu yüzden 2 GB içinde çalışırken 16 GB'a göre planlama yaparlar. Container'a verdiğiniz sınıra uygun şekilde shared_buffers ve work_mem veya innodb_buffer_pool_size ayarlarını yapın. Çekirdeğin hangi süreci seçtiğini doğrulamak için journalctl -k içindeki ilgili Memory cgroup out of memory satırını kontrol edin.