SSD Nodes Learn RAM 8GB — $66/mwaka
Mwongozo Matt ConnorNa Matt Connor · Imeboreshwa 2026-08-01

Jinsi ya Kuanzisha Docker Compose Kiotomatiki

Washa huduma za Docker Compose baada ya kuwasha upya: tumia restart: always au unless-stopped, na ujue kwa nini on-failure haitoshi bila kitengo cha systemd.

Jibu fupi

Huduma za Docker Compose huanza wakati wa kuwasha mfumo ikiwa masharti mawili yanatimizwa kwa wakati mmoja. Daemon ya Docker lazima iwe imewezeshwa kama huduma ya mfumo, na kila huduma iliyo kwenye faili lazima iwe na sera ya kuwasha upya ya unless-stopped au always. Ongeza restart: unless-stopped kwenye kila huduma, endesha docker compose up -d mara moja, na kontena zitaanza tena zenyewe baada ya kuwasha upya mfumo. Hakuna kingine kinachohitajika katika hali ya kawaida.

Unahitaji kitengo cha systemd tu wakati mpangilio wa kuanza una umuhimu: kwa stack inayotegemea diski iliyowekwa, kiolesura cha VPN, au share ya mtandao ambayo haijawa tayari wakati daemon ya Docker inaanza. Hali hiyo ni ya kawaida, na nusu ya pili ya mwongozo huu inaieleza. Ikiwa bado unajifunza kuhusu ufafanuzi wa huduma na volumes, anza na misingi ya Docker Compose kwenye VPS kisha urudi.

Weka sera ya kuanzisha upya katika compose.yaml

Sera huwekwa kwenye mstari mmoja kwa kila huduma. Hakuna swichi ya kimataifa. Kwa hiyo, huduma unayoisahau itabaki imesimama baada ya kuwasha upya, huku sehemu nyingine ya stack 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:

Tumia mabadiliko hayo, kisha soma tena sera kutoka kwenye container inayoendesha:

docker compose up -d
docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app)

Hii huchapisha unless-stopped. Ikiwa itachapisha no, faili ilihaririwa lakini container haikuundwa upya.

Hili ndilo kosa linalotokea mara nyingi zaidi. Sera ya kuanzisha upya huhifadhiwa kwenye container, si kwenye faili ya YAML. Kuhariri compose.yaml hakubadilishi chochote kwenye container ambayo tayari ipo. docker compose restart pia haisaidii, kwa sababu husimamisha na kuanzisha container hiyo hiyo bila kubadilisha usanidi wake. Ni docker compose up -d pekee inayolinganisha faili na container zinazoendesha, kugundua kuwa sera imebadilika, na kuziunda upya.

Kwa container ambayo hutaki kuiunda upya sasa, badilisha sera moja kwa moja:

docker update --restart unless-stopped my-container

Pia endelea kuhariri faili ya YAML. docker update hubadilisha container inayoendesha, na docker compose up -d inayofuata itasoma faili na kurejesha thamani ya zamani.

Kile kila thamani ya kuanzisha upya hufanya

Docker inafafanua thamani nne. Tofauti kati yazo huonekana tu mashine inapowashwa upya au daemon inapowashwa upya.

  • no ndiyo thamani chaguo-msingi. Container haianzishwi upya kiotomatiki, kwa hali yoyote.
  • always huanzisha container upya kila inaposimama. Ukiisimamisha mwenyewe, itaanza tena wakati Docker daemon itakapoanza tena. Hili mara nyingi hushangaza: container uliyoisimamisha kwa makusudi wiki iliyopita inaendelea kufanya kazi baada ya kuwasha upya.
  • unless-stopped hufanya kazi kama always, isipokuwa container iliyosimamishwa mwenyewe hubaki imesimama baada ya daemon kuanzishwa upya. Tumia thamani hii kwa huduma unayoisimamisha mara kwa mara kwa ajili ya matengenezo.
  • on-failure huanzisha container upya tu inapotoka ikiwa na msimbo wa kutoka usio wa sifuri. Unaweza kuweka kikomo cha majaribio, kama ilivyo katika restart: on-failure:3.

Kwa stack inayopaswa kuwa inafanya kazi kila seva inapokuwa inafanya kazi, unless-stopped ndiyo thamani sahihi ya chaguo-msingi. Chagua always tu unapotaka container isibaki ikiwa imesimamishwa.

Kwa nini kuwasha upya: on-failure haiendelei baada ya kuwasha upya

Watu wengi huchagua on-failure kwa sababu inaonekana kuwa ya tahadhari, kisha hugundua kuwa kila container imesimama baada ya kuwasha upya mara ya kwanza. Sababu iko katika ufafanuzi wake. on-failure hujibu jambo moja tu: mchakato wa container kutoka ukiwa na msimbo wa hitilafu.

Kuwasha upya si hitilafu. Host inapozimwa, systemd husimamisha docker.service, na daemon husimamisha kila container kwa makusudi. Container haikushindwa, kwa hiyo sera haina jambo la kuitikia. Mfumo unapowashwa tena, daemon huangalia container zinazohitaji kuanza tena, na container ya on-failure iliyosimamishwa kwa usafi si mojawapo ya hizo. Hubaki katika hali ya exited.

Unaweza kuona hili moja kwa moja. Weka restart: on-failure kwenye service, endesha docker compose up -d, washa upya, kisha endesha:

docker compose ps -a

Service itaorodheshwa ikiwa na hali ya Exited na status kama Exited (0) 2 minutes ago. Hakuna kilichoharibika na hakuna kitu kilichorekodiwa kama hitilafu, jambo linalofanya tatizo hili kuwa gumu kuligundua. Sera ilifanya hasa ilivyoelezwa.

on-failure bado ni muhimu. Inafaa kwa container inayoendesha kazi na inaweza kuacha kufanya kazi, ambapo unataka idadi maalum ya majaribio ya kuianzisha tena bila mzunguko usio na kikomo wa kuianzisha. Si zana sahihi ya kuweka service inayoendelea kufanya kazi hai baada ya kuwasha upya.

Sera za kuanzisha upya hufanya kazi tu ikiwa huduma ya Docker inaanza wakati wa kuwasha mfumo

Sera za kuanzisha upya hutekelezwa na daemon ya Docker. Ikiwa daemon haianzi, hakuna kinachotekeleza sera hizo. Ikague:

systemctl is-enabled docker
systemctl is-enabled containerd

Zote zinapaswa kuchapisha enabled. Vifurushi kutoka hazina rasmi ya Docker huziwezesha wakati wa usakinishaji, kwa hiyo hali hii kwa kawaida huwa sawa kwenye seva mpya. Ikiwa mojawapo itachapisha disabled, irekebishe:

sudo systemctl enable --now docker containerd

Kuna mtego hapa unaopaswa kuuelewa. Ubuntu pia husambaza docker.socket, ambayo huanzisha daemon inapohitajika mara ya kwanza kitu kinapowasiliana na Docker API. Watu huona docker.socket ikiwa imewezeshwa, hudhani daemon imeshughulikiwa, kisha huzima docker.service ili kuokoa kumbukumbu. Wakati wa kuwasha mfumo, hakuna kinachoitumia API, kwa hiyo socket haiguswi kamwe, daemon haianzi, na hakuna kontena linaloanza hadi uandike amri yako ya kwanza ya docker. Uanzishaji kupitia socket si mbadala wa kuwezesha docker.service.

Wakati ambapo systemd unit ndiyo jibu bora

Sera za kuanzisha upya hazina dhana ya kupanga utekelezaji kulingana na mfumo wote. Daemon huanza, kisha huanzisha containers zako mara tu inapoweza. Ikiwa stack yako inaunganisha directory kwa bind mount kutoka kwenye volume tofauti, share ya NFS (network file system), au diski iliyosimbwa kwa njia fiche, containers zinaweza kuanza kabla ya path hiyo kuwepo. Docker itaunda directory tupu kwenye mount point na kuanzisha container ikiwa inaitumia, hivyo database yako huanza bila data.

Andika systemd unit ikiwa mojawapo ya hali hizi inatumika. 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 service nyingine yoyote kwenye host. Au unataka stack izimwe kwa usafi wakati wa kuzima mfumo, badala ya kulazimishwa kusitishwa pamoja na daemon. Ikiwa systemd units ni mpya kwako, kuandika systemd service na timer kunaeleza zaidi kuhusu muundo wa faili.

Kuandika unit ya systemd

Weka stack katika njia isiyobadilika nje ya saraka ya nyumbani. /srv/myapp ni chaguo zuri, kwa sababu unit inayoendeshwa kabla mtu yeyote hajaingia haina sababu ya kusoma /home.

Unda /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

Iwashe na uianzishe:

sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.service

Unit yenye afya huonyesha Active: active (exited). Hilo huonekana kuwa kosa mara ya kwanza unapoliona. Ni sahihi: Type=oneshot pamoja na RemainAfterExit=yes inamaanisha unit iliendesha amri yake, amri ilikamilika, na systemd inaendelea kuiweka unit kuwa active ili ExecStop iendeshwe wakati wa kuzima mfumo.

Kila mstari una sababu ya kuwepo. Requires=docker.service inamaanisha unit itashindwa mara moja badala ya kuendesha docker compose dhidi ya socket ambayo haifanyi kazi. After= inaweka mpangilio, kwa sababu Requires= pekee haiweki mpangilio huo. RequiresMountsFor= inafanya systemd ijumuisha mount unit ya njia hiyo na kuisubiri. Hiyo ndiyo sababu kuu ya kutumia unit badala ya sera ya kuanzisha upya. TimeoutStartSec=0 inazuia systemd kusitisha kazi ya kuanzisha wakati image kubwa bado inapakuliwa.

Maelezo kuhusu kuchanganya mifumo hii miwili. Nyaraka za Docker zinashauri kutotumia pamoja sera za restart na process manager ya host. Onyo hilo linahusu process manager anayesimamia moja kwa moja mchakato wa container na kuuanza upya wakati daemon pia inajaribu kufanya hivyo. Unit ya Type=oneshot haisimamii mchakato wowote, kwa hiyo kuacha restart: unless-stopped katika faili ya compose pamoja na unit hii ni sahihi na ndilo unalotaka. systemd hushughulikia mpangilio wakati wa kuwasha mfumo, na daemon hushughulikia container inayoanguka saa 3 asubuhi.

Thibitisha kwa kuwasha upya halisi

Hakuna mbadala wa jaribio halisi. systemctl restart docker haijaribu mpangilio wa mount, na docker compose down ikifuatiwa na docker compose up -d haijaribu chochote kuhusu boot.

sudo reboot

Subiri, unganisha tena, kisha kagua kwa utaratibu huu:

uptime
systemctl is-active docker
docker compose ps

uptime inathibitisha kuwa unaangalia mashine ambayo iliwashwa upya kweli. docker compose ps, ikitekelezwa kutoka kwenye saraka ya stack, inapaswa kuorodhesha kila service ikiwa running, ikiwa na uptime inayokaribiana na ya mashine. Service inayoonyesha Exited ndiyo ya kuchunguza.

Ikiwa kitu hakikuwashwa, logi ya daemon inahifadhi taarifa za kipindi cha kuwasha:

journalctl -u docker.service -b --no-pager | tail -50

Kwa stack inayodhibitiwa na unit, journalctl -u myapp.service -b --no-pager inaonyesha matokeo halisi ya docker compose kutoka wakati wa kuwasha, ikijumuisha kushindwa kuvuta image au kukosekana kwa faili ya .env.

Mambo yanayovuruga kimya kimya uanzishaji wa kiotomatiki

Kontena zilizoundwa kwa kutumia docker compose run hazitumii kamwe sera ya kuwasha upya kutoka kwenye faili. Compose huzichukulia kama kontena za mara moja. Ikiwa huduma inaonekana kupuuza sera yake, angalia kama ilianzishwa kwa run badala ya up.

Njia ya kulinganisha katika volume au katika ingizo la env_file hutatuliwa kwa kuzingatia saraka ya faili ya compose. Hii hufanya kazi kutoka kwenye shell yako, na pia kutoka kwenye unit inayoweka WorkingDirectory. Hufeli kutoka kwenye unit isiyo na hiyo, kwa sababu saraka ya kufanya kazi huwa /.

Docker isiyotumia root ni hali tofauti. Daemon huendeshwa kama huduma ya mtumiaji, na huduma ya mtumiaji husimama kipindi cha mwisho cha mtumiaji huyo kinapoisha. Iwashe kwa mtumiaji huyo na iruhusu iendelee kufanya kazi bila mtumiaji yeyote kuingia:

systemctl --user enable docker
sudo loginctl enable-linger $USER

Bila enable-linger, daemon isiyotumia root huzima unapotoka, na kontena huondoka pamoja nayo. Hali hii huonekana sawa kabisa na sera ya kuwasha upya iliyoharibika.

Jambo moja la mwisho. Masasisho ya usalama ya kiotomatiki yanaweza kuwasha upya server saa iliyowekwa, jambo ambalo huwa zuri tu ikiwa stack yako inarudi yenyewe. Kuweka hilo kwenye mashine mpya ni sehemu ya kazi za 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 tena container inaposimama yenyewe. Zinatofautiana baada ya kusimamisha container mwenyewe. Ukiwa na always, container huanza tena wakati Docker daemon inapoanza mara inayofuata, hivyo kuwasha upya mfumo hubatilisha kusimamisha kwako mwenyewe. Ukiwa na unless-stopped, daemon hukumbuka kwamba container ilisimamishwa kwa makusudi na huiacha ikiwa imesimama. Tumia unless-stopped isipokuwa unahitaji mahsusi container ambayo itabaki ikiwa imesimama.

Niliongeza restart: unless-stopped lakini container bado haianzi baada ya kuwasha upya mfumo. Kwa nini?

Sera huhifadhiwa kwenye container, si kwenye file, na kuhariri YAML hakusasishi container ambayo tayari ipo. Tekeleza docker compose up -d ili Compose iunde upya container, kisha thibitisha kwa docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' $(docker compose ps -q app). Ikiwa hiyo itaonyesha no, container iliundwa kabla ya mabadiliko yako. Sababu nyingine ya kawaida ni kwamba docker.service haijawezeshwa; unaweza kukagua hilo kwa systemctl is-enabled docker.

Je, ninahitaji systemd unit ikiwa tayari ninatumia restart policies?

Kwa kawaida, huhitaji. Restart policy inatosha kwa stack inayohitaji mtandao pekee, na stacks nyingi ziko hivyo. Ongeza unit wakati containers zinategemea kitu ambacho hakijawa tayari Docker daemon inapoanza, kama diski ya nje, volume iliyosimbwa kwa njia fiche, NFS share, au interface ya VPN. Unit hukupa mpangilio wa uanzishaji kupitia After= na RequiresMountsFor=, ambao restart policy haiwezi kuonyesha.

Ninawezaje kusimamisha stack kabisa bila kuanza tena baada ya kuwasha upya mfumo?

Ukitumia unless-stopped, docker compose stop inatosha, kwa sababu container iliyosimamishwa mwenyewe haianzishwi tena daemon inapoanza upya. Ukitumia always, kusimamisha pekee hakutoshi na container itarudi baada ya kuwasha upya mfumo. Tekeleza docker compose down, ambayo huondoa containers, au badilisha sera kwanza kwa docker update --restart no my-container. Ikiwa systemd unit inasimamia stack, tekeleza sudo systemctl disable myapp.service pia; la sivyo unit itaianzisha tena.