SSD Nodes Learn 🎉 VPS $5.50/माह से
गाइड Matt Connorलेखक: Matt Connor

Docker Compose stack का सुरक्षित बैकअप और अपग्रेड कैसे

Docker Compose stack को अपग्रेड करने से पहले सही बैकअप कैसे लें। इसमें volumes, database dumps और compose files को सुरक्षित करने का सही तरीका बताया गया है ताकि डेटा न खोए।

Docker Compose stack backup में क्या शामिल होना चाहिए

Docker Compose stack के backup में चार अलग-अलग चीजें होनी चाहिए, और इनमें से किसी एक के भी खोने का मतलब है कि app वापस नहीं आएगी: compose file, उसके बगल में मौजूद .env, हर volume की सामग्री, और database के अपने client द्वारा तैयार किया गया database dump। container के चलते समय database की files को copy करना backup नहीं माना जाता है। अपग्रेड के लिए इसी सूची का उपयोग करें, साथ ही एक नियम का पालन करें: pull करने से पहले backup लें, क्योंकि schema migrations को आगे बढ़ने के लिए लिखा जाता है और अधिकांश projects में वापस जाने (rollback) का कोई तरीका नहीं होता है।

नीचे दी गई हर बात यह मानकर चलती है कि stack पहले से ही deployed है और docker compose ps यह दिखाता है कि वह चल रहा है। उदाहरणों में /srv/myapp पर स्थित project directory का उपयोग किया गया है, जिसमें app और db नाम की services हैं। अपने स्वयं के नामों का उपयोग करें। commands को जानबूझकर सामान्य रखा गया है, क्योंकि जो हिस्से मायने रखते हैं—यानी volumes और database—वे app चाहे कोई भी हो, एक ही तरह से काम करते हैं।

यह निर्धारित करें कि आपका stack वास्तव में क्या स्टोर करता है

cd /srv/myapp
docker compose ps
docker compose config --volumes
docker volume ls --filter label=com.docker.compose.project=myapp

docker compose config --volumes आपके द्वारा घोषित volumes के छोटे नाम प्रिंट करता है। docker volume ls उन नामों को प्रिंट करता है जो वास्तव में डिस्क पर मौजूद हैं। ये दोनों सूचियाँ अलग होती हैं, क्योंकि Compose प्रोजेक्ट के नाम को वॉल्यूम के नाम के आगे जोड़ देता है: फाइल में db_data के रूप में लिखा गया वॉल्यूम डिस्क पर myapp_db_data के रूप में मौजूद होता है। प्रोजेक्ट का नाम डिफ़ॉल्ट रूप से डायरेक्टरी का नाम होता है, इसलिए डायरेक्टरी का नाम बदलने पर stack नए और खाली वॉल्यूम्स के सेट का उपयोग करने लगता है और पुराने वॉल्यूम्स आपके डेटा के साथ वहीं रह जाते हैं। नीचे दिए गए प्रत्येक कमांड के लिए docker volume ls से प्राप्त वास्तविक नाम की आवश्यकता होती है।

Bind mounts इन दोनों सूचियों में दिखाई नहीं देते हैं। Compose फाइल में ये वे प्रविष्टियाँ हैं जिनमें कोलन के बाईं ओर host path होता है, जैसे ./config:/app/config। ये host पर सामान्य डायरेक्टरी होती हैं, इसलिए सामान्य टूल्स उन तक पहुँच सकते हैं। Named volumes /var/lib/docker/volumes/ के अंतर्गत रहते हैं, और docker volume inspect --format '{{.Mountpoint}}' myapp_db_data किसी एक का सटीक path प्रिंट करता है। आपका stack किस प्रकार का उपयोग करता है, यह इस बात को बदल देता है कि आप इसे कैसे कॉपी करते हैं, और bind mounts बनाम named volumes इस अंतर को विस्तार से समझाता है।

अब जो आपने पाया है उसे दो समूहों में विभाजित करें। कुछ वॉल्यूम्स में ऐसा state होता है जिसे दोबारा नहीं बनाया जा सकता: अपलोड की गई फाइलें, जनरेट की गई keys, स्वयं डेटाबेस, और वह सब कुछ जो किसी उपयोगकर्ता ने ऐप में टाइप किया है। अन्य वॉल्यूम्स में derived डेटा होता है जैसे कि थंबनेल और सर्च इंडेक्स, जिन्हें ऐप स्वयं दोबारा बना सकता है। दूसरे समूह का बैकअप लेने से डिस्क स्पेस और रिस्टोर करने का समय खर्च होता है, लेकिन इसका कोई लाभ नहीं मिलता। एक Redis cache वॉल्यूम इसका सबसे स्पष्ट उदाहरण है: इसे खोने का मतलब केवल एक धीमी पहली रिक्वेस्ट है।

Compose file और .env file का बैकअप लें

ये दोनों फाइलें host पर एक-दूसरे के बगल में स्थित होती हैं, और इनमें से कोई भी किसी volume के अंदर नहीं होती है। .env में database password, application secret और कोई भी API tokens होते हैं, इसलिए यही वह फाइल है जो volumes के ढेर को वापस एक कार्यशील app में बदल देती है। यह आमतौर पर .gitignore में भी listed होती है, जिसका अर्थ है कि "मेरा configuration git में है" वाली योजना उस एकमात्र फाइल को छोड़ देती है जो सबसे अधिक मायने रखती है। Secrets को env file में रखना सही तरीका है, और यह आपके बैकअप पर एक समान जिम्मेदारी डालता है।

sudo install -d -m 700 -o "$USER" -g "$(id -gn)" /srv/backups/myapp
cp -a compose.yaml .env /srv/backups/myapp/
chmod 600 /srv/backups/myapp/.env

stack द्वारा उपयोग की जाने वाली हर compose file को कॉपी करें, न कि केवल पहली वाली को। -f compose.yaml -f compose.prod.yaml के साथ शुरू किए गए stack को वापस उसी तरह लाने के लिए दोनों फाइलों की आवश्यकता होती है, और multiple compose files कैसे merge होती हैं यह तय करता है कि कौन से values वास्तव में container तक पहुँचते हैं।

एक चेतावनी .env को volumes से जोड़ती है। आधिकारिक Postgres image POSTGRES_PASSWORD को केवल तभी पढ़ती है जब वह एक खाली data directory को initialize करती है। उस value को बाद में बदलने से database के अंदर का password नहीं बदलता है। पिछले महीने के volume को आज की .env के बगल में restore करें और app FATAL: password authentication failed for user "appuser" के साथ connect होने में विफल हो जाएगी, जबकि निरीक्षण करने पर दोनों फाइलें सही दिखेंगी। .env और volumes को एक ही समय के बैकअप में एक साथ रखें।

अपने स्वयं के क्लाइंट के साथ डेटाबेस का डंप लें

एक डेटाबेस सर्वर लगातार अपनी फाइलों में लिखता रहता है। सर्वर के चलते समय ली गई tar की /var/lib/postgresql/data कुछ पेजों को लिखने से पहले और कुछ को बाद में कॉपी करती है, इसलिए आर्काइव में ऐसे क्षणों का मिश्रण होता है जिन्हें शायद दोबारा नहीं चलाया जा सकता। एक डंप टूल एक ही ट्रांजेक्शन के भीतर डेटा पढ़ता है, इसलिए फाइल एक सुसंगत क्षण को दर्शाती है। यही अंतर बैकअप और कॉपी को अलग करता है।

docker compose exec -T db sh -c \
  'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' \
  > /srv/backups/myapp/db-$(date +%F).dump

-T को बनाए रखें। यह TTY एलोकेशन को बंद कर देता है, और TTY अटैच होने पर Docker आउटपुट स्ट्रीम को आपके शेल तक पहुँचने के दौरान ट्रांसलेट करता है, जो बाइनरी डंप को दूषित कर देता है। आपको इसके बारे में तब तक पता नहीं चलेगा जब तक कि रिस्टोर विफल न हो जाए। सिंगल कोट्स भी महत्वपूर्ण हैं: वे आपके होस्ट शेल को $POSTGRES_USER को एक्सपैंड करने से रोकते हैं, ताकि कंटेनर के अंदर का शेल इसे एक्सपैंड करे, और उन वैल्यूज का उपयोग करे जिन्हें compose फाइल पहले से ही वहां सेट करती है। -Fc कस्टम फॉर्मेट में लिखता है, जो चलते समय कंप्रेस होता है और बाद में pg_restore को इसमें से ऑब्जेक्ट्स चुनने की अनुमति देता है।

रोल्स और उनके पासवर्ड किसी एक डेटाबेस के बाहर रहते हैं, इसलिए उन्हें भी लें:

docker compose exec -T db sh -c 'pg_dumpall -U "$POSTGRES_USER" --globals-only' \
  > /srv/backups/myapp/globals.sql

फिर जांचें कि फाइल एक डंप है न कि कोई एरर मैसेज:

ls -lh /srv/backups/myapp/
head -c 5 /srv/backups/myapp/db-$(date +%F).dump

एक कस्टम-फॉर्मेट डंप पांच बाइट्स PGDMP से शुरू होता है। शून्य बाइट्स की फाइल, या pg_dump: से शुरू होने वाली फाइल का मतलब है कि कमांड विफल हो गई। शेल कमांड चलने से पहले आउटपुट फाइल बनाता है, इसलिए एक विफल डंप भी एक प्रशंसनीय नाम और टाइमस्टैम्प के साथ फाइल छोड़ देता है। यह सबसे आम साइलेंट बैकअप विफलता है।

MariaDB या MySQL के लिए क्लाइंट बदल जाता है लेकिन तरीका वही रहता है:

docker compose exec -T db sh -c \
  'mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" --single-transaction --databases "$MARIADB_DATABASE"' \
  > /srv/backups/myapp/db-$(date +%F).sql

--single-transaction राइटर्स को ब्लॉक किए बिना InnoDB टेबल्स का एक सुसंगत डंप देता है। MySQL इमेज पर कमांड mysqldump है और वेरिएबल्स MYSQL_ROOT_PASSWORD और MYSQL_DATABASE हैं। वर्तमान MariaDB इमेज पर mysqldump अभी भी mariadb-dump के लिए एक कम्पैटिबिलिटी नाम के रूप में काम करता है। ध्यान दें कि कमांड लाइन पर दिया गया पासवर्ड कंटेनर की प्रोसेस लिस्ट में तब तक दिखाई देता है जब तक डंप चलता है।

SQLite को विशेष देखभाल की आवश्यकता होती है। डेटाबेस एक फाइल है, लेकिन हालिया ट्रांजेक्शन अभी भी इसके बगल में एक अलग -wal फाइल में हो सकते हैं, इसलिए केवल .db को कॉपी करने से आपको ऐसा डेटाबेस मिलेगा जिसमें नवीनतम राइट्स गायब होंगे। यदि इमेज में क्लाइंट मौजूद है, तो sqlite3 /data/app.db ".backup '/data/app-backup.db'" ऐप के चलते समय एक सुसंगत कॉपी लिखता है। यदि यह मौजूद नहीं है, तो कंटेनर को रोकें और .db फाइल को उसके -wal और -shm साथियों के साथ कॉपी करें।

यदि आपका डेटाबेस स्टैक के अंदर के बजाय होस्ट पर चलता है, तो वही कमांड docker compose exec प्रीफिक्स के बिना लागू होते हैं, और Docker में या होस्ट पर डेटाबेस चलाना आपके अगले रीबिल्ड से पहले पढ़ने योग्य है।

Volumes को कैप्चर करें

Named volume का कोई host path नहीं होता जिसे आप मैन्युअल रूप से edit कर सकें, इसलिए इसे एक अस्थायी container में mount करें और वहाँ से archive करें।

docker run --rm \
  -v myapp_uploads:/data:ro \
  -v /srv/backups/myapp:/backup \
  alpine:3 tar czf /backup/uploads.tar.gz -C /data .

Helper container volume को /data पर read-only मोड में और आपके backup directory को /backup पर mount करता है, फिर archive को host side पर लिखता है। --rm जैसे ही tar समाप्त होता है, helper को हटा देता है। :ro महत्वपूर्ण है, क्योंकि गलत टाइप की गई tar command source को नुकसान नहीं पहुँचा सकती। -C /data . वह है जो restore को सही जगह पर सुनिश्चित करता है: यह हर path को volume root के सापेक्ष (relative) स्टोर करता है। यदि आप tar czf /backup/uploads.tar.gz /data लिखते हैं, तो हर path में एक leading data/ जुड़ जाता है, जिससे restore volume के अंदर /data/data बना देता है और app को एक खाली directory दिखाई देती है। Archive root का होता है, क्योंकि container के अंदर tar root के रूप में चला था। यदि यह आपके काम में बाधा डालता है तो sudo chown "$USER" /srv/backups/myapp/uploads.tar.gz चलाएँ, और यदि restored files app के लिए unreadable हो जाती हैं तो PUID और PGID फाइल ओनरशिप कैसे तय करते हैं पढ़ें।

इसे प्रत्येक named volume के लिए एक बार चलाएँ। Bind mounts के लिए किसी container की आवश्यकता नहीं है: tar czf /srv/backups/myapp/config.tar.gz -C /srv/myapp/config . host पर वही काम करता है।

प्रत्येक volume के लिए तय करें कि app को रोकना है या नहीं। जिस volume को app लगातार rewrite कर रही हो, उसका live tar फाइल लिखते समय बीच में ही capture हो सकता है। Uploads directory के लिए, जहाँ फाइलें एक बार लिखी जाती हैं और फिर केवल पढ़ी जाती हैं, यह जोखिम कम है। अन्य किसी भी चीज़ के लिए, उस service को copy की अवधि के लिए docker compose stop app के साथ रोकें, फिर docker compose start app करें। stop containers और volumes को अपनी जगह पर छोड़ देता है, जो कि आप यहाँ चाहते हैं, और docker compose stop app या docker compose start app टाइप करने से पहले down और stop के बीच का अंतर समझना उचित है।

Database volume के tar को अपना database backup न मानें। Dump ही असली backup है। एक रुके हुए database का volume archive केवल एक उपयोगी और तेज़ rebuild का रास्ता है, इससे अधिक कुछ नहीं।

ऑपरेशन्स का क्रम

  1. compose files और .env को बैकअप डायरेक्टरी में कॉपी करें।
  2. डेटाबेस के चलते रहने के दौरान ही उसका डंप (dump) लें।
  3. यदि app container के volumes में बदलाव होता है, तो उसे रोक दें।
  4. प्रत्येक named volume और bind-mount डायरेक्टरी को आर्काइव करें।
  5. जिसे आपने रोका था उसे शुरू करें, फिर docker compose ps के साथ पुष्टि करें।
  6. stack जिन image tags और digests का उपयोग कर रहा है, उन्हें नोट कर लें।
  7. पूरी बैकअप डायरेक्टरी को इस सर्वर से बाहर कॉपी करें।

स्टेप 7 वह है जिसे लोग बाद के लिए छोड़ देते हैं।

सर्वर से बैकअप बाहर निकालें

उसी डिस्क पर बैकअप रखना जिस पर आपका stack मौजूद है, केवल आपकी अपनी गलतियों से सुरक्षा देता है, अन्य किसी चीज़ से नहीं। एक विफल वॉल्यूम, एक डिलीट किया गया सर्वर या एक खोया हुआ अकाउंट दोनों प्रतियों को एक साथ नष्ट कर देता है। डायरेक्टरी को किसी ऐसे स्टोरेज पर भेजें जो यह VPS नहीं है, इसे एक शेड्यूल के साथ करें और एक retention policy लागू करें। VPS से restic बैकअप में रिपॉजिटरी सेटअप, retention flags और check कमांड शामिल हैं, इसलिए यहाँ उन्हें दोहराने की आवश्यकता नहीं है।

restic सीधे पाइप से भी डंप पढ़ सकता है, जिससे plaintext डेटाबेस डिस्क पर बिल्कुल नहीं रहता:

docker compose exec -T db sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' \
  | restic backup --stdin --stdin-filename db.dump

आप चाहे जो भी टूल उपयोग करें, शेड्यूल को systemd timer या cron job में डालें, और जॉब को ऐसी जगह रिपोर्ट करने के लिए सेट करें जहाँ आप उसे देख सकें। एक बैकअप स्क्रिप्ट जिसका आउटपुट कहीं नहीं जाता, वह ऐसी बैकअप स्क्रिप्ट है जो छह महीने तक काम करना बंद कर सकती है और किसी को पता भी नहीं चलेगा।

Restore drill के साथ backup की पुष्टि करें

जिस backup को कभी restore करके नहीं देखा गया, वह केवल एक परिकल्पना है। नीचे दिया गया drill पहले stack के साथ-साथ एक दूसरे stack में restore करता है, ताकि production service चलती रहे और आपके द्वारा टाइप की गई कोई भी कमांड उसे प्रभावित न करे।

इसका मुख्य आधार project का नाम है। Docker Compose इसे directory के नाम से लेता है और अपने द्वारा बनाए गए हर container और volume पर लगा देता है। backup को एक नई directory में copy करें, और restored stack को अपने स्वयं के volumes अपने आप मिल जाएंगे।

sudo install -d -m 700 -o "$USER" -g "$(id -gn)" /srv/myapp-restore
cd /srv/myapp-restore
cp /srv/backups/myapp/compose.yaml /srv/backups/myapp/.env .

copy की गई compose file को edit करें ताकि published host port, चल रहे stack के साथ न टकराए। 18080:8080 के स्थान पर 8080:8080 का उपयोग करें, या copy की गई .env में उस variable को बदलें जो इसे सेट करता है। फिर बिना कुछ start किए containers और उनके खाली volumes बनाएँ:

docker compose create
docker volume ls --filter label=com.docker.compose.project=myapp-restore

दूसरी कमांड को production के समान ही volume names दिखाने चाहिए, जिनके आगे myapp-restore_ लगा हो। उन्हें भरें, database को अलग से start करें, और dump load करें:

docker run --rm -v myapp-restore_uploads:/data -v /srv/backups/myapp:/backup \
  alpine:3 tar xzf /backup/uploads.tar.gz -C /data
docker compose up -d db
docker compose exec -T db sh -c \
  'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists' \
  < /srv/backups/myapp/db-2026-08-16.dump

--clean --if-exists प्रत्येक object को फिर से बनाने से पहले उसे हटा देता है, जिससे restore प्रक्रिया को बार-बार दोहराया जा सकता है। इसके बिना, यदि database में पहले से ही वे tables मौजूद हों, तो दूसरी बार चलाने पर प्रक्रिया pg_restore: error: could not execute query: ERROR: relation "users" already exists के साथ रुक जाएगी।

फिर बाकी services को start करें और उन्हें उस तरह से जाँचें जैसे एक user करेगा:

docker compose up -d --wait
docker compose exec -T db sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt"'
docker compose logs --tail=50

docker compose up -d --wait तब तक इंतज़ार करता है जब तक कि हर service 'running' या 'healthy' न हो जाए। यदि कोई service ऐसा नहीं कर पाती, तो यह non-zero exit code देता है, जिससे इस चरण को scriptable बनाया जा सकता है। जब कोई service healthy नहीं होती, तो docker compose ps उसकी स्थिति दिखाता है, और Compose healthchecks बताता है कि वह column क्या दर्शा रहा है। इसके बाद, alternate port पर app खोलें और एक वास्तविक account से login करें। एक record लिखें और एक ऐसी file खोलें जो volume में मौजूद हो। यह जोड़ी ही प्रमाण है: dump restore हो गया, volume restore हो गया, और दोनों एक-दूसरे के साथ मेल खाते हैं। जो drill केवल यह साबित करती है कि login page खुल रहा है, वह आपके data के बारे में कुछ भी साबित नहीं करती।

सफल होने के बाद drill को हटा दें:

docker compose down -v

यह एकमात्र ऐसी जगह है जहाँ -v सही flag है। production directory में यही कमांड उन volumes को delete कर देगी जिन्हें आप सुरक्षित रखना चाहते हैं।

Compose stack को अपग्रेड कैसे करें

जिस वर्ज़न को आप चला रहे हैं और जिस वर्ज़न पर आप जाना चाहते हैं, उनके बीच के हर वर्ज़न के release notes पढ़ें। उनमें breaking और migration शब्द खोजें। जो प्रोजेक्ट्स कई major versions को छोड़कर सीधे अपग्रेड करने का समर्थन नहीं करते, वे इसका उल्लेख वहीं करते हैं। यदि कोई migration फेल हो जाता है, तो वह आपको तभी सूचित करेगा जब वह schema का कुछ हिस्सा पहले ही बदल चुका होगा।

कुछ भी बदलने से पहले, रिकॉर्ड करें कि आप अभी क्या चला रहे हैं:

docker compose images
docker image inspect --format '{{index .RepoDigests 0}}' postgres:16.4

docker compose images यह सूचीबद्ध करता है कि प्रत्येक service अभी कौन सी image और tag का उपयोग कर रही है। digest ही एकमात्र ऐसा मान है जो किसी image की सटीक पहचान करता है, क्योंकि tag को किसी भी समय कहीं और पॉइंट करने के लिए बदला जा सकता है।

ऊपर दिए गए sections से backup लें और उसे सर्वर से बाहर कहीं कॉपी करें। patch release के लिए भी ऐसा ही करें। सबसे सस्ते अपग्रेड वे होते हैं जिनके लिए लोग तैयारी करना बंद कर देते हैं।

इसके बाद, compose file में वर्ज़न को pin करें, क्योंकि latest कोई वर्ज़न नहीं है:

services:
  db:
    image: postgres:16.4

image: postgres:latest के साथ, docker compose pull आज उस tag पर जो भी उपलब्ध है उसे fetch कर लेता है, और आपके पास यह बताने का कोई तरीका नहीं होता कि आप कल क्या चला रहे थे। एक pinned tag अपग्रेड को एक ऐसी एक-लाइन की edit बना देता है जिसे आप git diff में पढ़ सकते हैं और एक और edit के साथ वापस पहले जैसा कर सकते हैं। application image को भी इसी तरह pin करें, और प्रोजेक्ट के release page से सटीक वर्ज़न लें।

Pull करें और recreate करें:

docker compose pull
docker compose up -d --wait

docker compose up -d फाइल की तुलना चल रहे containers से करता है और केवल उन्हीं services को recreate करता है जिनकी image या configuration बदल गई है। यह named volumes को नहीं छूता, इसलिए नया container मौजूदा डेटा पर ही शुरू होता है। यही इस प्रक्रिया का उद्देश्य है और यही जोखिम भी, क्योंकि नए वर्ज़न का पहला start आमतौर पर तब होता है जब उसका schema migration चलता है।

इसे होते हुए देखें:

docker compose ps
docker compose logs -f --tail=100 app

जो container फेल हो जाता है वह docker compose ps के STATUS कॉलम में Exited (1) दिखाता है, और इसका कारण उसके log की अंतिम पंक्तियों में होता है। migration errors वहाँ स्पष्ट दिखते हैं और बाकी कहीं नहीं। जब logs स्थिर हो जाएं, तो login करें और एक मिनट के लिए app का उपयोग करें।

यदि docker compose pull, no space left on device के साथ रुक जाता है, तो इसका सामान्य कारण पुरानी image layers होती हैं, और unused Docker images को prune करना जगह वापस पाने में मदद करता है। pruning अपग्रेड के सफल होने के बाद करें, पहले नहीं, क्योंकि वे पुरानी layers ही होती हैं जिन पर एक तेज़ rollback निर्भर करता है।

अपग्रेड विफल होने पर रोलबैक कैसे करें

दो स्थितियाँ होती हैं और दोनों की लागत बहुत अलग होती है। यदि नए संस्करण ने schema में कोई बदलाव नहीं किया है, तो रोलबैक केवल एक लाइन का काम है: compose file में पुराना tag वापस डालें और docker compose up -d चलाएँ। कंटेनर बदल दिया जाता है, volumes अपनी जगह पर रहते हैं, और पुराना कोड वही डेटा पढ़ता है जिसे उसने पहले लिखा था।

यदि नए संस्करण ने schema को migrate कर दिया है, तो पुराना कोड उसे पढ़ नहीं पाएगा। Migrations को आगे बढ़ने के लिए लिखा जाता है, और अधिकांश projects में कोई downgrade script नहीं होती है। इसलिए, पुराना संस्करण start तो हो जाता है, लेकिन किसी ऐसे column पर पहली query चलते ही विफल हो जाता है जिसे rename या drop कर दिया गया है, और ERROR: column "avatar_url" does not exist जैसे error मिलते हैं। वापस जाने का एकमात्र तरीका वह dump है जो आपने pull करने से पहले लिया था: पुराना tag वापस लगाएँ, database volume को हटाएँ, उसे खाली recreate करें, उसमें dump restore करें, और start करें। उस dump के बिना वापस जाने का कोई रास्ता नहीं है, यही कारण है कि pull करने से पहले backup लेना अनिवार्य है।

Postgres के major versions इसमें सबसे अधिक जोखिम पैदा करते हैं, और ये लोगों को इसलिए हैरान करते हैं क्योंकि विफलता रोलबैक के बजाय अपग्रेड के समय ही सामने आ जाती है। हर major release के साथ on-disk format बदल जाता है। postgres:16.4 को postgres:17.2 में बदलें, docker compose up -d चलाएँ, और नया सर्वर start होने से मना कर देगा:

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.2.

इमेज आपके लिए pg_upgrade नहीं चलाती है। Compose stack के भीतर समर्थित तरीका यह है: dump, replace, restore। पुराने संस्करण के चलते हुए dump लें, docker compose down चलाएँ, database volume को हटाएँ, नया tag सेट करें, एक नई खाली data directory के लिए docker compose create चलाएँ, database start करें, dump restore करें, और बाकी services शुरू करें। पुराने dump को तब तक सुरक्षित रखें जब तक कि नया major version एक दिन तक वास्तविक traffic न संभाल ले। एक ही major version के भीतर minor upgrades, जैसे 16.4 से 16.9, के लिए इसकी आवश्यकता नहीं होती है, क्योंकि उनके बीच format स्थिर रहता है और कंटेनर सीधे start हो जाता है।

क्या VPS snapshots बैकअप होते हैं?

ये बैकअप के पूरक (complement) हैं, और दोनों अलग-अलग स्थितियों में विफल होते हैं। Snapshot हाइपरवाइजर स्तर पर पूरी डिस्क की कॉपी बनाता है, इसलिए यह पूरी मशीन को कुछ ही मिनटों में वापस ले आता है, जिसमें वे हिस्से भी शामिल हैं जिन्हें आप बैकअप लेना भूल गए थे। यह इसे एक विशिष्ट कार्य के लिए सही उपकरण बनाता है: यदि किसी अपग्रेड ने सर्वर को खराब कर दिया है और आप उसे 20 मिनट पहले वाली स्थिति में वापस लाना चाहते हैं।

अन्य सभी कार्यों के लिए यह एक खराब उपकरण है। इसकी ग्रैन्युलैरिटी पूरी मशीन की होती है, इसलिए एक डिलीट की गई टेबल को रिकवर करने का मतलब है कि कहीं और पूरा सर्वर रिस्टोर करना और उसमें से टेबल को निकालना। रिटेंशन आमतौर पर कम समय के लिए होता है। ये कॉपियां सामान्यतः उसी प्रोवाइडर अकाउंट में रहती हैं जिसमें सर्वर है, इसलिए अकाउंट खोने पर सर्वर और उसके snapshots दोनों एक साथ चले जाते हैं। और चलती हुई मशीन का snapshot लेने पर डेटाबेस राइटिंग के बीच में ही कैप्चर हो जाता है, इसलिए पहली बार स्टार्ट होने पर डेटाबेस को crash recovery करनी पड़ती है और जो भी ट्रांजेक्शन प्रोसेस में था, वह चला जाता है।

दोनों का उपयोग करें। Snapshot अपग्रेड विंडो के लिए 'अंडू' बटन है। डंप वह कॉपी है जो अकाउंट डिलीट होने पर भी सुरक्षित रहती है। snapshots और बैकअप में अंतर यह बताता है कि प्रत्येक किस प्रकार की विफलता को कवर करता है। वही बैकअप डायरेक्टरी एक स्टैक को नए VPS पर ले जाने की प्रक्रिया को याददाश्त के आधार पर फिर से बनाने के बजाय एक नियमित कार्य बना देती है।

क्या गलत होता है और आप क्या देखेंगे

down पर volumes फ्लैग। docker compose down -v उन named volumes को हटा देता है जिन्हें फाइल घोषित करती है, और Compose इसकी पुष्टि Volume myapp_db_data Removed लिखी एक लाइन के साथ करता है। इसे वापस नहीं किया जा सकता। साधारण docker compose down उन्हें वैसा ही छोड़ देता है। लंबा फॉर्म, docker compose down --volumes टाइप करें, ताकि विनाशकारी फ्लैग एक ऐसा शब्द हो जिसे आपको पूरा लिखना पड़ा हो।

बिना मैजिक स्ट्रिंग वाला डंप। pg_restore: error: did not find magic string in file header का मतलब है कि फाइल एक आर्काइव नहीं है। इसका सामान्य कारण docker compose exec पर -T का न होना है, क्योंकि TTY अटैच होने पर स्ट्रीम आपके शेल तक पहुँचने के दौरान ट्रांसलेट हो जाती है और बाइनरी डंप क्षतिग्रस्त होकर पहुँचता है। -T के साथ डंप दोबारा लें, फिर head -c 5 के साथ पहले पाँच बाइट्स की जाँच करें।

एक पासवर्ड जो बदलेगा नहीं। रिस्टोर के बाद FATAL: password authentication failed for user "appuser" का मतलब है कि .env और डेटा डायरेक्टरी अलग-अलग समय के हैं। इमेज वह पासवर्ड तभी सेट करती है जब वह एक खाली डेटा डायरेक्टरी बनाती है, इसलिए बाद में .env को एडिट करने से डेटाबेस के अंदर कुछ भी नहीं बदलता। मेल खाने वाला .env रिस्टोर करें, या डेटाबेस के अंदर ALTER USER के साथ पासवर्ड बदलें।

एक दूसरा, खाली वॉल्यूम। Docker मांग पर एक वॉल्यूम बनाता है, इसलिए s के गायब होने पर docker run -v myapp_upload:/data एक बिल्कुल नए खाली वॉल्यूम में लिखता है और सफलता की रिपोर्ट देता है। docker volume ls तब दोनों नाम दिखाता है, जिनमें से एक में कुछ भी नहीं होता। याददाश्त से टाइप करने के बजाय docker volume ls से वॉल्यूम के नाम कॉपी करें।

प्रोडक्शन पर लक्षित रिस्टोर। /srv/myapp-restore के बजाय /srv/myapp में रिस्टोर कमांड चलाने से लाइव डेटा बैकअप के साथ ओवरराइट हो जाता है, और कमांड दोनों जगहों पर एक जैसे दिखते हैं। हर रिस्टोर कमांड से पहले pwd की जाँच करें, और ड्रिल को उसकी अपनी डायरेक्टरी में रखें।

FAQ

क्या docker compose down मेरा डेटा डिलीट करता है?

नहीं। docker compose down केवल containers और default network को हटाता है, यह named volumes और bind mounts को सुरक्षित रखता है। docker compose down -v उन named volumes को हटा देता है जिन्हें आपकी file में घोषित किया गया है, और वह प्रक्रिया स्थायी होती है। Bind mounts होस्ट डायरेक्टरी होती हैं, इसलिए Compose उन्हें कभी नहीं हटाता। यदि आप बैकअप के दौरान services को रोकना चाहते हैं और बाकी सब कुछ वैसा ही रखना चाहते हैं, तो इसके बजाय docker compose stop का उपयोग करें।

क्या मैं pg_dump चलाने के बजाय Postgres डेटा डायरेक्टरी को कॉपी कर सकता हूँ?

केवल container को रोककर ही ऐसा करें। जब सर्वर चल रहा होता है, तो उसकी फाइलें लगातार बदलती रहती हैं और कॉपी में अलग-अलग समय के डेटा का मिश्रण हो सकता है जो सही ढंग से रीप्ले नहीं होगा। फाइल-लेवल कॉपी एक विशिष्ट Postgres मेजर वर्जन से जुड़ी होती है, इसलिए यह किसी अन्य वर्जन पर स्टार्ट नहीं होगी। Container को रोकें, वॉल्यूम को आर्काइव करें, फिर से स्टार्ट करें, और इस परिणाम को केवल एक तेज़ रीबिल्ड विकल्प मानें, न कि अपना एकमात्र बैकअप। डंप ही पोर्टेबल कॉपी है, और उसी से आप डेटा रिस्टोर करते हैं।

मैं Compose में Postgres को नए मेजर वर्जन पर कैसे अपग्रेड करूँ?

केवल टैग बदलना पर्याप्त नहीं है। नया सर्वर पुरानी डेटा डायरेक्टरी पर स्टार्ट होने से मना कर देगा और The data directory was initialized by PostgreSQL version 16, which is not compatible with this version 17.2 लॉग करेगा। पुराने वर्जन के चलते रहने के दौरान pg_dump चलाएं, फिर docker compose down करें, डेटाबेस वॉल्यूम को हटा दें, नया टैग सेट करें, एक नए खाली वॉल्यूम के लिए docker compose create चलाएं, डेटाबेस स्टार्ट करें, और उसमें डंप रिस्टोर करें। पुराने डंप को तब तक सुरक्षित रखें जब तक नया वर्जन वास्तविक ट्रैफिक को सफलतापूर्वक हैंडल न कर ले।

बैकअप कितनी बार लेना चाहिए और उन्हें कितने समय तक रखना चाहिए?

बैकअप का अंतराल इस आधार पर तय करें कि आप कितना काम दोबारा करने के लिए तैयार हैं। व्यक्तिगत या छोटी टीम के स्टैक के लिए रात में बैकअप लेना उचित है, साथ ही किसी भी अपग्रेड से ठीक पहले एक अतिरिक्त मैनुअल बैकअप लें। रिटेंशन के लिए, इतना पुराना इतिहास रखें कि आप उन नुकसानों की भरपाई कर सकें जो तुरंत ध्यान में नहीं आए, क्योंकि शुक्रवार को मिली करप्ट टेबल को गुरुवार रात की कॉपी से ठीक नहीं किया जा सकता। restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune एक उचित शुरुआती नीति है। शेड्यूल चाहे जो भी हो, हर तिमाही में एक बार रिस्टोर करके देखें। जब तक आप ऐसा नहीं करते, आपके पास बैकअप नहीं, केवल फाइलें हैं।

क्या बैकअप लेने के लिए मुझे पूरा स्टैक रोकना होगा?

आमतौर पर नहीं। सर्वर के चलते रहने के दौरान भी डेटाबेस डंप कंसिस्टेंट रहता है, इसलिए डेटाबेस के लिए डाउनटाइम की आवश्यकता नहीं होती। मुख्य सवाल वॉल्यूम का है। यदि ऐप केवल फाइलें जोड़ता है, जैसे कि uploads डायरेक्टरी, तो लाइव आर्काइव सुरक्षित है। यदि यह फाइलों को वहीं ओवरराइट करता है, तो कॉपी की अवधि के लिए उस एक सर्विस को docker compose stop app के साथ रोकें और बाद में उसे फिर से स्टार्ट करें। डेटाबेस को चलते रहने देते हुए केवल ऐप को रोकना आमतौर पर सबसे छोटा सुरक्षित विंडो होता है जिसे आप व्यवस्थित कर सकते हैं।