Jinsi ya kuwasha Docker Compose kiotomatiki baada ya boot
Jifunze kusanidi restart policy ya always au unless-stopped ili huduma zako zianze zenyewe. Fahamu kwa nini on-failure haitoshi na wakati sahihi wa kutumia systemd unit.
Jibu fupi
Huduma za Docker Compose huanza wakati wa boot ikiwa masharti mawili yanatimizwa kwa wakati mmoja. Docker daemon lazima iwe imewezeshwa kama system service, na kila huduma kwenye faili lazima iwe na restart policy ya unless-stopped au always. Ongeza restart: unless-stopped kwenye kila huduma, endesha docker compose up -d mara moja, na container zitarudi zenyewe baada ya reboot. Hakuna kingine kinachohitajika kwa hali ya kawaida.
Unahitaji systemd unit pale tu ambapo mpangilio wa kuanza ni muhimu: stack inayotegemea diski iliyopachikwa (mounted disk), VPN interface, au network share ambayo haijawa tayari wakati Docker daemon inapoanza. Hali hiyo ni ya kweli, na nusu ya pili ya mwongozo huu inashughulikia hilo. Ikiwa bado unajifunza kuhusu ufafanuzi wa huduma na volumes, anza na misingi ya Docker Compose kwenye VPS kisha urudi hapa.
Weka sera ya kuanzisha upya (restart policy) katika compose.yaml
Sera hii huwekwa kwa mstari mmoja kwa kila huduma. Hakuna swichi ya kimataifa, kwa hivyo huduma unayoisahau itabaki imezimwa baada ya reboot wakati stack nyingine ikianza.
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:Itumie sera hiyo kisha usome sera iliyopo kwenye container inayofanya kazi:
docker compose up -d
docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app)Hiyo itachapisha unless-stopped. Ikitokea imechapisha no, faili ilihaririwa lakini container haikutengenezwa upya.
Hili ndilo kosa la kawaida zaidi. Sera ya kuanzisha upya huhifadhiwa kwenye container, si kwenye faili ya YAML. Kuhariri compose.yaml hakubadilishi chochote kuhusu container iliyopo tayari. docker compose restart haisaidii pia, kwa sababu inasimamisha na kuanzisha kitu kilekile cha container bila kugusa usanidi wake. Ni docker compose up -d pekee inayolinganisha faili na container zinazofanya kazi, inagundua kuwa sera imebadilika, na kuzitengeneza upya.
Kwa container ambayo hutaki kuitengeneza upya hivi sasa, badilisha sera hiyo moja kwa moja:
docker update --restart unless-stopped my-containerBado unapaswa kuhariri faili ya YAML pia. docker update inabadilisha container iliyo hai, na docker compose up -d inayofuata itasoma faili hiyo na kurudisha thamani ya zamani.
Kile ambacho kila thamani ya restart hufanya kwa hakika
Docker hufafanua thamani nne, na tofauti kati yao huonekana tu wakati mashine inapowaka upya (reboot) au daemon inapoanzishwa upya.
nondiyo thamani chaguo-msingi. Container haiwahi kuanzishwa upya kiotomatiki, chini ya hali yoyote ile.alwayshuanzisha upya container kila inapokoma. Ikiwa uliisimamisha kwa mkono, itarudi tena wakati mwingine Docker daemon itakapoanza. Hili mara nyingi hushangaza: container uliyoisimamisha kwa makusudi wiki iliyopita inafanya kazi tena baada ya reboot.unless-stoppedhufanya kazi kamaalways, isipokuwa kwamba container iliyosimamishwa kwa mkono hubaki imesimama hata baada ya daemon kuanza upya. Hii ndiyo thamani unayotaka kwa huduma unayoisimamisha mara kwa mara kwa ajili ya matengenezo.on-failurehuanzisha upya container pale tu inapokoma ikiwa na exit code isiyo ya sifuri. Unaweza kuweka kikomo cha majaribio, kama ilivyo katikarestart: on-failure:3.
Kwa stack ambayo inapaswa kuwa inafanya kazi wakati wowote seva inapokuwa hewani, unless-stopped ndiyo chaguo-msingi sahihi. Chagua always pale tu unapotaka container inayokataa kubaki imesimama.
Kwa nini restart: on-failure haifanyi kazi baada ya reboot
Watu wengi huchagua on-failure kwa sababu inaonekana kama chaguo makini, kisha hugundua kila container imesimama baada ya reboot ya kwanza. Sababu iko kwenye ufafanuzi wake. on-failure hujibu jambo moja tu: mchakato wa container unapoishia na error code.
Reboot siyo error. Seva inapozimwa, systemd husimamisha docker.service, na daemon husimamisha kila container kwa makusudi. Container haikufeli, kwa hivyo sera hiyo haina cha kujibu. Wakati seva inawaka tena, daemon huangalia containers zinazopaswa kuendelea, na container ya on-failure iliyosimamishwa kwa usahihi si miongoni mwa hizo. Inabaki katika hali ya exited.
Unaweza kuona hili moja kwa moja. Weka restart: on-failure kwenye service, endesha docker compose up -d, fanya reboot, kisha endesha:
docker compose ps -aService hiyo itaonekana ikiwa na hali ya Exited na status kama Exited (0) 2 minutes ago. Hakuna kitu kilichoharibika na hakuna error iliyorekodiwa, ndiyo maana ni vigumu kutambua tatizo hili. Sera hiyo ilifanya kazi kama ilivyoelekezwa.
on-failure bado ni muhimu. Inafaa kwa container inayotekeleza kazi na inaweza ku-crash, ambapo unataka idadi ndogo ya majaribio ya kurudia bila kuingia kwenye mzunguko wa restart usio na mwisho. Si zana sahihi ya kuweka huduma inayodumu kwa muda mrefu ikiwa hai baada ya reboot.
Sera za kuanzisha upya hufanya kazi tu ikiwa huduma ya Docker inaanza wakati wa boot
Sera za kuanzisha upya (restart policies) hutekelezwa na Docker daemon. Ikiwa daemon haitaanza, hakuna kitakachotekeleza sera hizo. Hakiki hali hiyo:
systemctl is-enabled docker
systemctl is-enabled containerdZote mbili zinapaswa kutoa matokeo ya enabled. Vifurushi kutoka kwenye hazina rasmi ya Docker huwezesha huduma hizi wakati wa usakinishaji, kwa hivyo kwenye seva mpya hii mara nyingi huwa sawa. Ikiwa yoyote kati ya hizo inatoa disabled, irekebishe:
sudo systemctl enable --now docker containerdKuna mtego hapa ambao ni muhimu kuuelewa. Ubuntu pia husafirisha docker.socket, ambayo huanzisha daemon pale tu inapoombwa wakati kitu cha kwanza kinapowasiliana na Docker API. Watu huona docker.socket imewezeshwa, hudhani daemon imeshughulikiwa, na kuzima docker.service ili kuokoa kumbukumbu. Wakati wa boot, hakuna kinachopiga API, kwa hivyo socket haigusiwi, daemon haiwaki, na hakuna container inayokuja hadi utakapochapa amri yako ya kwanza ya docker. Socket activation si mbadala wa docker.service kuwezeshwa.
Wakati systemd unit inapokuwa suluhisho bora
Sera za kuanzisha upya (restart policies) hazina utaratibu wa kupanga mfuatano wa kuanza kwa huduma ikilinganishwa na mfumo mzima. Daemon huanza, na huleta container zako juu haraka iwezekanavyo. Ikiwa stack yako inatumia bind-mount ya saraka kutoka kwenye volume tofauti, NFS (network file system), au diski iliyosimbwa (encrypted disk), container zinaweza kuanza kabla ya njia hiyo (path) kuwepo. Docker itatengeneza saraka tupu kwenye sehemu ya mount na kuanzisha container hiyo, na database yako itaanza bila data yoyote.
Andika systemd unit wakati wowote mojawapo ya hali hizi zinapojitokeza. Stack inahitaji mount, interface ya VPN, au unit nyingine iwe tayari kwanza. Unataka systemctl stop myapp na systemctl start myapp zifanye kazi kama zinavyofanya kwa huduma nyingine zote kwenye seva. Au unataka stack izimwe kwa usahihi wakati wa shutdown badala ya kukatishwa ghafla pamoja na daemon. Ikiwa systemd units ni ngeni kwako, kuandika systemd service na timer inaelezea muundo wa faili kwa kina zaidi.
Kuandika unit ya systemd
Weka stack kwenye njia maalum nje ya saraka ya nyumbani (home directory). /srv/myapp ni chaguo zuri, kwa sababu unit inayofanya kazi kabla ya mtumiaji yeyote kuingia kwenye mfumo haina sababu ya kusoma /home.
Tengeneza /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.targetIwezeshe na uianzishe:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.serviceUnit iliyo katika hali nzuri huonyesha Active: active (exited). Hilo linaweza kuonekana si sahihi unapoliona kwa mara ya kwanza. Ni sahihi: Type=oneshot pamoja na RemainAfterExit=yes inamaanisha kuwa unit imetekeleza amri yake, amri imekamilika, na systemd inaiweka unit hiyo katika hali ya active ili ExecStop iweze kutekelezwa wakati wa kuzima seva (shutdown).
Kila mstari una umuhimu wake. Requires=docker.service inamaanisha kuwa unit inafeli haraka badala ya kujaribu kutekeleza docker compose kwenye socket iliyokufa. After= inaweka mpangilio, kwa sababu Requires= pekee haifanyi hivyo. RequiresMountsFor= inailazimisha systemd kuvuta unit ya mount kwa ajili ya njia hiyo na kuisubiri, jambo ambalo ndilo sababu kuu ya kutumia unit badala ya sera ya restart pekee. TimeoutStartSec=0 inazuia systemd kusitisha kazi ya kuanza (start job) wakati image kubwa bado inapakuliwa.
Ujumbe kuhusu kuchanganya mifumo hii miwili. Nyaraka za Docker zinashauri kutochanganya sera za restart na meneja wa mchakato wa seva (host process manager). Onyo hilo linahusu meneja wa mchakato anayesimamia mchakato wa container yenyewe na kuianzisha upya wakati daemon inajaribu kufanya vivyo hivyo. Unit ya Type=oneshot haisimamii kitu chochote, kwa hivyo kuweka restart: unless-stopped kwenye faili ya compose pamoja na unit hii ni sawa, na ndivyo unavyopaswa kufanya. systemd inashughulikia mpangilio wakati wa boot, na daemon inashughulikia container inayokwama saa tisa za usiku.
Unit inaonekana tofauti wakati kitu unachokiweka hai ni mchakato wa kawaida unaoendelea kwa muda mrefu badala ya stack, kwa sababu hapo hakuna daemon chini yake na Restart= ya systemd yenyewe inabidi ifanye usimamizi; kuendesha dsh bila kichwa nyuma ya systemd ni mfano uliotekelezwa wa umbo hilo, hadi kufikia mtumiaji maalum na journal.
Thibitisha kwa kuwasha upya seva (reboot)
Hakuna mbadala wa jaribio la kweli. systemctl restart docker haijaribu mpangilio wa mount, na docker compose down ikifuatiwa na docker compose up -d haijaribu chochote kuhusu mchakato wa boot.
sudo rebootSubiri, unganisha tena, na uhakiki kwa mpangilio huu:
uptime
systemctl is-active docker
docker compose psuptime inathibitisha kuwa unaangalia mashine iliyowaka upya kikamilifu. docker compose ps, ikitekelezwa kutoka kwenye saraka ya stack, inapaswa kuorodhesha kila huduma kama running ikiwa na muda wa kufanya kazi (uptime) unaokaribiana na ule wa mashine. Huduma inayoonyesha Exited ndiyo unayopaswa kuichunguza.
Ikiwa kitu hakijaanza, logi ya daemon inashughulikia kipindi cha boot:
journalctl -u docker.service -b --no-pager | tail -50Kwa stack inayodhibitiwa na unit, journalctl -u myapp.service -b --no-pager inaonyesha matokeo kamili ya docker compose kutoka wakati wa boot, ikijumuisha kushindwa kuvuta image au faili ya .env inayokosekana. Reboot unayopanga ndiyo unayopaswa kuifuatilia, kwa hivyo acha unit ikutaarifu kuhusu zile usizozifuatilia: mstari wa OnFailure= unaoelekeza kwenye seva ya ntfy inayojiendesha hubadilisha stack iliyoshindwa kuanza kuwa taarifa ya papo hapo (push notification) badala ya kitu unachokigundua baada ya siku kadhaa.
Mambo yanayosababisha auto-start kufeli kimyakimya
Containers zilizoundwa kwa docker compose run hazipati kamwe sera ya restart kutoka kwenye faili. Compose huzichukulia kama containers za mara moja. Ikiwa huduma inaonekana kupuuza sera yake, angalia kama ilianzishwa kwa run badala ya up.
Njia ya jamaa (relative path) katika volume au katika ingizo la env_file hutatuliwa kulingana na saraka ya faili ya compose. Hiyo hufanya kazi kutoka kwenye shell yako, na hufanya kazi kutoka kwa unit inayoweka WorkingDirectory. Inafeli kutoka kwa unit isiyo na hiyo, kwa sababu saraka ya kazi (working directory) huwa ni /.
Rootless Docker ni kisa tofauti. Daemon huendeshwa kama huduma ya mtumiaji, na huduma ya mtumiaji husimama wakati kikao cha mwisho cha mtumiaji huyo kinapomalizika. Iwezeshe kwa mtumiaji na uiruhusu iendelee kufanya kazi bila mtu yeyote kuingia kwenye mfumo:
systemctl --user enable docker
sudo loginctl enable-linger $USERBila enable-linger, daemon ya rootless huzimika unapotoka (log out) na containers huondoka pamoja nayo, jambo ambalo linaonekana kama sera ya restart iliyovunjika.
Jambo la mwisho. Masasisho ya kiotomatiki ya usalama yanaweza kuwasha upya seva kwa saa maalum, jambo ambalo ni zuri tu ikiwa stack yako inajirejesha yenyewe. Kuweka hilo kwenye mashine mpya ni sehemu ya kazi ya saa ya kwanza katika dakika kumi za kwanza kwenye VPS mpya.
FAQ
Kuna tofauti gani kati ya restart: always na restart: unless-stopped?
Zote mbili huanzisha upya container inaposimama yenyewe. Zinatafautiana unaposimamisha container kwa mkono. Ukitumia always, container huanza tena wakati mwingine Docker daemon inapoanza, kwa hivyo reboot hufuta kitendo chako cha kusimamisha. Ukitumia unless-stopped, daemon hukumbuka kuwa container ilisimamishwa kwa makusudi na kuiacha ikiwa imesimama. Tumia unless-stopped isipokuwa kama unataka container ambayo haitakaa ikiwa imezimwa.
Nimeongeza restart: unless-stopped lakini container bado haianzi baada ya reboot. Kwa nini?
Sera hiyo hukaa kwenye container, si kwenye faili, na container iliyopo tayari haisasishwi kwa kuhariri YAML. Tekeleza docker compose up -d ili Compose iitengeneze upya, kisha thibitisha kwa docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app). Ikiwa inachapisha no, container hiyo ilikuwepo kabla ya kuhariri kwako. Sababu nyingine ya kawaida ni docker.service kutowezeshwa, jambo unaloweza kulikagua kwa systemctl is-enabled docker.
Je, ninahitaji systemd unit ikiwa tayari ninatumia sera za restart?
Kwa kawaida si lazima. Sera ya restart inatosha kwa stack inayohitaji mtandao pekee, ambayo ndiyo hali ya stack nyingi. Ongeza unit wakati container zinategemea kitu ambacho hakijawa tayari wakati Docker daemon inapoanza, kama vile diski ya nje, encrypted volume, NFS share, au VPN interface. Unit inakupa uwezo wa kupanga mtiririko kupitia After= na RequiresMountsFor=, jambo ambalo sera ya restart haiwezi kufanya.
Ninawezaje kusimamisha stack kabisa bila kurudi baada ya reboot?
Ukitumia unless-stopped, docker compose stop inatosha, kwa sababu container iliyosimamishwa kwa mkono haianzishwi tena wakati daemon inapoanza upya. Ukitumia always, kusimamisha hakutoshi na container itarudi baada ya reboot. Tekeleza docker compose down, ambayo huondoa container, au badilisha sera kwanza kwa docker update --restart no my-container. Ikiwa systemd unit inasimamia stack hiyo, tekeleza sudo systemctl disable myapp.service pia, vinginevyo unit hiyo itaiwasha tena.