Docker Compose کو boot پر خودکار شروع کریں
Reboot کے بعد Docker Compose services واپس لانے کے لیے restart policy استعمال کریں، جانیں کہ on-failure ایک بار کیوں نہیں چلتی، اور systemd unit کب ضروری ہے۔
مختصر جواب
Docker Compose سروسز بوٹ کے وقت اس وقت شروع ہوتی ہیں جب دو شرائط بیک وقت پوری ہوں۔ Docker daemon کا system service کے طور پر enabled ہونا ضروری ہے، اور فائل میں ہر service کے ساتھ unless-stopped یا always کی restart policy ہونی چاہیے۔ ہر service میں restart: unless-stopped شامل کریں، ایک بار docker compose up -d چلائیں، اور reboot کے بعد containers خود بخود دوبارہ شروع ہو جائیں گے۔ عام صورت میں مزید کسی چیز کی ضرورت نہیں ہوتی۔
systemd unit صرف اس وقت درکار ہوتی ہے جب ترتیب اہم ہو: مثلاً ایسا stack جو mounted disk، VPN interface، یا network share پر منحصر ہو، اور Docker daemon شروع ہونے کے وقت وہ دستیاب نہ ہو۔ یہ ایک حقیقی صورت ہے، اور اس 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 نہیں کیا گیا۔
یہ سب سے عام خرابی ہے۔ 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 live container کو تبدیل کرتا ہے، اور اگلا docker compose up -d file کو پڑھ کر پرانی value واپس نافذ کر دے گا۔
ہر restart value کا عملی کام
Docker چار values متعین کرتا ہے۔ ان کے درمیان فرق صرف اس وقت ظاہر ہوتا ہے جب مشین reboot ہو یا daemon دوبارہ شروع کیا جائے۔
nodefault value ہے۔ container کسی بھی صورت میں خودکار طور پر دوبارہ شروع نہیں ہوتا۔alwayscontainer کے رکنے پر اسے دوبارہ شروع کرتا ہے۔ اگر آپ نے اسے دستی طور پر روکا ہو، تو Docker daemon کے اگلی بار شروع ہونے پر یہ پھر چل جاتا ہے۔ یہ اکثر حیران کن ہوتا ہے: جس container کو آپ نے گزشتہ ہفتے دانستہ طور پر روکا تھا، وہ reboot کے بعد دوبارہ چل رہا ہوتا ہے۔unless-stoppedکا رویہalwaysجیسا ہے، لیکن دستی طور پر روکا گیا container daemon کے restart کے دوران رکا رہتا ہے۔ اس service کے لیے یہی value منتخب کریں جسے آپ maintenance کے لیے کبھی کبھار بند کرتے ہیں۔on-failurecontainer کو صرف اس وقت دوبارہ شروع کرتا ہے جب وہ non-zero exit code کے ساتھ بند ہو۔ آپ کوششوں کی تعداد محدود کر سکتے ہیں، جیسا کہrestart: on-failure:3میں ہے۔
ایسے stack کے لیے جو server کے چلنے تک مسلسل فعال رہنا چاہیے، unless-stopped درست default ہے۔ always صرف اس وقت منتخب کریں جب آپ ایسا container چاہتے ہوں جو بند رہ جانے کے خلاف مزاحمت کرے۔
restart کیوں: on-failure reboot کے بعد برقرار نہیں رہتا
بہت سے لوگ on-failure اس لیے منتخب کرتے ہیں کہ یہ محتاط انتخاب محسوس ہوتا ہے، پھر پہلے reboot کے بعد تمام containers کو stopped پاتے ہیں۔ وجہ اس کی تعریف میں موجود ہے۔ on-failure صرف ایک صورتِ حال پر ردِعمل دیتا ہے: container process کا error code کے ساتھ خارج ہونا۔
reboot کوئی error نہیں ہوتا۔ جب host بند ہوتا ہے تو systemd، docker.service کو روکتا ہے، اور daemon ہر container کو دانستہ طور پر روک دیتا ہے۔ container fail نہیں ہوا، اس لیے policy کے پاس ردِعمل دینے کے لیے کچھ نہیں ہوتا۔ دوبارہ شروع ہوتے وقت daemon ان containers کو دیکھتا ہے جنہیں resume کرنا ضروری ہے، اور صاف طور پر روکا گیا on-failure container ان میں شامل نہیں ہوتا۔ وہ exited state میں رہتا ہے۔
آپ یہ براہِ راست دیکھ سکتے ہیں۔ کسی service پر restart: on-failure سیٹ کریں، docker compose up -d چلائیں، reboot کریں، پھر یہ command چلائیں:
docker compose ps -aservice کو Exited کی state اور Exited (0) 2 minutes ago جیسی status کے ساتھ فہرست میں دکھایا جاتا ہے۔ کچھ بھی خراب نہیں ہوتا اور کسی چیز کو error کے طور پر log نہیں کیا جاتا، اسی لیے مسئلے کی تشخیص مشکل ہو جاتی ہے۔ policy نے بالکل وہی کیا جو اس کی تعریف میں ہے۔
on-failure اب بھی مفید ہے۔ یہ ایسے container کے لیے موزوں ہے جو کوئی job چلاتا ہو اور crash ہو سکتا ہو، جہاں آپ retries کی محدود تعداد چاہتے ہوں اور restart loop نہیں چاہتے۔ لیکن reboot کے بعد دیر تک چلنے والی service کو فعال رکھنے کے لیے یہ درست tool نہیں ہے۔
دوبارہ شروع کرنے کی پالیسیاں صرف اسی صورت کام کرتی ہیں جب Docker سروس بوٹ کے وقت شروع ہو
دوبارہ شروع کرنے کی پالیسیاں Docker daemon نافذ کرتا ہے۔ اگر daemon شروع نہ ہو تو کوئی چیز نافذ نہیں ہوتی۔ اسے چیک کریں:
systemctl is-enabled docker
systemctl is-enabled containerdدونوں کو enabled پرنٹ کرنا چاہیے۔ Docker کی آفیشل repository کے پیکیجز انسٹالیشن کے وقت انہیں فعال کر دیتے ہیں، اس لیے نئے server پر یہ جانچ عموماً کامیاب ہوتی ہے۔ اگر ان میں سے کوئی disabled پرنٹ کرے تو اسے درست کریں:
sudo systemctl enable --now docker containerdیہاں ایک اہم مسئلہ ہے جسے سمجھنا ضروری ہے۔ Ubuntu میں docker.socket بھی شامل ہوتا ہے، جو پہلی مرتبہ کوئی چیز Docker API سے رابطہ کرے تو daemon کو ضرورت کے وقت شروع کرتا ہے۔ لوگ docker.socket کو فعال دیکھ کر سمجھتے ہیں کہ daemon کا انتظام ہو گیا ہے، اور میموری بچانے کے لیے docker.service کو غیر فعال کر دیتے ہیں۔ بوٹ کے وقت API کو کوئی کال نہیں کرتا، اس لیے socket کو کبھی استعمال نہیں کیا جاتا، daemon شروع نہیں ہوتا، اور آپ کی پہلی docker کمانڈ ٹائپ کرنے تک کوئی container شروع نہیں ہوتا۔ Socket activation، docker.service کے فعال ہونے کا متبادل نہیں ہے۔
جب systemd unit بہتر حل ہو
Restart policies کو نظام کے باقی حصوں کے ساتھ ترتیب کا کوئی تصور نہیں ہوتا۔ 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 کے تیار ہونے کی ضرورت ہو۔ آپ چاہتے ہوں کہ systemctl stop myapp اور systemctl start myapp اسی طرح کام کریں جیسے host پر موجود ہر دوسری service کے لیے کرتے ہیں۔ یا آپ چاہتے ہوں کہ shutdown کے دوران stack کو باقاعدہ طور پر بند کیا جائے، بجائے اس کے کہ اسے daemon کے ساتھ ہی ختم کر دیا جائے۔ اگر systemd units آپ کے لیے نئی ہیں تو systemd service اور timer لکھنا فائل کے format کی مزید تفصیل فراہم کرتا ہے۔
systemd یونٹ لکھنا
Stack کو گھر کی ڈائریکٹری سے باہر ایک مقررہ path میں رکھیں۔ /srv/myapp ایک اچھا انتخاب ہے، کیونکہ جو یونٹ کسی کے login کرنے سے پہلے چلتا ہے، اسے /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صحت مند یونٹ Active: active (exited) دکھاتا ہے۔ پہلی بار دیکھنے پر یہ غلط معلوم ہوتا ہے۔ یہ درست ہے: Type=oneshot کے ساتھ RemainAfterExit=yes کا مطلب ہے کہ یونٹ نے اپنی command چلائی، command مکمل ہوئی، اور systemd یونٹ کو active رکھتا ہے تاکہ shutdown کے وقت ExecStop چل سکے۔
ہر line کی اپنی وجہ ہے۔ Requires=docker.service کا مطلب ہے کہ یونٹ تیزی سے fail ہو جاتا ہے، بجائے اس کے کہ مردہ socket کے خلاف docker compose چلائے۔ After= ترتیب مقرر کرتا ہے، کیونکہ صرف Requires= ایسا نہیں کرتا۔ RequiresMountsFor= systemd کو اس path کے لیے mount unit شامل کرنے اور اس کے مکمل ہونے تک انتظار کرنے کا پابند بناتا ہے۔ یہی وجہ ہے کہ restart policy کے بجائے یونٹ استعمال کیا جاتا ہے۔ TimeoutStartSec=0 systemd کو اس وقت start job ختم کرنے سے روکتا ہے جب بڑا image ابھی pull ہو رہا ہو۔
دونوں mechanisms کو یکجا کرنے کے بارے میں ایک وضاحت۔ Docker کی documentation restart policies کو host process manager کے ساتھ ملانے کے خلاف مشورہ دیتی ہے۔ یہ انتباہ ایسے process manager کے بارے میں ہے جو خود container process کی نگرانی کرتا ہے اور اسے restart کرتا ہے، جبکہ daemon بھی یہی کام کرنے کی کوشش کر رہا ہوتا ہے۔ Type=oneshot یونٹ کسی چیز کی نگرانی نہیں کرتا، اس لیے compose file میں restart: unless-stopped کو اس یونٹ کے ساتھ رکھنا درست ہے، اور یہی مطلوب ہے۔ systemd boot کے وقت ترتیب سنبھالتا ہے، جبکہ daemon اس container کو سنبھالتا ہے جو صبح تین بجے crash ہو جائے۔
حقیقی reboot کے ذریعے تصدیق کریں
حقیقی ٹیسٹ کا کوئی متبادل نہیں ہے۔ systemctl restart docker mount ordering کو جانچتا نہیں، اور docker compose down کے بعد docker compose up -d چلانے سے boot کے بارے میں کچھ بھی جانچا نہیں جاتا۔
sudo rebootانتظار کریں، دوبارہ connect کریں، اور اس ترتیب سے جانچیں:
uptime
systemctl is-active docker
docker compose psuptime تصدیق کرتا ہے کہ آپ واقعی reboot ہونے والی machine دیکھ رہے ہیں۔ stack directory سے چلایا گیا docker compose ps ہر service کو running کے طور پر دکھانا چاہیے، اور اس کا uptime machine کے uptime کے قریب ہونا چاہیے۔ Exited دکھانے والی service کی جانچ کریں۔
اگر کچھ شروع نہیں ہوا، تو daemon log boot window کا احاطہ کرتا ہے:
journalctl -u docker.service -b --no-pager | tail -50unit کے زیرِ انتظام stack کے لیے journalctl -u myapp.service -b --no-pager boot کے وقت کا درست docker compose output دکھاتا ہے، جس میں failed image pull یا missing .env file بھی شامل ہے۔
وہ چیزیں جو خاموشی سے خودکار آغاز کو متاثر کرتی ہیں
docker compose run کے ذریعے بنائے گئے containers کو فائل میں موجود restart policy کبھی نہیں ملتی۔ Compose انہیں one-off containers سمجھتا ہے۔ اگر کوئی service اپنی policy کو نظر انداز کرتی دکھائی دے تو جانچیں کہ اسے up کے بجائے run کے ذریعے شروع کیا گیا تھا۔
volume یا env_file entry میں موجود relative path کی resolution compose file کی directory کے نسبت ہوتی ہے۔ یہ آپ کے shell سے کام کرتا ہے، اور اس unit سے بھی کام کرتا ہے جو WorkingDirectory مقرر کرتی ہے۔ یہ اس unit سے ناکام ہو جاتا ہے جس میں یہ مقرر نہ ہو، کیونکہ اس صورت میں working directory / ہوتی ہے۔
Rootless Docker ایک الگ معاملہ ہے۔ daemon user service کے طور پر چلتا ہے، اور user service اس وقت رک جاتی ہے جب اس user کا آخری session ختم ہو جاتا ہے۔ اسے user کے لیے enable کریں اور اسے اس وقت بھی چلنے دیں جب کوئی user logged in نہ ہو:
systemctl --user enable docker
sudo loginctl enable-linger $USERenable-linger کے بغیر، rootless daemon کے logout کرتے ہی بند ہو جاتا ہے، اور containers بھی اس کے ساتھ رک جاتے ہیں۔ اس صورت حال سے restart policy کے خراب ہونے کا بالکل یہی تاثر ملتا ہے۔
ایک آخری بات۔ خودکار security updates server کو مقررہ وقت پر reboot کر سکتی ہیں۔ یہ صرف اسی صورت میں مفید ہے جب آپ کا stack خود بحال ہو جائے۔ نئی machine پر اس کی configuration، ابتدائی کام کے باقی حصے کے ساتھ، نئے VPS کے پہلے دس منٹ میں شامل ہے۔
FAQ
restart: always اور restart: unless-stopped میں کیا فرق ہے؟
دونوں پالیسیاں کنٹینر کے خود رکنے پر اسے دوبارہ شروع کرتی ہیں۔ فرق اس وقت ظاہر ہوتا ہے جب آپ کنٹینر کو دستی طور پر روکتے ہیں۔ always کے ساتھ، Docker daemon کے اگلی بار شروع ہونے پر کنٹینر دوبارہ شروع ہو جاتا ہے، اس لیے reboot آپ کے دستی stop کو ختم کر دیتا ہے۔ unless-stopped کے ساتھ، daemon یاد رکھتا ہے کہ کنٹینر کو جان بوجھ کر روکا گیا تھا اور اسے دوبارہ شروع نہیں کرتا۔ unless-stopped استعمال کریں، جب تک آپ خاص طور پر ایسا کنٹینر نہ چاہتے ہوں جو بند حالت میں برقرار نہ رہے۔
میں نے restart: unless-stopped شامل کیا، لیکن reboot کے بعد کنٹینر پھر بھی شروع نہیں ہوتا۔ کیوں؟
یہ پالیسی file کے بجائے کنٹینر میں محفوظ ہوتی ہے، اور پہلے سے موجود کنٹینر YAML میں ترمیم کرنے سے update نہیں ہوتا۔ Compose سے کنٹینر دوبارہ بنوانے کے لیے docker compose up -d چلائیں، پھر docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app) سے تصدیق کریں۔ اگر اس کا output no ہو، تو کنٹینر آپ کی ترمیم سے پہلے کا ہے۔ دوسری عام وجہ یہ ہے کہ docker.service enabled نہیں ہے۔ آپ اسے systemctl is-enabled docker سے چیک کر سکتے ہیں۔
اگر میں restart policies پہلے ہی استعمال کر رہا ہوں تو کیا مجھے systemd unit کی ضرورت ہے؟
عام طور پر نہیں۔ ایسے stack کے لیے restart policy کافی ہے جسے صرف network درکار ہو، اور زیادہ تر stack اسی نوعیت کے ہوتے ہیں۔ جب کنٹینرز کسی ایسی چیز پر منحصر ہوں جو Docker daemon کے شروع ہونے کے وقت تیار نہ ہو، تو unit شامل کریں۔ مثال کے طور پر external disk، encrypted volume، NFS share، یا VPN interface۔ unit آپ کو After= اور RequiresMountsFor= کے ذریعے ترتیب متعین کرنے کی سہولت دیتی ہے، جس کا اظہار restart policy سے نہیں کیا جا سکتا۔
میں stack کو مستقل طور پر کیسے روکوں تاکہ اگلے reboot پر یہ دوبارہ شروع نہ ہو؟
unless-stopped کے ساتھ docker compose stop کافی ہے، کیونکہ دستی طور پر روکا گیا کنٹینر daemon کے دوبارہ شروع ہونے پر resume نہیں ہوتا۔ always کے ساتھ صرف stop کافی نہیں ہوتا، اور کنٹینر reboot کے بعد دوبارہ آ جاتا ہے۔ یا تو docker compose down چلائیں، جو کنٹینرز کو ہٹا دیتا ہے، یا پہلے docker update --restart no my-container کے ذریعے policy تبدیل کریں۔ اگر systemd unit stack کو manage کرتی ہے تو sudo systemctl disable myapp.service بھی چلائیں، ورنہ unit اسے دوبارہ شروع کر دے گی۔