Jinsi ya kuendesha Docker kwenye VPS kwa usalama
Kujua tofauti za Docker kwenye VPS ni muhimu. Jifunze jinsi ya kuzuia hitilafu za RAM, kuepuka kufungua port kwenye UFW, na kuhakikisha containers zinaanza upya baada ya reboot.
Mabadiliko yanayotokea unapoendesha Docker kwenye VPS
Docker kwenye VPS huendesha engine ileile na images zilezile kama Docker kwenye laptop yako, kwa hivyo kila command unayoijua bado inafanya kazi. Kinachobadilika ni mazingira yanayoizunguka. Laptop ina kumbukumbu ya ziada, firewall ambayo hakuna anayeichunguza, na disk kubwa kiasi kwamba huwahi kuiangalia. Seva iliyokodishwa ina ukomo wa kumbukumbu, anwani ya IP ya umma inayochunguzwa ndani ya dakika chache baada ya kuwaka, na root filesystem ambayo Docker itaijaza bila kuuliza.
Tofauti nne husababisha matatizo mengi kwenye seva ndogo:
- Kumbukumbu ina ukomo, na kernel hutatua uhaba kwa kuua mchakato (process).
- Port iliyochapishwa (published port) hupita moja kwa moja kwenye UFW (uncomplicated firewall), kwa sababu Docker huandika sheria zake za firewall.
- Containers hazirudi baada ya reboot isipokuwa kama uliomba hivyo mapema.
- Images, containers, volumes na build cache hukua hadi disk ijae.
Kila sehemu hapa chini inataja hitilafu, ujumbe utakaouona, na mwongozo unaotatua tatizo hilo kwa kina. Ikiwa bado hujaandika compose file, soma Misingi ya Docker Compose kwenye VPS kwanza kisha urudi. Ukurasa huu unadhani kuwa tayari una uwezo wa kuendesha stack.
Docker container hutumia kiasi gani cha RAM?
Kidogo kuliko wengi wanavyodhani. Container ni mchakato ndani ya cgroup (control group), si mashine pepe (virtual machine), kwa hivyo hakuna kernel ya mgeni wala mgao uliopangwa. Gharama ya kumbukumbu ni kile ambacho mchakato wa ndani kinagusa. Hii ndiyo sababu stack nzima inaweza kutoshea katika 2 GB wakati stack hiyo hiyo ikijengwa kwa mashine pepe isingeweza.
Takwimu hapa chini ni namba za kawaida za hali ya utulivu (idle) kwa images za kawaida kwenye Ubuntu 24.04 zenye usanidi chaguo-msingi, zilizosomwa kutoka docker stats dakika chache baada ya kuanza. Hizi ni sehemu ya kuanzia kwa ajili ya kupanga, si kipimo cha utendaji wa mzigo wako wa kazi (workload). Endesha docker stats --no-stream kwenye seva yako mwenyewe kabla ya kuamini takwimu yoyote, ikiwemo hizi.
The data behind this chart
[
{
"label": "nginx",
"idle_mb": 8,
"budget_mb": 64
},
{
"label": "Redis 7",
"idle_mb": 12,
"budget_mb": 128
},
{
"label": "Traefik v3",
"idle_mb": 40,
"budget_mb": 128
},
{
"label": "PostgreSQL 16",
"idle_mb": 45,
"budget_mb": 512
},
{
"label": "Uptime Kuma",
"idle_mb": 95,
"budget_mb": 256
},
{
"label": "MariaDB 11",
"idle_mb": 190,
"budget_mb": 512
},
{
"label": "Nextcloud (Apache)",
"idle_mb": 210,
"budget_mb": 768
}
]Safu wima mbili hufanya kazi tofauti. idle_mb ni kile ambacho container hutumia wakati haifanyi kazi yoyote. budget_mb ni kile unachopaswa kutenga unapopanga, kwa sababu matumizi halisi si ya utulivu. PostgreSQL hutulia karibu na 45 MB na huhitaji 512 MB pindi miunganisho, upangaji (sorts) na cache zinapokuwa hai. Panga kwa kutumia safu ya bajeti. Fanya utatuzi wa makosa kwa kutumia safu ya utulivu.
Angalia muundo wa safu hizo 7. nginx hutulia kwenye 8 MB na Nextcloud kwenye 210 MB. Proxy iliyo mbele ya programu zako haina gharama kubwa. Database na programu ya PHP ndizo unazopaswa kuzingatia wakati wa kupima ukubwa wa seva.
Onyo moja kuhusu docker stats: takwimu ya kumbukumbu inajumuisha page cache ambayo usomaji wa faili wa container yenyewe umevuta, kwa hivyo hupanda kwa muda baada ya kuanza na kisha hutulia. Iangalie kwa saa moja kabla ya kuamua kuwa kuna kitu kinavuja kumbukumbu (leaking).
Kupima VPS: nini kinafaa katika 2 GB, 4 GB na 8 GB
Ondoa kwanza sehemu inayotumiwa na mwenyeji (host). Kernel, systemd, journald, sshd na Docker daemon zote hukaa kwenye RAM sawa na containers zako, na dockerd pamoja na containerd hutumia takriban 100 MB ya RAM hiyo. Unahitaji pia kumbukumbu ya ziada kwa ajili ya page cache, na kwa ajili ya ongezeko la matumizi wakati wa kujenga image au kufanya database dump.
The data behind this chart
[
{
"plan": "2 GB VPS",
"total_mb": 2048,
"host_reserve_mb": 768,
"container_mb": 1280
},
{
"plan": "4 GB VPS",
"total_mb": 4096,
"host_reserve_mb": 1024,
"container_mb": 3072
},
{
"plan": "8 GB VPS",
"total_mb": 8192,
"host_reserve_mb": 1536,
"container_mb": 6656
}
]host_reserve_mb inashughulikia mfumo wa uendeshaji, Docker daemon na nafasi ya ziada inayofanya seva iwe na mwitikio mzuri chini ya mzigo. Kilichobaki ni container_mb, na hiyo ndiyo namba pekee unayoweza kuitumia. Akiba hii huongezeka kulingana na mpango, kutoka 768 MB kwenye seva ndogo hadi 1536 MB kwenye seva kubwa, kwa sababu seva kubwa huendesha containers nyingi zaidi, huandika logs nyingi zaidi na huhitaji page cache kubwa zaidi.
Mpango wa 2 GB huacha 1280 MB kwa ajili ya containers. Tumia 512 MB ya hiyo kwa PostgreSQL na 128 MB kwa Traefik, na nusu yake itakuwa imekwisha. Kilichobaki kinatosha kwa programu mbili ndogo za takriban 256 MB kila moja. Hiyo ni seva halisi na yenye manufaa. Hiyo haitoshi kwa Nextcloud na search cluster juu yake.
Mpango wa 4 GB huacha 3072 MB, ambapo database, reverse proxy, programu tatu na container ya ufuatiliaji (monitoring) zote zinaweza kutoshea kwa wakati mmoja. Hii ndiyo ukubwa mdogo zaidi unaofaa kutumika kwa kitu chochote unachokijali, kwa sababu kumbukumbu ya ziada ndiyo inayoweza kuhimili deploy mbaya.
Mpango wa 8 GB huacha 6656 MB kati ya 8192 MB zake, na kikomo kwa kawaida huhama kutoka kumbukumbu kwenda CPU au kasi ya disk. Aina moja ya container hujipima yenyewe kulingana na configuration yake badala ya mzigo: seva ya local model huhifadhi KV cache kulingana na context window yake, kwa hivyo kuongeza num_ctx ya Ollama kunaweza kuongeza gigabytes kwenye bajeti kabla ya ombi lolote kufika. Ikiwa hesabu inaonyesha stack yako haitoshi, nunua mpango mkubwa zaidi badala ya kujaribu kuibadilisha: gharama halisi ya VPS inaeleza thamani ya gigabytes za ziada kwa mwezi.
Kanuni mbili huweka hesabu kuwa sahihi. Weka kikomo cha kumbukumbu (memory limit) kwenye kila huduma, ili mchakato mmoja usio na udhibiti usichukue rasilimali zote za seva. Na uache sehemu ya juu ya bajeti bila kutumika, kwa sababu docker compose build na pg_dump zote huhitaji kumbukumbu wakati mbaya zaidi. Memory limits katika Docker Compose inaonyesha sintaksia na mitego ya kuepuka.
Kwa nini container yangu inafunga na code 137?
Hii hutokea kwa sababu kernel imeifunga. 137 ni 128 jumlisha 9, na signal 9 ni SIGKILL. Container iliomba kumbukumbu (memory) nyingi kuliko iliyoruhusiwa, na mchakato wa out of memory (OOM) killer ukaifunga.
CONTAINER ID IMAGE STATUS
9f2c1a4d7b3e postgres:16 Exited (137) 4 minutes agoThibitisha sababu badala ya kukisia:
docker inspect my-db | grep -i oomkilled
sudo journalctl -k | grep -i "out of memory""OOMKilled": true inamaanisha container imefika kikomo chake cha cgroup, na log ya kernel inataja mchakato iliyouchagua:
Memory cgroup out of memory: Killed process 2417 (postgres) total-vm:1284416kBHii ni hali nafuu, kwa sababu madhara yameishia kwenye container moja tu. Hali mbaya ni container isiyo na kikomo chochote. Bila kikomo, uwezo wake ni sawa na mashine nzima, kwa hiyo leak katika huduma moja itanyima host rasilimali, na kernel itachagua mhanga kulingana na ukubwa katika mfumo mzima. Mstari wa logi hupoteza prefix ya Memory cgroup na kusomeka Out of memory: Killed process 2417 (postgres). Mchakato unaochaguliwa mara nyingi ni database yako, wakati container iliyosababisha leak inaendelea kufanya kazi. Ndiyo maana kuweka kikomo kwa kila huduma ni muhimu zaidi kuliko thamani kamili ya kikomo kimoja.
Swap inabadilisha muda wa tukio, si hesabu yenyewe. Picha nyingi za VPS huja bila swap. Hakiki kwa swapon --show, ambayo haitoi matokeo yoyote ikiwa swap haipo. Faili la swap huipa kernel mahali pa kuweka kurasa za kumbukumbu zisizotumika (cold pages), jambo linalokupa dakika chache za kugundua tatizo.
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -hfree -h sasa inapaswa kuonyesha jumla isiyo sifuri katika mstari wa Swap. Swap haiongezi RAM. Mashine iliyo chini ya shinikizo la kumbukumbu mara kwa mara itakuwa polepole kiasi kwamba huwezi kuingia kupitia SSH ili kurekebisha, kwa hiyo chukulia swap kama buffer ya tahadhari na urekebishe ukubwa wake.
Kwa nini UFW haizuii port ya Docker niliyochapisha?
Kwa sababu trafiki haifiki kamwe kwenye chain inayolindwa na UFW. Unapochapisha port kwa kutumia -p 5432:5432 au ingizo la ports: kwenye compose, daemon huandika sheria ya DNAT (destination network address translation) kwenye jedwali la nat na sheria ya accept kwenye chain yake ya DOCKER. Pakiti inayoelekezwa kwenye container husukumwa (forwarded) kwenye container hiyo badala ya kupelekwa kwa host, hivyo inashughulikiwa katika njia ya FORWARD na haipiti kamwe sheria za INPUT zilizoandikwa na UFW.
Unaweza kuona hili likitokea kwenye seva:
sudo ufw status | grep 5432
sudo iptables -t nat -L DOCKER -n | grep 5432UFW inaweza kuonyesha 5432 DENY IN Anywhere wakati jedwali la nat linashikilia sheria ya DNAT tcp ... to:172.18.0.2:5432 kwa port hiyo hiyo. Kutoka kwa mashine nyingine, nc -vz your.server.ip 5432 bado inaunganisha. Database iko kwenye mtandao wa umma na firewall inasema haipo.
Suluhisho ni kuchapisha kidogo. Container katika mradi mmoja wa compose hushiriki mtandao na kufikiana kwa kutumia jina la huduma, kwa hivyo database inayohudumia programu iliyo kando yake haihitaji ingizo la ports: hata kidogo. Unapotaka ufikiaji wa ndani, funga uchapishaji kwenye loopback:
services:
db:
image: postgres:16
ports:
- "127.0.0.1:5432:5432"Baada ya docker compose up -d, nc -vz your.server.ip 5432 kutoka nje inafeli, na psql -h 127.0.0.1 -p 5432 kwenye mashine hiyo bado inafanya kazi. Katika stack ndogo yenye afya, reverse proxy pekee ndiyo inayochapisha chochote, kwenye 80 na 443. Kwa nini ports zilizochapishwa na Docker hupita UFW inashughulikia chain ya DOCKER-USER kwa hali ambazo lazima uchapishe port na bado uichuje, na Misingi ya UFW firewall inashughulikia sheria za host zilizo chini yake.
Kwa nini container zangu zimepotea baada ya reboot?
Kwa sababu hakuna kilichoziagiza zirudi. Container huundwa ikiwa na sera ya restart ya no isipokuwa ukiweka nyingine, hivyo reboot huiacha ikiwa imesimama na daemon haijali. Reboot si jambo la nadra kwenye VPS: masasisho ya kernel kutoka kwa unattended upgrades, matengenezo ya mtoa huduma, na mlolongo wa OOM hapo juu yote husababisha reboot.
Mambo mawili lazima yawe kweli. Daemon lazima ianze wakati wa boot:
systemctl is-enabled dockerHiyo huchapisha enabled kwenye usakinishaji wa kawaida wa Ubuntu. Kisha kila huduma inahitaji sera:
services:
app:
image: ghcr.io/example/app:1.4
restart: unless-stoppedunless-stopped huirudisha container baada ya reboot na huheshimu container uliyoisimamisha kwa makusudi. always pia huanzisha upya zile ulizozisimamisha kwa makusudi wakati wowote daemon inapoanza upya, jambo ambalo ni mshangao katikati ya utatuzi wa hitilafu. Kuhariri faili pekee hakutoshi, kwa sababu sera ya restart huwekwa wakati container inaundwa. Tekeleza docker compose up -d ili iundwe upya, kisha kagua thamani ya sasa:
docker inspect my-app | grep -A3 RestartPolicyKisha fanya reboot ya seva kwa makusudi na utekeleze docker compose ps katika saraka ya mradi. Stack inayostahimili reboot iliyopangwa itastahimili ile isiyotarajiwa. Ikiwa stack yako inahitaji mpangilio maalum au kazi ya mara moja wakati wa boot, systemd unit ni zana bora zaidi: kuanzisha Docker Compose wakati wa boot ina faili ya unit. Ili kujua kama container iliyorejea inafanya kazi kweli, ongeza Compose healthchecks.
Kwa nini diski ya VPS yangu imejaa?
Kwa sababu Docker huhifadhi kila kitu hadi utakapoiambia isifanye hivyo. Kila image tag uliyowahi kudownload, kila container iliyosimamishwa, kila anonymous volume iliyoachwa baada ya recreate, na kila layer ya build cache hubaki kwenye diski. Kwenye root filesystem ya 40 GB au 80 GB, ambayo ni ya kawaida kwa ukubwa wa mipango hii, hiyo husababisha kukatika kwa huduma ndani ya miezi michache badala ya miaka.
Diski iliyojaa haionekani kama crash. Utapata no space left on device kutoka kwa container, kutoka kwa apt, kutoka kwa journald na kutoka kwa docker pull ndani ya saa moja. PostgreSQL huacha kukubali uandishi wa data. Seva bado inafanya kazi, jambo linalofanya iwe vigumu kugundua kuliko reboot loop.
Angalia kabla ya kufuta:
docker system df
df -h /docker system df hugawanya jumla ya nafasi katika images, containers, local volumes na build cache, ikiwa na safu ya RECLAIMABLE kando ya kila moja. Kwenye seva inayojijengea images zake, build cache kwa kawaida ndiyo sehemu kubwa zaidi.
docker image prune -a
docker builder prune
docker system dfdocker image prune -a huondoa kila image ambayo hakuna container inayotumia. docker builder prune husafisha build cache. Zote ni salama wakati huduma zinafanya kazi, kwa sababu chochote kinachotumika hurukwa. Kitu ambacho si salama ni docker system prune --volumes, ambayo hufuta kila volume ambayo hakuna container inayoiunganishia kwa sasa. Stack uliyoisimamisha kwa ajili ya wikendi ina umbo hilo hasa, na database volume yake itafutwa pamoja nayo. Soma bind mounts versus named volumes kabla ya kuandika flag hiyo, na chukua backup kwanza.
Log za container ni ukuaji wa kimya kimya. Dereva chaguo-msingi wa json-file hana kikomo cha ukubwa, kwa hivyo container inayozalisha log nyingi huandika gigabytes kwenye /var/lib/docker/containers. Iwekee kikomo kwa kila container katika /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}Itekeleze kwa sudo systemctl restart docker, ambayo huanzisha upya containers zako, kwa hivyo chagua wakati mwafaka. Kikomo hicho hutumika kwa containers zilizoundwa baada ya mabadiliko hayo, kwa hivyo fanya recreate kwa zile zinazoendelea kufanya kazi kwa kutumia docker compose up -d --force-recreate na uthibitishe:
docker inspect my-app | grep -A5 LogConfig
sudo du -sh /var/lib/docker/containersMatokeo ya inspect yanapaswa kuonyesha max-size imewekwa. Ikiwa ni tupu, container hiyo ilikuwepo kabla ya mabadiliko na bado inaandika bila kikomo.
Tabia zinazodumisha afya ya seva ndogo ya Docker
Hakuna kati ya haya yanayohitaji dashibodi au zana unayopaswa kujifunza.
- Tekeleza
docker system dfnadf -h /kila tarehe moja ya mwezi. Amri mbili, sekunde thelathini, na utaona mwelekeo wa matumizi muda mrefu kabla ya tatizo kuwa kubwa. - Weka kikomo cha kumbukumbu (memory limit) kwa kila huduma, hata zile unazohakikisha ni ndogo. Kikomo hiki hubadilisha tatizo la seva nzima kuwa container moja tu inayowashwa upya.
- Fuatilia seva kutoka sehemu nyingine, ili upate taarifa kuhusu shinikizo la kumbukumbu au diski kabla ya kernel kuchukua hatua. Uptime Kuma huendeshwa ndani ya container na hutumia takriban 95 MB ikiwa haifanyi kazi.
- Hifadhi nakala (backup) za volumes, siyo containers. Container ni kitu kinachoweza kutupwa, lakini volume siyo. restic backups on a VPS inaelezea ratiba na jaribio la urejeshaji.
- Funga (pin) image tags kwenye faili ya compose na uzisashe siku unayochagua wewe. Kwa kutumia
latest, toleo unalopata kutoka kwadocker compose pullinayofuata ni lile lililotolewa asubuhi hiyo.
VPS ndogo inayoendesha Docker hubaki katika hali nzuri kwa miaka mingi ikiwa namba nne zitabaki katika kiwango kinachotakiwa: bajeti ya kumbukumbu, orodha ya ports zilizofunguliwa, sera ya restart kwenye kila huduma, na nafasi iliyobaki kwenye diski. Kila kitu kingine ni Docker ile ile unayoendesha nyumbani.
FAQ
Je, nahitaji RAM kiasi gani ili kuendesha Docker kwenye VPS?
Docker yenyewe haitumii rasilimali nyingi. Daemon na containerd kwa pamoja hutumia takriban 100 MB, na mahitaji mengine hutegemea containers zako. Tenga kwanza sehemu ya seva: 768 MB kwenye mashine ya 2048 MB kwa ajili ya mfumo wa uendeshaji, daemon, na nafasi ya ziada, jambo linalokuachia 1280 MB za kutumia. Database inayotumia 512 MB, reverse proxy ya 128 MB na programu mbili ndogo zinaweza kutoshea hapo. Pima stack yako mwenyewe kwa kutumia docker stats --no-stream badala ya kuamini takwimu zozote zilizochapishwa.
Je, ninaweza kuendesha Docker kwenye VPS ya 1 GB?
Ndiyo, kwa container moja au mbili ndogo, na ongeza swap file kabla ya kuanza. Takriban nusu ya mashine ya 1 GB hutumika mara tu mfumo wa uendeshaji na Docker daemon vinapoanza, jambo linaloacha nafasi kwa programu ndogo na reverse proxy, lakini si kwa database iliyo chini ya mzigo halisi. Kujenga (build) images kwenye mashine ya ukubwa huo kutafeli au kusababisha mchakato mwingine kusitishwa, kwa hiyo jenga kwingine na u-pull image iliyokamilika.
Je, UFW inalinda Docker container?
Hapana kwa port unazozichapisha (publish). Docker huandika sheria zake za DNAT na forward, kwa hiyo pakiti inayoelekezwa kwenye port ya container iliyochapishwa hupitishwa moja kwa moja kwenye container badala ya kufikishwa kwa host, na sheria za INPUT zinazosimamiwa na UFW hazioni trafiki hiyo. ufw deny 5432 inaweza kuwa hai wakati port hiyo inajibu kutoka kwenye Internet. Chapisha kwenye loopback kwa kutumia 127.0.0.1:5432:5432, acha huduma za ndani zikiwa hazijachapishwa, au chuja trafiki katika chain ya DOCKER-USER.
Je, containers zangu zitajiwasha upya baada ya VPS kuwaka upya (reboot)?
Zitajiwasha tu ikiwa ziliundwa na sera ya restart. Weka restart: unless-stopped kwenye kila huduma, endesha docker compose up -d ili containers ziundwe upya na sera hiyo, na uthibitishe kuwa systemctl is-enabled docker inatoa enabled. Kisha fanya reboot kwa makusudi na uangalie docker compose ps. Sera ya restart ambayo hujawahi kuijaribu si sera ya restart.
Ni mara ngapi ninapaswa kusafisha (prune) Docker images?
Mara moja kwa mwezi inatosha kwa seva nyingi ndogo, au wakati wowote docker system df inapoonyesha nafasi inayoweza kurejeshwa ambayo ungependa kuitumia. docker image prune -a na docker builder prune zote ni salama wakati huduma zinafanya kazi, kwa sababu images na cache zinazotumika hurukwa. Epuka docker system prune --volumes isipokuwa kama unajua vyema ni volumes zipi hazitumiki, kwa sababu inafuta data za stack yoyote ambayo imesimama kwa bahati mbaya.