SSD Nodes Learn 🎉 VPS dari $5.50/bln
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-08-13

Apa Itu PUID dan PGID dalam Docker Compose?

PUID dan PGID bukan tetapan Docker tetapi konvensyen imej linuxserver.io. Ketahui punca fail bind mount menjadi 911:911 dan cara menetapkan ID pengguna yang betul.

Apakah sebenarnya PUID dan PGID

PUID dan PGID ialah dua pemboleh ubah persekitaran yang dibaca oleh imej kontena tertentu semasa permulaan. Docker sendiri tidak pernah melihat pemboleh ubah ini. Ia merupakan satu konvensyen yang digunakan oleh imej linuxserver.io dan beberapa imej lain, jadi imej yang tidak ditulis untuk membacanya akan mengabaikannya secara senyap.

Di dalam imej linuxserver.io terdapat pengguna bernama abc, yang dicipta semasa masa binaan dengan UID (ID pengguna) 911 dan GID (ID kumpulan) 911. Kontena bermula sebagai root, menjalankan skrip initnya, dan salah satu skrip tersebut menukar nombor pengguna itu sebelum perkara lain berlaku:

groupmod -o -g "${PGID}" abc
usermod -o -u "${PUID}" abc

Flag -o membenarkan ID yang sudah digunakan di tempat lain. Selepas itu, init menggugurkan keistimewaan dan menjalankan aplikasi sebagai abc. Jadi PUID=1000 tidak pernah sampai ke Docker. Pemboleh ubah ini menukar nombor pengguna di dalam kontena sebelum aplikasi bermula, yang bermaksud setiap fail yang ditulis oleh aplikasi tersebut akan disimpan pada cakera anda dengan pemilikan 1000. Biarkan PUID tidak ditetapkan dan abc mengekalkan 911, itulah sebabnya bind mount yang tidak dikonfigurasikan dipenuhi dengan fail yang dimiliki oleh 911:911.

Dapatkan dua nombor anda dengan id

Jalankan arahan ini pada hos, sebagai pengguna yang memiliki direktori data tersebut:

id
uid=1000(deploy) gid=1000(deploy) groups=1000(deploy),27(sudo),988(docker)

uid ialah PUID anda dan gid ialah PGID anda. Untuk skrip, id -u dan id -g akan memaparkan nombor tersebut sahaja. Pada kebanyakan imej VPS baharu, akaun manusia pertama ialah 1000:1000, tetapi jangan buat andaian. Pelayan yang dibina semula, atau akaun kedua yang ditambah kemudian, akan memberikan nombor 1001 atau lebih tinggi, dan nombor yang salah di sini adalah punca utama pepijat. Jika servis anda berjalan di bawah akaun servis khusus dan bukannya pengguna log masuk anda sendiri, jalankan id thatuser dan ambil nombor daripada akaun tersebut.

Mengapa fail anda dipaparkan sebagai 911:911

ls -l mencetak ID berangka dan bukannya nama apabila tiada akaun hos yang sepadan dengan ID tersebut. Tiada apa-apa pada pelayan anda yang mempunyai UID 911, jadi tiada nama untuk dicetak. Gunakan ls -ln untuk melihat nombor setiap kali dan menghapuskan kekaburan:

ls -ln /srv/appdata/sonarr
drwxr-xr-x 2 911 911 4096 Aug  7 09:12 Backups
-rw-r--r-- 1 911 911  512 Aug  7 09:12 config.xml

Output tersebut menyatakan bahawa kontena dijalankan dengan tetapan lalai terbina dalam. Sahkan perkara ini dari dalam kontena dan bukannya membuat andaian:

docker exec sonarr id abc
docker compose logs sonarr | head -n 25

Init linuxserver mencetak hasilnya dalam log permulaan sebagai dua baris:

User UID:    911
User GID:    911

Jika baris tersebut membaca 911 selepas anda menetapkan PUID=1000 dalam fail Compose anda, pemboleh ubah tersebut tidak sampai ke kontena. Punca biasa ialah anda menyunting docker-compose.yml dan kemudian menjalankan docker compose restart, yang menggunakan semula kontena sedia ada dengan persekitaran asalnya. Perubahan persekitaran memerlukan docker compose up -d, yang mencipta semula kontena tersebut.

Mengapa anda tidak boleh memadam fail yang ditulis oleh kontena

Kernel membandingkan nombor, bukan nama. Shell anda berjalan sebagai UID 1000. Fail tersebut dimiliki oleh UID 911. Direktori yang menyimpannya ialah drwxr-xr-x dan juga dimiliki oleh 911, jadi kumpulan dan pengguna lain hanya mendapat kebenaran baca dan laksana tetapi tiada kebenaran tulis. Memadam fail memerlukan kebenaran tulis pada direktori fail tersebut, bukan pada fail itu sendiri, jadi anda mendapat ralat ini walaupun fail itu sendiri kelihatan tidak berbahaya:

rm: cannot remove '/srv/appdata/sonarr/config.xml': Permission denied

Kontena yang menulis menghadapi halangan yang sama dari sisi yang berbeza. Jika direktori hos dimiliki oleh pengguna anda dengan mod 755 dan aplikasi berjalan sebagai 911, penulisan pertamanya akan gagal dengan Permission denied dan aplikasi akan melaporkannya dalam bahasa tersendiri. Dalam aplikasi .NET seperti Sonarr atau Radarr, ini muncul sebagai UnauthorizedAccessException: Access to the path '/data/downloads' is denied. Rentetan kebenaran di hadapan fail memberitahu anda set kebenaran yang mana satu yang sebenarnya digunakan untuk menilai anda, dan membaca drwxr-xr-x dengan betul adalah perkara yang mengubah ralat tersebut daripada sesuatu yang misteri kepada sesuatu yang jelas.

Ini merupakan masalah bind mount secara khusus. Apabila Docker mencipta named volume kosong dan melekapkannya pada laluan yang wujud dalam imej, ia menyalin kandungan laluan tersebut ke dalam volume, termasuk hak milik dan bit kebenaran, supaya aplikasi menemui direktori yang sudah dimilikinya. Bind mount tidak menerima layanan tersebut: Docker melekapkan direktori hos anda tepat seperti sedia ada. Perbezaan itu adalah salah satu sebab praktikal untuk mengetahui bila bind mount lebih baik daripada named volume dan bila tidak.

Membaiki direktori yang sudah salah

Menetapkan PUID dan PGID hanya mengubah tindakan aplikasi mulai sekarang. Ia tidak membaiki fail yang sudah sedia ada pada cakera secara retroaktif. Hentikan stack, betulkan pemilikan fail sendiri, kemudian mulakan semula:

docker compose down
sudo chown -R 1000:1000 /srv/appdata/sonarr
docker compose up -d

Gunakan sudo chown -R "$(id -u):$(id -g)" /srv/appdata/sonarr jika anda tidak mahu menaip nombor tersebut. Lakukan ini semasa kontena dihentikan, kerana aplikasi yang sedang berjalan dan melakukan penulisan semasa chown rekursif boleh menyebabkan pepohon direktori yang separuh dibaiki serta pusingan ralat kedua yang mengelirukan.

Perkara yang tidak diselesaikan oleh PUID dan PGID

Ini adalah bahagian yang sering memerangkap pengguna yang telah melakukan segala-galanya dengan betul. Skrip init linuxserver melakukan chown pada tepat tiga laluan semasa permulaan: /app, /config dan /defaults. Mount media anda tidak termasuk dalam senarai tersebut. /data, /downloads dan /tv diserahkan kepada aplikasi tanpa sebarang perubahan. Oleh itu, jika bahagian hos bagi mount tersebut mempunyai pemilikan yang tidak boleh ditulis oleh pengguna kontena, kontena akan bermula dengan lancar, memaparkan UID yang betul dalam bannernya, dan kemudian gagal pada import pertama.

Itu adalah kelakuan yang betul. Operasi chown secara rekursif chown ke atas pustaka media bersaiz dua belas terabait pada setiap permulaan kontena akan membawa bencana. Ini bermakna direktori media adalah tanggungjawab anda, dan ia merupakan mount di mana masalah kebenaran akses (permissions) sebenarnya berlaku.

Tiga cara untuk mengawal pengguna, dan bila setiap satunya digunakan

Pemboleh ubah persekitaran PUID dan PGID

Cara ini hanya berfungsi pada imej yang entrypoint-nya membaca pemboleh ubah tersebut. Ia popular kerana kontena masih bermula sebagai root, melakukan persediaan sendiri, membetulkan /config, dan hanya kemudian melepaskan keistimewaan. Docker Mods dan skrip init tersuai terus berfungsi. Kekurangannya ialah anda mempercayai konvensyen dan bukannya ciri platform, dan nama pemboleh ubah tidak seragam merentas projek.

Kunci user: dalam Compose

Ini adalah ciri sebenar Docker dan berfungsi pada setiap imej, kerana runtime kontena menggunakannya sebelum kod imej itu sendiri dijalankan:

services:
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    user: "1000:1000"

Proses tersebut tidak pernah berjalan sebagai root, walaupun untuk seketika, yang merupakan peningkatan keselamatan yang tulen. Ia juga akan merosakkan mana-mana bahagian dalam entrypoint yang memerlukan root. Pada imej linuxserver, projek ini menyokongnya berdasarkan usaha yang munasabah dan hanya untuk imej yang telah diuji, dan terdapat kaveat khusus: PUID dan PGID tidak lagi memberi kesan, Docker Mods tidak akan berjalan, servis tersuai tidak akan berjalan, dan anda bertanggungjawab ke atas kebenaran pada setiap volum yang dipasang (mounted). Corak yang didokumentasikan oleh mereka menggandingkan flag tersebut dengan /run yang boleh ditulis:

user: 1000:1000
tmpfs:
  - /run:uid=1000,gid=1000,exec
security_opt:
  - no-new-privileges=true

Satu kesan sampingan kosmetik mengejutkan pengguna. user: berangka tidak mempunyai entri yang sepadan dalam /etc/passwd kontena, jadi alatan di dalam melaporkan whoami: cannot find name for user ID 1000. ID tersebut sah dan akses fail berfungsi seperti biasa. Hanya carian nama yang gagal.

Rootless Docker

Rootless Docker menjalankan daemon itu sendiri sebagai pengguna tanpa keistimewaan anda, jadi tiada apa-apa pada mesin tersebut yang berjalan sebagai root sebenar. Ia mengubah aritmetik pemilikan sepenuhnya. UID 0 kontena dipetakan kepada UID hos pengguna yang menjalankan rootless Docker, dan UID n kontena untuk sebarang n 1 atau lebih dipetakan kepada subuid + (n - 1), di mana subuid ialah asas julat yang diperuntukkan kepada anda dalam /etc/subuid dan /etc/subgid. Docker menjangkakan sekurang-kurangnya 65,536 ID bawahan di sana.

Baca semula pemetaan itu, kerana ia menyongsangkan nasihat biasa. Di bawah rootless Docker, kontena yang menulis sebagai root menghasilkan fail yang dimiliki oleh anda. Kontena yang menulis sebagai UID 1000 menghasilkan fail yang dimiliki oleh ID bawahan sekitar 100999, yang tidak boleh disentuh oleh shell anda. Jadi, nilai PUID yang betul pada daemon rootful adalah salah di sini. Kedua-dua mekanisme menyelesaikan masalah yang sama pada lapisan yang berbeza, dan menggabungkannya tanpa pemeriksaan adalah punca pengguna berakhir dengan direktori yang memerlukan sudo untuk dipadamkan. Jika anda menggunakan rootless, uji pemilikan satu fail yang ditulis pada pelayan anda sendiri sebelum anda memindahkan pustaka ke dalamnya.

Bagi kebanyakan stack self-hosted pada satu VPS, PUID dan PGID pada daemon rootful adalah pilihan pragmatik, kerana itulah tujuan imej dibina dan didokumentasikan. Gunakan user: apabila README imej menyatakan bahawa imej tersebut telah diuji untuknya, atau apabila anda menjalankan imej upstream rasmi yang langsung tidak mempunyai sokongan PUID. Ruang kerja dokumen seperti instans AFFiNE yang dihoskan sendiri pada satu VPS termasuk dalam kes terakhir ini, kerana tiada satu pun kontena miliknya membaca PUID dan pemilikan direktori pangkalan data serta fail yang dimuat naik diselesaikan oleh runtime dan bukannya oleh apa-apa dalam blok persekitaran.

Kes media stack: satu kumpulan dikongsi merentasi kontena

Arr media stack dengan Sonarr, Radarr dan klien muat turun adalah tempat di mana perkara ini bukan lagi sekadar teori. Klien muat turun menulis fail yang telah selesai ke dalam /data/downloads. Sonarr kemudian melakukan hardlink atau memindahkan fail tersebut ke dalam /data/media. Agar hardlink berfungsi, kedua-dua kontena memerlukan akses tulis ke direktori yang sama. Jika klien muat turun berjalan sebagai 1000 manakala Sonarr berjalan sebagai 1001, salah satu daripadanya akan memiliki fail yang hanya boleh dibaca oleh yang satu lagi.

Penyelesaiannya ialah kumpulan kongsi yang digunakan oleh setiap kontena dalam stack tersebut sebagai PGID mereka:

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 {} +

2 di hadapan 2775 ialah bit setgid. Pada sesebuah direktori, ini bermakna setiap fail dan subdirektori baharu yang dicipta di dalamnya akan mewarisi kumpulan media dan bukannya kumpulan utama penciptanya. Oleh itu, tetapan ini kekal berkesan untuk muat turun baharu tanpa anda perlu menjalankan chown semula. Log keluar dan masuk semula, atau jalankan newgrp media, sebelum anda menyemak akses anda sendiri: kumpulan yang ditambah dengan usermod -aG tidak akan muncul dalam sesi shell yang sedang dibuka.

Di dalam kontena, groupmod -o -g 13000 abc menukar nombor kumpulan abc kepada 13000, supaya abc menulis dengan GID yang sama seperti kumpulan media pada hos anda. Setiap kontena dalam stack mengekalkan PUID masing-masing dan berkongsi PGID yang sama.

Kemudian, tetapkan UMASK=002 pada setiap kontena linuxserver dalam stack tersebut. Ini adalah langkah yang sering terlepas pandang. Nilai lalai dalam imej ini ialah UMASK=022, yang membuang bit tulis kumpulan daripada setiap fail baharu. Akibatnya, fail disimpan sebagai 0644 dan perkongsian yang baru anda konfigurasikan tidak akan berfungsi. 002 menghasilkan fail 0664 dan direktori 0775, dan kumpulan tersebut boleh melakukan penulisan:

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-stopped

Kedua-dua nilai tersebut perlu diletakkan dalam fail .env bersebelahan dengan fail Compose, supaya keseluruhan stack membaca satu definisi yang sama:

PUID=1000
PGID=13000

Compose membaca fail tersebut secara automatik untuk penggantian gaya ${PUID}, yang merupakan mekanisme sama yang anda gunakan untuk kelayakan (credentials). Tabiat mengenai menyimpan nilai di luar docker-compose.yml dan memasukkannya ke dalam fail .env juga terpakai di sini, dengan perbezaan bahawa kedua-dua nombor ini bukanlah rahsia.

Sahkan tetapan ini dari hujung ke hujung dan jangan hanya mempercayai konfigurasi tersebut. Tulis fail dari dalam satu kontena dan baca fail tersebut daripada hos:

docker exec sonarr touch /data/downloads/permtest
ls -ln /srv/media/downloads/permtest

Hasil yang betul akan menunjukkan PUID anda sebagai pemilik, 13000 sebagai kumpulan, dan -rw-rw-r-- sebagai mod. Jika kumpulan membaca 1000, bermakna bit setgid tiada pada direktori tersebut. Jika mod membaca -rw-r--r--, bermakna pemboleh ubah UMASK tidak berkesan; pastikan anda mencipta semula kontena tersebut dan bukannya sekadar memulakannya semula. Padam fail ujian dengan rm /srv/media/downloads/permtest apabila anda selesai.

Imej mana yang menggunakan pemboleh ubah yang mana

Imej linuxserver.io menggunakan PUID, PGID dan UMASK. Paperless-ngx menggunakan nama yang berbeza untuk konsep yang sama: USERMAP_UID dan USERMAP_GID, kedua-duanya menggunakan nilai lalai 1000, dan dokumentasinya mengarahkan anda untuk membacanya daripada id -u dan id -g. Pelayan foto menunjukkan kepelbagaian yang sama: PhotoPrism mempunyai pasangan PHOTOPRISM_UID dan PHOTOPRISM_GID tersendiri, manakala Immich tidak menyertakan setara dan membiarkan pengguna kontena kepada kunci user: milik Docker, jadi memilih antara PhotoPrism dan Immich juga menentukan mekanisme mana yang akan anda selenggara untuk pustaka terbesar pada pelayan tersebut. Banyak imej hulu rasmi, termasuk imej pangkalan data dan pelayan web yang biasa, menyertakan pengguna binaan dalam yang tetap dan menjangkakan anda menggunakan user: atau membiarkannya begitu sahaja. Perkara yang sama terpakai kepada infrastruktur yang anda tambah kemudian, jadi meletakkan Authentik di hadapan aplikasi anda untuk log masuk tunggal bermakna menjalankan imej pelayan rasmi, Postgres dan Redis yang tidak membaca PUID langsung, dan pemilikan volumnya datang daripada masa jalan (runtime) dan bukannya daripada entrypoint yang boleh anda konfigurasi.

Oleh itu, semak README bagi setiap imej sebelum anda menyalin blok persekitaran antara projek. Docker menghantar sebarang pemboleh ubah persekitaran yang anda tetapkan ke dalam mana-mana kontena, sama ada sesuatu di dalamnya membacanya atau tidak, dan PUID yang tidak digunakan oleh apa-apa tidak akan menghasilkan ralat, amaran atau kesan. Kontena tersebut berjalan sebagai pengguna yang ditetapkan pada akhir Dockerfile miliknya sendiri, dan anda akan mengetahuinya melalui pemilikan fail yang ditulis olehnya.

FAQ

Mengapakah fail Docker saya dimiliki oleh 911:911?

911 ialah UID dan GID bagi pengguna abc yang dibina ke dalam imej linuxserver.io. Jika anda melihat nombor ini, bermakna kontena bermula tanpa PUID dan PGID ditetapkan, jadi skrip init mengekalkan tetapan lalai asal. ls -l memaparkan nombor mentah kerana tiada akaun pada hos anda yang mempunyai ID 911, maka tiada nama untuk dipaparkan. Tetapkan PUID dan PGID kepada output id, cipta semula kontena dengan docker compose up -d, kemudian betulkan fail sedia ada menggunakan sudo chown -R 1000:1000 pada direktori yang terjejas.

Adakah PUID dan PGID berfungsi pada setiap imej Docker?

Tidak. Ia bukan ciri Docker dan Docker tidak pernah membacanya. Ia hanya berfungsi pada imej yang entrypoint-nya membaca pemboleh ubah tersebut dan memanggil usermod serta groupmod sebelum memulakan aplikasi, iaitu keluarga linuxserver.io dan beberapa projek lain yang meniru corak tersebut. Projek lain menggunakan nama berbeza, seperti USERMAP_UID dan USERMAP_GID dalam paperless-ngx. Pada imej yang tidak membaca mana-mana pemboleh ubah ini, ia akan diterima tetapi diabaikan tanpa sebarang amaran.

Patutkah saya menggunakan PUID dan PGID atau kunci user: dalam Docker Compose?

Gunakan PUID dan PGID apabila imej menyokongnya, kerana entrypoint masih berjalan sebagai root untuk tempoh yang cukup bagi membetulkan /config dan memulakan servisnya sendiri dengan betul. Gunakan user: apabila imej tidak mempunyai sokongan PUID, atau apabila README imej menyatakan ia telah diuji untuk operasi bukan root. Pada imej linuxserver, menetapkan user: akan menjadikan PUID dan PGID tidak berfungsi, menghalang Docker Mods dan servis tersuai daripada berjalan, serta menjadikan keizinan setiap volum yang dipasang sebagai tanggungjawab anda sepenuhnya.

Sonarr mempunyai PUID yang betul tetapi masih tidak boleh mengalihkan fail. Apakah masalahnya?

Semak tiga perkara mengikut urutan. Pertama, pemasangan media itu sendiri: init hanya melakukan chown pada /app, /config dan /defaults, jadi /data atau /downloads akan mengekalkan pemilikan asal pada hos. Kedua, kumpulan kongsi: jika klien muat turun dan Sonarr berjalan di bawah GID yang berbeza, kedua-duanya tidak boleh mengubah suai fail pihak lain, jadi berikan setiap kontena dalam stack tersebut PGID yang sama. Ketiga, umask: tetapan lalai imej UMASK=022 menulis fail sebagai 0644 tanpa bit tulis kumpulan, yang menggagalkan fungsi kumpulan kongsi sepenuhnya. Tetapkan UMASK=002 dan tetapkan bit setgid pada direktori dengan chmod 2775 supaya fail baharu mewarisi kumpulan tersebut.