PUID na PGID katika Docker Compose ni nini?
PUID na PGID si mipangilio ya Docker bali ni makubaliano ya picha za linuxserver.io. Jifunze kwa nini faili zako zinamilikiwa na 911 na jinsi ya kurekebisha ruhusa za ufikiaji.
PUID na PGID ni nini hasa
PUID na PGID ni vigezo viwili vya mazingira (environment variables) ambavyo picha (images) fulani za container husoma wakati wa kuanza. Docker yenyewe haviangalii vigezo hivi. Hii ni kawaida inayotumiwa na picha za linuxserver.io na nyingine chache, kwa hivyo picha ambayo haikuandikwa kuvitumia itavipuuza kimya kimya.
Ndani ya picha ya linuxserver.io kuna mtumiaji anayeitwa abc, aliyeundwa wakati wa ujenzi (build time) akiwa na UID (user ID) 911 na GID (group ID) 911. Container huanza kama root, huendesha hati zake za kuanzisha (init scripts), na moja ya hati hizo hubadilisha namba ya mtumiaji huyo kabla ya jambo lingine lolote kutokea:
groupmod -o -g "${PGID}" abc
usermod -o -u "${PUID}" abcFlag ya -o inaruhusu ID ambayo tayari inatumika mahali pengine. Baada ya hapo, mchakato wa init huacha upendeleo (privileges) na kuendesha programu kama abc. Kwa hiyo, PUID=1000 haifiki kamwe kwa Docker. Kigezo hiki hubadilisha namba ya mtumiaji ndani ya container kabla ya programu kuanza, jambo linalomaanisha kuwa kila faili ambalo programu hiyo huandika litahifadhiwa kwenye diski yako likimilikiwa na 1000. Ukiacha PUID bila kuwekwa, abc hubaki na 911, ndiyo sababu bind mount isiyosanidiwa hujaza faili zinazomilikiwa na 911:911.
Pata namba zako mbili ukitumia id
Tekeleza amri hii kwenye seva, ukiwa kama mtumiaji anayemiliki saraka za data:
iduid=1000(deploy) gid=1000(deploy) groups=1000(deploy),27(sudo),988(docker)uid ndiyo PUID yako na gid ndiyo PGID yako. Kwa ajili ya hati (script), id -u na id -g huchapisha namba hizo pekee. Kwenye picha nyingi za VPS mpya, akaunti ya kwanza ya binadamu ni 1000:1000, lakini usichukulie kuwa ni hivyo kila wakati. Seva iliyojengwa upya, au akaunti ya pili iliyoongezwa baadaye, hutoa 1001 au zaidi, na namba isiyo sahihi hapa ndiyo chanzo cha hitilafu nzima. Ikiwa huduma zako zinaendeshwa chini ya akaunti maalum ya huduma badala ya mtumiaji wako wa kawaida, tekeleza id thatuser na uchukue namba kutoka hapo.
Kwa nini faili zako zinaonekana kama 911:911
ls -l huchapisha namba ya kitambulisho (ID) badala ya jina wakati hakuna akaunti ya mtumiaji inayolingana na ID hiyo. Hakuna kitu kwenye seva yako chenye UID 911, kwa hivyo hakuna jina la kuchapishwa. Tumia ls -ln ili kuona namba kila wakati na kuondoa utata:
ls -ln /srv/appdata/sonarrdrwxr-xr-x 2 911 911 4096 Aug 7 09:12 Backups
-rw-r--r-- 1 911 911 512 Aug 7 09:12 config.xmlTokeo hilo linasema kuwa container iliendeshwa kwa kutumia mipangilio chaguo-msingi iliyojengwa ndani. Thibitisha hilo ukiwa ndani ya container badala ya kukisia:
docker exec sonarr id abc
docker compose logs sonarr | head -n 25Init ya linuxserver huchapisha matokeo yake kwenye logi ya kuanza kama mistari miwili:
User UID: 911
User GID: 911Ikiwa mistari hiyo inasoma 911 baada ya kuweka PUID=1000 kwenye faili yako ya Compose, kigezo hicho hakikufika kwenye container. Sababu ya kawaida ni kwamba ulihariri docker-compose.yml kisha ukaendesha docker compose restart, ambayo hutumia tena container iliyopo na mazingira yake ya awali. Mabadiliko ya mazingira yanahitaji docker compose up -d, ambayo huunda upya container.
Kwa nini huwezi kufuta faili iliyoandikwa na container
Kernel hulinganisha namba, si majina. Shell yako inaendeshwa kama UID 1000. Faili hiyo inamilikiwa na UID 911. Saraka (directory) inayoshikilia faili hiyo ni drwxr-xr-x na pia inamilikiwa na 911, kwa hivyo kundi (group) na wengine wana ruhusa ya kusoma na kutekeleza (read and execute) lakini si kuandika (write). Kufuta faili kunahitaji ruhusa ya kuandika kwenye saraka yake, si kwenye faili yenyewe, kwa hivyo unapata hitilafu hii hata wakati faili yenyewe inaonekana haina madhara:
rm: cannot remove '/srv/appdata/sonarr/config.xml': Permission deniedContainer inayojaribu kuandika inakumbana na kikwazo hicho hicho kutoka upande mwingine. Ikiwa saraka ya host inamilikiwa na mtumiaji wako kwa mode 755 na programu inaendeshwa kama 911, jaribio lake la kwanza la kuandika litafeli kwa Permission denied na programu itaripoti hilo kwa maneno yake yenyewe. Katika programu ya .NET kama Sonarr au Radarr, hii inaonekana kama UnauthorizedAccessException: Access to the path '/data/downloads' is denied. Mfuatano wa ruhusa mbele ya faili hukuambia ni seti ipi kati ya tatu unayohukumiwa kwayo, na kusoma drwxr-xr-x kwa usahihi ndiko kunakofanya hitilafu hiyo kutoka kuwa ya ajabu hadi kuwa dhahiri.
Hili ni tatizo la bind mount hasa. Wakati Docker inapotengeneza named volume tupu na kuipachika (mount) juu ya njia (path) iliyopo kwenye image, inanakili yaliyomo kwenye njia hiyo kwenda kwenye volume, ikijumuisha umiliki na bits za ruhusa, kwa hivyo programu hupata saraka ambayo tayari inaimiliki. Bind mount haipati matibabu hayo: Docker hupachika saraka yako ya host kama ilivyo. Tofauti hiyo ni moja ya sababu za kivitendo za kujua wakati bind mount inapozidi named volume na wakati haifanyi hivyo.
Kurekebisha saraka iliyo na makosa tayari
Kuweka PUID na PGID hubadilisha utendaji wa programu kuanzia sasa. Hii hairekebishi faili zilizopo kwenye diski. Simamisha stack, rekebisha umiliki wewe mwenyewe, kisha uianzishe tena:
docker compose down
sudo chown -R 1000:1000 /srv/appdata/sonarr
docker compose up -dTumia sudo chown -R "$(id -u):$(id -g)" /srv/appdata/sonarr ikiwa hutaki kuandika namba hizo. Fanya hivi wakati container imesimamishwa, kwa sababu programu inayofanya kazi na kuandika data wakati wa chown ya recursive inaweza kusababisha saraka kuwa na umiliki uliorekebishwa nusu na kuleta mfululizo wa makosa mengine.
Mambo ambayo PUID na PGID hayatatui
Hii ndiyo sehemu inayowatatiza watumiaji ambao wamefanya kila kitu kwa usahihi. Script ya kuanzisha ya linuxserver hufanya chown kwenye njia tatu pekee wakati wa kuanza: /app, /config, na /defaults. Mount zako za media hazimo kwenye orodha hiyo. /data, /downloads, na /tv hupewa programu bila kubadilishwa, kwa hivyo ikiwa upande wa host wa mount hizo una umiliki ambao mtumiaji wa container hawezi kuandikia, container huanza vizuri, huonyesha UID sahihi kwenye banner yake, kisha hushindwa wakati wa import ya kwanza.
Huo ndio mwenendo sahihi. Kufanya chown ya kurudia (recursive) kwenye maktaba ya media ya terabyte kumi na mbili kila wakati container inapoanza itakuwa janga. Hii inamaanisha kuwa saraka za media ni jukumu lako, na ndizo mount ambazo ruhusa (permissions) hukosewa mara nyingi.
Three ways to control the user, and when each one applies
PUID and PGID environment variables
This works only on images whose entrypoint reads them. It is popular because the container still starts as root, does its own setup, fixes /config, and only then drops privileges. Docker Mods and custom init scripts keep working. The cost is that you are trusting a convention rather than a platform feature, and the variable names are not standard across projects.
The user: key in Compose
This one is a real Docker feature and works on every image, because the container runtime applies it before the image's own code runs:
services:
sonarr:
image: lscr.io/linuxserver/sonarr:latest
user: "1000:1000"The process never runs as root, not even for a moment, which is a genuine security gain. It also breaks anything in the entrypoint that needed root. On linuxserver images the project supports this on a reasonable endeavours basis and only for images it has tested, and the caveats are specific: PUID and PGID stop having any effect, Docker Mods will not run, custom services will not run, and you become responsible for the permissions on every mounted volume. Their documented pattern pairs the flag with a writable /run:
user: 1000:1000
tmpfs:
- /run:uid=1000,gid=1000,exec
security_opt:
- no-new-privileges=trueOne cosmetic side effect surprises people. A numeric user: has no matching entry in the container's /etc/passwd, so tools inside report whoami: cannot find name for user ID 1000. The ID is valid and file access works normally. Only the name lookup fails.
Rootless Docker
Rootless Docker runs the daemon itself as your unprivileged user, so nothing on the box runs as real root. It changes the ownership arithmetic completely. Container UID 0 maps to the host UID of the user running rootless Docker, and container UID n for any n of 1 or more maps to subuid + (n - 1), where subuid is the base of the range allocated to you in /etc/subuid and /etc/subgid. Docker expects at least 65,536 subordinate IDs there.
Read that mapping again, because it inverts the usual advice. Under rootless Docker a container writing as root produces files owned by you. A container writing as UID 1000 produces files owned by a subordinate ID somewhere around 100999, which your shell cannot touch. So the PUID value that is correct on a rootful daemon is the wrong one here. The two mechanisms solve the same problem in different layers, and stacking them without checking is how people end up with a directory they need sudo to remove. If you go rootless, test the ownership of one written file on your own server before you migrate a library into it.
For most self-hosted stacks on a single VPS, PUID and PGID on a rootful daemon is the pragmatic choice, because it is what the images are built and documented for. Reach for user: when the image README says that image is tested for it, or when you are running an official upstream image that has no PUID support at all. A document workspace such as a self-hosted AFFiNE instance on one VPS falls into that last case, because none of its containers read PUID and the ownership of its database directory and uploaded files is settled by the runtime rather than by anything in the environment block.
Kisa cha media stack: kikundi kimoja kinachoshirikiwa kati ya containers
Media stack ya arr inayotumia Sonarr, Radarr na download client ni mahali ambapo nadharia hii inakuwa uhalisia. Download client huandika faili iliyokamilika ndani ya /data/downloads. Kisha Sonarr hufanya hardlink au kuhamisha faili hiyo kwenda /data/media. Ili hardlink ifanye kazi, containers zote mbili zinahitaji ruhusa ya kuandika (write access) kwenye mti huo wa saraka, na ikiwa download client inaendeshwa kama 1000 huku Sonarr ikiendeshwa kama 1001, mmoja wao atamiliki faili ambazo mwenzake anaweza kuzisoma tu.
Suluhisho ni kikundi kimoja (shared group) ambacho kila container kwenye stack hiyo inakitumia kama PGID yake:
sudo groupadd -g 13000 media
sudo usermod -aG media deploy
sudo chown -R deploy:media /srv/media
sudo find /srv/media -type d -exec chmod 2775 {} +
sudo find /srv/media -type f -exec chmod 0664 {} +Alama ya 2 iliyo mwanzo wa 2775 ni setgid bit. Kwenye saraka, hii inamaanisha kila faili mpya na saraka ndogo inayotengenezwa ndani yake hurithi kikundi cha media badala ya kikundi kikuu cha mtumiaji aliyetengeneza faili hiyo, hivyo mpangilio huu hudumu hata kwa vipakuliwa vipya bila wewe kuhitaji kuendesha chown tena. Ondoka (log out) na uingie tena, au endesha newgrp media, kabla ya kukagua ruhusa zako: kikundi kilichoongezwa kwa usermod -aG hakionekani kwenye shell session iliyo wazi tayari.
Ndani ya container, groupmod -o -g 13000 abc hubadilisha namba ya kikundi cha abc kuwa 13000, hivyo abc huandika kwa kutumia GID sawa na kikundi chako cha media kwenye host. Kila container kwenye stack huweka PUID yake yenyewe na kushiriki PGID hiyo moja.
Kisha weka UMASK=002 kwenye kila container ya linuxserver iliyo kwenye stack. Hii ndiyo hatua ambayo watu wengi husahau. Thamani chaguo-msingi kwenye images hizi ni UMASK=022, ambayo huondoa ruhusa ya kuandika ya kikundi (group write bit) kutoka kwa kila faili mpya, hivyo faili huonekana kama 0644 na ushirikiano uliosanidi haufanyi kazi. 002 huzalisha faili za 0664 na saraka za 0775, na kikundi kinaweza kuandika:
services:
sonarr:
image: lscr.io/linuxserver/sonarr:latest
container_name: sonarr
environment:
- PUID=${PUID}
- PGID=${PGID}
- UMASK=002
- TZ=Etc/UTC
volumes:
- /srv/appdata/sonarr:/config
- /srv/media:/data
restart: unless-stoppedThamani hizo mbili zinapaswa kuwekwa kwenye faili ya .env iliyo karibu na faili ya Compose, ili stack nzima isome ufafanuzi mmoja:
PUID=1000
PGID=13000Compose husoma faili hiyo kiotomatiki kwa ajili ya uingizwaji wa thamani wa mtindo wa ${PUID}, ambao ni utaratibu uleule unaotumia kwa ajili ya vitambulisho (credentials). Mazoea ya kuweka thamani nje ya docker-compose.yml na ndani ya faili ya .env yanatumika hapa pia, tofauti ikiwa ni kwamba namba hizi mbili si siri.
Thibitisha kuanzia mwanzo hadi mwisho badala ya kuamini usanidi tu. Andika faili kutoka ndani ya container moja na uisome kutoka kwenye host:
docker exec sonarr touch /data/downloads/permtest
ls -ln /srv/media/downloads/permtestMatokeo sahihi yanaonyesha PUID yako kama mmiliki, 13000 kama kikundi, na -rw-rw-r-- kama mode. Ikiwa kikundi kinasoma 1000, basi setgid bit haipo kwenye saraka hiyo. Ikiwa mode inasoma -rw-r--r--, basi variable ya UMASK haikufanya kazi, hivyo hakikisha umetengeneza upya (recreate) container badala ya kuianzisha upya (restart). Futa faili ya majaribio kwa kutumia rm /srv/media/downloads/permtest ukimaliza.
Ni picha zipi zinazotumia vigezo vipi
Picha za linuxserver.io hutumia PUID, PGID na UMASK. Paperless-ngx hutumia majina tofauti kwa dhana hiyo hiyo: USERMAP_UID na USERMAP_GID, zote zikiwa na thamani chaguo-msingi ya 1000, na nyaraka zake hukuagiza kuzisoma kutoka id -u na id -g. Seva za picha huonyesha tofauti kama hiyo: PhotoPrism ina jozi yake ya PHOTOPRISM_UID na PHOTOPRISM_GID, wakati Immich haitoi kigezo chochote sawa na hicho na inamwacha mtumiaji wa container atumie ufunguo wa user: wa Docker, kwa hivyo kuchagua kati ya PhotoPrism na Immich pia huamua ni utaratibu upi kati ya hii utakaokuwa ukiusimamia kwa ajili ya maktaba kubwa zaidi kwenye seva yako. Picha nyingi rasmi kutoka kwa watengenezaji, zikiwemo picha za kawaida za database na seva za wavuti, huja na mtumiaji maalum aliyewekwa ndani na hutegemea utumie user: au uachane nayo. Hali hiyo hiyo inatumika kwa miundombinu unayoongeza baadaye, kwa hivyo kuweka Authentik mbele ya programu zako kwa ajili ya kuingia mara moja inamaanisha kuendesha picha rasmi za seva, Postgres na Redis ambazo hazisomi PUID yoyote, na umiliki wa volume zao hutokana na wakati wa uendeshaji badala ya kutoka kwa entrypoint unayoweza kusanidi.
Kwa hivyo kagua README ya kila picha kabla ya kunakili kizuizi cha mazingira (environment block) kati ya miradi. Docker hupitisha kigezo chochote cha mazingira unachoweka kwenye container yoyote, iwe kitu kilicho ndani kinakisoma au la, na PUID ambayo haitumiwi na kitu chochote haitoi kosa, onyo, wala athari yoyote. Container huendeshwa kama mtumiaji yeyote ambaye Dockerfile yake iliishia naye, na utagundua hili kupitia umiliki wa faili inazoandika.
FAQ
Kwa nini faili zangu za Docker zinamilikiwa na 911:911?
911 ni UID na GID ya mtumiaji abc aliyejengwa ndani ya picha za linuxserver.io. Kuona namba hizi inamaanisha kuwa kontena ilianza bila PUID na PGID kuwekwa, kwa hivyo hati yake ya kuanzisha (init script) iliacha mipangilio chaguo-msingi iliyojengwa ndani. ls -l inaonyesha namba ghafi kwa sababu hakuna akaunti kwenye seva yako yenye ID 911, hivyo hakuna jina la kuonyesha. Weka PUID na PGID kwa matokeo ya id, tengeneza upya kontena kwa docker compose up -d, kisha rekebisha faili zilizopo kwa sudo chown -R 1000:1000 kwenye saraka husika.
Je, PUID na PGID hufanya kazi kwenye kila picha ya Docker?
Hapana. Hizi si kipengele cha Docker na Docker haizisomi kamwe. Hufanya kazi tu kwenye picha ambazo entrypoint yake inazisoma na kuita usermod na groupmod kabla ya kuanza programu, ambayo ni familia ya linuxserver.io na miradi michache iliyonakili muundo huo. Miradi mingine hutumia majina tofauti, kama vile USERMAP_UID na USERMAP_GID katika paperless-ngx. Kwenye picha isiyosoma yoyote kati ya hizo, vigezo hivyo hukubaliwa na kupuzwa bila onyo lolote.
Je, nitumie PUID na PGID au ufunguo wa user: katika Docker Compose?
Tumia PUID na PGID wakati picha inazikubali, kwa sababu entrypoint bado huendeshwa kama root kwa muda wa kutosha kurekebisha /config na kuanza huduma zake kwa usahihi. Tumia user: wakati picha haina msaada wa PUID, au wakati README ya picha inasema kuwa imefanyiwa majaribio ya kufanya kazi bila root. Kwenye picha ya linuxserver, kuweka user: hufanya PUID na PGID kutofanya kazi, husimamisha Docker Mods na huduma maalum zisiendeshwe, na hufanya ruhusa za kila volume iliyopachikwa kuwa jukumu lako.
Sonarr ina PUID sahihi lakini bado haiwezi kuhamisha faili. Nini tatizo?
Angalia mambo matatu kwa mpangilio. Kwanza, sehemu ya media iliyopachikwa (media mount): init hufanya chown tu kwa /app, /config na /defaults, kwa hivyo /data au /downloads hubaki na umiliki wowote ilionao kwenye seva. Pili, kundi lililoshirikiwa (shared group): ikiwa mteja wa kupakua (download client) na Sonarr vinaendeshwa chini ya GID tofauti, hakuna kinachoweza kurekebisha faili za mwenzake, kwa hivyo wape kontena zote kwenye stack hiyo PGID sawa. Tatu, umask: chaguo-msingi la picha UMASK=022 huandika faili kama 0644 bila ruhusa ya kuandika kwa kundi, jambo ambalo huharibu dhana ya kundi lililoshirikiwa kabisa. Weka UMASK=002 na uweke setgid bit kwenye saraka kwa chmod 2775 ili faili mpya zirithi kundi hilo.