دليل عملي

ترحيل MinIO إلى Garage أو RustFS دون فقدان كائن حالي

الاستضافة الذاتية13 دقيقةً للقراءةعدد الخطوات: 20

أُرشف مستودع MinIO منذ 25 أبريل 2026، فصار تخزين S3 لديك يعمل دون تصحيحات أمنية من المصدر. يتكرر ذكر Garage وRustFS هدفين قابلين للاستضافة الذاتية، لكن نسخ الكائنات نصف العمل فقط، فسياسات IAM وسجل الإصدارات والروابط الموقّعة مسبقًا لا تنتقل معها. يجرد هذا الدليل المصدر وينسخ بأداة rclone ويثبت النتيجة بالأعداد والفحوص، ثم يحوّل التطبيق على ثلاث مراحل مع انقطاع كتابة أدنى ورجوع جاهز.

المحتويات· لماذا لا تترك MinIO حيث هو1/14
  1. 01لماذا لا تترك MinIO حيث هو
  2. 02ما لا ينقله نسخ الحاوية وحده
  3. 03المتطلبات وخطة السعة
  4. 04الخطوة 1: جرد المصدر قبل النسخ
  5. 05Garage وRustFS: الفروق التي يجب معرفتها قبل الاختيار
  6. 06تعدد الإصدارات: ما يضيع في النسخ وما العمل
  7. 07الخطوة 2: تجهيز الهدف، Garage أو RustFS
  8. 08الخطوة 3: النسخ بـ rclone وإثبات النتيجة
  9. 09ETag متعدد الأجزاء وmc mirror: قراءة الفروق دون خطأ
  10. 10الروابط الموقّعة مسبقًا: لماذا تتعطل عند التحويل
  11. 11الخطوة 4: التحويل على ثلاث مراحل دون قطع حاد
  12. 12الرجوع إلى الوراء يقتصر على متغير واحد
  13. 13استكشاف الأخطاء: الأعراض التي تتكرر
  14. 14الوثائق الرسمية

لماذا لا تترك MinIO حيث هو

أُرشف مستودع minio/minio من قِبل مالكه في 25 أبريل 2026: أصبح للقراءة فقط، ويذكر ملف README أن المشروع لم يعد مُصانًا وأن الملفات التنفيذية المنشورة لن تتلقى تحديثات. عمليًا، لن يصلح أحد في المصدر الثغرة التالية التي تُكتشف في خادم S3 لديك. أما العميل mc، وهو أيضًا تحت رخصة AGPLv3، فقد أُرشف في 14 يوليو 2026.

يواصل MinIO لديك العمل، وهذا ما يجعل الأمر خادعًا: لا ينكسر شيء يوم الأرشفة. لكن مخزن الكائنات معرَّض للشبكة، ويحتوي وسائطك أو نسخك الاحتياطية أو صادراتك، وهو يعمل الآن دون تصحيحات أمنية. هدفان قابلان للاستضافة الذاتية يتكرران في النقاشات: Garage المنشور برخصة AGPLv3، وRustFS المنشور برخصة Apache 2.0.

لا يعيد هذا المقال تثبيت أيٍّ منهما، فلكل منهما دليله: Garage على خادم VPS وRustFS على VPS. هنا ننطلق من MinIO قيد الإنتاج ونجيب عن سؤال واحد: كيف تنقل البيانات، وتثبت أنه لم يُفقد شيء، وتحوّل التطبيق دون روابط مكسورة.

ما لا ينقله نسخ الحاوية وحده

  • الكائنات الحالية — هذا هو الجزء السهل: ينسخها rclone أو mc mirror، مع فحص يُجرى بعد ذلك.
  • الإصدارات القديمة — توضح وثائق mc mirror أنه لا يزامن إلا الكائن الحالي، دون أي معلومة عن الإصدارات.
  • مستخدمو IAM وسياساته — تعيش في MinIO لا في الحاويات. الأسرار لا تُصدَّر: تُنشئ مفاتيح جديدة في الهدف.
  • الروابط الموقّعة مسبقًا التي وُزّعت — يعتمد التوقيع على المضيف والمنطقة والمفاتيح. تغيير نقطة الوصول يبطلها.
  • فروق التوافق مع S3 — قوائم ACL وسياسات الحاويات والوصول المجهول وتعدد الإصدارات: لكل هدف ثغراته، تُقرأ في وثائقه بدل افتراضها.
  • إعدادات العملاء — نقطة الوصول والمنطقة ونمط العنونة path-style: كل ما يثبّته تطبيقك ونسخك restic وشبكة CDN لديك.

المتطلبات وخطة السعة

تحتاج إلى صلاحية مسؤول على MinIO، وجهازًا أو خادم VPS عليه mc وrclone، وهدفًا مثبّتًا مسبقًا ويمكن بلوغه عبر HTTPS (راجع الدليلين أعلاه للوكيل العكسي والشهادة). قاعدة السعة بسيطة: ما لم تتحقق من الترحيل تُبقي المصدر سليمًا، فتدفع ثمن القرص مرتين.

توصيتنا التحريرية: خصّص في الهدف الحجم الكلي لبيانات المصدر، مضافًا إليه هامش يقارب 30% للبيانات الوصفية وفروق التوزيع. على الخادم نفسه يعني ذلك توفر ضعف الحجم الحالي على الأقل مع الهامش؛ وعلى خادمين يتحمل كل منهما نصيبه. عقدة Garage واحدة مع replication_factor = 1 تحتفظ بنسخة واحدة فقط من كل كائن: هذه ليست نسخة احتياطية، والمصدر القائم هو شبكة الأمان الوحيدة أثناء الترحيل.

الخطوة 1: جرد المصدر قبل النسخ

  1. عرّف MinIO باسم مستعار

    أنشئ اسمًا مستعارًا src ببيانات اعتماد تقرأ كل الحاويات:
    mc alias set src https://s3.your-domain.com ACCESS_KEY SECRET_KEY

  2. عُدّ الكائنات والحجم

    لكل حاوية دوّن عدد الكائنات والحجم:
    mc du --recursive src/medias
    mc ls --recursive src/medias | wc -l
    ضع هذه الأرقام في جدول «قبل / بعد»: هو دليلك على اكتمال الترحيل.

  3. عُدّ الإصدارات

    إن كان تعدد الإصدارات مفعّلًا فقائمة الإصدارات أطول من قائمة الكائنات:
    mc ls --recursive --versions src/medias | wc -l
    توضح وثائق mc ls أن --versions يتطلب خدمة تدعم تعدد الإصدارات. الفرق الكبير بين العددين يدل على حجم السجل المعرَّض للخطر.

  4. صدّر قائمة السياسات والمستخدمين

    احتفظ بسجل لما ستعيد إنشاءه:
    mc admin policy list src
    mc admin user list src
    الأسرار ليست في هذا الخرج ولا يمكن أن تكون: ستعيد توليدها.

  5. دوّن إعدادات العملاء

    في كل تطبيق يتحدث مع MinIO دوّن نقطة الوصول والمنطقة ونمط العنونة واسم متغير البيئة الذي يحملها. التحويل النهائي لن يغيّر إلا هذه القيم.

Garage وRustFS: الفروق التي يجب معرفتها قبل الاختيار

مرّر الجدول أفقيًا

الموضوعGarageRustFS
الرخصةAGPLv3 (ملف README للمستودع)Apache 2.0 (ملف README للمستودع)
تعدد الإصداراتغير مدعوم: `PutBucketVersioning` و`ListObjectVersions` مدرجتان ضمن المفقودمذكور على أنه متاح في README
سياسات الحاويات وقوائم ACLلا هذه ولا تلك: نظام خاص حسب المفتاح والحاويةIAM وسياسات الحاويات؛ قوائم ACL غير مدعومة عن قصد
الوصول المجهولمرفوض باستجابة 403يُقيَّم وفق سياسة الحاوية
منطقة العميل`s3_region` من `garage.toml`، تُنسخ إلى العميل`RUSTFS_REGION`، والقيمة الافتراضية `us-east-1`، تُنسخ إلى العميل
العنونةpath-style وvhost-style مدعومانpath-style افتراضيًا ودون إعداد DNS
الروابط الموقّعة مسبقًامدعومةمدعومة؛ يجب أن يطابق التوقيعَ المضيفُ والمخطط والمنفذ والمنطقة والمسار
واجهة إدارة MinIOلا ينطبق: تُدار بالأمر `garage`سطح منفصل: يعمل S3 دون أن يكون `mc admin` مضمونًا

تعدد الإصدارات: ما يضيع في النسخ وما العمل

هذه النقطة هي التي تحسم اختيار الهدف. لا يدعم Garage تعدد الإصدارات، وتقول صفحة توافقه مع S3 ذلك بوضوح. إن كانت حاوياتك تحتفظ بسجل يقرؤه التطبيق أو يجب حفظه لأسباب مهنية فليس Garage وجهتك. يذكر RustFS تعدد الإصدارات على أنه متاح، لكن النسخ بـ rclone sync أو mc mirror لن يعيد إنشاء سجلك هناك.

ثلاث طرق، تُختار حاوية بحاوية. قبول الفقد: لا تنتقل إلا النسخة الحالية، وهذا يناسب الحالات التي كان فيها تعدد الإصدارات مجرد شبكة أمان ضد الخطأ البشري. النسخ إصدارًا إصدارًا: تسرد المعرّفات بالأمر mc ls --versions ثم تعيد تشغيل الإصدارات من الأقدم إلى الأحدث نحو هدف يدعم تعدد الإصدارات بعد تفعيله على الحاوية؛ وستكون تواريخ الإصدارات تواريخ النسخ لا الأصلية. أو أرشفة السجل على حدة في حاوية أرشيف وترحيل الحالي فقط. في كل الحالات جرّب كائنًا ذا عدة إصدارات قبل إطلاق النسخ العام.

الخطوة 2: تجهيز الهدف، Garage أو RustFS

  1. Garage: عيّن التخطيط ثم طبّقه

    لا تصلح أي حاوية قبل تطبيق التخطيط (layout). اقرأ معرّف العقدة ثم أسند إليها منطقة وسعة:
    garage status
    garage layout assign -z dc1 -c 1G <node_id>
    garage layout apply --version 1
    اضبط -c على مساحة القرص المخصصة فعلًا.

  2. Garage: أنشئ المفتاح والحاوية والصلاحيات

    تُمنح الصلاحيات حسب المفتاح والحاوية:
    garage key create app-key
    garage bucket create medias
    garage bucket allow --read --write --owner medias --key app-key
    يظهر السر عند إنشاء المفتاح: انسخه فورًا إلى مدير الأسرار لديك.

  3. Garage: انسخ المنطقة إلى العميل

    يحدد القسم [s3_api] في garage.toml القيمة s3_region. ضع هذه القيمة نفسها في إعدادات عملائك وأبقِ على العنونة path-style. اختلاف المنطقة يعني توقيعات مرفوضة.

  4. RustFS: الاسم المستعار والحاوية

    مع ضبط mc على الهدف:
    mc alias set dst http://127.0.0.1:9000 ACCESS_KEY SECRET_KEY
    mc mb dst/medias
    توصي وثائق RustFS بمستخدمي IAM أو حسابات الخدمة بدل المفاتيح الجذرية للتطبيقات.

  5. RustFS: أعد إنشاء المستخدمين والسياسات

    خذ القائمة المصدَّرة في الخطوة 1 وأعد إنشاء كل مستخدم وكل سياسة في RustFS، بمفتاح جديد لكل تطبيق. ثم وحّد المنطقة: القيمة الافتراضية لـ RUSTFS_REGION هي us-east-1 ويجب أن يستخدم العميل القيمة نفسها.

الخطوة 3: النسخ بـ rclone وإثبات النتيجة

  1. عرّف الوجهتين

    استخدم المزوّد Minio للمصدر وOther للهدف:
    rclone config create src s3 provider=Minio access_key_id=ACCESS_KEY secret_access_key=SECRET_KEY endpoint=https://s3.your-domain.com
    rclone config create dst s3 provider=Other access_key_id=ACCESS_KEY secret_access_key=SECRET_KEY endpoint=http://127.0.0.1:3900 region=garage
    region=garage يفترض أن s3_region = "garage"، وهي قيمة مثال Garage: ضع قيمتك إن اختلفت. مع RustFS استبدل نقطة الوصول بنقطة الهدف والمنطقة بقيمة RUSTFS_REGION.

  2. أجرِ تجربة جافة

    يعدّل rclone sync الوجهة لتعكس المصدر، بما في ذلك الحذف. لا تعكسه أبدًا، وابدأ بالتجربة الجافة:
    rclone sync src:medias dst:medias --checksum --metadata --transfers 16 --dry-run

  3. شغّل النسخ الفعلي والخدمة قائمة

    يبقى MinIO في الخدمة خلال هذه الجولة الأولى:
    rclone sync src:medias dst:medias --checksum --metadata --transfers 16 --progress
    يطلب --metadata من rclone الحفاظ على البيانات الوصفية: تحقق على كائن تجريبي من وصول نوع المحتوى سليمًا.

  4. تحقق من النسخ

    تأكد أن كل ما في المصدر موجود في الهدف:
    rclone check src:medias dst:medias --one-way --combined /tmp/check-medias.txt
    يسرد الملف كل مسار برمز: = مطابق، + غائب عن الوجهة، * مختلف، ! خطأ. الهدف صفر سطر من + أو * أو !.

  5. أعد العدّ بعد النسخ

    أعد تشغيل mc du --recursive وعدّ الكائنات على الهدف بالاسم المستعار dst، واملأ عمود «بعد» في جدولك. يجب أن يتطابق الرقمان إلا في الفروق التي تفسرها الإصدارات.

ETag متعدد الأجزاء وmc mirror: قراءة الفروق دون خطأ

ETag لكائن صغير أُرسل في طلب واحد هو MD5 الخاص به، ويستخدمه rclone مجموعًا اختباريًا. أما في كائن متعدد الأجزاء فتنبّه وثائق rclone إلى أن ETag لم يعد MD5 البيانات: إنه MD5 لتسلسل قيم MD5 لكل جزء، يليه عدد الأجزاء. فهو يتوقف إذن على حجم الأجزاء الذي اختاره العميل عند الرفع.

استقبل MinIO لديك الكائن بتقطيع معيّن، ويرسله rclone إلى الهدف بتقطيع آخر: المحتوى متطابق بايتًا ببايت، أما ETag فلا. وأمر rclone check الذي يبلغ عن هذه الكائنات على أنها مختلفة ليس مصيبًا بالضرورة. أعد تشغيله عليها بالخيار --download الذي ينزّل الطرفين ويقارن البيانات نفسها: أبطأ لكنه بلا لبس.

إن فضّلت البقاء ضمن منظومة mc فالنسخ يُكتب mc mirror --preserve src/medias dst/medias. يحتفظ --preserve بخصائص المصدر وقواعد سياسة الحاوية؛ والأخيرة لا معنى لها إلا إن كان الهدف يقرؤها، وهذا يستبعد Garage. بدون --overwrite لا يُنسخ من جديد كائن موجود في الهدف: يُسجَّل الخطأ ويستمر النسخ. ومع --remove تُحذف كائنات الهدف الغائبة عن المصدر. وmc mirror لا يزامن إلا الكائن الحالي بلا إصدارات. وتقارن مقارنته الاسم والحجم والتاريخ والمجموع الاختباري دون قراءة المحتوى، وقد تختلف المجاميع المركبة لمجرد تغيّر توزيع الأجزاء، فتظهر فروق وهمية خصوصًا في الكائنات الكبيرة التي رُفعت بأحجام أجزاء مختلفة. وتذكّر أن مستودع mc مؤرشف أيضًا: الأداة تعمل لكنها لن تتطور، فلا تبنِ عليها أتمتة طويلة الأمد.

الروابط الموقّعة مسبقًا: لماذا تتعطل عند التحويل

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

النتيجة مسألة ترتيب. الروابط التي يولّدها تطبيقك لحظيًا تتجدد من تلقاء نفسها فور ربطه بالهدف الجديد. أما التي أرسلتها بالبريد أو خزّنتها في قاعدة البيانات فستموت عند التحويل. لذا قصّر مدة صلاحية الروابط قبل ذلك بأيام قليلة كي يقل عدد الروابط الطويلة المتداولة، ونبّه الفرق التي توزعها يدويًا.

الخطوة 4: التحويل على ثلاث مراحل دون قطع حاد

  1. مزامنة أولى والخدمة قائمة

    هي نسخ الخطوة 3 يجري ومازال MinIO يخدم الحركة. تستغرق ما تستغرقه ولا تزعج أحدًا. دوّن وقت انتهائها.

  2. جمّد الكتابة

    حوّل التطبيق إلى وضع القراءة فقط أو إلى صيانة قصيرة، أو فعّل الكتابة المزدوجة إن سمح بها شيفرتك. يمكن أن تستمر القراءة على MinIO أثناء المزامنة الأخيرة.

  3. المزامنة الأخيرة بالخيار --update

    انقل فقط ما تغيّر منذ ذلك الحين:
    rclone sync src:medias dst:medias --update --metadata --transfers 16 --progress
    rclone check src:medias dst:medias --one-way
    أعد عدّ الكائنات والحجم وقارنها بجدول الخطوة 1.

  4. غيّر نقطة الوصول عبر متغير بيئة

    يجب أن يقرأ تطبيقك نقطة الوصول والمنطقة والمفاتيح من بيئته لا من الشيفرة. عدّل هذه المتغيرات وأعد تشغيل الخدمة ثم اختبر رفعًا وقراءة وحذفًا على كائن تجريبي. ولّد من جديد الروابط الموقّعة التي تهمك.

  5. راقب ثم فكّك لاحقًا فقط

    أبقِ MinIO في مكانه متوقفًا أو للقراءة فقط مدة كافية لمرور دورة كاملة من نسخك الاحتياطية ومهامك المجدولة. وجّه نسخك restic إلى الهدف من جديد، راجع دليل النسخ الاحتياطية بـ restic.

الرجوع إلى الوراء يقتصر على متغير واحد

ما دام MinIO لم يُحذف وكانت المزامنة الأخيرة قد جرت في وضع القراءة فقط، فالرجوع يعني إعادة نقطة الوصول القديمة إلى البيئة وإعادة التشغيل. وإن جرت كتابات على الهدف منذ التحويل فأعدها أولًا إلى المصدر بأمر rclone copy في الاتجاه المعاكس (لا sync أبدًا لأنه سيحذف) ثم ارجع. لا تمحُ MinIO إلا بعد فترة مراقبة تحددها مسبقًا.

استكشاف الأخطاء: الأعراض التي تتكرر

يردّ Garage على نداء غير موقّع برمز 403 مع الرسالة Garage does not support anonymous access yet. هذا هو السلوك المتوقع من Garage، وطلب الوصول المجهول لا يزال في متتبع المشروع على أنه ميزة لم تُعطَ أولوية قط. إن كان تطبيقك يقدّم ملفات عامة بلا توقيع فسيلزمك استخدام روابط موقّعة مسبقًا أو وكيل أمام الحاوية.

إن رُفضت الكتابات بأخطاء توقيع بعد التحويل مباشرة فقارن منطقة العميل بمنطقة الهدف (s3_region في Garage وRUSTFS_REGION في RustFS) وتأكد أن العميل يستخدم العنونة path-style. وإن أبلغ rclone check عن كائنات متعددة الأجزاء على أنها مختلفة مع تساوي أحجامها فأعد تشغيله بالخيار --download. وإن لم تنسخ إعادةُ تشغيل mc mirror كائنًا معدَّلًا فالسبب غياب --overwrite. أخيرًا، إن كانت حاوية فارغة في الهدف رغم نجاح المزامنة فتحقق أن المفتاح مُنح --read --write على تلك الحاوية في Garage، أو السياسة المناسبة في RustFS.

الوثائق الرسمية

أعد قراءة هذه المصادر قبل التنفيذ فالمشاريع تتغير: مستودع github.com/minio/minio وملف README فيه لحالة MinIO ورخصته؛ ومستودع github.com/rustfs/rustfs وdocs.rustfs.com (صفحة بروتوكول S3) لـ RustFS؛ وgaragehq.deuxfleurs.fr لصفحة توافق Garage مع S3 ودليل البدء السريع؛ وrclone.org لأمري sync وcheck وصفحة واجهة S3؛ ووثائق MinIO عن mc mirror وmc ls للخيارات المذكورة. لتثبيت الهدف راجع دليلينا عن Garage وRustFS، ولنسخ هذا التخزين احتياطيًا راجع الاستراتيجية الموصوفة في مقال 3-2-1 مع restic وS3.

خادم VPS ثانٍ لاختبار الهدف قبل إيقاف MinIO

يستضيف خادم VPS ثانٍ بصلاحية root وقرص NVMe الهدفَ أثناء الترحيل: تختبر بجانب الإنتاج ولا توقف MinIO إلا بعد اعتماد أعداد الكائنات. يتم التحويل دون المساس بالجهاز الأصلي.

بحاجة إلى مساعدة؟

تصفّح مركز المساعدة والأسئلة الشائعة، أو تواصل مع فريقنا — معاودة اتصال أو WhatsApp أو بريد إلكتروني. الدعم بـالعربية والفرنسية والإنجليزية.

راسلنا على WhatsAppيُفتح في علامة تبويب جديدة