الآلية: لماذا يرفض Docker الكتابة
Docker يشارك نواة Linux للمضيف. عند تثبيت مجلد من المضيف (bind-mount)، يطبّق نظام الملفات قواعد أذونات POSIX نفسها. ملف يملكه UID 1000 على المضيف يبقى تحت ملكية UID 1000 بغض النظر عن الاسم — سواء كان alice على المضيف أو paperless داخل الحاوية. إذا كانت العملية في الحاوية تعمل بـUID 472 والمجلد يملكه root (UID 0)، تُرفض الكتابة — حتى لو استخدمت chmod 755.
الفخ الكلاسيكي: تُنشئ المجلد بجلسة SSH الخاصة بك (UID 1000)، ثم تُشغّل حاوية Grafana التي تعمل بـUID 472. يحاول Grafana الكتابة في /var/lib/grafana المُثبَّت من /opt/grafana/data — الذي يملكه مستخدم SSH. النتيجة: GF_PATHS_DATA='/var/lib/grafana' is not writable.
التطبيقات الأكثر تأثراً ومعرّفات المستخدم الخاصة بها
تؤثر مشكلات أذونات Docker بصورة رئيسية على التطبيقات التي تعمل بـUID محدد يختلف عن UID المضيف.
- Paperless-ngx —
UID 1000 (المستخدم paperless): يدير مجلدات consume وexport وmedia وdata - Grafana —
UID 472 (المستخدم grafana): يكتب قاعدة بيانات SQLite والإضافات في /var/lib/grafana - Nextcloud (صورة Debian) —
UID 33 (المستخدم www-data): مجلد البيانات والإعدادات والسجلات - Immich —
UID 1000 (المستخدم node): مكتبة الصور والصور المصغّرة وقاعدة بيانات الذكاء الاصطناعي - Gitea —
UID 1000 (المستخدم git): المستودعات ومفاتيح SSH والسجلات وقاعدة بيانات SQLite الافتراضية
التشخيص: تحديد المشكلة في أقل من دقيقتين
قبل الإصلاح، تأكد أن المشكلة فعلاً تخص الأذونات وحدد UID المعني. ثلاثة أوامر تكفي.
قراءة رسالة الخطأ الدقيقة
راجع سجلات الحاوية المُشكِلة:
docker logs <اسم-الحاوية> 2>&1 | grep -i 'permission\|denied\|cannot\|mkdir'رسالة
permission denied أو cannot create directory تؤكد التشخيص.تحديد UID العملية داخل الحاوية
docker exec <اسم-الحاوية> idمثال على الناتج:
uid=472(grafana) gid=0(root). لاحظ UID — هنا 472.التحقق من مالك مجلد المضيف
ls -ln /opt/grafana/dataناتج
drwxr-xr-x 2 0 0 ... يعني أن المجلد يملكه root (UID 0). UID 472 لديه فقط صلاحيات «other» — القراءة والتنفيذ، لا الكتابة.استخدام stat للتشخيص الكامل
stat /opt/grafana/dataتحقق من سطري
Uid: وGid:. إذا أظهرا (0/root) بينما تعمل الحاوية بـ472، تأكدت المشكلة.فحص إعدادات الحاوية
docker inspect <اسم-الحاوية> | grep -A5 'Mounts'يسرد هذا الأمر كل bind-mounts والمجلدات المُسمّاة النشطة.
الإصلاح حالة بحالة: chown على مجلد المضيف
الإصلاح الأساسي هو chown على مجلد المضيف نحو UID الذي تتوقعه الحاوية. إليك الأوامر للتطبيقات الأكثر شيوعاً.
Grafana (UID 472)
mkdir -p /opt/grafana/data chown -R 472:472 /opt/grafana/dataفي
compose.yml الخاص بك:volumes: - /opt/grafana/data:/var/lib/grafanaNextcloud (UID 33، صورة Debian)
mkdir -p /opt/nextcloud/{data,config,apps} chown -R 33:33 /opt/nextcloud/data chown -R 33:33 /opt/nextcloud/configتنبيه: صورة Alpine تستخدم UID 82. تحقق بـ
docker exec <حاوية> id www-data إذا لم تكن متأكداً.Paperless-ngx (UID 1000)
mkdir -p /opt/paperless/{consume,export,media,data} chown -R 1000:1000 /opt/paperless/consume chown -R 1000:1000 /opt/paperless/export chown -R 1000:1000 /opt/paperless/media chown -R 1000:1000 /opt/paperless/dataImmich (UID 1000)
mkdir -p /opt/immich/{library,thumbnails,encoded-video,profile} chown -R 1000:1000 /opt/immichتنبيه: متغيرات البيئة
PUID/PGID لا تعمل مع صور Immich الرسمية.التحقق بعد الإصلاح
ls -ln /opt/grafana/dataيجب أن يُظهر
drwxr-xr-x 2 472 472 .... ثم أعد تشغيل الحاوية:docker compose restart grafana docker logs grafana --tail 20
الأنواع المختلفة: bind-mounts والمجلدات المُسمّاة و user:
يعمل chown على مجلد المضيف لـbind-mounts، لكن Docker يوفر مقاربات أخرى.
توجيه user: في compose.yml. بعض الصور مُصمَّمة لقبول UID اعتباطي عبر user:. هذا يتجنب chown إذا كان مجلدك يملكه مستخدم المضيف:
services:
app:
image: my-image
user: "1000:1000"
volumes:
- /home/user/data:/app/dataهذه المقاربة تعمل فقط إذا كانت الصورة لا تتطلب ملفات داخلية بـUID محدد.
المجلدات المُسمّاة في Docker. مع مجلد Docker مُسمّى، يدير Docker المجلد تحت /var/lib/docker/volumes/. عند أول كتابة، يُنشأ المجلد بأذونات عملية الحاوية — لا مشاكل أذونات عند بدء التشغيل، لكن ترحيل البيانات الموجودة يتطلب خطوة نسخ صريحة.
حالات NFS والتثبيتات البعيدة
تُضيف تثبيتات NFS طبقة تعقيد: يطبّق خادم NFS قواعد UID الخاصة به. إذا كان الخادم يُصدِّر مع root_squash (الافتراضي)، يُخفَّض وصول root من العميل إلى nobody.
الحلول:
1. ضبط تصدير NFS بـall_squash,anonuid=472,anongid=472 لـGrafana.
2. استخدام no_root_squash فقط إذا كنت تتحكم كلياً في الشبكة (خطر أمني).
3. لـCIFS/SMB، مرّر uid=33,gid=33 في خيارات التثبيت لـNextcloud.
في /etc/fstab:
//server/share /opt/nextcloud/data cifs uid=33,gid=33,credentials=/etc/cifs-creds,iocharset=utf8 0 0مقارنة طرق الإصلاح
مرّر الجدول أفقيًا
| الطريقة | المزايا | المخاطر / القيود |
|---|---|---|
| chown UID:GID على مجلد المضيف | بسيطة وعالمية ومتوافقة مع جميع الصور | يجب معرفة UID الدقيق؛ تحتاج إعادة التطبيق عند إعادة إنشاء المجلد |
| user: UID:GID في compose.yml | لا حاجة لـ chown؛ قابل للنقل بين المضيفين | الصورة يجب أن تدعم UIDs اعتباطية؛ قد يكسر الملفات الداخلية |
| المجلدات المُسمّاة في Docker | تُدار الأذونات تلقائياً عند أول تشغيل | أقل شفافية؛ ترحيل البيانات الموجودة أكثر تعقيداً |
| --privileged أو chmod 777 | يحل المشكلة فوراً | خطر: يكشف المضيف وجميع العمليات؛ لا تستخدم أبداً في الإنتاج |
استكشاف الأخطاء: 4 أخطاء كلاسيكية مع رسائلها الدقيقة
إليك أكثر أربعة أخطاء Docker شيوعاً المتعلقة بالأذونات، مع رسالة الخطأ الدقيقة وحلها.
-
mkdir: cannot create directory '/var/lib/grafana/plugins': Permission denied ← مجلد المضيف لا يملكه UID 472. طبّق chown -R 472:472 /opt/grafana/data. -
[Errno 13] Permission denied: '/usr/src/paperless/media' ← Paperless-ngx لا يمكنه الكتابة في مجلد media. تحقق أن bind-mount يملكه UID 1000 على المضيف. -
Could not create lock file /var/lib/grafana/.~lock.grafana.db ← Grafana يقرأ المجلد لكنه لا يستطيع الكتابة. مشكلة أذونات على الملفات الموجودة: احذف ملف القفل. -
chown: changing ownership of '/data': Operation not permitted (عند بدء الحاوية) ← الصورة تحاول إصلاح الأذونات لكنها لا تعمل بـroot. نفّذ chown يدوياً على المضيف قبل تشغيل الحاوية.
SELinux وAppArmor: العَلَمان :z و:Z في bind-mounts. على الأنظمة ذات SELinux النشط (CentOS، RHEL، Fedora)، قد يُحظر bind-mount حتى لو كانت أذونات POSIX صحيحة. Docker يوفر لاحقتين: :z يُعيد تسمية المحتوى للمشاركة بين حاويات متعددة، و:Z للوصول الخاص. مثال: - /opt/grafana/data:/var/lib/grafana:z. للتحقق: ausearch -m AVC -ts recent | grep docker.
الخلاصة
Permission denied في سجلات Docker ليس قدراً محتوماً. الحل في ثلاثة أوامر: docker exec <حاوية> id لمعرفة UID، ثم ls -ln <مجلد-المضيف> للتأكد من المالك الحالي، ثم chown -R <UID>:<GID> <مجلد-المضيف> للإصلاح. القاعدة الذهبية: أنشئ مجلدات المضيف بالمالك الصحيح قبل تشغيل الحاوية، لا بعدها.