Docker Compose: auto-start ang services sa boot
Paano ibalik ang Docker Compose services pagkatapos ng reboot gamit ang restart policies, bakit hindi sapat ang on-failure, at kailan kailangan ang systemd unit.
Ang maikling sagot
Awtomatikong nagsisimula sa boot ang mga serbisyo ng Docker Compose kapag parehong natutupad ang dalawang kondisyon. Kailangang naka-enable ang Docker daemon bilang system service, at kailangang may restart policy na unless-stopped o always ang bawat serbisyo sa file. Idagdag ang restart: unless-stopped sa bawat serbisyo, patakbuhin ang docker compose up -d nang isang beses, at awtomatikong babalik ang mga container pagkatapos ng reboot. Wala nang ibang kailangan sa karaniwang sitwasyon.
Kailangan mo lamang ng systemd unit kapag mahalaga ang pagkakasunod-sunod: halimbawa, kapag nakadepende ang stack sa naka-mount na disk, VPN interface, o network share na hindi pa handa sa oras na magsimula ang Docker daemon. Totoo at mahalaga ang sitwasyong ito, at tinatalakay ito sa ikalawang bahagi ng gabay na ito. Kung inaalam mo pa ang mga service definition at volume, magsimula sa mga pangunahing konsepto ng Docker Compose sa isang VPS at bumalik dito.
Itakda ang restart policy sa compose.yaml
Isang linya ang policy para sa bawat service. Walang global switch, kaya mananatiling down pagkatapos ng reboot ang service na nakalimutan mo, habang umaandar muli ang natitirang 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:I-apply ito, pagkatapos ay basahin ang policy mula sa tumatakbong container:
docker compose up -d
docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app)Ipi-print nito ang unless-stopped. Kung no ang ma-print nito, na-edit ang file pero hindi kailanman na-recreate ang container.
Ito ang pinakakaraniwang failure. Naka-store ang restart policy sa container, hindi sa YAML file. Walang binabago ang pag-edit sa compose.yaml sa container na mayroon na. Hindi rin nakatutulong ang docker compose restart, dahil pinatitigil at pinapaandar lang nito ang parehong container object nang hindi binabago ang configuration nito. docker compose up -d lamang ang nagko-compare sa file sa mga tumatakbong container, nakapapansin na nagbago ang policy, at nagre-recreate sa mga ito.
Para sa container na ayaw mong i-recreate ngayon, baguhin ang policy nang direkta:
docker update --restart unless-stopped my-containerI-edit pa rin ang YAML file. Binabago ng docker update ang live container, at babasahin ng susunod na docker compose up -d ang file at ibabalik ang dating value.
Ang aktuwal na ginagawa ng bawat restart value
Tinutukoy ng Docker ang apat na value. Lumilitaw lamang ang pagkakaiba ng mga ito kapag nag-reboot ang machine o nag-restart ang daemon.
noang default. Hindi kailanman awtomatikong nire-restart ang container, anuman ang mangyari.- Nire-restart ng
alwaysang container tuwing humihinto ito. Kung mano-mano mo itong itinigil, bumabalik pa rin ito sa susunod na mag-start ang Docker daemon. Madalas itong nakakagulat: ang container na sadyang itinigil mo noong nakaraang linggo ay tumatakbo na muli pagkatapos ng reboot. - Katulad ng
alwaysang pagkilos ngunless-stopped, maliban kung mananatiling nakahinto ang container na mano-mano mong itinigil kahit mag-restart ang daemon. Ito ang dapat gamitin para sa service na paminsan-minsan mong ihihinto para sa maintenance. - Nire-restart lamang ng
on-failureang container kapag lumabas ito na may non-zero exit code. Maaari mong limitahan ang bilang ng mga pagtatangka, gaya ng nasarestart: on-failure:3.
Para sa stack na dapat laging tumatakbo kapag tumatakbo ang server, unless-stopped ang tamang default. Piliin lamang ang always kung gusto mo ng container na hindi basta mananatiling nakahinto.
Bakit nagre-restart: hindi nagpapatuloy ang on-failure pagkatapos ng reboot
Maraming tao ang pumipili sa on-failure dahil maingat itong pakinggan, ngunit nakikita nilang lahat ng container ay stopped pagkatapos ng unang reboot. Nasa definition ang dahilan. Isang bagay lang ang tinutugunan ng on-failure: ang pag-exit ng container process na may error code.
Hindi error ang reboot. Kapag nag-shutdown ang host, itinitigil ng systemd ang docker.service, at sadyang itinitigil ng daemon ang bawat container. Hindi nag-fail ang container, kaya walang tutugunan ang policy. Sa pag-start muli ng system, tinitingnan ng daemon ang mga container na kailangan nitong i-resume, at hindi kasama rito ang on-failure container na malinis na itinigil. Nananatili ito sa exited state.
Makikita mo ito nang direkta. Itakda ang restart: on-failure sa isang service, patakbuhin ang docker compose up -d, mag-reboot, pagkatapos ay patakbuhin:
docker compose ps -aNakalista ang service na may state na Exited at status na gaya ng Exited (0) 2 minutes ago. Walang sira at walang naka-log na error, kaya mahirap itong i-diagnose. Ginawa ng policy ang eksaktong sinasabi nito.
Kapaki-pakinabang pa rin ang on-failure. Angkop ito sa container na nagpapatakbo ng isang job at maaaring mag-crash, kapag gusto mo ng limitadong bilang ng retries at walang restart loop. Mali itong gamitin para panatilihing tumatakbo ang isang long-running service pagkatapos ng mga reboot.
Gumagana lamang ang mga restart policy kung nagsisimula ang Docker service sa pag-boot
Ipinapatupad ng Docker daemon ang mga restart policy. Kung hindi magsisimula ang daemon, walang magpapatupad sa mga ito. Suriin ito:
systemctl is-enabled docker
systemctl is-enabled containerdDapat mag-print ang parehong command ng enabled. Pinapagana ng mga package mula sa opisyal na repository ng Docker ang mga ito kapag ini-install, kaya karaniwang pumapasa ito sa bagong server. Kung disabled ang i-print ng alinman, ayusin ito:
sudo systemctl enable --now docker containerdMay isang mahalagang pitfall dito. Kasama rin sa Ubuntu ang docker.socket, na nagsisimula sa daemon kapag hinihingi sa unang pagkakataong may kumonekta sa Docker API. Nakikita ng mga tao na naka-enable ang docker.socket, ipinapalagay nilang nasasaklaw ang daemon, at dini-disable ang docker.service para makatipid ng memory. Sa pag-boot, walang tumatawag sa API, kaya hindi naa-access ang socket, hindi nagsisimula ang daemon, at walang container na umaandar hanggang i-type mo ang una mong command na docker. Hindi kapalit ng pag-enable sa docker.service ang socket activation.
Kailan mas angkop ang systemd unit
Walang konsepto ang mga restart policy ng pagkakasunod-sunod kaugnay ng iba pang bahagi ng system. Nagsisimula ang daemon at inaakyat nito ang iyong mga container sa lalong madaling panahon. Kung nagba-bind-mount ang iyong stack ng directory mula sa hiwalay na volume, isang NFS (network file system) share, o isang naka-encrypt na disk, maaaring magsimula ang mga container bago maging available ang path. Awtomatikong makagagawa ang Docker ng walang lamang directory sa mount point at sisimulan ang container gamit ito. Dahil dito, maaaring mag-start ang iyong database nang walang data.
Sumulat ng systemd unit kapag naaangkop ang alinman sa mga sumusunod. Kailangan munang maging handa ang isang mount, VPN interface, o ibang unit bago magsimula ang stack. Gusto mong gumana ang systemctl stop myapp at systemctl start myapp gaya ng sa lahat ng iba pang service sa system. O gusto mong maayos na ihinto ang stack sa panahon ng shutdown sa halip na patayin ito kasabay ng daemon. Kung bago sa iyo ang systemd units, mas detalyadong ipinapaliwanag ng pagsulat ng systemd service at timer ang format ng file.
Pagsulat ng systemd unit
Ilagay ang stack sa isang nakapirming path sa labas ng home directory. Magandang piliin ang /srv/myapp, dahil walang dahilan para basahin ng unit na tumatakbo bago mag-login ang sinuman ang /home.
Gawin ang /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.targetI-enable at simulan ito:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.serviceAng maayos na unit ay nagpapakita ng Active: active (exited). Maaaring magmukhang mali ito sa unang pagkakataong makita mo. Tama ito: ang Type=oneshot kasama ang RemainAfterExit=yes ay nangangahulugang pinatakbo ng unit ang command nito, natapos ang command, at pinananatiling active ng systemd ang unit upang tumakbo ang ExecStop sa shutdown.
May dahilan ang bawat linya. Ang Requires=docker.service ay nangangahulugang mabilis na mabibigo ang unit sa halip na patakbuhin ang docker compose laban sa patay na socket. Itinatakda ng After= ang pagkakasunud-sunod, dahil hindi ito ginagawa ng Requires= nang mag-isa. Ipinapakuha ng RequiresMountsFor= sa systemd ang mount unit para sa path na iyon at hinihintay ito. Ito ang pangunahing dahilan kung bakit unit ang ginagamit sa halip na restart policy. Pinipigilan ng TimeoutStartSec=0 ang systemd na patayin ang start job habang kinukuha pa ang malaking image.
Tungkol sa pagsasama ng dalawang mekanismo. Hindi inirerekomenda ng dokumentasyon ng Docker ang pagsasama ng restart policies sa isang host process manager. Ang babalang iyon ay para sa process manager na direktang nagsa-supervise sa container process at nagre-restart dito habang pareho ring ginagawa iyon ng daemon. Walang sinusu-supervise ang Type=oneshot unit, kaya ayos lang na panatilihin ang restart: unless-stopped sa compose file kasabay ng unit na ito, at ito ang kailangan mo. Pinamamahalaan ng systemd ang pagkakasunud-sunod sa boot, at pinamamahalaan ng daemon ang container kapag nag-crash ito nang alas-tres ng umaga.
Mag-verify gamit ang aktuwal na reboot
Walang kapalit ang aktuwal na pagsubok. Hindi sinusubukan ng systemctl restart docker ang pagkakasunod-sunod ng pag-mount, at ang docker compose down na sinusundan ng docker compose up -d ay walang sinusubukan tungkol sa boot.
sudo rebootMaghintay, kumonekta muli, at magsagawa ng pagsusuri sa ganitong pagkakasunod-sunod:
uptime
systemctl is-active docker
docker compose psKinukumpirma ng uptime na tumitingin ka sa isang machine na tunay na nag-reboot. Ang docker compose ps, kapag pinatakbo mula sa stack directory, ay dapat maglista sa bawat service bilang running na may uptime na malapit sa uptime ng machine. Ang service na nagpapakita ng Exited ang dapat suriin.
Kung may hindi nag-start, saklaw ng daemon log ang boot window:
journalctl -u docker.service -b --no-pager | tail -50Para sa stack na pinamamahalaan ng isang unit, ipinapakita ng journalctl -u myapp.service -b --no-pager ang eksaktong docker compose output mula sa boot, kasama ang failed image pull o nawawalang .env file.
Mga bagay na tahimik na nakakasira sa auto-start
Ang mga container na ginawa gamit ang docker compose run ay hindi kailanman kumukuha ng restart policy mula sa file. Itinuturing ng Compose ang mga ito bilang one-off container. Kung tila binabalewala ng isang service ang policy nito, tingnan kung sinimulan ito gamit ang run sa halip na up.
Ang relative path sa isang volume o sa isang entry na env_file ay nire-resolve batay sa directory ng compose file. Gumagana ito mula sa iyong shell, at gumagana rin ito mula sa isang unit na nagse-set ng WorkingDirectory. Nabibigo ito mula sa isang unit na walang ganitong setting dahil ang working directory ay /.
Hiwalay na kaso ang rootless Docker. Tumatakbo ang daemon bilang user service, at humihinto ang user service kapag nagwakas ang huling session ng user na iyon. I-enable ito para sa user at payagan itong magpatuloy sa pagtakbo kahit walang naka-log in:
systemctl --user enable docker
sudo loginctl enable-linger $USERKung wala ang enable-linger, nagsasara ang rootless daemon kapag nag-log out ka, at sumasara rin ang mga container. Mukha itong eksaktong sirang restart policy.
May isa pang bagay. Maaaring mag-reboot ang server dahil sa mga automatic security update sa itinakdang oras. Mabuti lamang ito kung awtomatikong bumabalik ang iyong stack. Ang pag-set up nito sa bagong machine ay kabilang sa iba pang gawain sa unang oras sa unang sampung minuto sa bagong VPS.
FAQ
Ano ang pagkakaiba ng restart: always at restart: unless-stopped?
Pareho nilang nire-restart ang container kapag kusa itong huminto. Nagkakaiba sila kapag mano-mano mong pinahinto ang container. Sa always, muling nagsisimula ang container sa susunod na pag-start ng Docker daemon, kaya binabawi ng reboot ang mano-mano mong pagpapahinto. Sa unless-stopped, natatandaan ng daemon na sadyang pinahinto ang container at hindi ito muling sinisimulan. Gamitin ang unless-stopped maliban kung partikular mong kailangan ng container na mananatiling naka-stop.
Nagdagdag ako ng restart: unless-stopped pero hindi pa rin nagsisimula ang container pagkatapos ng reboot. Bakit?
Nasa container ang policy, hindi sa file, at hindi ina-update ng pag-edit ng YAML ang dati nang container. Patakbuhin ang docker compose up -d upang muling likhain ito ng Compose, pagkatapos ay kumpirmahin gamit ang docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app). Kung no ang output, nauna nang ginawa ang container bago mo na-edit ang file. Ang isa pang karaniwang sanhi ay hindi naka-enable ang docker.service, na maaari mong suriin gamit ang systemctl is-enabled docker.
Kailangan ko ba ng systemd unit kung gumagamit na ako ng restart policies?
Karaniwan, hindi. Sapat ang restart policy para sa stack na network lamang ang kailangan, at ito ang karamihan sa mga stack. Magdagdag ng unit kapag nakadepende ang mga container sa isang bagay na hindi pa handa kapag nagsisimula ang Docker daemon, gaya ng external disk, encrypted volume, NFS share, o VPN interface. Nagbibigay ang unit ng ordering sa pamamagitan ng After= at RequiresMountsFor=, na hindi kayang ipahayag ng restart policy.
Paano ko permanenteng ihihinto ang stack nang hindi ito muling nagsisimula sa susunod na reboot?
Sa unless-stopped, sapat na ang docker compose stop dahil hindi awtomatikong ipinagpapatuloy ang container na mano-manong pinahinto kapag nag-restart ang daemon. Sa always, hindi sapat ang pagpapahinto at babalik ang container pagkatapos ng reboot. Patakbuhin ang docker compose down upang alisin ang mga container, o baguhin muna ang policy gamit ang docker update --restart no my-container. Kung systemd unit ang namamahala sa stack, patakbuhin din ang sudo systemctl disable myapp.service; kung hindi, sisimulan itong muli ng unit.