डेटाबेस Docker मध्ये चालवावा की होस्टवर?
PostgreSQL, MySQL, MongoDB किंवा Redis कंटेनरमध्ये चालवणे सुरक्षित आहे का? डेटाबेस व्हॉल्यूम्स, बॅकअप, मेमरी लिमिट्स आणि अपग्रेडच्या आव्हानांची सविस्तर माहिती या लेखात दिली आहे.
डेटाबेस Docker मध्ये चालवावा की होस्टवर?
डेटाबेस Docker मध्ये चालवा. एका VPS वर एका ॲप्लिकेशन स्टॅकसाठी, कंटेनराइज्ड PostgreSQL, MySQL, MongoDB किंवा Redis हा एक सामान्य प्रॉडक्शन पर्याय आहे आणि त्याबद्दल होणारी चर्चा सहसा चुकीच्या मुद्द्यांवर आधारित असते. कंटेनर म्हणजे Linux प्रोसेस असते, ज्याच्या भोवती namespaces आणि cgroups असतात; ती व्हर्च्युअल मशीन नसते, त्यामुळे डेटाबेस आणि डिस्कच्या मध्ये कोणताही हायपरवाइजर नसतो. bind mount किंवा लोकल named volume वापरल्यास, वाचन आणि लेखनाच्या क्रिया थेट होस्ट फाइलसिस्टमवर होतात, जी पॅकेज इन्स्टॉल करताना वापरली जाणारी फाइलसिस्टमच असते.
याचा खरा खर्च ऑपरेशनल असतो. ही रचना योग्य ठरेल की एक संथ आपत्ती, हे चार गोष्टी ठरवतात: डेटा कुठे साठवला जातो, त्या डिरेक्टरीचा मालक कोण आहे, मेजर व्हर्जन अपग्रेडची प्रक्रिया कशी आहे आणि तुम्ही कधी बॅकअप रिस्टोअर केला आहे का. या गोष्टी नीट हाताळल्यास कंटेनर हा केवळ एक तांत्रिक तपशील उरतो. जर या गोष्टी चुकल्या, तर तुम्ही कंटेनरलाच दोष द्याल.
प्रत्येक सर्व्हर डेटाबेससाठी हा निर्णय सारखाच असतो. खालील उदाहरणांमध्ये PostgreSQL, MySQL, MongoDB आणि Redis चा वापर केला आहे आणि जिथे आवश्यक आहे तिथे उत्पादन-विशिष्ट फरक स्पष्ट केले आहेत.
कंटेनर नेमके काय बदलतो
जोपर्यंत तुम्ही स्टोरेज पाथ माउंट करता, तोपर्यंत तो बदलत नाही. कर्नल, पेज कॅशे आणि फाइलसिस्टम सारखीच राहते.
कामगिरीच्या बाबतीत एक मुख्य अडथळा आहे, तो म्हणजे जेव्हा तुम्ही काहीही माउंट करत नाही. व्हॉल्यूमशिवाय, डेटा डिरेक्टरी कंटेनरच्या रायटेबल लेयरमध्ये जाते, जी इमेजवर आधारित एक ओव्हरले फाइलसिस्टम असते. तिथे लिहिण्याची प्रक्रिया संथ असते आणि कंटेनर काढून टाकल्यावर संपूर्ण लेयर नष्ट होते. "आज सकाळी माझा डेटाबेस रिकामा का होता" याचे कारण हेच आहे.
जे खरोखर बदलते ते खालीलप्रमाणे:
- लाइफसायकल (Lifecycle).
docker compose downकंटेनर नष्ट करतो. व्हॉल्यूममध्ये नसलेली कोणतीही गोष्ट त्यासोबत नष्ट होते. - व्हर्जन (Version). इमेज टॅग हेच व्हर्जन असते. डेटाबेस कंटेनरच्या आत अशी कोणतीही
apt upgradeनसते जी पुढीलdocker compose pullनंतर टिकून राहील. - मेमरी अकाउंटिंग (Memory accounting). cgroup मर्यादा ही कर्नलद्वारे लागू केलेली एक कठोर भिंत असते आणि डेटाबेसला ती अस्तित्वात असल्याची कल्पना नसते.
- युजर (User). प्रक्रिया कंटेनरच्या आत एका अंकीय युजर आयडी (numeric user id) म्हणून चालते, ज्याची तुमच्या होस्टवर कोणतीही मालकी नसू शकते.
डेटा कुठे साठवायचा हे सर्व काही ठरवते
यासाठी दोन चांगले पर्याय आहेत आणि एक सामान्य चूक आहे.
- Named volume:
pgdata:/var/lib/postgresql/data. Docker/var/lib/docker/volumes/<project>_pgdata/_dataवर डिरेक्टरी तयार करते आणि इमेजचे entrypoint पहिल्या रनला मालकी हक्क (ownership) सेट करते. हा डीफॉल्ट पर्याय आहे. - Bind mount:
/srv/appname/pg:/var/lib/postgresql/data. तुम्ही पाथ निवडता, त्यामुळे परवानग्यांची समस्या तुमची जबाबदारी असते. - कोणताही माउंट न वापरणे. वर नमूद केल्याप्रमाणे, डेटा कंटेनरच्या आत राहतो.
यातील पूर्ण तौलनिक फरक हा एक स्वतंत्र विषय आहे आणि bind mounts against named volumes मध्ये तो कव्हर केला आहे. डेटाबेससाठी थोडक्यात सांगायचे तर: जोपर्यंत तुम्हाला होस्ट पाथ माहित असण्याचे विशिष्ट कारण नसेल, तोपर्यंत named volume वापरा. जर तुम्ही bind mount वापरत असाल, तर ते /srv/appname/pg सारख्या स्थिर ठिकाणी ठेवा, जेणेकरून git clean तिथे पोहोचू शकणार नाही.
एक महत्त्वाची मर्यादा: डेटाबेसची डेटा डिरेक्टरी NFS (network file system) किंवा अशा कोणत्याही नेटवर्क माउंटवर ठेवू नका ज्याचे लॉकिंग आणि fsync वर्तन तुम्ही तपासलेले नाही. डेटाबेस असे गृहीत धरतात की यशस्वी fsync चा अर्थ असा आहे की बाइट्स स्थिर स्टोरेजवर (stable storage) सुरक्षित आहेत. जेव्हा हे गृहीतक चुकीचे ठरते, तेव्हा डेटा करप्शन होते जे काही आठवड्यांनंतर दिसून येते.
व्हॉल्यूम गहाळ होण्यापूर्वी त्याचे नाव पिन करा
Compose व्हॉल्यूमचे नाव <project>_<volume> असे ठेवते आणि प्रोजेक्टचे नाव डीफॉल्टनुसार डिरेक्टरीच्या नावावरून ठरते. त्यामुळे व्हॉल्यूमची ओळख डिरेक्टरीच्या नावावर अवलंबून असते, जे लोक विचार न करता बदलतात.
जर तुम्ही /srv/app ला /srv/app-old मध्ये हलवले किंवा compose फाईलमधील pgdata की (key) बदलली, तर पुढच्या वेळी docker compose up -d चालवल्यावर एक नवीन रिकामे व्हॉल्यूम तयार होईल. Postgres त्यात एक नवीन क्लस्टर इनिशिअलाईज करेल. कंटेनर हेल्दी असेल, ॲप्लिकेशन सुरू होईल, पण सर्व टेबल्स नष्ट झालेली असतील. चांगली बातमी ही आहे की जुने व्हॉल्यूम अजूनही जुन्या नावाने डिस्कवर उपलब्ध असते.
docker volume ls
docker volume inspect app_pgdataअसे घडू नये म्हणून नावे पिन करा. प्रोजेक्टचे नाव आणि व्हॉल्यूमचे नाव स्पष्टपणे सेट करा:
name: myapp
services:
db:
image: postgres:17
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
name: myapp_pgdataजर तुमचा डेटा आधीच एखाद्या जुन्या व्हॉल्यूममध्ये असेल, तर डेटाबेस थांबवून तो कॉपी करा:
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 dbडेटाबेस सुरू असताना कॉपी केल्यास फाईल्स अर्धवट कॉपी होऊ शकतात, कारण त्या वेळी त्यामध्ये लिहीले जात असते. त्यामुळे आधी डेटाबेस थांबवा.
डेटा डिरेक्टरीची मालकी कोणाकडे असते
अधिकृत Postgres, MySQL आणि MongoDB इमेजेस त्यांचा सर्व्हर एका अनप्रिव्हिलेज्ड (unprivileged) युजर आयडीवर चालवतात, जो सहसा 999 असतो. जेव्हा कंटेनर root म्हणून सुरू होतो, तेव्हा एंट्रीपॉइंट डेटा डिरेक्टरीची मालकी त्या युजरकडे सोपवतो आणि त्यानंतर स्वतःचे अधिकार कमी करतो. म्हणूनच रिकामे bind mount सहसा पहिल्या प्रयत्नात काम करतात.
ज्या क्षणी तुम्ही compose फाईलमध्ये user: सेट करता, त्या क्षणी ही प्रक्रिया खंडित होते, कारण त्यानंतर एंट्रीपॉइंटकडे कोणतीही गोष्ट दुरुस्त करण्याचे अधिकार उरत नाहीत. Postgres हे थेट स्पष्ट करते:
initdb: error: could not change permissions of directory "/var/lib/postgresql/data": Operation not permittedचुकीच्या मोडसह अस्तित्वात असलेली डेटा डिरेक्टरी वेगळा संदेश देते, आणि हा संदेश ओळखणे महत्त्वाचे आहे कारण त्यावर उपाय chmod हा आहे, chown नाही:
FATAL: data directory "/var/lib/postgresql/data" has invalid permissions
DETAIL: Permissions should be u=rwx (0700) or u=rwx,g=rx (0750).root-owned bind mount वर MongoDB लॉक फाईलमुळे अपयशी ठरते:
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.यावर उपाय म्हणजे होस्ट डिरेक्टरीची मालकी (chown) नावाऐवजी अंकीय आयडीकडे (numeric id) हस्तांतरित करणे:
sudo chown -R 999:999 /srv/appname/pg
sudo chmod 700 /srv/appname/pg
ls -ldn /srv/appname/pgls -ldn नावाऐवजी क्रमांक दर्शवते, आणि तिथे 999 999 दिसले पाहिजे. तुमच्या होस्टवरील postgres नावाचे खाते आणि इमेजमधील postgres नावाचे खाते यांचा एकमेकांशी संबंध नसतो: कर्नल केवळ क्रमांकांची तुलना करते, आणि नावे दोन्ही बाजूंना स्वतंत्रपणे शोधली जातात. PUID आणि PGID होस्ट युजर्सना कंटेनरमध्ये कसे मॅप करतात या लेखात या मॅपिंगची सविस्तर माहिती दिली आहे. rootless Docker किंवा user namespace remapping अंतर्गत हे क्रमांक पुन्हा बदलतात, त्यामुळे 999 गृहीत धरण्याऐवजी चालू असलेल्या कंटेनरमधून आयडी तपासा.
Named volumes वापरल्यास हा संपूर्ण विभाग पहिल्या रनमध्येच निकालात निघतो, कारण Docker एक रिकामी डिरेक्टरी तयार करते आणि एंट्रीपॉइंट तिची मालकी घेतो.
अपग्रेड्स: इमेज टॅग बदलून पॅकेज अपग्रेड करणे
होस्टवर, apt upgrade तुम्हाला मायनर व्हर्जनवर पुढे नेते. तुमचे डिस्ट्रिब्युशन तुमच्या नकळत डेटाबेसचे मेजर व्हर्जन बदलणार नाही, आणि जेव्हा तुम्ही व्हर्जन बदलण्याचे ठरवता, तेव्हा दोन्ही संचातील बायनरीज एकाच वेळी इन्स्टॉल करता येतात, जे pg_upgrade साठी आवश्यक असते.
कंटेनरमध्ये टॅग म्हणजे व्हर्जन असते, त्यामुळे अपग्रेड म्हणजे फक्त एक ओळ बदलणे. यामुळे मायनर अपग्रेड्स सोपे होतात आणि मेजर अपग्रेड्ससाठी एक प्रक्रिया पाळावी लागते.
postgres:16 बदलून postgres:17 करा, docker compose up -d रन करा, आणि कंटेनर लगेच बंद होईल:
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.काहीही नुकसान होत नाही. नवीन बायनरीज जुन्या ऑन-डिस्क कॅटलॉग लेआउटला वाचण्यास नकार देतात, जो मेजर व्हर्जन दरम्यान बदलतो. टॅग पुन्हा postgres:16 वर सेट करा आणि ते पुन्हा सुरू होईल. तो रोलबॅक हा कंटेनरमुळे मिळणारा एक खरा अपग्रेड फायदा आहे.
समर्थित मार्ग म्हणजे डंप आणि रिस्टोअर. PostgreSQL ला नवीन क्लायंटद्वारे डंप घेणे सोयीचे वाटते, म्हणून compose नेटवर्कवर अजूनही चालू असलेल्या जुन्या सर्व्हरच्या विरुद्ध नवीन इमेजवरून ते रन करा:
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.sqlफाईल किमान काही दहा किलोबाइट्सची असावी आणि ती PostgreSQL database cluster dump complete या ओळीने संपली पाहिजे. काहीशे बाइट्सची फाईल म्हणजे डंप अयशस्वी झाला आहे आणि तुम्ही विनाकारण व्हॉल्यूम डिलीट करणार आहात. ही तपासणी केल्यानंतरच:
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.sqlइतर इंजिन्सचे नियम वेगळे आहेत:
- MySQL 8 स्टार्टअपच्या वेळी स्वतःचा डेटा डिक्शनरी अपग्रेड करते, त्यामुळे मायनर टॅग बदलणे म्हणजे सहसा फक्त रीस्टार्ट करणे असते. रिलीज सिरीजमधील बदलापूर्वी रिलीज नोट्स वाचा आणि कोणत्याही परिस्थितीत आधी डंप घ्या.
- MariaDB मध्ये नवीन व्हर्जनवर सर्व्हर सुरू झाल्यानंतर
mariadb-upgradeरन करणे अपेक्षित असते. - MongoDB एका वेळी एक मेजर व्हर्जन अपग्रेड करणे आवश्यक आहे, आणि प्रत्येक टप्प्यानंतर पुढे जाण्यापूर्वी तुम्हाला फीचर कंपॅटिबिलिटी व्हर्जन सेट करावे लागते. एखादे व्हर्जन वगळल्यास
mongodसुरू होण्यास नकार देते आणि लॉगमध्येfeatureCompatibilityVersionचा उल्लेख असलेलीUPGRADE PROBLEMओळ दिसते. MongoDB 7.0 पासून पुढे या कमांडसाठी स्पष्ट कन्फर्मेशन फ्लॅग आवश्यक आहे:db.adminCommand({ setFeatureCompatibilityVersion: "8.0", confirm: true }). - Redis जुन्या स्नॅपशॉट फाईल्स सहज लोड करते पण नवीन फाईल्स नाही, त्यामुळे अपग्रेड म्हणजे रीस्टार्ट असतो आणि डाउनग्रेड करताना डेटा लोड होण्यास अपयश येऊ शकते.
सर्वसाधारण नियम: कंटेनर डाउनग्रेड करणे सोपे करतात, पण अपग्रेड करणे अधिक सोपे करत नाहीत.
माझा डेटाबेस कंटेनर एक्झिट कोड 137 सह का बंद होतो?
कारण कर्नलच्या out of memory (OOM) किलरने त्याला बंद केले आहे. 137 म्हणजे 128 अधिक सिग्नल 9.
docker compose ps
docker inspect myapp-db-1 | grep -i oomkilled
journalctl -k | tail -n 20docker compose ps मध्ये Exited (137) दिसते, inspect ओळीमध्ये "OOMKilled": true वाचले जाते आणि कर्नल लॉगमध्ये एक जुळणारी नोंद असते:
Memory cgroup out of memory: Killed process 4711 (postgres) total-vm:2170416kBयामागील यंत्रणा अशी आहे, जी अनेकांना आश्चर्यचकित करते. PostgreSQL आणि MySQL त्यांच्या बफरचा आकार होस्टने नोंदवलेल्या एकूण मेमरीवरून ठरवतात. cgroup मर्यादा त्यांच्यासाठी तो आकडा बदलत नाही. 16 GB च्या होस्टवर 2 GB ची मर्यादा असताना, डेटाबेस 16 GB मेमरी उपलब्ध असल्यासारखे नियोजन करतो आणि होस्टवर कोणताही ताण नसतानाही cgroup त्याला बंद करते. त्यामुळे केवळ मेमरी मर्यादा पुरेशी नाही. तुम्हाला डेटाबेसकडे किती मेमरी उपलब्ध आहे हे देखील सांगावे लागेल:
- PostgreSQL:
shared_buffersसेट करा आणिwork_memकडे लक्ष द्या.work_memहे प्रति कनेक्शन प्रति सॉर्ट ऑपरेशनसाठी अलोकेट केले जाते, त्यामुळे पन्नास कनेक्शनसाठी दिलेले मोठे मूल्य हे सहसा स्टार्टअपऐवजी लोड असताना कंटेनर बंद होण्याचे कारण असते. - MySQL आणि MariaDB:
innodb_buffer_pool_sizeसेट करा, जे डीफॉल्टनुसार 128M असते. कंटेनरमध्येinnodb_dedicated_serverबंद ठेवा, कारण त्याचे मुख्य काम मशीनच्या मेमरीवरून स्वतःचा आकार ठरवणे हे असते. - MongoDB: होस्ट मेमरीवरून अंदाज लावू देण्याऐवजी WiredTiger कॅशेचा आकार स्पष्टपणे सेट करा.
- Redis:
maxmemoryडीफॉल्टनुसार अमर्यादित असते, त्यामुळे cgroup थांबवेपर्यंत Redis वाढत राहते.maxmemoryला कंटेनर मर्यादेच्या खाली सोयीस्करपणे सेट करा आणि एकmaxmemory-policyनिवडा.
Postgres स्वतःच्या बाजूनेही या घटनेची नोंद करते आणि लॉगमध्ये तुम्हाला या दोन ओळी सापडतील:
LOG: server process (PID 123) was terminated by signal 9: Killed
LOG: terminating any other active sessions due to crash of another server processएक बॅकएंड बंद झाल्यामुळे इतर सर्व बॅकएंडना रीस्टार्ट करावे लागते, कारण शेअर केलेली मेमरी आता विसंगत असू शकते. तुमच्या ॲप्लिकेशनसाठी हा एक कनेक्शन स्टॉर्म असतो, शांत घटना नसते. Docker Compose मध्ये मेमरी मर्यादा सेट करणे यामध्ये सिंटॅक्स आणि mem_limit व deploy.resources फॉरमॅटमधील फरक स्पष्ट केला आहे.
यातील काहीही होस्टवर नाहीसे होत नाही. ते फक्त हलते. cgroup शिवाय डेटाबेस बॉक्सवरील इतर सर्व गोष्टींशी स्पर्धा करतो आणि होस्ट OOM किलर स्कोअरनुसार बळी निवडतो, जो sshd देखील असू शकतो. डेटाबेस बंद करणारी मर्यादा हाताळणे, तुम्हाला सिस्टमबाहेर काढणाऱ्या होस्ट OOM पेक्षा सोपे असते.
बॅकअप: डेटाबेस डंप करा, बाहेर बॅकअप घ्या
चालू असलेल्या डेटाबेसची डेटा डिरेक्टरी कॉपी करून बॅकअप घेऊ नका. सर्व्हर डेटा लिहित असताना घेतलेली फाईल-लेव्हल कॉपी ही 'torn copy' असते आणि ती रिस्टोर करतानाच लक्षात येते.
दोन खात्रीशीर पद्धती आहेत: डेटाबेस चालू असताना त्याच्या स्वतःच्या टूलने डंप घ्या आणि त्या डंपचा बॅकअप घ्या, किंवा कंटेनर थांबवून व्हॉल्यूमची 'cold' कॉपी करा.
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 महत्त्वाचे आहे. त्याशिवाय, docker compose exec कमांडला टर्मिनल जोडू शकते आणि टर्मिनल लेयर आउटपुट स्ट्रीममध्ये कॅरेज रिटर्न्स (carriage returns) जोडते. यामुळे टेक्स्ट डंप रिस्टोर करताना विचित्र त्रुटी येतात आणि बायनरी डंप पूर्णपणे खराब होतो. बॅकअप घेताना हे शांतपणे अपयशी ठरते आणि महिनाभरानंतर रिस्टोर करताना मोठ्या त्रुटी निर्माण होतात.
--single-transaction मुळे mysqldump ला संपूर्ण सर्व्हर लॉक न करता InnoDB टेबल्सचा सुसंगत स्नॅपशॉट मिळतो.
या कमांड्स प्रत्येकी एक फाईल तयार करतात. ही बॅकअप सिस्टिम नाही: यात रिटेंशन (retention), ऑफ-बॉक्स कॉपी किंवा पडताळणी नसते. डंप डिरेक्टरी अशा टूलकडे सोपवा जे या तिन्ही गोष्टी करते, ज्यासाठी restic backups from a VPS वापरले जाते. /var/lib/docker/volumes चा नाही, तर /srv/backups चा बॅकअप घ्या.
त्यानंतर रिस्टोर करून पहा, कारण जो बॅकअप तुम्ही कधीही रिस्टोर केला नाही तो बॅकअप नसतो:
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 ने तुमच्या ॲप्लिकेशनची टेबल्स दिसली पाहिजेत. निकाल रिकामा असणे किंवा Did not find any relations. येणे, याचा अर्थ डंप तुमच्या अपेक्षेप्रमाणे नाही. काम झाल्यावर restore_test ड्रॉप करा.
सर्व काही हटवणारी कमांड
docker compose down -v.
साधी down कमांड कंटेनर आणि नेटवर्क काढून टाकते. -v कमांड त्या compose फाईलमध्ये घोषित केलेले प्रत्येक named volume आणि त्या कंटेनरशी जोडलेले प्रत्येक anonymous volume देखील काढून टाकते. यासाठी कोणतीही विचारणा (prompt) केली जात नाही आणि ही क्रिया पूर्ववत (undo) करता येत नाही. self-hosted डेटाबेस नष्ट होण्याची ही सर्वात सामान्य पद्धत आहे. सहसा, एखाद्या वेगळ्या समस्येचे निवारण करत असताना, फोरमवरील उत्तरामध्ये ही कमांड चालवण्यास सांगितल्यामुळे असे घडते.
खालील चार गोष्टींमुळे होणारे नुकसान कमी करता येते:
- डेटाबेस व्हॉल्यूम
external: trueम्हणून घोषित करा. Compose स्वतःच्या मालकीचे नसलेले व्हॉल्यूम काढत नाही, त्यामुळे-vत्यापर्यंत पोहोचू शकत नाही. तुम्ही तेdocker volume create myapp_pgdataवापरून एकदाच तयार करता. - नियमित रीस्टार्टसाठी
docker compose stopआणिdocker compose startवापरा. Compose मधील down विरुद्ध stop मध्ये प्रत्येक कमांड काय काढून टाकते, याचे सविस्तर वर्णन दिले आहे. - डेटाचे डंप्स (dumps) compose द्वारे व्यवस्थापित केल्या जाणाऱ्या व्हॉल्यूम्सच्या बाहेर, होस्ट पाथवर ठेवा.
- ज्या स्टॅकमध्ये तुमचा महत्त्वाचा डेटा आहे, तिथे ट्रबलशूटिंग उत्तरातील
-vकधीही पेस्ट करू नका.
डेटाबेस पोर्ट सार्वजनिक करू नका
ही ओळ तुमचा डेटाबेस सार्वजनिक इंटरनेटवर उघड करते:
ports:
- "5432:5432"हे सर्व इंटरफेसेसवर बाइंड होते. Docker जेव्हा पोर्ट पब्लिश करते, तेव्हा ते फायरवॉलच्या इनपुट नियमांपर्यंत पोहोचण्यापूर्वीच पॅकेटचे डेस्टिनेशन बदलून टाकते. ufw चे नियम इनपुट चेनमध्ये असतात, त्यामुळे ufw deny 5432 चा काहीही उपयोग होत नाही. Docker पब्लिश केलेले पोर्ट ufw ला कसे बायपास करतात हे चेन ट्रॅव्हर्सल दर्शवते.
एकाच compose प्रोजेक्टमधील ॲप्लिकेशन डेटाबेसशी compose नेटवर्कवर सर्व्हिसच्या नावाने संपर्क साधू शकते, त्यामुळे त्याला पोर्ट पब्लिश करण्याची गरज नसते. हा ब्लॉक काढून टाका. जर तुम्हाला होस्टवरून क्लायंट वापरायचा असेल, तर फक्त लूपबॅकवर बाइंड करा:
ports:
- "127.0.0.1:5432:5432"सध्या काय लिसन करत आहे ते तपासा:
sudo ss -ltnp | grep 5432127.0.0.1:5432 हे तुम्हाला हवे असलेले आउटपुट आहे. 0.0.0.0:5432 चा अर्थ असा की कोणीही तुमच्या पासवर्डचा प्रयत्न करू शकते.
कुठे काय चालवावे
एका VPS वर एक ॲप्लिकेशन. कंटेनर वापरा. एका निश्चित नावासह (pinned name) नेमड व्हॉल्यूम वापरा, पोर्ट पब्लिश करू नका, मेमरी लिमिट सेट करा आणि त्यानुसार डेटाबेस सेटिंग्ज ठेवा. दररोज रात्री होणारा डंप होस्ट पाथवर घ्या, जो restic द्वारे गोळा केला जाईल. VPS वर क्लीन Docker इन्स्टॉल करण्यापासून सुरुवात करा आणि संपूर्ण स्टॅक एका compose फाईलमध्ये ठेवा जी तुम्ही git मध्ये कमिट कराल. याचा मोठा फायदा असा की, डेटाबेस व्हर्जन ही git मध्ये रिव्ह्यू करता येणारी एक ओळ बनते.
एका होस्टवर अनेक सेवा. कंटेनर वापरा, प्रत्येक ॲप्लिकेशनसाठी स्वतंत्र डेटाबेस ठेवा, सर्वांसाठी एकच सामायिक सर्व्हर वापरू नका. सामायिक सर्व्हरमुळे सर्व ॲप्लिकेशन्स एकाच अपग्रेड शेड्यूलशी बांधले जातात आणि एक चुकीची क्वेरी सर्वांच्या सेवेमध्ये व्यत्यय आणू शकते. प्रत्येक कंटेनरला स्वतःची मेमरी लिमिट द्या, जेणेकरून एखादी चुकीची क्वेरी फक्त संबंधित ॲप्लिकेशनपुरती मर्यादित राहील. अनेक लहान Postgres इन्स्टन्स वापरल्यास थोडी जास्त डिस्क लागते, पण समन्वयाचा त्रास खूप कमी होतो.
डेटाबेस हेच उत्पादन असेल तर. तो व्हेंडरच्या पॅकेज रिपॉझिटरीमधून होस्टवर चालवा किंवा मॅनेज्ड सर्व्हिसचा वापर करा. pg_upgrade ला एकाच वेळी बायनरीजच्या दोन्ही प्रमुख आवृत्त्या (major versions) इन्स्टॉल करण्याची आवश्यकता असते, जे पॅकेजेसद्वारे शक्य होते पण सिंगल-व्हर्जन इमेजमध्ये नाही. जेव्हा डेटाबेसचे मशीन आणि डिस्कवर पूर्ण नियंत्रण असते, तेव्हा रेप्लिकेशन आणि WAL (write ahead log) आर्काइव्हिंग वापरून पॉइंट-इन-टाइम रिकव्हरी करणे सोपे जाते. ज्या सिस्टिममुळे तुम्हाला पहाटे 03:00 वाजता अलर्ट येऊ शकतो, त्यासाठी नेहमी सुरक्षित आणि खात्रीशीर मार्ग निवडा.
ॲप्लिकेशन लहान असेल तर. सर्व्हर-आधारित डेटाबेस न वापरण्याचा विचार करा. एका VPS वर चालणाऱ्या सिंगल-रायटर वेब ॲप्लिकेशनसाठी VPS वर प्रॉडक्शनमध्ये SQLite वापरणे अनेकदा अधिक चांगले ठरते, जिथे बॅकअप म्हणजे फक्त एक फाईल असते आणि अपग्रेड पाथ म्हणजे लायब्ररीचे व्हर्जन असते.
FAQ
प्रोडक्शन डेटाबेस Docker मध्ये चालवणे सुरक्षित आहे का?
हो, सिंगल-सर्व्हर ॲप्लिकेशन स्टॅकसाठी हे सुरक्षित आहे. कंटेनर म्हणजे Linux namespaces आणि cgroups द्वारे मर्यादित केलेली एक प्रक्रिया (process) असते. त्यामुळे, व्हॉल्यूम माउंट केल्यास डेटाबेस त्याच होस्ट फाइलसिस्टमवर लिहितो, ज्यावर तो पॅकेजद्वारे इन्स्टॉल केल्यावर लिहितो. यात धोके वेगापेक्षा ऑपरेशनल स्वरूपाचे असतात: ज्याचे नाव पिन केलेले नाही असा व्हॉल्यूम, चुकीच्या युजर आयडीच्या मालकीचे बाइंड माउंट, तुम्ही कधीही टेस्ट न केलेले रिस्टोर आणि docker compose down -v. या चार गोष्टींची काळजी घेतल्यास कंटेनर सुरक्षित राहतो. जेव्हा डेटाबेस हे मुख्य वर्कलोड असते आणि तुम्हाला pg_upgrade, रेप्लिकेशन किंवा पॉइंट-इन-टाइम रिकव्हरीची गरज असते, तेव्हा होस्ट इन्स्टॉलवर स्थलांतर करा.
डेटाबेस डेटासाठी मी बाइंड माउंट वापरावे की नेमड व्हॉल्यूम?
जोपर्यंत तुम्हाला होस्ट पाथ माहित असण्याचे काही विशिष्ट कारण नसेल, तोपर्यंत नेमड व्हॉल्यूमच वापरा. Docker डिरेक्टरी तयार करते आणि इमेजचा एंट्रीपॉइंट पहिल्यांदा सुरू होताना मालकी हक्क (ownership) सेट करतो, त्यामुळे परमिशनच्या समस्या उद्भवत नाहीत. व्हॉल्यूमला स्पष्ट name: ने पिन करा किंवा त्याला external: true म्हणून चिन्हांकित करा, अन्यथा प्रोजेक्ट डिरेक्टरीचे नाव बदलल्यास नकळत एक नवीन रिकामी व्हॉल्यूम आणि रिकामा डेटाबेस तयार होईल. जर तुम्ही होस्ट डिरेक्टरीला इमेज ज्या न्यूमेरिक युजर आयडीवर चालते (अधिकृत Postgres, MySQL आणि MongoDB इमेजेससाठी हा 999 असतो) त्यावर chown केले, तर बाइंड माउंट वापरणे ठीक आहे. हे ls -ldn ने तपासा, कारण ls -l त्या नंबरसाठी तुमच्या होस्टचे नाव दाखवते आणि ते नाव कंटेनरच्या आत निरर्थक असते.
docker compose down -v काय डिलीट करते?
हे कंटेनर आणि नेटवर्कला सामान्य down प्रमाणे काढून टाकते, आणि -v त्यासोबत त्या कंपोज फाइलमध्ये घोषित केलेले प्रत्येक नेमड व्हॉल्यूम आणि त्या कंटेनरला जोडलेले प्रत्येक अनोनिमस व्हॉल्यूम देखील काढून टाकते. यामध्ये डेटाबेसचाही समावेश असतो. यासाठी कोणतीही कन्फर्मेशन प्रॉम्प्ट येत नाही आणि डेटा रिकव्हर करता येत नाही. external: true म्हणून चिन्हांकित केलेले व्हॉल्यूम काढले जात नाहीत, म्हणूनच डेटाबेस व्हॉल्यूमला एक्सटर्नल म्हणून चिन्हांकित करणे महत्त्वाचे आहे. नियमित रीस्टार्टसाठी docker compose stop आणि docker compose start वापरा.
Docker मध्ये PostgreSQL ला नवीन मेजर व्हर्जनवर अपग्रेड कसे करावे?
डंप आणि रिस्टोर करा. postgres:16 बदलून postgres:17 केल्यास आणि रीस्टार्ट केल्यास FATAL: database files are incompatible with server एरर येते, ज्यामध्ये DETAIL ओळ दोन्ही व्हर्जनची नावे दर्शवते, कारण नवीन बायनरीज जुन्या कॅटलॉग लेआउटला वाचू शकत नाहीत. काहीही खराब होत नाही: जुना टॅग परत लावल्यास ते पुन्हा सुरू होते. चालू असलेल्या जुन्या कंटेनरवर नवीन व्हर्जनचा क्लायंट वापरून pg_dumpall घ्या, फाइल PostgreSQL database cluster dump complete ने संपते का ते तपासा, त्यानंतर नवीन टॅग रिकाम्या व्हॉल्यूमवर सुरू करा आणि डंप लोड करा. एकाच मेजर व्हर्जनमधील मायनर अपग्रेडसाठी फक्त पुल आणि रीस्टार्ट पुरेसे असते.
माझा डेटाबेस कंटेनर कोड 137 सह का बंद होतो?
137 म्हणजे 128 अधिक सिग्नल 9, याचा अर्थ एखाद्या गोष्टीने प्रक्रियेला थेट थांबवले आहे. docker inspect <container> | grep -i oomkilled चालवा; true व्हॅल्यूचा अर्थ असा की कंटेनर त्याच्या cgroup मेमरी मर्यादेपर्यंत पोहोचला आहे. याचे सामान्य कारण असे की PostgreSQL आणि MySQL होस्टची एकूण मेमरी वाचतात आणि कंटेनरची मर्यादा त्यांना दिसत नाही, त्यामुळे ते 2 GB मध्ये असताना 16 GB साठी नियोजन करतात. कंटेनरला दिलेल्या मर्यादेनुसार shared_buffers आणि work_mem, किंवा innodb_buffer_pool_size सेट करा. कर्नलने कोणती प्रक्रिया निवडली हे पाहण्यासाठी journalctl -k मधील संबंधित Memory cgroup out of memory ओळ तपासा.