Docker Compose-ஐ boot நேரத்தில் தானாகத் தொடங்குவது எப்படி
reboot பிறகு Docker Compose services மீண்டும் தொடங்க restart policy அமைப்பது, on-failure ஏன் போதாது, எப்போது systemd unit தேவை என்பதைக் கற்றுக்கொள்ளுங்கள்.
சுருக்கமான பதில்
Docker Compose services boot நேரத்தில் தொடங்க, இரண்டு நிபந்தனைகள் ஒரே நேரத்தில் பூர்த்தியாக வேண்டும். Docker daemon system service ஆக enable செய்யப்பட்டிருக்க வேண்டும். மேலும், file-இல் உள்ள ஒவ்வொரு service-க்கும் unless-stopped அல்லது always restart policy இருக்க வேண்டும். ஒவ்வொரு service-க்கும் restart: unless-stopped சேர்த்து, docker compose up -d என்பதை ஒருமுறை இயக்குங்கள். reboot முடிந்ததும் containers தானாகவே மீண்டும் தொடங்கும். பொதுவான நிலைக்கு வேறு எதுவும் தேவையில்லை.
Order முக்கியமானதாக இருக்கும் போது மட்டுமே systemd unit தேவைப்படும். உதாரணமாக, Docker daemon தொடங்கும் நேரத்தில் இன்னும் தயாராகாத mounted disk, VPN interface அல்லது network share மீது stack சார்ந்திருக்கலாம். இந்த நிலை நடைமுறையில் ஏற்படும். இந்த வழிகாட்டியின் இரண்டாம் பகுதியில் அதைப் பார்க்கலாம். Service definitions மற்றும் volumes குறித்து இன்னும் அறிமுகம் தேவைப்பட்டால், முதலில் VPS-இல் Docker Compose பற்றிய அடிப்படைகள் பகுதியைப் படித்துவிட்டு திரும்புங்கள்.
compose.yaml-ல் restart policy-யை அமைக்கவும்
இந்த policy ஒவ்வொரு service-க்கும் ஒரு வரியாக அமைக்கப்படுகிறது. உலகளாவிய switch எதுவும் இல்லை. எனவே நீங்கள் அமைக்க மறக்கும் service, reboot-க்கு பிறகு இயங்காமல் இருக்கும். Stack-இன் மற்ற பகுதிகள் இயங்கத் தொடங்கும்.
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 என்று அச்சிட்டால், கோப்பு திருத்தப்பட்டுள்ளது. ஆனால் container மீண்டும் உருவாக்கப்படவில்லை.
இதுவே மிகவும் பொதுவான தோல்வியாகும். restart policy, YAML கோப்பில் அல்ல; container-ல் சேமிக்கப்படுகிறது. ஏற்கனவே உள்ள container-க்கு compose.yaml-ஐத் திருத்துவது எந்த மாற்றத்தையும் ஏற்படுத்தாது. docker compose restart-ம் உதவாது. ஏனெனில் அது அதே container object-ஐ நிறுத்தி மீண்டும் தொடங்குகிறது. அதன் configuration-ஐ மாற்றாது. docker compose up -d மட்டுமே கோப்பை இயங்கும் containers-உடன் ஒப்பிடும். policy மாறியிருப்பதை கண்டறிந்து, containers-ஐ மீண்டும் உருவாக்கும்.
இப்போது மீண்டும் உருவாக்க விரும்பாத container-க்கு, policy-யை நேரடியாக மாற்றவும்:
docker update --restart unless-stopped my-containerYAML கோப்பையும் திருத்தவும். docker update இயங்கும் container-ஐ மாற்றும். அடுத்த docker compose up -d கோப்பிலிருந்து மதிப்பைப் படித்து, பழைய மதிப்பை மீண்டும் அமைக்கும்.
ஒவ்வொரு restart மதிப்பும் உண்மையில் செய்யும் செயல்
Docker நான்கு மதிப்புகளை வரையறுக்கிறது. அவற்றுக்கிடையிலான வேறுபாடு machine reboot ஆகும்போது அல்லது daemon restart செய்யப்படும்போது மட்டுமே வெளிப்படும்.
noஎன்பது default ஆகும். எந்தச் சூழ்நிலையிலும் container தானாக restart செய்யப்படாது.alwayscontainer நிறுத்தப்படும் ஒவ்வொரு முறையும் அதை restart செய்கிறது. அதை நீங்கள் கையால் நிறுத்தினாலும், அடுத்த முறை Docker daemon தொடங்கும்போது அது மீண்டும் தொடங்கும். இது அடிக்கடி எதிர்பாராத விளைவை ஏற்படுத்தும்: கடந்த வாரம் நீங்கள் திட்டமிட்டு நிறுத்திய container, reboot-க்கு பிறகு மீண்டும் இயங்கும்.unless-stopped,alwaysபோலவே செயல்படும். ஆனால் கையால் நிறுத்தப்பட்ட container, daemon restart செய்யப்பட்ட பிறகும் நிறுத்தப்பட்ட நிலையிலேயே இருக்கும். பராமரிப்புக்காக அவ்வப்போது நிறுத்த வேண்டிய service-க்கு இந்த மதிப்பைப் பயன்படுத்த வேண்டும்.on-failure, container non-zero exit code உடன் வெளியேறும்போது மட்டுமே அதை restart செய்கிறது.restart: on-failure:3போன்ற அமைப்பில் முயற்சிகளின் எண்ணிக்கைக்கு வரம்பு வைக்கலாம்.
server இயங்கும் போதெல்லாம் stack இயங்கிக்கொண்டிருக்க வேண்டும் என்றால், unless-stopped சரியான default ஆகும். நிறுத்தப்பட்ட நிலையில் container நீண்ட நேரம் இருக்காமல் தானாக மீண்டும் தொடங்க வேண்டும் என்றால் மட்டுமே always-ஐத் தேர்ந்தெடுக்கவும்.
ஏன் restart: on-failure reboot-ஐத் தாண்டி தொடராது
பலர் on-failure-ஐ கவனமாகத் தோன்றுவதால் தேர்வு செய்கிறார்கள். ஆனால் முதல் reboot-க்குப் பிறகு ஒவ்வொரு container-உம் stopped நிலையில் இருப்பதை அவர்கள் காண்கிறார்கள். இதற்கான காரணம் அதன் வரையறையிலேயே உள்ளது. on-failure ஒரே ஒரு நிகழ்வுக்கு மட்டுமே பதிலளிக்கிறது: container process பிழைக் code-உடன் வெளியேறுவது.
reboot என்பது பிழை அல்ல. host shutdown ஆகும்போது, systemd docker.service-ஐ நிறுத்துகிறது. பின்னர் daemon ஒவ்வொரு container-ஐயும் திட்டமிட்டு நிறுத்துகிறது. container fail ஆகவில்லை. எனவே அந்த policy-க்கு பதிலளிக்க வேண்டிய நிகழ்வு இல்லை. system மீண்டும் start ஆகும்போது, daemon resume செய்ய வேண்டிய container-களைப் பார்க்கிறது. சுத்தமாக நிறுத்தப்பட்ட on-failure container அவற்றில் ஒன்றாக இருக்காது. அது exited state-லேயே இருக்கும்.
இதை நேரடியாகக் காணலாம். ஒரு service-ல் restart: on-failure-ஐ அமைத்து, docker compose up -d-ஐ இயக்கி, reboot செய்த பிறகு, இதை இயக்கவும்:
docker compose ps -aஅந்த service Exited state-உடன், Exited (0) 2 minutes ago போன்ற status-உடன் பட்டியலிடப்படும். எதுவும் செயலிழக்கவில்லை. எந்தப் பிழையும் log செய்யப்படவில்லை. இதனால் இதைக் கண்டறிவது கடினமாகிறது. அந்த policy தன் வரையறைப்படியே செயல்பட்டது.
on-failure இன்னும் பயனுள்ளதாக உள்ளது. ஒரு job-ஐ இயக்கும் container அவ்வப்போது crash ஆகக்கூடிய சூழலில் இது பொருத்தமானது. அங்கு retry எண்ணிக்கையை வரையறுக்கவும் restart loop-ஐத் தவிர்க்கவும் முடியும். ஆனால் reboot-களுக்குப் பிறகும் நீண்ட நேரம் இயங்கும் service-ஐ alive நிலையில் வைத்திருக்க இது சரியான கருவி அல்ல.
Docker service boot நேரத்தில் தொடங்கினால் மட்டுமே restart policies செயல்படும்
Restart policies-ஐ Docker daemon செயல்படுத்துகிறது. Daemon தொடங்கவில்லை என்றால், எதுவும் செயல்படுத்தப்படாது. இதைச் சரிபார்க்கவும்:
systemctl is-enabled docker
systemctl is-enabled containerdஇரண்டும் enabled என்பதை வெளியிட வேண்டும். Docker-ன் அதிகாரப்பூர்வ repository-யிலிருந்து கிடைக்கும் packages, installation நேரத்திலேயே இவற்றை enable செய்கின்றன. எனவே புதிய server-ல் இது வழக்கமாக வெற்றியடையும். ஏதேனும் ஒன்று disabled என்பதை வெளியிட்டால், அதைச் சரிசெய்யவும்:
sudo systemctl enable --now docker containerdஇங்கே புரிந்துகொள்ள வேண்டிய ஒரு சிக்கல் உள்ளது. Ubuntu, docker.socket-ஐயும் வழங்குகிறது. ஏதேனும் ஒன்று Docker API-யுடன் முதன்முறையாக தொடர்பு கொள்ளும்போது, இது daemon-ஐ தேவைக்கேற்ப தொடங்குகிறது. docker.socket enabled நிலையில் இருப்பதைப் பார்த்து, daemon பாதுகாக்கப்பட்டுள்ளது என்று கருதி, memory-ஐ சேமிக்க docker.service-ஐ disable செய்கிறார்கள். Boot நேரத்தில் API-ஐ அழைக்கும் எதுவும் இல்லை. எனவே socket அணுகப்படாது, daemon தொடங்காது, மேலும் நீங்கள் முதல் docker command-ஐ உள்ளிடும் வரை எந்த container-உம் தொடங்காது. Socket activation என்பது docker.service enabled நிலையில் இருப்பதற்கான மாற்று அல்ல.
systemd unit சிறந்த தீர்வாக இருக்கும் நிலைகள்
Restart policies-க்கு, கணினியின் பிற பகுதிகளுடன் செயல்பாட்டு வரிசையை ஒருங்கிணைக்கும் திறன் இல்லை. Daemon தொடங்கியவுடன், முடிந்த விரைவில் உங்கள் containers-ஐ அது தொடங்கும். உங்கள் stack, தனி volume, NFS (network file system) share அல்லது encrypted disk-இலிருந்து ஒரு directory-ஐ bind-mount செய்தால், அந்த path உருவாகும் முன்பே containers தொடங்கக்கூடும். Docker mount point-இல் காலியான directory-ஐ உருவாக்கி, அதைப் பயன்படுத்தி container-ஐ தொடங்கிவிடும். இதனால் உங்கள் database தரவு இல்லாமல் தொடங்கும்.
பின்வரும் நிலைகளில் ஏதேனும் ஒன்று இருந்தால் systemd unit-ஐ எழுதுங்கள். Stack இயங்குவதற்கு முன் mount, VPN interface அல்லது வேறு unit தயாராக இருக்க வேண்டும். கணினியில் உள்ள மற்ற services போலவே systemctl stop myapp மற்றும் systemctl start myapp செயல்பட வேண்டும் என்று நீங்கள் விரும்புகிறீர்கள். அல்லது shutdown நேரத்தில் daemon-உடன் சேர்த்து கட்டாயமாக நிறுத்தப்படுவதற்குப் பதிலாக, stack முறையாகக் கீழிறக்கப்பட வேண்டும் என்று விரும்புகிறீர்கள். systemd units உங்களுக்கு புதியதாக இருந்தால், systemd service மற்றும் timer எழுதுதல் கோப்பு வடிவத்தை மேலும் விரிவாக விளக்குகிறது.
systemd unit எழுதுதல்
Stack-ஐ home directory-க்கு வெளியே உள்ள நிலையான பாதையில் வைக்கவும். /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 செய்து தொடங்கவும்:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.serviceசரியாக இயங்கும் unit, Active: active (exited) என்பதைக் காட்டும். இதை முதன்முறையாகப் பார்க்கும்போது இது தவறாகத் தோன்றும். ஆனால் இது சரியான நிலை. Type=oneshot உடன் RemainAfterExit=yes இருப்பது, unit தனது command-ஐ இயக்கி முடித்துவிட்டது என்பதைக் குறிக்கும். மேலும், systemd அந்த unit-ஐ active நிலையில் வைத்திருக்கும். இதனால் shutdown நேரத்தில் ExecStop இயங்கும்.
ஒவ்வொரு வரிக்கும் தேவையான காரணம் உள்ளது. Requires=docker.service என்பதால், செயலிழந்த socket-க்கு எதிராக docker compose இயக்குவதற்குப் பதிலாக unit உடனடியாகத் தோல்வியடையும். After= வரிசையை அமைக்கிறது. ஏனெனில் Requires= மட்டும் வரிசையை அமைக்காது. RequiresMountsFor= அந்தப் பாதைக்கான mount unit-ஐ systemd உள்ளிழுத்து, அது தயாராகும் வரை காத்திருக்கச் செய்கிறது. Restart policy-க்கு பதிலாக unit-ஐப் பயன்படுத்துவதற்கான முக்கிய காரணம் இதுவே. பெரிய image இன்னும் pull செய்யப்படும் போது start job-ஐ systemd நிறுத்தாமல் இருக்க TimeoutStartSec=0 உதவுகிறது.
இரண்டு mechanisms-ஐ இணைப்பது குறித்த குறிப்பு. Restart policies-ஐ host process manager உடன் கலக்க வேண்டாம் என்று Docker-ன் documentation பரிந்துரைக்கிறது. Container process-ஐ நேரடியாகக் கண்காணித்து, daemon அதையே செய்ய முயற்சிக்கும் போது அதை மீண்டும் தொடங்கும் process manager பற்றியே அந்த எச்சரிக்கை கூறுகிறது. Type=oneshot unit எதையும் கண்காணிக்காது. எனவே, இந்த unit-உடன் சேர்த்து compose file-ல் restart: unless-stopped வைத்திருப்பது சரியானது. நீங்கள் விரும்புவதும் அதுவே. Boot நேரத்தில் systemd வரிசையை நிர்வகிக்கும். Daemon அதிகாலை 3 மணிக்கு crash ஆகும் container-ஐ நிர்வகிக்கும்.
உண்மையான reboot மூலம் சரிபார்க்கவும்
உண்மையான சோதனைக்கு மாற்று எதுவும் இல்லை. systemctl restart docker mount வரிசையைச் சோதிக்காது. docker compose down-ஐத் தொடர்ந்து docker compose up -d இயக்குவதும் boot தொடர்பான எதையும் சோதிக்காது.
sudo rebootகாத்திருந்து, மீண்டும் இணைந்து, பின்வரும் வரிசையில் சரிபார்க்கவும்:
uptime
systemctl is-active docker
docker compose psuptime மூலம் உண்மையில் reboot செய்யப்பட்ட machine-ஐப் பார்க்கிறீர்கள் என்பதை உறுதிப்படுத்தலாம். stack directory-யிலிருந்து இயக்கப்படும் docker compose ps, ஒவ்வொரு service-ஐயும் running நிலையில், machine-ன் uptime-க்கு நெருக்கமான 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-ஐக் காட்டும். இதில் தோல்வியடைந்த image pull அல்லது காணாமல் போன .env file ஆகியவையும் அடங்கும்.
auto-start அமைதியாக செயலிழக்கச் செய்யும் காரணங்கள்
docker compose run கொண்டு உருவாக்கப்பட்ட Containers, file-இல் குறிப்பிடப்பட்ட restart policy-ஐ பெறாது. Compose அவற்றை one-off containers ஆகக் கருதுகிறது. ஒரு service தனது policy-ஐ புறக்கணிப்பது போல் தெரிந்தால், அது up-க்கு பதிலாக run கொண்டு தொடங்கப்பட்டதா என்பதைச் சரிபார்க்கவும்.
ஒரு volume-இல் அல்லது env_file entry-இல் உள்ள relative path, compose file இருக்கும் directory-ஐ அடிப்படையாகக் கொண்டு தீர்மானிக்கப்படுகிறது. இது உங்கள் shell-இலிருந்து இயங்கும். WorkingDirectory அமைக்கும் unit-இலிருந்தும் இது இயங்கும். ஆனால் WorkingDirectory இல்லாத unit-இலிருந்து இது தோல்வியடையும். அப்போது working directory / ஆக இருக்கும்.
Rootless Docker தனியான நிலையாகும். Daemon user service ஆக இயங்கும். அந்த user-க்கான கடைசி session முடிந்ததும் user service நிறுத்தப்படும். அதை அந்த user-க்காக enable செய்து, யாரும் login செய்யாதபோதும் இயங்க அனுமதிக்கவும்:
systemctl --user enable docker
sudo loginctl enable-linger $USERenable-linger இல்லாமல், நீங்கள் logout செய்யும்போது rootless daemon நிறுத்தப்படும். அதனுடன் containers-உம் நிறுத்தப்படும். இது restart policy செயலிழந்தது போல் தோன்றும்.
இறுதியாக ஒரு விஷயம். Automatic security updates, நிர்ணயிக்கப்பட்ட நேரத்தில் server-ஐ reboot செய்யக்கூடும். உங்கள் stack தானாகவே மீண்டும் தொடங்கினால் மட்டுமே இது பயனுள்ளதாக இருக்கும். புதிய machine-இல் இதை அமைப்பது, முதல் ஒரு மணி நேர பணிகளின் மற்ற பகுதிகளுடன் சேர்ந்து புதிய VPS-இல் முதல் பத்து நிமிடங்கள் செய்ய வேண்டியதாகும்.
FAQ
restart: always மற்றும் restart: unless-stopped ஆகியவற்றுக்கு என்ன வித்தியாசம்?
Container தானாக நிறுத்தப்படும்போது, இரண்டும் அதை மீண்டும் தொடங்கும். Container-ஐ கைமுறையாக நிறுத்திய பிறகு அவை வேறுபடுகின்றன. always பயன்படுத்தினால், Docker daemon அடுத்த முறை தொடங்கும்போது container மீண்டும் தொடங்கும். எனவே reboot உங்கள் கைமுறை நிறுத்தலை நீக்கிவிடும். unless-stopped பயன்படுத்தினால், container திட்டமிட்டு நிறுத்தப்பட்டது என்பதை daemon நினைவில் வைத்துக்கொண்டு, அதை மீண்டும் தொடங்காது. Container தொடர்ந்து நிறுத்தப்பட்ட நிலையில் இருக்க வேண்டும் என்ற சிறப்பு தேவையில்லையெனில் unless-stopped பயன்படுத்தவும்.
restart: unless-stopped சேர்த்த பிறகும் reboot முடிந்ததும் container தொடங்கவில்லை. ஏன்?
இந்த policy file-ல் அல்ல, container-ல் சேமிக்கப்படுகிறது. ஏற்கனவே உள்ள container, YAML-ஐத் திருத்துவதால் புதுப்பிக்கப்படாது. Compose அதை மீண்டும் உருவாக்குவதற்காக docker compose up -d இயக்கவும். பின்னர் docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app) மூலம் சரிபார்க்கவும். அதன் வெளியீடு no என இருந்தால், அந்த container உங்கள் திருத்தத்திற்கு முன்பே உருவாக்கப்பட்டது. மற்றொரு பொதுவான காரணம் docker.service enable செய்யப்படாதது. இதை systemctl is-enabled docker மூலம் சரிபார்க்கலாம்.
ஏற்கனவே restart policies பயன்படுத்தினால் systemd unit தேவையா?
பொதுவாக தேவையில்லை. Network மட்டும் தேவைப்படும் stack-க்கு restart policy போதுமானது. பெரும்பாலான stack-கள் இப்படித்தான் இயங்குகின்றன. Docker daemon தொடங்கும்போது தயாராக இல்லாத ஒன்றை container-கள் சார்ந்திருந்தால் unit-ஐச் சேர்க்கவும். எடுத்துக்காட்டாக, external disk, encrypted volume, NFS share அல்லது VPN interface ஆகியவை இதுபோன்ற சார்புகளாகும். Restart policy மூலம் வெளிப்படுத்த முடியாத startup order-ஐ After= மற்றும் RequiresMountsFor= வழியாக unit வழங்குகிறது.
அடுத்த reboot-ல் மீண்டும் தொடங்காமல் stack-ஐ நிரந்தரமாக எவ்வாறு நிறுத்துவது?
unless-stopped பயன்படுத்தினால் docker compose stop போதுமானது. ஏனெனில் கைமுறையாக நிறுத்தப்பட்ட container, daemon மீண்டும் தொடங்கும்போது மீண்டும் தொடங்கப்படாது. always பயன்படுத்தினால் stop மட்டும் போதாது; reboot பிறகு container மீண்டும் தொடங்கும். Containers-ஐ அகற்றும் docker compose down இயக்கவும் அல்லது முதலில் docker update --restart no my-container மூலம் policy-ஐ மாற்றவும். systemd unit stack-ஐ நிர்வகித்தால் sudo systemctl disable myapp.service ஐயும் இயக்கவும். இல்லையெனில் unit அதை மீண்டும் தொடங்கும்.