Paano Awtomatikong Mag-start ang Docker Compose sa Boot
Alamin kung kailan gagamit ng restart: always o unless-stopped, bakit hindi sapat ang on-failure sa reboot, at kailan kailangan ang systemd unit.
Ang maikling sagot
Awtomatikong nagsisimula sa boot ang mga Docker Compose service 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 service sa file. Idagdag ang restart: unless-stopped sa bawat service, patakbuhin nang isang beses ang docker compose up -d, at awtomatikong babalik ang mga container pagkatapos ng reboot. Wala nang ibang kailangan sa karaniwang kaso.
Kailangan mo lang ng systemd unit kapag mahalaga ang pagkakasunod-sunod: halimbawa, kapag nakadepende ang isang stack sa naka-mount na disk, VPN interface, o network share na hindi pa handa nang magsimula ang Docker daemon. Totoo ang ganitong kaso, at tinatalakay ito sa ikalawang bahagi ng gabay na ito. Kung pinag-aaralan mo pa ang mga service definition at volume, magsimula sa mga pangunahing kaalaman sa Docker Compose sa VPS at bumalik dito.
Itakda ang restart policy sa compose.yaml
Isang linya ang policy para sa bawat service. Walang global switch, kaya mananatiling naka-down pagkatapos ng reboot ang service na nakalimutan mong i-configure habang umaandar ang iba pang bahagi ng 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:Ilapat 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 mai-print nito, na-edit ang file pero hindi muling ginawa 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 umiiral na. Hindi rin nakatutulong ang docker compose restart dahil ihihinto at sisimulan lamang nito ang parehong container object nang hindi binabago ang configuration nito. Tanging docker compose up -d ang naghahambing sa file at sa tumatakbong mga container, nakapapansin na nagbago ang policy, at muling lumilikha sa mga ito.
Para sa container na ayaw mong muling likhain ngayon, baguhin ang policy nito habang tumatakbo:
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.
Ano ang aktuwal na ginagawa ng bawat restart value
May apat na value ang Docker. Lumilitaw lamang ang pagkakaiba ng mga ito kapag nag-reboot ang machine o nag-restart ang daemon.
noang default. Hindi awtomatikong nire-restart ang container sa anumang sitwasyon.alwaysnire-restart ang container sa tuwing hihinto ito. Kung manu-mano mo itong pinahinto, muli pa rin itong magsisimula sa susunod na pag-start ng Docker daemon. Madalas itong nakapagtataka: tumatakbo muli pagkatapos ng reboot ang container na sinadya mong ihinto noong nakaraang linggo.unless-stoppeday gumagana gaya ngalways, maliban kung mananatiling nakahinto ang container na manu-mano mong pinahinto kahit mag-restart ang daemon. Ito ang dapat gamitin para sa serbisyong paminsan-minsan mong pinapahinto para sa maintenance.on-failurenire-restart lamang ang container kapag nag-exit 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 palaging gumagana kapag gumagana ang server, unless-stopped ang tamang default. Piliin lamang ang always kung gusto mong pigilan ang container na manatiling nakahinto.
Bakit hindi nananatili ang on-failure pagkatapos ng reboot
Maraming gumagamit ng on-failure dahil mukhang maingat itong opsyon, ngunit pagkatapos ng unang reboot, makikitang naka-stop ang bawat container. Nasa definition ang dahilan. Isang bagay lamang 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 muling pag-start ng system, sinusuri ng daemon ang mga container na kailangan nitong i-resume. Hindi kabilang dito ang on-failure container na malinis na na-stop. 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, at pagkatapos ay patakbuhin ang:
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. Eksaktong ginawa ng policy ang nakasaad dito.
Kapaki-pakinabang pa rin ang on-failure. Angkop ito sa container na nagpapatakbo ng job at maaaring mag-crash, kung saan gusto mo ng limitadong bilang ng retries at walang restart loop. Maling tool ito para panatilihing tumatakbo ang isang long-running service pagkatapos ng reboot.
Gumagana lamang ang restart policies kung nagsisimula ang Docker service sa boot
Ipinapatupad ng Docker daemon ang restart policies. Kung hindi nagsisimula ang daemon, walang nagpapatupad sa mga ito. Suriin ito:
systemctl is-enabled docker
systemctl is-enabled containerdDapat parehong mag-print ang mga ito ng enabled. Ine-enable ng mga package mula sa official repository ng Docker ang mga ito sa oras ng installation, kaya karaniwan itong pumapasa sa bagong server. Kung disabled ang i-print ng alinman sa mga ito, ayusin ito:
sudo systemctl enable --now docker containerdMay isang mahalagang trap dito. Kasama rin sa Ubuntu ang docker.socket, na nagsisimula sa daemon kapag may unang kumonekta sa Docker API. Nakikita ng mga user na naka-enable ang docker.socket, ipinapalagay nilang awtomatikong napoprotektahan ang daemon, at dini-disable ang docker.service para makatipid ng memory. Sa boot, walang kumokonekta sa API. Kaya hindi naa-access ang socket, hindi nagsisimula ang daemon, at walang container na umaandar hanggang sa i-type mo ang una mong docker command. Hindi kapalit ng pag-enable sa docker.service ang socket activation.
Kapag mas angkop ang systemd unit
Walang konsepto ang restart policy ng pagkakasunod-sunod nito kaugnay ng ibang bahagi ng system. Magsisimula ang daemon at iaangat nito ang mga container sa lalong madaling panahon. Kung gumagamit ang stack ng bind mount mula sa hiwalay na volume, NFS (network file system) share, o encrypted disk, maaaring magsimula ang mga container bago maging available ang path. Kusang gagawa ang Docker ng walang-lamang directory sa mount point at sisimulan ang container gamit iyon. Dahil dito, magsisimula ang database nang walang data.
Gumawa ng systemd unit kung naaangkop ang alinman sa mga sumusunod. Kailangang handa muna ang mount, VPN interface, o ibang unit bago magsimula ang stack. Gusto mong gumana ang systemctl stop myapp at systemctl start myapp tulad ng paggana ng mga ito sa iba pang service sa server. O gusto mong maayos na maibaba ang stack habang nagshu-shutdown, sa halip na mapatay kasama 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 fixed path sa labas ng home directory. Magandang piliin ang /srv/myapp, dahil walang dahilan ang isang unit na tumatakbo bago mag-log in ang sinuman na magbasa ng /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 isang healthy na unit ay nagpapakita ng Active: active (exited). Mukhang mali ito sa unang pagkakataong makita mo. Tama ito: ang Type=oneshot na may RemainAfterExit=yes ay nangangahulugang pinatakbo ng unit ang command nito, natapos ang command, at pinananatili ng systemd na active ang unit upang tumakbo ang ExecStop kapag nag-shutdown.
May dahilan ang bawat linya. Ibig sabihin ng Requires=docker.service, mabilis na magfa-fail ang unit sa halip na patakbuhin ang docker compose laban sa dead socket. Itinatakda ng After= ang order, dahil hindi ito ginagawa ng Requires= nang mag-isa. Dahil sa RequiresMountsFor=, isinasama ng 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 patigilin ang start job habang kinukuha pa ang malaking image.
Tungkol sa pagsasama ng dalawang mekanismo. Hindi inirerekomenda ng documentation ng Docker ang paghahalo ng restart policies at host process manager. Ang babalang iyon ay para sa process manager na direktang nagso-supervise sa container process at nagre-restart dito habang ginagawa rin iyon ng daemon. Walang sini-supervise ang isang Type=oneshot unit, kaya ayos lang na panatilihin ang restart: unless-stopped sa compose file kasama ng unit na ito, at iyon ang kailangan mo. Hinahawakan ng systemd ang ordering sa boot, habang hinahawakan naman ng daemon ang container na nag-crash nang alas-tres ng madaling-araw.
Iba ang anyo ng unit kapag plain long-running process ang pinananatiling tumatakbo, sa halip na isang stack, dahil walang daemon sa ilalim nito. Kailangang gamitin ng systemd ang sarili nitong Restart= para sa supervision; isang gumaganang halimbawa nito ang pagpapatakbo ng dsh nang headless sa likod ng systemd, kasama ang dedicated user at journal.
Tiyakin gamit ang aktuwal na reboot
Walang kapalit ang aktuwal na pagsubok. Hindi sinusubukan ng systemctl restart docker ang mount ordering, at wala ring sinusubukan tungkol sa boot ang docker compose down na sinusundan ng docker compose up -d.
sudo rebootMaghintay, kumonekta muli, at magsuri sa ganitong pagkakasunod-sunod:
uptime
systemctl is-active docker
docker compose psTinitiyak ng uptime na tinitingnan mo ang isang machine na talagang nag-reboot. Ang docker compose ps, kapag pinatakbo mula sa stack directory, ay dapat maglista ng bawat service bilang running, na ang uptime ay malapit sa uptime ng machine. Ang service na nagpapakita ng Exited ang dapat mong suriin.
Kung may hindi nagsimula, makikita sa daemon log ang mga pangyayari sa oras ng boot:
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 output ng docker compose mula sa boot, kabilang ang nabigong image pull o nawawalang .env file. Ang reboot na isi-schedule mo ang iyong susubaybayan, kaya hayaan mong sabihin sa iyo ng unit ang tungkol sa mga reboot na hindi mo direktang nasusubaybayan: ang isang linya ng OnFailure= na tumuturo sa isang self-hosted na ntfy server ay nagiging push notification ang stack na hindi muling nagsimula, sa halip na matuklasan mo ito makalipas ang ilang araw.
Mga bagay na tahimik na nakakasira sa auto-start
Ang mga container na ginawa gamit ang docker compose run ay hindi kailanman tumatanggap ng restart policy mula sa file. Itinuturing ng Compose ang mga ito bilang one-off container. Kung mukhang hindi sinusunod ng isang service ang policy nito, tingnan kung sinimulan ito gamit ang run sa halip na up.
Ang relative path sa volume o sa env_file entry ay nire-resolve batay sa directory ng compose file. Gumagana ito mula sa iyong shell, at gumagana rin ito mula sa unit na nagse-set ng WorkingDirectory. Nabibigo ito mula sa unit na walang ganito dahil ang working directory ay /.
Hiwalay na kaso ang rootless Docker. Tumatakbo ang daemon bilang user service, at humihinto ang user service kapag natapos ang huling session ng user na iyon. I-enable ito para sa user at payagan itong magpatuloy sa pagtakbo kahit walang naka-login:
systemctl --user enable docker
sudo loginctl enable-linger $USERKung wala ang enable-linger, nagsa-shutdown ang rootless daemon kapag nag-logout ka, at kasabay nitong nawawala ang mga container. Mukha itong eksaktong sirang restart policy.
May isa pang dapat tandaan. Maaaring mag-reboot ang server sa itinakdang oras dahil sa automatic security updates. Mabuti lamang ito kung awtomatikong bumabalik ang iyong stack. Ang pag-set up nito sa bagong machine ay bahagi ng iba pang first-hour na gawain 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 itinigil ang container. Sa always, muling magsisimula ang container sa susunod na magsimula ang Docker daemon, kaya nababawi ng reboot ang mano-mano mong paghinto. Sa unless-stopped, naaalala ng daemon na sinadya mong ihinto ang container at hindi na ito gagalawin. Gamitin ang unless-stopped maliban kung partikular mong nais na manatiling nakahinto ang container.
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 naa-update sa 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 nito, 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 na ang restart policy para sa stack na network lang ang kailangan, at ganito ang karamihan ng 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 bumabalik sa susunod na reboot?
Sa unless-stopped, sapat na ang docker compose stop dahil hindi ipinagpapatuloy kapag nag-restart ang daemon ang container na mano-mano mong itinigil. Sa always, hindi sapat ang paghinto 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, muli itong sisimulan ng unit.