SSD Nodes Learn Hosting plans →
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-08-27

أساسيات Docker Compose على VPS بنظام Ubuntu 24.04

ثبّت Docker Engine وCompose v2 على Ubuntu 24.04، وابنِ ملف compose.yml بخدمتين، وتعلّم لماذا تتجاوز المنافذ المنشورة قواعد ufw وكيف تنسخ وحدات التخزين احتياطياً.

ما الذي ستبنيه

يُعد Docker Compose الأساس الذي تعتمد عليه معظم العناصر الأخرى في هذا الموقع. تبدأ أدلة Nextcloud وVaultwarden وn8n وImmich وRocket.Chat جميعها تقريباً بعبارة «اكتب ملف compose هذا». وتشرح هذه الصفحة المعنى الفعلي لذلك الملف. ستثبّت Docker Engine وإضافة Compose v2 من مستودع apt الرسمي لـDocker على Ubuntu 24.04. ثم ستشغّل حزمة حقيقية تتكون من خدمتين: Miniflux، وهو قارئ RSS صغير، وPostgreSQL. يختبر هذا الزوج كل الأنماط التي تستخدمها التطبيقات الأكبر: صور مثبتة الإصدارات، وقاعدة بيانات تتضمن healthcheck، ووحدة تخزين مسماة، وأسرار في ملف .env، ومنفذ منشور على localhost فقط.

يستغرق التثبيت خمس دقائق. أما بقية هذا الدليل فتغطي الجوانب التي تسبب المشكلات لاحقاً: كون مجموعة docker اسماً آخر لـroot، وتجاوز المنافذ المنشورة لقواعد ufw مباشرة، والعَلَم الوحيد في docker compose down الذي يحذف قاعدة بياناتك من دون مطالبتك بالتأكيد.

المتطلبات المسبقة: Ubuntu 24.04 جديد على KVM VPS، ومستخدم لديه sudo، و1 gigabyte من RAM أو أكثر. لا مشكلة في وجود تثبيت Docker مسبقاً؛ يوضح القسم الأول ما يجب إزالته.

ثبّت من مستودع Docker، وليس من مستودع Ubuntu

ارفض مسارين خاطئين قبل تنفيذ الأمر الأول. تعمل حزمة docker.io الخاصة بـUbuntu، لكنها تتأخر عن إصدارات Docker ولا تتضمن بنية الإضافات التي تفترضها بقية الأدوات. أما الملف التنفيذي المستقل docker-compose، الذي يحتوي اسمه على واصلة، فهو Compose v1 المكتوب بلغة Python، وقد انتهى دعمه منذ 2023، وهو سبب تعطل الشروحات الأقدم. الإصدار الحالي من Compose هو docker compose مع وجود مسافة بين الكلمتين. وهو إضافة CLI تُثبّت من المستودع نفسه الذي يوفّر المحرك.

إذا كان أي من ذلك موجوداً على الخادم، فأزله أولاً، بما في ذلك docker-compose-v2، وهي حزمة Ubuntu الخاصة بالإضافة، حتى تأتي كل المكونات من مستودع واحد:

sudo apt remove -y docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc

يُعد Package 'docker.io' is not installed, so not removed الناتج المعتاد على VPS جديد. أضف بعد ذلك مستودع Docker وثبّت الحزم:

sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

تحقق من الطبقات الثلاث كلها:

docker --version
docker compose version
sudo docker run --rm hello-world

يعرض الأمران الأولان سلاسل الإصدار. ويؤكد Docker Compose version v2.x.x أن لديك الإضافة، وليس الملف التنفيذي القديم v1 الذي انتهى دعمه. يجب أن ينتهي تشغيل hello-world بالقيمة Hello from Docker!. تفعّل الحزمة الخدمة عند الإقلاع، ويعرض systemctl is-enabled docker القيمة enabled.

مجموعة docker هي root، فاتخذ قرارك وأنت على دراية كاملة

حالياً، يحتاج كل أمر docker إلى sudo، لأن مقبس البرنامج الخفي في /var/run/docker.sock مملوك لحساب root ولمجموعة docker. من دون العضوية في هذه المجموعة، سيظهر لك خطأ Docker الأكثر بحثاً عنه:

permission denied while trying to connect to the Docker daemon socket at
unix:///var/run/docker.sock

الإصلاح المعتاد:

sudo usermod -aG docker $USER

تُطبَّق عضوية المجموعة عند تسجيل الدخول، لذلك يستمر الخطأ في جلسة الصدفة الحالية. شغّل newgrp docker لهذه الجلسة، أو سجّل الخروج ثم سجّل الدخول مجدداً؛ وبعد ذلك يجب أن يعرض id المجموعة docker ضمن مجموعاتك.

والآن الجزء الذي يجب توضيحه بصراحة: العضوية في مجموعة docker تعادل امتلاك صلاحيات root على المضيف. ليست «شبيهة بـroot»، وليست «مرتفعة» فقط، بل هي root. يستطيع أي مستخدم في هذه المجموعة تشغيل docker run --rm -it -v /:/host alpine chroot /host والسيطرة على نظام الملفات بالكامل، من دون طلب كلمة مرور. وُجدت المجموعة لتسهيل الاستخدام، لا لتوفير العزل.

يُعد وضع Docker دون root البديل الفعلي، إذ يعمل البرنامج الخفي نفسه بصفته المستخدم غير المميّز الخاص بك. لكنه يفرض قيوداً: تحتاج المنافذ الأقل من 1024 إلى إعداد إضافي، وتعمل الشبكات عبر طبقة وسيطة في مساحة المستخدم مع تكلفة أداء قابلة للقياس، وقد تتصرف بعض الصور بصورة غير صحيحة من دون صلاحيات root فعلية. على VPS يديره مسؤول واحد، حيث يملك تسجيل الدخول الوحيد صلاحية sudo أصلاً، لا تغيّر المجموعة شيئاً من الناحية العملية. وهذا ما تفترضه كل الأدلة هنا، لكن لا تمنح عضويتها لأحد كما لو كانت أقل خطورة من sudo.

بنية ملف Compose

ضع كل مكدس في دليله الخاص. يصبح اسم الدليل اسم المشروع، ويُضاف هذا الاسم إلى أسماء الحاويات والشبكات ووحدات التخزين:

sudo mkdir -p /opt/miniflux && sudo chown $USER /opt/miniflux && cd /opt/miniflux

أنشئ compose.yml (وهو الاسم الحديث؛ وما زال docker-compose.yml يعمل). تخطَّ مفتاح version: القديم، فقد أصبح مهجوراً، ويصدر Compose تحذيراً عند العثور عليه.

services:
  miniflux:
    image: miniflux/miniflux:2.2.9
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      - DATABASE_URL=postgres://miniflux:${POSTGRES_PASSWORD}@db/miniflux?sslmode=disable
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=admin
      - ADMIN_PASSWORD=${ADMIN_PASSWORD}
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=miniflux
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "miniflux", "-d", "miniflux"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  db-data:

كل سطر أعلاه يمثل قراراً. عالج هذه القرارات واحداً تلو الآخر.

ثبّت إصدارات الصور، لأن استخدام :latest مع pull يؤدي إلى ترقية غير مراقبة

استخدم postgres:16-alpine، وليس postgres:latest. الوسم ليس ثابتاً؛ إذ يعيد :latest حلّه إلى آخر إصدار دفعه المشرف، في كل مرة تنفّذ فيها pull. وعند جمع ذلك مع عادة الترقية الدورية التي ستتعلمها الآن، وهي docker compose pull && docker compose up -d، فإن :latest يعني أن الانتقال بين الإصدارات الرئيسية سيحدث كلما أصدرت الجهة upstream إصداراً جديداً، لا عندما تختار أنت ذلك. هذا الأمر ليس افتراضياً مع PostgreSQL: فقد يؤدي انتقال مفاجئ من 16 إلى 17 إلى دخول الحاوية في حلقة تعطل بسبب دليل بيانات غير متوافق، لأن الترقية بين الإصدارات الرئيسية في Postgres تتطلب تفريغ البيانات واستعادتها، لا إعادة التشغيل.

ثبّت الإصدار الرئيسي على الأقل (إذ يتبع postgres:16-alpine إصدارات التصحيح من 16.x)، وثبّت التطبيقات على إصدار دقيق مثل miniflux/miniflux:2.2.9. راجع صفحة إصدارات المشروع واستخدم الإصدار الحالي عند كتابة الملف. عندها تصبح الترقية تعديلاً من سطر واحد تنفذه قصداً، ويظهر في git diff.

انشر على 127.0.0.1، لأن Docker يتجاوز ufw

"127.0.0.1:8080:8080": عنوان المضيف، ومنفذ المضيف، ومنفذ الحاوية. تكتب معظم البرامج التعليمية "8080:8080"، وهو اختصار لـ 0.0.0.0:8080:8080، أي الاستماع على كل الواجهات، بما فيها الواجهة العامة.

هنا يكمن الخطأ، وقد يقع فيه الجميع تقريباً مرة واحدة. ينشر Docker المنفذ بكتابة قاعدة DNAT تعيد كتابة وجهة الحزمة إلى عنوان IP الداخلي للحاوية قبل تطبيق التصفية. لذلك تسلك الحزمة مسار FORWARD ولا تصل مطلقاً إلى INPUT، حيث توجد قواعد ufw. يبلّغ sudo ufw deny 8080 عن نجاح العملية، ويعرض ufw status أن المنفذ محجوب، ومع ذلك تظل الخدمة تستجيب للإنترنت بأكمله. جدارك الناري ليس معطلاً؛ بل يجري تجاوزه عمداً حسب التصميم. يشرح لماذا يتجاوز Docker ufw وكيف تصفي حركة مرور الحاويات فعلياً هذه الآلية وحل DOCKER-USER للمنافذ التي يجب أن تبقى عامة.

العادَة التي تنهي المشكلة بالكامل هي ربط المنافذ المنشورة بـ 127.0.0.1 ما لم يكن لديك سبب محدد لعدم فعل ذلك، ووضع reverse proxy أمام أي خدمة يجب أن تكون متاحة للعالم. وهذا هو بالضبط ما ينشئه دليل reverse proxy باستخدام Traefik في الخطوة التالية بعد هذه الصفحة: حاوية واحدة تملك المنفذين 80 و443، وتوجّه الطلبات إلى كل ما عداهما وفق اسم المضيف، مع TLS. (إذا كنت تستخدم إعداد Traefik v2 قديماً، فراجع دليل الترحيل من Traefik v2 إلى v3 لمعرفة تغييرات الأسماء والقواعد.)

تحقق من الربط بعد بدء المكدس: يجب أن يعرض sudo ss -tlnp | grep 8080 القيمة 127.0.0.1:8080، لا 0.0.0.0:8080 أو *:8080.

وحدات التخزين المسماة مقابل الربط المباشر

db-data:/var/lib/postgresql/data وحدة تخزين مسماة؛ ينشئ Docker دليلاً ويديره تحت /var/lib/docker/volumes/، ثم يربطه داخل الحاوية. البديل هو الربط المباشر، ./data:/var/lib/postgresql/data، الذي يربط مساراً اخترته على المضيف.

التقسيم العملي المتين هو الآتي: استخدم وحدات التخزين المسماة للبيانات التي تتعامل معها الحاويات فقط، وقواعد البيانات أولاً، لأن Docker يهيّئ الوحدة بملكية تتوقعها الصورة، فتعمل صلاحيات الملفات كما ينبغي. استخدم الربط المباشر للملفات التي تتعامل معها من المضيف، مثل ملفات الإعداد التي تعدّلها بمحرر نصوص، أو مكتبة الوسائط التي تنسخها باستخدام rsync، أو أي بيانات تريد أن يكون مسارها واضحاً. الخطأ الشائع في الربط المباشر هو الملكية: تعمل الحاوية باستخدام UID 999، بينما يكون دليل المضيف مملوكاً لـ UID 1000، فتتوقف الخدمة عند بدء التشغيل مع ظهور permission denied في سجلاتها. تجعل وحدات التخزين المسماة هذا النوع من الأخطاء نادراً، مقابل بقاء البيانات في مسار يديره Docker، كما سيأتي شرحه أدناه.

environment و .env، أبقِ الأسرار خارج git

لا تُقرأ ${POSTGRES_PASSWORD} من shell الخاص بك؛ بل يستبدل Compose متغيراتها من ملف اسمه .env موجود بجوار compose.yml. أنشئه:

cat > .env <<'EOF'
POSTGRES_PASSWORD=change-me-to-something-long
ADMIN_PASSWORD=change-me-too
EOF
chmod 600 .env
echo ".env" >> .gitignore

ولّد قيماً حقيقية باستخدام openssl rand -hex 24. استخدم Hex لا base64، وذلك عمداً: ستدخل كلمة المرور هذه داخل سلسلة اتصال DATABASE_URL، كما أن الأحرف / و+ و= التي ينتجها base64 تفسد تحليل URL. يظهر الفشل عندها كخطأ مصادقة، لا كخطأ في الصياغة، وقد يستهلك أمسية كاملة. يجب إضافة سطر .gitignore قبل أول commit: ملف Compose آمن للنشر والإصدار، أما ملف .env فلا يجوز نشره مطلقاً. والسر الذي وصل إلى سجل git هو سر يجب تغييره. إذا بدأت المكدس مع متغير مفقود، يصدر Compose تحذيراً واضحاً ويتابع التنفيذ باستخدام سلسلة فارغة. وبالنسبة إلى كلمة مرور Postgres، يؤدي ذلك إلى نشر معطل:

WARN[0000] The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string.

يعرض docker compose config الملف بعد استبدال جميع المتغيرات، وهو أسرع طريقة للتحقق مما ستتلقاه الحاويات فعلياً. تذكّر أن الناتج يتضمن أسرارك.

لا ينتظر depends_on شيئاً ما لم تضف healthcheck

يتحكم depends_on: [db] المجرد في ترتيب البدء فقط: يشغّل Compose Postgres أولاً، ثم يشغّل التطبيق بعد لحظة، بينما لا يزال Postgres يحتاج إلى عدة ثوانٍ قبل قبول الاتصالات. يتصل التطبيق بقاعدة البيانات، ويفشل، ثم يتوقف أو يعيد المحاولة وفق جودة تصميمه.

الإعداد الموثوق هو ما يستخدمه الملف أعلاه: تعرّف خدمة db عن healthcheck (إذ يوفر Postgres pg_isready لهذا الغرض تحديداً)، ويعلن التطبيق depends_on مع condition: service_healthy. يبدأ Compose قاعدة البيانات، ويفحص الحالة كل 10 ثوانٍ، ولا يبدأ Miniflux إلا بعد نجاح الفحص. إذا لم تصبح قاعدة البيانات سليمة، بسبب كلمة مرور خاطئة أو وحدة تخزين تالفة مثلاً، فلن يبدأ التطبيق، وسيخبرك Compose بأي اعتماد فشل:

dependency failed to start: container miniflux-db-1 is unhealthy

تشير هذه الرسالة إلى docker compose logs db، حيث يوجد الخطأ الفعلي.

restart: unless-stopped

يعني restart: unless-stopped على الخدمتين أن الحاويات ستعود بعد التعطل وبعد إعادة تشغيل VPS، لكنها ستبقى متوقفة إذا نفذت docker compose stop عمداً. أما البديل always فيعيد تشغيل الحاويات حتى بعد إيقافها يدوياً، وهذا نادراً ما يكون ما قصدته. ومن دون سياسة إعادة تشغيل، تؤدي إعادة التشغيل بعد تحديث kernel عند الساعة 4 صباحاً إلى إيقاف خدماتك بصمت حتى تلاحظ ذلك.

الأوامر اليومية

تُنجز جميع العمليات اليومية باستخدام خمسة أوامر، تُشغّلها من مجلد المشروع.

docker compose up -d        # create and start; idempotent, recreates only what changed
docker compose ps           # status, ports, and health of this project's containers
docker compose logs -f miniflux   # follow one service's logs; --tail 100 for recent history
docker compose pull && docker compose up -d   # upgrade to the pinned tags
docker compose down         # stop and remove containers and the network

يمكن تشغيل up -d بأمان بشكل متكرر؛ إذ يقارن الملف بالحالة الفعلية ولا يلمس إلا الخدمات التي تغيّر إعدادها أو صورتها. يجلب زوج أوامر الترقية ما تشير إليه العلامات المثبّتة حالياً: إصدارات التصحيح تحت postgres:16-alpine، ولا يجلب شيئاً عند استخدام تثبيت دقيق إلى أن تعدّله، وهذا هو المقصود. تتراكم الصور القديمة بعد الترقية؛ استعد المساحة عبر docker image prune -f.

والآن الأمر المدمّر، ونؤكد ذلك بوضوح: docker compose down آمن لأن الحاويات والشبكة قابلة للحذف، بينما توجد بياناتك في volume. يحذف docker compose down -v الـvolumes المسماة أيضاً. هذا يعني حذف قاعدة بياناتك فوراً، من دون مطالبة بالتأكيد ومن دون إمكانية للتراجع. يوجد الخيار -v لإزالة بيئات التجارب؛ أما في stack يحتوي على بيانات فعلية، فتعامل معه كما تتعامل مع rm -rf. لا توجد سلة محذوفات تحت /var/lib/docker/volumes/.

لفتح shell لمرة واحدة داخل حاوية قيد التشغيل: ينقلك docker compose exec db psql -U miniflux إلى قاعدة البيانات، بينما يفتح docker compose exec miniflux sh shell داخل التطبيق.

أين توجد بياناتك فعلياً

تحصل وحدات التخزين المُسمّاة على بادئة المشروع، لذلك تصبح db-data داخل دليل يُسمّى miniflux بالشكل التالي: miniflux_db-data

docker volume ls
docker volume inspect miniflux_db-data

يتضمن خرج inspect السطر المهم:

"Mountpoint": "/var/lib/docker/volumes/miniflux_db-data/_data"

ذلك الدليل هو قاعدة البيانات، ومالكه root، وموجود على نظام ملفات المضيف. ويظل موجوداً بعد down والترقيات وإعادة إنشاء الحاويات. وهو أيضاً ما يجب أن تلتقطه النسخ الاحتياطية تحديداً.

نسخ وحدة تخزين مسماة احتياطياً

النمط القياسي هو استخدام حاوية مؤقتة تُحمّل وحدة التخزين للقراءة فقط إلى جانب مجلد على المضيف، ثم تنشئ أرشيف tar عبر المسارين:

docker run --rm \
  -v miniflux_db-data:/data:ro \
  -v "$PWD":/backup \
  alpine:3.22 tar czf /backup/miniflux-db-$(date +%F).tar.gz -C /data .

لا تحتاج إلى تثبيت أي شيء، ولا تترك أي عملية قيد التشغيل. أما الاستعادة فهي العملية المعاكسة، إذ تستخدم tar xzf في وحدة تخزين جديدة وفارغة، مع عكس نقاط التحميل نفسها.

هناك ملاحظة مهمة بشأن قواعد البيانات: قد يؤدي إنشاء أرشيف tar من مجلد بيانات Postgres قيد التشغيل إلى التقاط حالة أثناء الكتابة، ولن تبدأ قاعدة البيانات بهذه الحالة بصورة سليمة. أوقف Postgres مؤقتاً عبر docker compose stop طوال المدة التي يستغرقها tar، أو الأفضل من ذلك، أنشئ تفريغاً منطقياً؛ فهو متسق بطبيعته:

docker compose exec -T db pg_dump -U miniflux miniflux | gzip > miniflux-$(date +%F).sql.gz

يعطّل -T الطرفية الافتراضية التي يخصصها Compose افتراضياً. فقد يؤدي تمرير مخرجات التفريغ عبر TTY إلى إتلافها. ضع أحد هذين الأمرين في cron، وانسخ الناتج إلى خارج VPS؛ فالنسخة الاحتياطية الموجودة على القرص نفسه الذي يحتوي على البيانات التي تحميها هي نسخة، وليست نسخة احتياطية. يوضّح دليل Nextcloud إجراءً مجدولاً كاملاً يعتمد على هذين النمطين تحديداً.

أنماط الأعطال، مع النصوص التي ستظهر لك

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock، لم تُضف إلى مجموعة docker بعد، أو أنك أُضفت إليها لكن جلستك بدأت قبل ذلك. يعرض id مجموعاتك الفعلية؛ ويُصلح newgrp docker الصدفة الحالية، بينما تؤدي مغادرة الجلسة وتسجيل الدخول مجدداً إلى تطبيق التغيير على جميع الجلسات.

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?، هذه مشكلة مختلفة: الـdaemon نفسه متوقف. يوضح sudo systemctl status docker وsudo journalctl -u docker -n 50 السبب. في VPS، السبب الشائع هو امتلاء القرص؛ افحص df -h /var/lib/docker أولاً.

Bind for 127.0.0.1:8080 failed: port is already allocated، نشرت حاوية أخرى ذلك المنفذ على المضيف. يعرض docker ps الحاوية المعنية؛ وعادةً تكون حاوية قديمة من تجربة docker run أُجريت قبل أسابيع. إذا كان docker ps لا يعرض شيئاً، فهناك عملية ليست تابعة لـDocker تشغل المنفذ؛ ويحددها sudo ss -tlnp | grep 8080.

yaml: line 14: did not find expected key، يوجد خطأ في المسافات البادئة عند السطر المذكور أو قبله مباشرة. ملفات Compose هي YAML: استخدم مسافتين للمستوى الواحد، والمسافات فقط، لأن وجود حرف جدولة في أي موضع يؤدي إلى فشل الملف. يتحقق docker compose config من صحة الملف دون تشغيل أي شيء، وتشغيله بعد كل تعديل عادة بسيطة ومفيدة.

مفاجأة ufw لا تعرض أي خطأ إطلاقاً، وهذا ما يجعلها خطيرة: ينجح النشر، ويبدو ufw status صحيحاً، لكن فحص المنافذ من خارج الخادم يعثر على قاعدة بياناتك. أعد قراءة قسم المنافذ أعلاه، وافحص كل إدخال ports: بحثاً عن غياب البادئة 127.0.0.1:، وتحقق من جهاز مختلف باستخدام curl http://your-vps-ip:8080؛ فالنتيجة التي تريدها هي رفض الاتصال.

من هنا، يحوّل دليل Traefik هذه الحزمة الواحدة إلى عدة تطبيقات خلف نقطة دخول HTTPS واحدة، بينما تمثل الخدمات التي تستحق الاستضافة الذاتية في 2026 قائمة الخدمات التي يمكنك تشغيلها من خلالها. بعد تشغيل عدة حزم من هذه الحزم واستخدام كل منها نموذج تسجيل دخول خاصاً بها، يدمج خادم SSO مستضاف ذاتياً مثل Authentik الحسابات في حساب واحد خلف الـproxy نفسه.

يُعد خادم ألعاب مثل خادم Minecraft على VPS مشروع Compose أولياً مناسباً للتدرّب عليه. وإذا كنت تفضّل التعلّم باستخدام شيء تفتحه كل يوم، فإن فتح openGym، متتبّع تمارين مستضاف ذاتياً عبارة عن مكدس صغير مثبّت على وسم git بدلاً من وسم صورة، ويتطلب TLS أمامه قبل تسجيل أول passkey. تكون الصور عادةً أول ما يرغب الناس في استعادته من سحابة شخص آخر، وتساعدك مقارنة PhotoPrism وImmich على تحديد الحد الأدنى من RAM وروتين النسخ الاحتياطي الذي ستلتزم به قبل ربط volume بأيٍّ منهما. وعندما لا تعود خدمتان كافيتين، فإن تشغيل AFFiNE كمساحة عمل بأسلوب Notion يطبّق الأنماط نفسها على أربعة containers، ويختبر بجدية ما إذا كانت الوسوم المثبّتة وhealthchecks وnamed volumes الواردة أعلاه قد أصبحت عادة.

FAQ

لماذا تظهر الرسالة "permission denied while trying to connect to the Docker daemon socket"؟

المستخدم ليس عضواً في المجموعة docker، أو أُضيف إليها بعد بدء الجلسة الحالية؛ إذ لا تُطبَّق العضوية إلا عند تسجيل الدخول. شغّل sudo usermod -aG docker $USER، ثم newgrp docker، أو سجّل الخروج ثم سجّل الدخول مجدداً، وتحقق باستخدام id. تمنح هذه المجموعة صلاحيات تعادل صلاحيات root على المضيف، لذلك لا تضف إليها إلا المستخدمين الذين تمنحهم صلاحية sudo.

هل يحذف docker compose down بياناتي؟

لا يحذف docker compose down العادي البيانات؛ فهو يزيل الحاويات وشبكة المشروع. تبقى وحدات التخزين المسماة، ويعيد up -d ربطها عند التشغيل التالي. أما docker compose down -v فهو الصيغة المدمرة؛ إذ يحذف وحدات التخزين المسماة، بما فيها قاعدة بياناتك، من دون تأكيد ومن دون إمكانية التراجع. لا تشغّل -v على مكدس يحتوي على بيانات فعلية إلا إذا كانت لديك نسخة احتياطية موثوقة تم التحقق منها.

ما الفرق بين docker-compose وdocker compose؟

إنّ docker-compose (بواصلة) هو Compose v1، وهو ملف ثنائي مستقل مكتوب بلغة Python. انتهى عمره الافتراضي في 2023، ولا ينبغي تثبيته على خوادم جديدة. أمّا docker compose (بمسافة) فهو Compose v2، وهو إضافة مكتوبة بلغة Go لواجهة Docker CLI، وتُثبَّت باستخدام docker-compose-plugin من مستودع apt الخاص بـDocker. الأوامر وملفات YAML متوافقة تقريباً بالكامل، لذلك عندما يذكر دليل قديم docker-compose up، اكتب docker compose up.

لماذا يمكنني الوصول إلى حاوية Docker من الإنترنت رغم أن ufw يحظر المنفذ؟

لأن Docker ينشر المنافذ باستخدام قواعد DNAT في سلسلة PREROUTING الخاصة بـiptables. وتسلك الحزم المعادَة كتابتها المسار FORWARD عبر سلاسل Docker الخاصة، لذلك لا تصل إلى سلسلة INPUT التي تُطبَّق فيها قواعد ufw. لذلك لا يفعل ufw deny 8080 شيئاً لمنفذ حاوية منشور. أصلح المشكلة من المصدر: انشر المنفذ إلى 127.0.0.1:، وعرّض الخدمات من خلال reverse proxy بدلاً من ذلك.

هل أستخدم وحدة تخزين مسماة أم bind mount؟

استخدم وحدات التخزين المسماة للبيانات التي تتعامل معها الحاوية فقط، وخصوصاً قواعد البيانات، لأن Docker يضبط الملكية بما يتوقعه image وتعمل الصلاحيات بصورة صحيحة. استخدم bind mounts للملفات التي تتعامل معها أيضاً من المضيف، مثل ملفات الإعداد التي تعدّلها، والوسائط التي ترفعها، وكل ما تريد أن يكون مساره واضحاً. إذا فشلت حاوية عند بدء التشغيل وظهرت permission denied على bind mount، فتحقق أولاً من عدم تطابق UID بين المضيف والحاوية.