VPS पर Docker चलाने से वास्तव में क्या बदलता है
VPS पर Docker में RAM जल्दी खत्म होती है, published ports UFW को bypass करते हैं, reboot के बाद containers बंद रहते हैं और disk भर सकती है।
VPS पर Docker चलाने पर क्या बदलता है
VPS पर Docker वही engine और वही images चलाता है जो आपके laptop पर Docker चलाता है, इसलिए आपके परिचित सभी 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 खुद लिखता है।
- Reboot के बाद containers अपने-आप वापस start नहीं होते, जब तक आपने पहले से इसकी configuration न की हो।
- Images, containers, volumes और build cache बढ़ते रहते हैं और अंततः disk भर जाती है।
नीचे दिए गए प्रत्येक section में उस failure का नाम, वह string जो आपको वास्तव में दिखाई देगी, और उसे विस्तार से ठीक करने वाला guide दिया गया है। यदि आपने अभी तक compose file नहीं लिखी है, तो पहले VPS पर Docker Compose की मूल बातें पढ़ें और फिर वापस आएँ। इस page में यह मानकर चला गया है कि आप पहले से stack को start कर सकते हैं।
Docker container कितनी RAM का उपयोग करता है?
अधिकांश लोगों की अपेक्षा से कम। Container एक cgroup (control group) के भीतर चलने वाली process है, virtual machine नहीं। इसलिए इसमें guest kernel या fixed allocation नहीं होती। लागत उतनी ही होती है जितना अंदर चल रही process memory को छूती है। इसी कारण 2 GB में पूरा stack चल सकता है, जबकि virtual machines से बनाया गया वही stack नहीं चल पाता।
नीचे दिए गए आंकड़े Ubuntu 24.04 पर default configuration वाली stock images के सामान्य idle आंकड़े हैं। इन्हें start होने के कुछ मिनट बाद docker stats से पढ़ा गया है। ये planning के लिए शुरुआती आंकड़े हैं, आपके workload का benchmark नहीं। किसी भी आंकड़े पर भरोसा करने से पहले, इन आंकड़ों सहित, अपने box पर 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 वह memory है जिसका container कोई काम न करते समय उपयोग करता है। budget_mb वह memory है जिसे planning के समय reserve करना चाहिए, क्योंकि वास्तविक उपयोग idle नहीं होता। PostgreSQL लगभग 45 MB पर idle रहता है और connections, sorts तथा cache सक्रिय होने पर 512 MB चाहता है। Planning के लिए budget column का उपयोग करें। Debugging के लिए idle column देखें।
7 rows के pattern पर ध्यान दें। nginx 8 MB पर idle रहता है और Nextcloud 210 MB पर। आपके applications के सामने लगा proxy लगभग कोई memory नहीं लेता। Database और PHP application के लिए ही box का आकार तय करना पड़ता है।
docker stats के बारे में एक चेतावनी: memory का आंकड़ा उस page cache को भी शामिल करता है जिसे container की अपनी file reads ने memory में लाया है। इसलिए start होने के बाद यह कुछ समय तक बढ़ता है और फिर स्थिर हो जाता है। किसी memory leak का निष्कर्ष निकालने से पहले इसे एक घंटे तक monitor करें।
2 GB, 4 GB और 8 GB में VPS का आकार: क्या समा सकता है
सबसे पहले host का हिस्सा अलग रखें। Kernel, systemd, journald, sshd और Docker daemon उसी RAM में चलते हैं जिसमें आपके containers चलते हैं, और dockerd तथा containerd इसमें लगभग 100 MB लेते हैं। Page cache के लिए और image build या database dump चलने के दौरान आने वाले memory spike के लिए भी free memory चाहिए।
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 में operating system, Docker daemon और वह अतिरिक्त headroom शामिल है जो load के दौरान box को responsive बनाए रखता है। बची हुई memory container_mb है, और खर्च करने के लिए आपके पास यही एक संख्या है। Plan बड़ा होने पर reserve भी बढ़ता है: सबसे छोटे box में 768 MB से लेकर सबसे बड़े box में 1536 MB तक। इसका कारण यह है कि बड़ा box अधिक containers चलाता है, अधिक logs लिखता है और अधिक page cache चाहता है।
2 GB plan containers के लिए 1280 MB छोड़ता है। इसमें से 512 MB PostgreSQL और 128 MB Traefik को देने पर आधी memory पहले ही उपयोग हो जाती है। बाकी memory में लगभग 256 MB के दो छोटे applications चल सकते हैं। यह एक वास्तविक और उपयोगी server है। लेकिन इसमें Nextcloud और search cluster के लिए अतिरिक्त जगह नहीं है।
4 GB plan 3072 MB छोड़ता है। इसमें database, reverse proxy, तीन applications और monitoring container एक साथ चल सकते हैं। जिस workload की आपको परवाह है, उसके लिए यह उपयोग करने लायक सबसे छोटा size है, क्योंकि अतिरिक्त memory खराब deploy के प्रभाव को संभालती है।
8 GB plan अपने कुल 8192 MB में से 6656 MB छोड़ता है। इस स्थिति में सीमा आम तौर पर memory से हटकर CPU या disk throughput पर आ जाती है। यदि गणना बताती है कि आपका stack fit नहीं होता, तो उसके आसपास tuning करने के बजाय बड़ा plan खरीदें: VPS की वास्तविक लागत बताता है कि अतिरिक्त gigabytes की प्रति माह कीमत कितनी है।
गणना को सही रखने के लिए दो नियम अपनाएँ। हर service पर memory limit लगाएँ, ताकि कोई runaway process पूरे box को अपने साथ प्रभावित न कर सके। Budget का ऊपरी हिस्सा खर्च न करें, क्योंकि docker compose build और pg_dump दोनों को सबसे खराब समय पर memory चाहिए। Docker Compose में memory limits में syntax और सामान्य समस्याएँ दी गई हैं।
मेरा container 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 limit तक पहुंच गया। kernel log उस process का नाम दिखाता है जिसे उसने समाप्त करने के लिए चुना:
Memory cgroup out of memory: Killed process 2417 (postgres) total-vm:1284416kBयह बेहतर स्थिति है, क्योंकि नुकसान केवल एक container तक सीमित रहता है। खराब स्थिति तब होती है जब किसी container पर कोई limit नहीं होती। ऐसी स्थिति में उसकी सीमा पूरी machine की memory होती है। इसलिए एक service में memory leak होने पर host की memory समाप्त होने लगती है। फिर kernel पूरे system में memory usage के आधार पर किसी process को समाप्त करने के लिए चुनता है। Log line में Memory cgroup prefix नहीं रहता और वह Out of memory: Killed process 2417 (postgres) के रूप में दिखाई देती है। चुना गया process अक्सर आपका database होता है, जबकि memory leak करने वाला container चलता रहता है। इसलिए प्रत्येक service पर limit लगाना, किसी एक limit की सटीक value से अधिक महत्वपूर्ण है।
Swap timing बदलता है, arithmetic नहीं। अधिकांश VPS images में swap नहीं होता। swapon --show से जाँच करें। Swap न होने पर यह command कुछ भी output नहीं करती। Swap file kernel को inactive 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 -hअब free -h को Swap row में non-zero total दिखाना चाहिए। Swap RAM नहीं बढ़ाता। लगातार memory pressure में चलने वाली machine इतनी धीमी हो सकती है कि आप समस्या ठीक करने के लिए SSH से connect न कर पाएं। इसलिए swap को alarm buffer मानें और memory sizing ठीक करें।
UFW मेरे प्रकाशित Docker port को block क्यों नहीं करता?
क्योंकि traffic उस chain तक पहुँचता ही नहीं है जिसकी निगरानी UFW करता है। जब आप -p 5432:5432 के साथ कोई port publish करते हैं या compose में ports: entry देते हैं, तो daemon nat table में DNAT (destination network address translation) rule और अपनी DOCKER chain में accept rule लिखता है। Container के लिए भेजा गया packet host को deliver होने के बजाय उस container को forward कर दिया जाता है। इसलिए वह FORWARD path में handle होता है और UFW द्वारा लिखे गए INPUT rules से कभी नहीं गुजरता।
आप server पर यह प्रक्रिया देख सकते हैं:
sudo ufw status | grep 5432
sudo iptables -t nat -L DOCKER -n | grep 5432UFW 5432 DENY IN Anywhere दिखा सकता है, जबकि nat table में उसी port के लिए DNAT tcp ... to:172.18.0.2:5432 rule मौजूद होता है। किसी दूसरी machine से nc -vz your.server.ip 5432 अभी भी connect हो जाता है। Database public internet पर उपलब्ध है, जबकि firewall इसे उपलब्ध नहीं दिखाता।
समाधान है कि कम ports publish करें। एक compose project के containers network share करते हैं और service name के माध्यम से एक-दूसरे तक पहुँच सकते हैं। इसलिए केवल उसके साथ चलने वाली application को serve करने वाले database को ports: entry की आवश्यकता नहीं होती। जब आपको local access चाहिए, तो publish को loopback पर bind करें:
services:
db:
image: postgres:16
ports:
- "127.0.0.1:5432:5432"docker compose up -d के बाद बाहर से nc -vz your.server.ip 5432 विफल हो जाता है, जबकि box पर psql -h 127.0.0.1 -p 5432 अभी भी काम करता है। एक स्वस्थ छोटे stack में केवल reverse proxy कोई port publish करता है, और वह भी 80 और 443 पर। Docker के प्रकाशित ports UFW को bypass क्यों करते हैं उन स्थितियों में DOCKER-USER chain को cover करता है, जहाँ आपको port publish करके भी उसे filter करना हो। UFW firewall की मूल बातें इसके नीचे लागू host rules को cover करता है।
रीबूट के बाद मेरे containers क्यों गायब हो गए?
क्योंकि उन्हें वापस शुरू करने के लिए कोई configuration नहीं थी। यदि आप restart policy सेट नहीं करते हैं, तो container को no के साथ बनाया जाता है। इसलिए रीबूट के बाद वह stopped रहता है और daemon उसे दोबारा शुरू नहीं करता। VPS पर रीबूट असामान्य नहीं हैं। unattended upgrades के kernel updates, provider maintenance और ऊपर बताया गया OOM sequence, सभी रीबूट का कारण बन सकते हैं।
दो बातें सही होनी चाहिए। daemon को boot पर शुरू होना चाहिए:
systemctl is-enabled dockerStock Ubuntu install पर यह enabled दिखाता है। इसके बाद प्रत्येक service के लिए policy सेट करें:
services:
app:
image: ghcr.io/example/app:1.4
restart: unless-stoppedunless-stopped रीबूट के बाद container को वापस शुरू करता है और आपके द्वारा जानबूझकर stopped किए गए container का सम्मान करता है। always daemon के restart होने पर आपके द्वारा deliberately stopped किए गए containers को भी दोबारा शुरू करता है। Debugging के बीच यह unexpected हो सकता है। केवल file edit करना पर्याप्त नहीं है, क्योंकि restart policy container बनाते समय सेट होती है। इसे दोबारा बनाने के लिए docker compose up -d चलाएँ, फिर वर्तमान value जाँचें:
docker inspect my-app | grep -A3 RestartPolicyइसके बाद जानबूझकर host को reboot करें और project directory में docker compose ps चलाएँ। जो stack planned reboot के बाद चलता रहता है, वह unplanned reboot के बाद भी चलता रहेगा। यदि आपके stack को startup order की guarantee या boot पर one-shot job चाहिए, तो systemd unit बेहतर tool है: boot पर Docker Compose शुरू करना में unit file दी गई है। रीबूट के बाद वापस आए container से वास्तव में service मिल रही है या नहीं, यह जानने के लिए Compose healthchecks जोड़ें।
मेरा VPS disk full क्यों है?
क्योंकि Docker तब तक सब कुछ रखता है, जब तक आप उसे हटाने के लिए न कहें। आपके द्वारा pull किया गया हर image tag, हर stopped container, recreate के बाद बचा हर anonymous volume और build cache की हर layer disk पर बनी रहती है। इन plan sizes में 40 GB या 80 GB का root filesystem सामान्य है। ऐसे में outage वर्षों के बजाय कुछ महीनों में हो सकता है।
Full disk किसी crash जैसा दिखाई नहीं देता। आपको उसी घंटे किसी container से no space left on device, apt, journald और docker pull से errors मिल सकती हैं। PostgreSQL writes स्वीकार करना बंद कर देता है। मशीन फिर भी चलती रहती है, इसलिए इसे reboot loop की तुलना में पहचानना कठिन होता है।
हटाने से पहले जाँच करें:
docker system df
df -h /docker system df कुल उपयोग को images, containers, local volumes और build cache में बाँटता है। प्रत्येक के सामने RECLAIMABLE column होता है। जो मशीन अपने images स्वयं build करती है, उसमें build cache आम तौर पर सबसे बड़ी मात्रा होती है।
docker image prune -a
docker builder prune
docker system dfdocker image prune -a उन सभी images को हटाता है जिन्हें कोई container उपयोग नहीं कर रहा है। docker builder prune build cache साफ करता है। Services चलने के दौरान दोनों commands सुरक्षित हैं, क्योंकि उपयोग में मौजूद चीजें छोड़ दी जाती हैं। असुरक्षित command docker system prune --volumes है। यह उन सभी volumes को हटा देता है जिनका इस समय कोई container reference नहीं करता। आपने weekend के लिए जो stack रोक रखा है, वह इसी स्थिति में होता है और उसका database volume भी हट जाता है। यह flag चलाने से पहले bind mounts और named volumes पढ़ें और पहले backup लें।
Container logs धीरे-धीरे disk भरते हैं। Default json-file driver की कोई size limit नहीं होती। इसलिए कोई बहुत अधिक output वाला container /var/lib/docker/containers में gigabytes लिख सकता है। /etc/docker/daemon.json में हर container के लिए limit निर्धारित करें:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}इसे sudo systemctl restart docker से लागू करें। यह आपके containers को restart करता है, इसलिए उचित समय चुनें। यह limit change के बाद बनाए गए containers पर लागू होती है। इसलिए चल रहे containers को docker compose up -d --force-recreate से recreate करें और पुष्टि करें:
docker inspect my-app | grep -A5 LogConfig
sudo du -sh /var/lib/docker/containersInspect output में max-size set दिखना चाहिए। यदि यह खाली है, तो वह container change से पहले बनाया गया था और अभी भी बिना limit के लिख रहा है।
छोटे Docker बॉक्स को स्वस्थ रखने वाली आदतें
इनमें से किसी के लिए dashboard या ऐसा tool आवश्यक नहीं है जिसे आपको सीखना पड़े।
- महीने की पहली तारीख को
docker system dfऔरdf -h /चलाएँ। दो commands और तीस सेकंड में आपको outage बनने से काफी पहले trend दिखाई देगा। - हर service के लिए memory limit निर्धारित करें, उन services के लिए भी जिन्हें आप निश्चित रूप से छोटा समझते हैं। यह limit पूरे host को प्रभावित करने वाले outage को केवल एक restarted container तक सीमित कर देती है।
- बॉक्स को किसी दूसरी जगह से monitor करें, ताकि kernel के कार्रवाई करने से पहले ही आपको memory या disk pressure की जानकारी मिल जाए। Uptime Kuma एक container में चलता है और idle स्थिति में लगभग 95 MB memory लेता है।
- Containers का नहीं, volumes का backup लें। Container disposable होता है, volume नहीं। VPS पर restic backups में schedule और restore test दोनों शामिल हैं।
- compose file में image tags को pin करें और उन्हें अपनी चुनी हुई तारीख को update करें।
latestके साथ, अगलेdocker compose pullसे मिलने वाला version वही होगा जो उस सुबह release हुआ था।
Docker चलाने वाला छोटा VPS वर्षों तक स्वस्थ रहता है, जब चार संख्याएँ अपनी सीमा में रहें: memory budget, published ports की सूची, प्रत्येक service की restart policy और उपलब्ध disk। बाकी सब वही Docker है जिसे आप पहले से घर पर चलाते हैं।
FAQ
VPS पर Docker चलाने के लिए मुझे कितनी RAM चाहिए?
Docker स्वयं कम संसाधन लेता है। daemon और containerd मिलकर लगभग 100 MB लेते हैं, और बाकी आवश्यकता आपके containers पर निर्भर करती है। पहले host के हिस्से का budget रखें: 768 MB वाले 2048 MB box पर operating system, daemon और headroom के लिए 768 MB रखें। इससे containers के लिए 1280 MB बचते हैं। 512 MB का database, 128 MB का reverse proxy और दो छोटे applications इसमें चल सकते हैं। प्रकाशित किसी भी आंकड़े पर निर्भर करने के बजाय अपने stack को docker stats --no-stream से मापें।
क्या मैं 1 GB VPS पर Docker चला सकता हूँ?
हाँ, एक या दो हल्के containers के लिए चला सकते हैं। शुरू करने से पहले swap file बनाएँ। Operating system और Docker daemon चलने के बाद 1 GB box की लगभग आधी memory उपयोग हो जाती है। इसके बाद एक छोटे application और reverse proxy के लिए जगह बचती है, लेकिन वास्तविक load वाले database के लिए नहीं। इतने छोटे box पर images build करने से build fail हो सकता है या कोई दूसरा process बंद हो सकता है। इसलिए images किसी दूसरे स्थान पर build करें और तैयार image pull करें।
क्या UFW Docker container को सुरक्षित करता है?
Publish किए गए ports के लिए नहीं। Docker अपने DNAT और forward rules लिखता है। इसलिए published container port के लिए आया packet host को दिए जाने के बजाय container को forward हो जाता है। UFW द्वारा managed INPUT rules उस packet को देख ही नहीं पाते। ufw deny 5432 active हो सकता है, जबकि वह port internet से response दे रहा हो। 127.0.0.1:5432:5432 के साथ loopback पर publish करें, internal services को unpublished रखें, या DOCKER-USER chain में filtering करें।
क्या VPS reboot के बाद मेरे containers restart होंगे?
केवल तब, जब वे restart policy के साथ बनाए गए हों। प्रत्येक service पर restart: unless-stopped सेट करें। फिर docker compose up -d चलाएँ, ताकि containers उस policy के साथ दोबारा बनाए जाएँ। पुष्टि करें कि systemctl is-enabled docker, enabled print करता है। इसके बाद जानबूझकर reboot करें और docker compose ps जाँचें। जिस restart policy का आपने कभी परीक्षण नहीं किया है, उसे विश्वसनीय restart policy न मानें।
मुझे Docker images को कितनी बार prune करना चाहिए?
अधिकांश छोटे servers के लिए महीने में एक बार पर्याप्त है। आप इसे तब भी कर सकते हैं, जब docker system df ऐसा reclaimable space बताए जिसकी आपको आवश्यकता हो। Services चलने के दौरान docker image prune -a और docker builder prune दोनों सुरक्षित हैं, क्योंकि उपयोग में आने वाली images और cache को छोड़ दिया जाता है। docker system prune --volumes से बचें, जब तक आपको ठीक-ठीक पता न हो कि कौन-से volumes unreferenced हैं। यह गलती से बंद पड़े किसी stack का data delete कर सकता है।