Docker Compose کو boot پر خودکار start کیسے کریں
Docker Compose کی services reboot کے بعد خودکار چلائیں: restart policies، on-failure کے reboot پر ناکام ہونے کی وجہ، اور systemd unit کب ضروری ہے۔
مختصر جواب
Docker Compose کی services boot کے وقت اس وقت start ہوتی ہیں جب دو شرائط بیک وقت پوری ہوں۔ Docker daemon کا system service کے طور پر enabled ہونا ضروری ہے، اور file میں موجود ہر service کے ساتھ unless-stopped یا always کی restart policy مقرر ہونی چاہیے۔ ہر service میں restart: unless-stopped شامل کریں، ایک بار docker compose up -d چلائیں، اور reboot کے بعد containers خود بخود دوبارہ start ہو جائیں گے۔ عام صورت میں مزید کسی چیز کی ضرورت نہیں ہوتی۔
systemd unit صرف اس وقت درکار ہوتی ہے جب ترتیب اہم ہو: مثلاً ایسا stack جو mounted disk، VPN interface، یا network share پر منحصر ہو اور Docker daemon کے start ہونے کے وقت وہ تیار نہ ہو۔ یہ حقیقی صورت ہے، اور اس guide کا دوسرا نصف اسی کا احاطہ کرتا ہے۔ اگر آپ ابھی service definitions اور volumes کو سمجھ رہے ہیں تو VPS پر Docker Compose کی بنیادی باتوں سے شروع کریں اور پھر واپس آئیں۔
compose.yaml میں restart policy مقرر کریں
یہ policy ہر service کے لیے ایک الگ لائن پر مقرر کی جاتی ہے۔ کوئی global switch موجود نہیں۔ اس لیے جس service کو آپ بھول جائیں گے، وہ reboot کے بعد بند رہے گی، جبکہ stack کی باقی services شروع ہو جائیں گی۔
services:
app:
image: nginx:1.27
restart: unless-stopped
ports:
- "8080:80"
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_PASSWORD: change-me
volumes:
- dbdata:/var/lib/postgresql/data
volumes:
dbdata:اسے نافذ کریں، پھر چلتے ہوئے container سے policy دوبارہ پڑھیں:
docker compose up -d
docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app)اس سے unless-stopped ظاہر ہوتا ہے۔ اگر no ظاہر ہو، تو file میں ترمیم کی گئی تھی، لیکن container دوبارہ create نہیں کیا گیا۔
یہ failure کی سب سے عام وجہ ہے۔ restart policy container میں محفوظ ہوتی ہے، YAML file میں نہیں۔ compose.yaml میں ترمیم کرنے سے پہلے سے موجود container پر کوئی اثر نہیں پڑتا۔ docker compose restart بھی مدد نہیں کرتا، کیونکہ یہ اسی container object کو روکتا اور دوبارہ شروع کرتا ہے، اس کی configuration تبدیل نہیں کرتا۔ صرف docker compose up -d file کا چلتے ہوئے containers سے موازنہ کرتا ہے، policy میں تبدیلی کا پتا لگاتا ہے، اور containers کو دوبارہ create کرتا ہے۔
جس container کو آپ ابھی دوبارہ create نہیں کرنا چاہتے، اس کی policy وہیں تبدیل کریں:
docker update --restart unless-stopped my-containerYAML file میں بھی ترمیم ضرور کریں۔ docker update چلتے ہوئے container کو تبدیل کرتا ہے، جبکہ اگلا docker compose up -d file پڑھے گا اور پرانی value دوبارہ نافذ کر دے گا۔
ہر restart value کا عملی اثر
Docker چار values فراہم کرتا ہے۔ ان کے درمیان فرق صرف اس وقت ظاہر ہوتا ہے جب machine reboot ہو یا daemon restart کیا جائے۔
nodefault ہے۔ container کسی بھی صورت میں خودکار طور پر restart نہیں ہوتا۔alwayscontainer کے stop ہوتے ہی اسے restart کرتا ہے۔ اگر آپ نے اسے دستی طور پر stop کیا ہو، تب بھی Docker daemon کے اگلی بار start ہونے پر یہ دوبارہ چل جاتا ہے۔ یہ اکثر حیران کن ہوتا ہے: جس container کو آپ نے گزشتہ ہفتے جان بوجھ کر stop کیا تھا، وہ reboot کے بعد دوبارہ چل رہا ہوتا ہے۔unless-stopped،alwaysکی طرح کام کرتا ہے، لیکن دستی طور پر stop کیا گیا container daemon restart کے بعد بھی stop رہتا ہے۔ کسی ایسی service کے لیے یہی value استعمال کریں جسے آپ کبھی کبھار maintenance کے لیے بند کرتے ہیں۔on-failurecontainer کو صرف اس وقت restart کرتا ہے جب وہ non-zero exit code کے ساتھ exit ہو۔ آپ کوششوں کی تعداد محدود کر سکتے ہیں، جیسا کہrestart: on-failure:3میں ہے۔
ایسے stack کے لیے جو server کے up ہونے تک لازماً چلتا رہنا چاہیے، unless-stopped درست default ہے۔ always صرف اس وقت منتخب کریں جب آپ ایسا container چاہتے ہوں جو stop رہ جانے کے باوجود دوبارہ چلنے کی کوشش کرے۔
ری اسٹارٹ پالیسی on-failure reboot کے بعد برقرار کیوں نہیں رہتی
بہت سے لوگ `on-failure اس لیے منتخب کرتے ہیں کہ یہ محتاط انتخاب محسوس ہوتی ہے، لیکن پہلی reboot کے بعد انہیں ہر container stopped ملتا ہے۔ وجہ اس کی تعریف میں موجود ہے۔ on-failure` صرف ایک صورت پر ردعمل دیتی ہے: container process کا error code کے ساتھ ختم ہونا۔
reboot کوئی error نہیں ہے۔ جب host shutdown ہوتا ہے تو systemd، `docker.service کو stop کرتا ہے، اور daemon ہر container کو دانستہ طور پر stop کر دیتا ہے۔ container fail نہیں ہوا، اس لیے policy کے پاس ردعمل دینے کے لیے کچھ نہیں ہوتا۔ host کے دوبارہ start ہونے پر daemon ان containers کو دیکھتا ہے جنہیں resume کرنا ضروری ہے، اور صاف طور پر stopped کیا گیا on-failure` container ان میں شامل نہیں ہوتا۔ وہ exited state میں رہتا ہے۔
آپ اسے براہ راست دیکھ سکتے ہیں۔ کسی service پر `restart: on-failure set کریں، docker compose up -d` چلائیں، reboot کریں، پھر یہ command چلائیں:
docker compose ps -aservice `Exited state کے ساتھ اور Exited (0) 2 minutes ago` جیسی status کے ساتھ listed ہوگی۔ کچھ خراب نہیں ہوا اور کسی چیز کو error کے طور پر log بھی نہیں کیا گیا، اسی لیے اس مسئلے کی تشخیص مشکل ہوتی ہے۔ policy نے بالکل وہی کیا جو اس کی تعریف میں درج ہے۔
`on-failure` اب بھی مفید ہے۔ یہ ایسے container کے لیے موزوں ہے جو کوئی job چلاتا ہو اور crash ہو سکتا ہو، جہاں آپ retries کی محدود تعداد چاہتے ہوں اور restart loop نہیں چاہتے۔ لیکن reboot کے بعد کسی طویل مدت تک چلنے والی service کو فعال رکھنے کے لیے یہ درست tool نہیں ہے۔
Restart policies صرف اسی وقت کام کرتی ہیں جب boot کے وقت Docker service شروع ہو
Restart policies کا نفاذ Docker daemon کرتا ہے۔ اگر daemon شروع ہی نہ ہو تو کسی policy کا نفاذ نہیں ہوتا۔ اس کی جانچ کریں:
systemctl is-enabled docker
systemctl is-enabled containerdدونوں کمانڈز کا نتیجہ enabled ہونا چاہیے۔ Docker کے official repository کے packages انہیں installation کے وقت فعال کر دیتے ہیں، اس لیے نئے server پر یہ جانچ عموماً کامیاب رہتی ہے۔ اگر کسی ایک کمانڈ کا نتیجہ disabled آئے تو اسے درست کریں:
sudo systemctl enable --now docker containerdیہاں ایک اہم نکتہ سمجھنا ضروری ہے۔ Ubuntu میں docker.socket بھی شامل ہوتا ہے، جو پہلی بار Docker API سے رابطہ ہونے پر daemon کو ضرورت کے مطابق شروع کرتا ہے۔ لوگ docker.socket کو enabled دیکھ کر سمجھتے ہیں کہ daemon بھی محفوظ ہے، اور memory بچانے کے لیے docker.service کو disable کر دیتے ہیں۔ boot کے وقت API کو کوئی call نہیں کرتا، اس لیے socket کبھی access نہیں ہوتا، daemon شروع نہیں ہوتا، اور آپ کی پہلی docker کمانڈ لکھنے تک کوئی container شروع نہیں ہوتا۔ Socket activation، docker.service کے enabled ہونے کا متبادل نہیں ہے۔
جب systemd unit بہتر انتخاب ہو
Restart policies میں پورے system کے ساتھ startup order کی کوئی ترتیب موجود نہیں ہوتی۔ daemon شروع ہوتا ہے اور دستیاب ہوتے ہی آپ کے containers شروع کر دیتا ہے۔ اگر آپ کے stack میں کسی الگ volume، NFS (network file system) share یا encrypted disk کی directory bind-mount کی گئی ہو تو containers اس path کے موجود ہونے سے پہلے شروع ہو سکتے ہیں۔ Docker mount point پر خالی directory بنا کر container شروع کر دے گا، اور آپ کا database بغیر data کے شروع ہو جائے گا۔
اگر درج ذیل میں سے کوئی صورت حال موجود ہو تو systemd unit لکھیں۔ stack کے لیے پہلے کسی mount، VPN interface یا کسی دوسری unit کا ready ہونا ضروری ہے۔ آپ چاہتے ہیں کہ systemctl stop myapp اور systemctl start myapp اسی طرح کام کریں جیسے system کے دیگر services کے لیے کرتے ہیں۔ یا آپ چاہتے ہیں کہ shutdown کے دوران stack کو daemon کے ساتھ ختم کرنے کے بجائے باقاعدہ طور پر بند کیا جائے۔ اگر systemd units آپ کے لیے نئی ہیں تو systemd service اور timer لکھنا file format کی مزید تفصیل فراہم کرتا ہے۔
systemd unit لکھنا
Stack کو home directory سے باہر ایک مقررہ path میں رکھیں۔ /srv/myapp ایک اچھا انتخاب ہے، کیونکہ login سے پہلے چلنے والی unit کو /home پڑھنے کی کوئی ضرورت نہیں۔
/etc/systemd/system/myapp.service بنائیں:
[Unit]
Description=myapp docker compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
RequiresMountsFor=/srv/myapp/data
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/srv/myapp
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.targetاسے enable اور start کریں:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.serviceصحت مند unit میں Active: active (exited) دکھائی دیتا ہے۔ پہلی بار دیکھنے پر یہ غلط محسوس ہوتا ہے۔ یہ درست ہے: RemainAfterExit=yes کے ساتھ Type=oneshot کا مطلب ہے کہ unit نے اپنا command چلایا، command مکمل ہو گیا، اور systemd unit کو active نشان زد رکھتا ہے تاکہ shutdown کے وقت ExecStop چل سکے۔
ہر line کی اپنی وجہ ہے۔ Requires=docker.service کا مطلب ہے کہ unit تیزی سے fail ہو جائے گی، بجائے اس کے کہ dead socket کے خلاف docker compose چلائے۔ After= ترتیب مقرر کرتا ہے، کیونکہ صرف Requires= ایسا نہیں کرتا۔ RequiresMountsFor= systemd کو اس path کے لیے mount unit شامل کرنے اور اس کا انتظار کرنے پر مجبور کرتا ہے۔ یہی وہ بنیادی وجہ ہے جس کے لیے restart policy کے بجائے unit استعمال کی جاتی ہے۔ TimeoutStartSec=0 systemd کو اس وقت start job ختم کرنے سے روکتا ہے جب بڑا image ابھی pull ہو رہا ہو۔
دونوں mechanisms کو یکجا کرنے کے بارے میں ایک نوٹ۔ Docker کی documentation host process manager کے ساتھ restart policies ملانے کے خلاف مشورہ دیتی ہے۔ یہ انتباہ ایسے process manager کے بارے میں ہے جو خود container process کی نگرانی کرتا ہے اور اسے restart کرتا ہے، جبکہ daemon بھی یہی کام کرنے کی کوشش کر رہا ہوتا ہے۔ Type=oneshot unit کسی چیز کی نگرانی نہیں کرتی، اس لیے اس unit کے ساتھ compose file میں restart: unless-stopped رکھنا درست ہے، اور یہی مطلوب ہے۔ systemd boot کے وقت ordering سنبھالتا ہے، جبکہ daemon ایسے container کو handle کرتا ہے جو رات کے تین بجے crash ہو جائے۔
جب برقرار رکھنے والی چیز stack کے بجائے ایک سادہ long-running process ہو تو unit مختلف دکھائی دیتی ہے، کیونکہ اس صورت میں اس کے نیچے کوئی daemon نہیں ہوتا اور نگرانی کا کام systemd کے اپنے Restart= کو کرنا پڑتا ہے؛ systemd کے پیچھے headless dsh چلانا اس ساخت کی عملی مثال ہے، جس میں dedicated user اور journal بھی شامل ہیں۔
حقیقی reboot سے تصدیق کریں
حقیقی test کا کوئی متبادل نہیں۔ systemctl restart docker mount ordering کو test نہیں کرتا، جبکہ docker compose down کے بعد docker compose up -d چلانے سے boot سے متعلق کسی چیز کی test نہیں ہوتی۔
sudo rebootانتظار کریں، دوبارہ connect کریں، اور اس ترتیب سے check کریں:
uptime
systemctl is-active docker
docker compose psuptime سے تصدیق ہوتی ہے کہ آپ واقعی reboot ہونے والی machine دیکھ رہے ہیں۔ stack directory سے چلایا گیا docker compose ps ہر service کو running حالت میں دکھانا چاہیے، اور اس کا uptime machine کے uptime کے قریب ہونا چاہیے۔ Exited دکھانے والی service کو دیکھیں۔
اگر کوئی چیز start نہ ہوئی ہو تو daemon log boot window کا record فراہم کرتا ہے:
journalctl -u docker.service -b --no-pager | tail -50unit کے ذریعے manage کیے جانے والے stack کے لیے journalctl -u myapp.service -b --no-pager boot کے دوران حاصل ہونے والا مکمل docker compose output دکھاتا ہے، جس میں failed image pull یا missing .env file بھی شامل ہے۔ آپ جس reboot کو schedule کرتے ہیں، اسی کی نگرانی کرتے ہیں؛ اس لیے unit کو ان reboots کے بارے میں اطلاع دینے دیں جن کی آپ نگرانی نہیں کرتے: self-hosted ntfy server کی طرف اشارہ کرنے والی OnFailure= line ایسے stack کو، جو واپس start نہ ہو سکا ہو، push notification میں تبدیل کر دیتی ہے، بجائے اس کے کہ آپ کو کئی دن بعد اس کا پتا چلے۔
خودکار start-up کو خاموشی سے متاثر کرنے والی چیزیں
docker compose run سے بنائے گئے containers کو file میں درج restart policy نہیں ملتی۔ Compose انہیں one-off containers سمجھتا ہے۔ اگر کوئی service اپنی policy کو نظرانداز کرتی محسوس ہو تو دیکھیں کہ اسے up کے بجائے run کے ساتھ start تو نہیں کیا گیا۔
volume یا env_file entry میں relative path، compose file کی directory کے مطابق resolve ہوتا ہے۔ یہ آپ کے shell سے کام کرتا ہے، اور ایسی unit سے بھی کام کرتا ہے جو WorkingDirectory set کرتی ہو۔ ایسی unit سے یہ fail ہو جاتا ہے جس میں یہ موجود نہ ہو، کیونکہ اس صورت میں working directory / ہوتی ہے۔
Rootless Docker الگ معاملہ ہے۔ daemon بطور user service چلتا ہے، اور user service اس user کا آخری session ختم ہونے پر stop ہو جاتی ہے۔ اسے user کے لیے enable کریں اور اسے اس وقت بھی چلتے رہنے کی اجازت دیں جب کوئی logged in نہ ہو:
systemctl --user enable docker
sudo loginctl enable-linger $USERenable-linger کے بغیر، logout کرتے وقت rootless daemon بند ہو جاتا ہے اور containers بھی اس کے ساتھ بند ہو جاتے ہیں۔ یہ صورت بالکل ایسی دکھائی دیتی ہے جیسے restart policy خراب ہو۔
ایک آخری بات۔ خودکار security updates server کو مقررہ وقت پر reboot کر سکتی ہیں۔ یہ صرف اسی وقت مفید ہے جب آپ کا stack خود بخود دوبارہ start ہو جائے۔ نئی machine پر اس کی configuration، نئے VPS کے پہلے دس منٹ میں کیے جانے والے ابتدائی کاموں کا حصہ ہونی چاہیے۔
FAQ
restart: always اور restart: unless-stopped میں کیا فرق ہے؟
دونوں اس وقت container کو دوبارہ شروع کرتے ہیں جب وہ خود بند ہو جائے۔ فرق اس وقت ظاہر ہوتا ہے جب آپ container کو دستی طور پر بند کرتے ہیں۔ `always کے ساتھ Docker daemon اگلی بار شروع ہونے پر container دوبارہ شروع کر دیتا ہے، اس لیے reboot آپ کے دستی stop کو ختم کر دیتا ہے۔ unless-stopped کے ساتھ daemon یاد رکھتا ہے کہ container کو جان بوجھ کر روکا گیا تھا اور اسے دوبارہ شروع نہیں کرتا۔ unless-stopped` استعمال کریں، الا یہ کہ آپ خاص طور پر ایسا container چاہتے ہوں جو بند رہنے کے بعد دوبارہ شروع نہ ہو۔
میں نے restart: unless-stopped شامل کیا ہے، لیکن reboot کے بعد container پھر بھی شروع نہیں ہوتا۔ کیوں؟
یہ policy file میں نہیں بلکہ container پر لاگو ہوتی ہے، اور پہلے سے موجود container کو YAML میں ترمیم کرنے سے update نہیں کیا جاتا۔ `docker compose up -d چلائیں تاکہ Compose اسے دوبارہ بنائے، پھر docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app) سے تصدیق کریں۔ اگر اس کا نتیجہ no ہو تو container آپ کی ترمیم سے پہلے کا موجود ہے۔ دوسری عام وجہ یہ ہے کہ docker.service فعال نہیں ہے۔ آپ اسے systemctl is-enabled docker` سے جانچ سکتے ہیں۔
اگر میں restart policies پہلے ہی استعمال کر رہا ہوں تو کیا مجھے systemd unit کی ضرورت ہے؟
عام طور پر نہیں۔ ایسے stack کے لیے restart policy کافی ہوتی ہے جسے صرف network درکار ہو، اور زیادہ تر stack اسی نوعیت کے ہوتے ہیں۔ جب container کسی ایسی چیز پر منحصر ہوں جو Docker daemon کے شروع ہوتے وقت تیار نہ ہو، تو unit شامل کریں۔ مثال کے طور پر external disk، encrypted volume، NFS share یا VPN interface۔ unit آپ کو `After= اور RequiresMountsFor=` کے ذریعے startup order متعین کرنے دیتی ہے، جس کا اظہار restart policy سے نہیں کیا جا سکتا۔
میں stack کو مستقل طور پر کیسے روکوں تاکہ اگلے reboot پر دوبارہ شروع نہ ہو؟
`unless-stopped کے ساتھ docker compose stop کافی ہے، کیونکہ دستی طور پر روکا گیا container daemon کے دوبارہ شروع ہونے پر resume نہیں ہوتا۔ always کے ساتھ صرف stop کرنا کافی نہیں، اور reboot کے بعد container دوبارہ شروع ہو جاتا ہے۔ یا تو docker compose down چلائیں، جو container ہٹا دیتا ہے، یا پہلے docker update --restart no my-container کے ذریعے policy تبدیل کریں۔ اگر systemd unit stack کو manage کرتی ہے تو sudo systemctl disable myapp.service` بھی چلائیں، ورنہ unit اسے دوبارہ شروع کر دے گی۔