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 رہ جانے کے باوجود دوبارہ چلنے کی کوشش کرے۔
Restart کیوں: on-failure reboot کے بعد برقرار نہیں رہتا
بہت سے لوگ on-failure کا انتخاب اس لیے کرتے ہیں کہ یہ محتاط معلوم ہوتا ہے، پھر پہلی reboot کے بعد تمام containers کو stopped پاتے ہیں۔ وجہ اس کی definition میں موجود ہے۔ on-failure صرف ایک چیز پر ردعمل دیتا ہے: container process کا error code کے ساتھ ختم ہونا۔
Reboot کوئی error نہیں ہے۔ جب host shutdown ہوتا ہے تو systemd، docker.service کو stop کرتا ہے، اور daemon ہر container کو دانستہ طور پر stop کر دیتا ہے۔ container fail نہیں ہوا، اس لیے policy کے پاس ردعمل دینے کی کوئی وجہ نہیں ہوتی۔ دوبارہ start ہوتے وقت daemon ان containers کو دیکھتا ہے جنہیں resume کرنا ضروری ہے، اور صاف طور پر stop کیا گیا 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 کے ساتھ list کیا جاتا ہے۔ کچھ بھی خراب نہیں ہوا اور کسی چیز کو error کے طور پر log نہیں کیا گیا، اسی لیے اس مسئلے کی تشخیص مشکل ہوتی ہے۔ policy نے بالکل وہی کیا جو اس میں لکھا ہے۔
on-failure اب بھی مفید ہے۔ یہ ایسے container کے لیے موزوں ہے جو کوئی job چلاتا ہو اور crash ہو سکتا ہو۔ اپنے طور پر restart: on-failure کوئی limit مقرر نہیں کرتا اور مسلسل fail ہونے والی job کو بار بار restart کرتا رہتا ہے، اس لیے جب آپ retries کی محدود تعداد اور restart loop سے بچنا چاہیں تو restart: on-failure:3 جیسی cap شامل کریں۔ 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) دکھاتی ہے۔ پہلی بار دیکھنے پر یہ غلط معلوم ہوتا ہے۔ یہ درست ہے: Type=oneshot کے ساتھ RemainAfterExit=yes کا مطلب ہے کہ 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 شامل کرنے اور اس کے مکمل ہونے کا انتظار کرنے پر مجبور کرتا ہے۔ unit استعمال کرنے کی یہی بنیادی وجہ ہے، restart policy نہیں۔ TimeoutStartSec=0 systemd کو اس وقت start job ختم کرنے سے روکتا ہے جب بڑا image ابھی pull ہو رہا ہو۔
دونوں mechanisms کو یکجا کرنے کے بارے میں ایک بات۔ Docker کی documentation host-level process manager کے ساتھ restart policies یکجا کرنے سے منع کرتی ہے اور صرف یہ کہتی ہے کہ اس سے conflicts پیدا ہوتے ہیں۔ Conflict اس process manager کی وجہ سے پیدا ہوتا ہے جو خود container process کی نگرانی کرتا ہے اور اسے restart کرتا ہے، جبکہ daemon بھی یہی کام کرنے کی کوشش کر رہا ہوتا ہے۔ Type=oneshot unit کسی چیز کی نگرانی نہیں کرتی، اس لیے اس unit کے ساتھ compose file میں restart: unless-stopped رکھنا درست ہے، اور یہی مطلوب ہے۔ systemd boot کے وقت ordering سنبھالتا ہے، جبکہ daemon صبح 3 بجے crash ہونے والے container کو سنبھالتا ہے۔
جب آپ جس چیز کو فعال رکھنا چاہتے ہیں وہ stack کے بجائے ایک سادہ long-running process ہو تو unit مختلف نظر آتی ہے، کیونکہ اس صورت میں اس کے نیچے کوئی daemon نہیں ہوتا اور systemd کا اپنا Restart= نگرانی کرتا ہے؛ systemd کے پیچھے headless dsh چلانا اسی structure کی عملی مثال ہے، جس میں 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 نہیں کیا جاتا۔ Compose سے اسے دوبارہ بنانے کے لیے `docker compose up -d چلائیں، پھر docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app) سے تصدیق کریں۔ اگر اس کا output no ہو تو container آپ کی ترمیم سے پہلے کا ہے۔ دوسری عام وجہ یہ ہے کہ docker.service enabled نہیں ہے، جسے آپ systemctl is-enabled docker` سے چیک کر سکتے ہیں۔
اگر میں پہلے ہی restart policies استعمال کر رہا ہوں تو کیا مجھے systemd unit کی ضرورت ہے؟
عموماً نہیں۔ ایسے stack کے لیے restart policy کافی ہے جسے صرف network درکار ہو، اور زیادہ تر stack اسی نوعیت کے ہوتے ہیں۔ جب containers کسی ایسی چیز پر منحصر ہوں جو Docker daemon کے شروع ہوتے وقت تیار نہ ہو، تو unit شامل کریں۔ مثال کے طور پر external disk، encrypted volume، NFS share یا VPN interface۔ unit آپ کو `After= اور RequiresMountsFor=` کے ذریعے ordering فراہم کرتی ہے، جس کا اظہار restart policy نہیں کر سکتی۔
میں stack کو مستقل طور پر کیسے روکوں تاکہ اگلے reboot پر یہ دوبارہ شروع نہ ہو؟
`unless-stopped کے ساتھ docker compose stop کافی ہے، کیونکہ دستی طور پر بند کیا گیا container daemon کے دوبارہ شروع ہونے پر resume نہیں ہوتا۔ always کے ساتھ صرف stop کافی نہیں ہوتا اور reboot کے بعد container واپس آ جاتا ہے۔ یا تو docker compose down چلائیں، جو containers کو remove کر دیتا ہے، یا پہلے docker update --restart no my-container کے ذریعے policy تبدیل کریں۔ اگر systemd unit stack کو manage کرتی ہے تو sudo systemctl disable myapp.service` بھی چلائیں، ورنہ unit اسے دوبارہ شروع کر دے گی۔