VPS पर Docker चलाने के मुख्य अंतर और सावधानियां
VPS पर Docker चलाते समय RAM की कमी, UFW bypass, reboot के बाद containers का बंद होना और disk full होने जैसी समस्याओं का सामना कैसे करें? इन चार चुनौतियों का समाधान यहाँ जानें।
VPS पर Docker चलाने पर क्या बदलता है
VPS पर Docker वही engine और वही images चलाता है जो आपके laptop पर चलती हैं, इसलिए आप जो भी commands जानते हैं, वे यहाँ भी काम करती हैं। जो बदलता है, वह इसके आसपास का वातावरण है। Laptop में अतिरिक्त memory होती है, एक ऐसा firewall होता है जिसे कोई scan नहीं कर रहा होता, और disk इतनी बड़ी होती है कि आपको उसे देखने की जरूरत नहीं पड़ती। किराए के server में memory की एक निश्चित सीमा होती है, एक public IP address होता है जिसे boot होने के कुछ ही मिनटों के भीतर scan किया जाने लगता है, और एक root filesystem होता है जिसे Docker बिना पूछे भर देगा।
चार अंतर एक छोटे server पर अधिकांश समस्याओं का कारण बनते हैं:
- Memory सीमित होती है, और kernel कमी होने पर किसी process को kill करके उसे हल करता है।
- एक published port सीधे UFW (uncomplicated firewall) से होकर गुजरता है, क्योंकि Docker अपने स्वयं के firewall rules लिखता है।
- Containers reboot के बाद वापस नहीं आते, जब तक कि आपने पहले से ऐसा न कहा हो।
- Images, containers, volumes और build cache तब तक बढ़ते रहते हैं जब तक disk भर न जाए।
नीचे दिया गया प्रत्येक section विफलता का नाम, वह string जो आपको वास्तव में दिखाई देगी, और उसे गहराई से ठीक करने वाली मार्गदर्शिका बताता है। यदि आपने अभी तक compose file नहीं लिखी है, तो पहले VPS पर Docker Compose की बुनियादी बातें पढ़ें और फिर वापस आएं। यह पृष्ठ मानता है कि आप पहले से ही एक stack को run करना जानते हैं।
Docker container कितनी RAM का उपयोग करता है?
जितना ज्यादातर लोग सोचते हैं, उससे कहीं कम। Container एक cgroup (control group) में चलने वाली एक process है, न कि virtual machine, इसलिए इसमें कोई guest kernel और न ही कोई निश्चित allocation होता है। इसकी लागत उतनी ही होती है जितनी process के भीतर की चीजें उपयोग करती हैं। यही कारण है कि एक पूरा stack 2 GB में समा जाता है, जबकि virtual machines से बना वही stack इतनी RAM में नहीं चल पाता।
नीचे दिए गए आंकड़े Ubuntu 24.04 पर default configuration के साथ stock images के लिए सामान्य idle numbers हैं, जिन्हें शुरू होने के कुछ मिनट बाद docker stats से पढ़ा गया है। ये योजना बनाने के लिए एक शुरुआती बिंदु हैं, न कि आपके workload का कोई benchmark। किसी भी आंकड़े पर भरोसा करने से पहले, जिसमें ये भी शामिल हैं, अपने सिस्टम पर docker stats --no-stream चलाकर देखें।
The data behind this chart
[
{
"label": "nginx",
"idle_mb": 8,
"budget_mb": 64
},
{
"label": "Redis 7",
"idle_mb": 12,
"budget_mb": 128
},
{
"label": "Traefik v3",
"idle_mb": 40,
"budget_mb": 128
},
{
"label": "PostgreSQL 16",
"idle_mb": 45,
"budget_mb": 512
},
{
"label": "Uptime Kuma",
"idle_mb": 95,
"budget_mb": 256
},
{
"label": "MariaDB 11",
"idle_mb": 190,
"budget_mb": 512
},
{
"label": "Nextcloud (Apache)",
"idle_mb": 210,
"budget_mb": 768
}
]ये दो columns अलग-अलग काम करते हैं। idle_mb वह है जो container खाली रहने (idle) के दौरान उपयोग करता है। budget_mb वह है जिसे आपको योजना बनाते समय reserve करना चाहिए, क्योंकि वास्तविक उपयोग idle जैसा नहीं होता। PostgreSQL लगभग 45 MB पर idle रहता है और एक बार connections, sorts और cache के live हो जाने पर इसे 512 MB की आवश्यकता होती है। बजट column के साथ योजना बनाएँ। Idle column के साथ debug करें।
उन 7 rows के आकार पर ध्यान दें। nginx 8 MB पर और Nextcloud 210 MB पर idle रहता है। आपके applications के सामने लगा proxy लगभग मुफ्त है। database और PHP application ही वे चीजें हैं जिनके आधार पर आप box का size तय करते हैं।
docker stats के बारे में एक चेतावनी: memory के आंकड़े में वह page cache शामिल होता है जिसे container की अपनी file reads ने खींच लिया है, इसलिए यह शुरू होने के बाद कुछ समय तक बढ़ता है और फिर स्थिर हो जाता है। यह तय करने से पहले कि कुछ leak हो रहा है, इसे एक घंटे तक monitor करें।
VPS का आकार तय करना: 2 GB, 4 GB और 8 GB में क्या समा सकता है
सबसे पहले होस्ट का हिस्सा अलग निकालें। kernel, systemd, journald, sshd और Docker daemon उसी RAM का उपयोग करते हैं जिसमें आपके containers चलते हैं, और dockerd के साथ containerd इसमें से लगभग 100 MB घेर लेते हैं। आपको page cache के लिए और image build या database dump के दौरान आने वाले लोड स्पाइक्स के लिए भी खाली मेमोरी की आवश्यकता होती है।
The data behind this chart
[
{
"plan": "2 GB VPS",
"total_mb": 2048,
"host_reserve_mb": 768,
"container_mb": 1280
},
{
"plan": "4 GB VPS",
"total_mb": 4096,
"host_reserve_mb": 1024,
"container_mb": 3072
},
{
"plan": "8 GB VPS",
"total_mb": 8192,
"host_reserve_mb": 1536,
"container_mb": 6656
}
]host_reserve_mb ऑपरेटिंग सिस्टम, Docker daemon और उस अतिरिक्त क्षमता (headroom) को कवर करता है जो लोड के दौरान सर्वर को responsive रखती है। जो बचता है वह container_mb है, और यही वह एकमात्र संख्या है जिसे आप खर्च कर सकते हैं। यह रिज़र्व प्लान के साथ बढ़ता है, सबसे छोटे बॉक्स पर 768 MB से लेकर सबसे बड़े पर 1536 MB तक, क्योंकि एक बड़ा बॉक्स अधिक containers चलाता है, अधिक logs लिखता है और उसे अधिक page cache की आवश्यकता होती है।
2 GB का प्लान containers के लिए 1280 MB छोड़ता है। इसमें से 512 MB PostgreSQL पर और 128 MB Traefik पर खर्च करें, तो आधी मेमोरी पहले ही खत्म हो जाती है। बाकी बची मेमोरी में लगभग 256 MB के दो छोटे applications चलाए जा सकते हैं। यह एक वास्तविक और उपयोगी सर्वर है। इसमें Nextcloud और एक सर्च क्लस्टर दोनों को एक साथ चलाने की जगह नहीं है।
4 GB का प्लान 3072 MB छोड़ता है, जिसमें एक database, एक reverse proxy, तीन applications और एक monitoring container एक साथ समा सकते हैं। किसी भी महत्वपूर्ण काम के लिए यह सबसे छोटा उपयोगी आकार है, क्योंकि अतिरिक्त मेमोरी ही खराब deploy के प्रभाव को सोखती है।
8 GB का प्लान अपने 8192 MB में से 6656 MB खाली छोड़ता है, और ऐसी स्थिति में सीमा आमतौर पर मेमोरी से हटकर CPU या disk throughput पर आ जाती है। एक विशेष प्रकार के container का आकार लोड के बजाय उसके configuration से तय होता है: एक local model server अपने context window के अनुपात में KV cache रिज़र्व करता है, इसलिए Ollama के num_ctx को बढ़ाना एक भी request आने से पहले ही बजट में कई gigabytes जोड़ सकता है। यदि गणना यह बताती है कि आपका stack फिट नहीं हो रहा है, तो उसे ट्यून करने के बजाय बड़ा प्लान लें: एक VPS की वास्तविक लागत यह बताती है कि अतिरिक्त gigabytes का मासिक मूल्य क्या है।
दो नियम इस गणना को सटीक रखते हैं। हर service पर एक memory limit लगाएँ, ताकि कोई एक अनियंत्रित process पूरे सर्वर को क्रैश न कर सके। और बजट का ऊपरी हिस्सा खर्च न करें, क्योंकि docker compose build और pg_dump दोनों को सबसे खराब समय पर मेमोरी की आवश्यकता होती है। Docker Compose में memory limits में इसका syntax और सावधानियाँ दी गई हैं।
मेरा container exit code 137 के साथ क्यों बंद हो जाता है?
ऐसा इसलिए होता है क्योंकि kernel ने इसे बंद कर दिया है। 137 का मतलब 128 जमा 9 है, और signal 9 का अर्थ SIGKILL है। container ने अपनी निर्धारित सीमा से अधिक memory की मांग की, जिसके कारण out of memory (OOM) killer ने इसे समाप्त कर दिया।
CONTAINER ID IMAGE STATUS
9f2c1a4d7b3e postgres:16 Exited (137) 4 minutes agoअनुमान लगाने के बजाय कारण की पुष्टि करें:
docker inspect my-db | grep -i oomkilled
sudo journalctl -k | grep -i "out of memory""OOMKilled": true का अर्थ है कि container अपनी cgroup सीमा तक पहुँच गया है, और kernel log उस process का नाम बताता है जिसे उसने चुना है:
Memory cgroup out of memory: Killed process 2417 (postgres) total-vm:1284416kBयह एक बेहतर स्थिति है, क्योंकि नुकसान केवल एक container तक सीमित रहा। खराब स्थिति वह है जहाँ container पर कोई सीमा (limit) निर्धारित न हो। बिना किसी सीमा के, इसकी अधिकतम क्षमता पूरी machine के बराबर होती है, इसलिए एक service में memory leak होने पर पूरा host प्रभावित होता है, और kernel पूरे system में से किसी भी process को चुनकर उसे बंद कर देता है। ऐसी स्थिति में log line से Memory cgroup prefix हट जाता है और वह Out of memory: Killed process 2417 (postgres) दिखाई देता है। kernel अक्सर आपकी database process को चुन लेता है, जबकि leak करने वाला container चलता रहता है। यही कारण है कि किसी एक limit के सटीक मान से अधिक महत्वपूर्ण यह है कि हर service पर एक सीमा निर्धारित हो।
Swap समय को बदलता है, गणना को नहीं। अधिकांश VPS images बिना swap के आती हैं। swapon --show के साथ जाँच करें, जो swap न होने पर कुछ भी print नहीं करता है। एक swap file kernel को cold pages रखने के लिए जगह देती है, जिससे आपको समस्या पर ध्यान देने के लिए कुछ मिनट मिल जाते हैं।
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -hfree -h में अब Swap row में शून्य के अलावा कोई मान दिखना चाहिए। Swap RAM नहीं बढ़ाता है। लगातार memory दबाव में रहने वाला server इतना धीमा हो जाता है कि आप उसे ठीक करने के लिए SSH भी नहीं कर पाते, इसलिए swap को केवल एक alarm buffer के रूप में देखें और memory sizing को ठीक करें।
UFW मेरे पब्लिश किए गए Docker पोर्ट को ब्लॉक क्यों नहीं करता है?
क्योंकि ट्रैफिक कभी भी उस चेन तक नहीं पहुँचता है जिसे UFW सुरक्षित करता है। जब आप -p 5432:5432 या compose ports: एंट्री के साथ कोई पोर्ट पब्लिश करते हैं, तो daemon nat टेबल में एक DNAT (destination network address translation) नियम और अपनी स्वयं की DOCKER चेन में एक accept नियम लिख देता है। कंटेनर के लिए लक्षित पैकेट को होस्ट तक पहुँचाने के बजाय सीधे उस कंटेनर पर फॉरवर्ड कर दिया जाता है, इसलिए इसे FORWARD पाथ में हैंडल किया जाता है और यह कभी भी उन INPUT नियमों से नहीं गुजरता जिन्हें UFW लिखता है।
आप सर्वर पर इसे होते हुए देख सकते हैं:
sudo ufw status | grep 5432
sudo iptables -t nat -L DOCKER -n | grep 5432UFW 5432 DENY IN Anywhere दिखा सकता है जबकि nat टेबल में उसी पोर्ट के लिए एक DNAT tcp ... to:172.18.0.2:5432 नियम मौजूद होता है। किसी अन्य मशीन से, nc -vz your.server.ip 5432 अभी भी कनेक्ट हो जाता है। डेटाबेस सार्वजनिक इंटरनेट पर है और फायरवॉल कहता है कि यह नहीं है।
इसका समाधान यह है कि कम पोर्ट पब्लिश करें। एक compose प्रोजेक्ट के कंटेनर एक नेटवर्क साझा करते हैं और सर्विस नाम के जरिए एक-दूसरे तक पहुँचते हैं, इसलिए जिस डेटाबेस को केवल अपने बगल वाले एप्लिकेशन को सर्विस देनी है, उसे किसी ports: एंट्री की आवश्यकता नहीं है। जब आप स्थानीय एक्सेस चाहते हैं, तो पब्लिश को loopback पर बाइंड करें:
services:
db:
image: postgres:16
ports:
- "127.0.0.1:5432:5432"docker compose up -d के बाद, बाहर से nc -vz your.server.ip 5432 विफल हो जाता है, और बॉक्स पर psql -h 127.0.0.1 -p 5432 अभी भी काम करता है। एक स्वस्थ छोटे स्टैक में केवल रिवर्स प्रॉक्सी ही 80 और 443 पर कुछ पब्लिश करता है। Docker पब्लिश पोर्ट UFW को बायपास क्यों करते हैं उन मामलों के लिए DOCKER-USER चेन को कवर करता है जहाँ आपको पोर्ट पब्लिश करना है और फिर भी उसे फिल्टर करना है, और UFW फायरवॉल की बुनियादी बातें होस्ट नियमों को कवर करता है।
Reboot के बाद मेरे containers गायब क्यों हो जाते हैं?
क्योंकि उन्हें वापस आने का निर्देश नहीं दिया गया था। जब तक आप कोई restart policy सेट नहीं करते, तब तक container no के साथ बनाया जाता है, इसलिए reboot के बाद वह बंद ही रहता है और daemon उस पर ध्यान नहीं देता। VPS पर reboot दुर्लभ नहीं हैं: unattended upgrades से kernel updates, provider maintenance, और ऊपर वर्णित OOM sequence, ये सभी reboot का कारण बनते हैं।
दो चीजें सही होनी चाहिए। Daemon को boot के समय start होना चाहिए:
systemctl is-enabled dockerयह एक stock Ubuntu install पर enabled प्रिंट करता है। फिर प्रत्येक service के लिए एक policy की आवश्यकता होती है:
services:
app:
image: ghcr.io/example/app:1.4
restart: unless-stoppedunless-stopped reboot के बाद container को वापस लाता है और आपके द्वारा जानबूझकर रोके गए container का सम्मान करता है। always उन containers को भी restart कर देता है जिन्हें आपने जानबूझकर रोका था, जब भी daemon restart होता है, जो debugging के दौरान एक आश्चर्य हो सकता है। केवल file को edit करना पर्याप्त नहीं है, क्योंकि restart policy तब सेट होती है जब container बनाया जाता है। docker compose up -d चलाएं ताकि इसे फिर से बनाया जा सके, फिर live value की जाँच करें:
docker inspect my-app | grep -A3 RestartPolicyफिर box को जानबूझकर reboot करें और project directory में docker compose ps चलाएं। जो stack एक नियोजित reboot के बाद जीवित रहता है, वह अनियोजित reboot के बाद भी जीवित रहेगा। यदि आपके stack को boot के समय ordering guarantee या one-shot job की आवश्यकता है, तो systemd unit एक बेहतर tool है: boot पर Docker Compose शुरू करना में unit file दी गई है। यह जानने के लिए कि क्या वापस आया container वास्तव में सेवा दे रहा है, Compose healthchecks जोड़ें।
मेरा VPS डिस्क फुल क्यों है?
क्योंकि Docker तब तक सब कुछ रखता है जब तक आप उसे हटाने के लिए न कहें। आपके द्वारा पुल किया गया हर image tag, हर बंद पड़ा container, recreate के बाद छूटा हुआ हर anonymous volume, और build cache की हर लेयर डिस्क पर बनी रहती है। 40 GB या 80 GB के root filesystem पर, जो इन प्लान साइज़ में सामान्य है, यह कुछ वर्षों के बजाय कुछ महीनों में ही आउटेज का कारण बन जाता है।
डिस्क फुल होने पर सिस्टम क्रैश जैसा नहीं दिखता। आपको एक ही घंटे के भीतर container से no space left on device, apt से, journald से और docker pull से एरर मिलते हैं। PostgreSQL राइट्स लेना बंद कर देता है। सर्वर चालू रहता है, जिससे इसे रीबूट लूप की तुलना में पहचानना कठिन हो जाता है।
डिलीट करने से पहले जाँचें:
docker system df
df -h /docker system df कुल डेटा को images, containers, local volumes और build cache में विभाजित करता है, और प्रत्येक के बगल में RECLAIMABLE कॉलम दिखाता है। जिस सर्वर पर खुद images बिल्ड होती हैं, वहां build cache आमतौर पर सबसे बड़ी लाइन होती है।
docker image prune -a
docker builder prune
docker system dfdocker image prune -a उन सभी images को हटा देता है जिनका उपयोग कोई container नहीं कर रहा है। docker builder prune बिल्ड कैश को क्लियर करता है। दोनों ही कमांड्स सर्विसेज चलते समय सुरक्षित हैं, क्योंकि जो उपयोग में है उसे छोड़ दिया जाता है। जो सुरक्षित नहीं है वह है docker system prune --volumes, जो उन सभी volumes को हटा देता है जिन्हें अभी कोई container रेफर नहीं कर रहा है। वीकेंड के लिए रोकी गई स्टैक की स्थिति बिल्कुल ऐसी ही होती है, और उसका डेटाबेस वॉल्यूम भी इसके साथ डिलीट हो जाएगा। उस फ्लैग को टाइप करने से पहले bind mounts versus named volumes पढ़ें, और पहले बैकअप लें।
Container logs धीरे-धीरे डिस्क भरते हैं। डिफ़ॉल्ट json-file ड्राइवर की कोई साइज़ लिमिट नहीं होती, इसलिए एक अधिक डेटा लिखने वाला container /var/lib/docker/containers में गीगाबाइट डेटा भर देता है। इसे /etc/docker/daemon.json में हर container के लिए सीमित करें:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}इसे sudo systemctl restart docker के साथ लागू करें, जो आपके containers को रीस्टार्ट करता है, इसलिए सही समय चुनें। यह लिमिट बदलाव के बाद बनाए गए containers पर लागू होती है, इसलिए चल रहे containers को docker compose up -d --force-recreate के साथ recreate करें और पुष्टि करें:
docker inspect my-app | grep -A5 LogConfig
sudo du -sh /var/lib/docker/containersinspect आउटपुट में max-size सेट दिखना चाहिए। यदि यह खाली है, तो वह container बदलाव से पहले का है और अभी भी बिना किसी लिमिट के डेटा लिख रहा है।
एक छोटे Docker सर्वर को स्वस्थ रखने की आदतें
इसके लिए किसी डैशबोर्ड या किसी ऐसे टूल की आवश्यकता नहीं है जिसे आपको अलग से सीखना पड़े।
- महीने की पहली तारीख को
docker system dfऔरdf -h /चलाएं। केवल दो कमांड और तीस सेकंड का समय, और आप आउटेज होने से काफी पहले ही ट्रेंड को समझ पाएंगे। - हर सर्विस को एक मेमोरी लिमिट दें, उन सर्विसेज को भी जो आपको छोटी लगती हैं। यह लिमिट पूरे होस्ट के आउटेज को केवल एक कंटेनर के रीस्टार्ट तक सीमित कर देती है।
- सर्वर की निगरानी कहीं और से करें, ताकि कर्नल के कोई कदम उठाने से पहले ही आपको मेमोरी या डिस्क के दबाव के बारे में पता चल जाए। Uptime Kuma एक कंटेनर में चलता है और लगभग 95 MB पर आइडल रहता है।
- कंटेनर्स का नहीं, बल्कि वॉल्यूम्स का बैकअप लें। कंटेनर डिस्पोजेबल होते हैं, लेकिन वॉल्यूम नहीं। restic backups on a VPS में शेड्यूल और रिस्टोर टेस्ट की जानकारी दी गई है।
- compose फाइल में इमेज टैग्स को पिन करें और उन्हें अपनी पसंद के दिन अपडेट करें।
latestके बिना, अगलेdocker compose pullसे आपको वही वर्जन मिलेगा जो उस सुबह रिलीज हुआ हो।
Docker चलाने वाला एक छोटा VPS वर्षों तक स्वस्थ रहता है यदि चार संख्याएं सीमा में रहें: मेमोरी बजट, पब्लिश किए गए पोर्ट्स की सूची, प्रत्येक सर्विस पर रीस्टार्ट पॉलिसी, और खाली डिस्क। बाकी सब कुछ वही Docker है जिसे आप पहले से ही अपने घर पर चला रहे हैं।
FAQ
How much RAM do I need to run Docker on a VPS?
Docker itself is cheap. The daemon and containerd together sit near 100 MB, and the rest of the requirement is your containers. Budget the host's share first: 768 MB on a 2048 MB box for the operating system, the daemon and headroom, which leaves 1280 MB to spend. A database at 512 MB, a reverse proxy at 128 MB and two small applications fit inside that. Measure your own stack with docker stats --no-stream rather than trusting any published figure.
Can I run Docker on a 1 GB VPS?
Yes, for one or two light containers, and add a swap file before you start. Roughly half of a 1 GB box is gone once the operating system and the Docker daemon are running, which leaves room for a small application and a reverse proxy, but not for a database under real load. Building images on a box that size will fail or kill something else, so build elsewhere and pull the finished image.
Does UFW protect a Docker container?
Not for ports you publish. Docker writes its own DNAT and forward rules, so a packet aimed at a published container port is forwarded to the container instead of being delivered to the host, and the INPUT rules UFW manages never see it. ufw deny 5432 can be active while that port answers from the internet. Publish to loopback with 127.0.0.1:5432:5432, leave internal services unpublished, or filter in the DOCKER-USER chain.
Will my containers restart after a VPS reboot?
Only if they were created with a restart policy. Set restart: unless-stopped on each service, run docker compose up -d so the containers are recreated with it, and confirm systemctl is-enabled docker prints enabled. Then reboot on purpose and check docker compose ps. A restart policy you have never tested is not a restart policy.
How often should I prune Docker images?
Monthly is enough for most small servers, or whenever docker system df reports reclaimable space you would miss. docker image prune -a and docker builder prune are both safe while services run, because images and cache in use are skipped. Avoid docker system prune --volumes unless you know exactly which volumes are unreferenced, because it deletes the data of any stack that happens to be stopped.