تجميع اشتراكين Ollama Pro على نفس الجهاز باستخدام Docker
Publié le 08 May 2026
اشتراكان احترافيان، جهاز واحد، بطاقة مصرفية واحدة، ولا صراع شبكي. كيف مكنتني Docker من مضاعفة قدرتي على الاستدلال السحابي دون الحاجة لشراء جهاز ثاني.
مقدمة
أستخدم Ollama Pro منذ عدة أشهر لتشغيل جلسات OpenCode الخاصة بي بنماذج سحابية. الحقيقة هي أن حتى مع اشتراك Pro، نواجه حدًا سريعًا بسبب rate limiting عند تشغيل عدة وكلاء بالتوازي. الحل الواضح: اشتراك ثاني.
لكن هنا، إنها المأساة.
يحدد Ollama كل جهاز بمفتاح SSH فريد — وهو مفتاح الجهاز الشهير. تشترك مثليتين على نفس نظام التشغيل في نفس الهوية، ولا يمكن ربط حسابين Pro بنفس الجهاز. وكما تتوقع، لم أكن سأشتري لابتوبًا ثانيًا فقط لهذا السبب.
الحل: الغش. إجبار أولاما على الاعتقاد بأنه يعمل على جهازين مختلفين، بينما يشتركان في نفس وحدة المعالجة المركزية، ونفس ذاكرة الوصول العشوائي، ونفس اتصال الشبكة. سيوفر دوكّر لنا فقاعة عزلٍ مثالية.
Failed to generate image: PlantUML preprocessing failed: [From <input> (line 10) ]
@startuml
...
... ( skipping 130 lines )
...
skinparam StereotypeI {
BackgroundColor white
BorderColor black
}
skinparam StereotypeN {
BackgroundColor white
BorderColor black
}
skinparam UseCaseStereoType {
FontColor black
FontName Verdana
}
skinparam BoxPadding 10
skinparam DefaultFontSize 12
left to right direction
node "آلة فيزياء" {
frame "Ollama مثيل أ (الأصلي)" as Native {
database "الهوية
^^^^^
Syntax Error? (Assumed diagram type: class)
@startuml
!theme plain
skinparam BoxPadding 10
skinparam DefaultFontSize 12
left to right direction
node "آلة فيزياء" {
frame "Ollama مثيل أ (الأصلي)" as Native {
database "الهوية
/usr/share/ollama/.ollama/id_ed25519" as KeyA
portin "واجهة برمجة التطبيقات
:11434" as PortA
}
frame "مثيل Ollama B (Docker)" as Docker {
database "الهوية
~/ollama-b-data/id_ed25519" as KeyB
portin "واجهة برمجة التطبيقات
:11435" as PortB
}
}
cloud "أولاما كلاود" {
actor "حساب Pro A
(البريد الإلكتروني 1)" as AccountA
actor "الحساب الاحترافي ب\n(البريد الإلكتروني 2)" as AccountB
}
KeyA --> AccountA : "مفتاح SSH أ"
KeyB --> AccountB : "مفتاح SSH ب"
PortA --> AccountA : "طلبات A"
PortB --> AccountB : "طلبات B"
note bottom of Docker
Conteneur isolé : identité SSH distincte,
port réseau distinct, volume persistant
end note
@enduml
لماذا نفس الشيء مرتين؟
قبل أن تتهمني بالمرض العقلي، دعني أشرح لك حالة الاستخدام.
باشتراك Pro واحد فقط، يمكنني تشغيل نموذج كما`deepseek-v4-pro:cloud`في جلسة OpenCode. المشكلة تظهر عندما أريد جلستين متزامنتين. حصة معدل التحديد (rate limiting) تجعل الجلسة الثانية بطيئة أو تُرفض بالكامل.
مع اشتراكين برو مستقلين:
-
جلسة OpenCode 1 → حساب Pro A`localhost:11434`)
-
جلسة OpenCode 2 → حساب Pro B`localhost:11435`)
كل جلسة لها حصة خاصة وسياق خاص، ولا تزعج الأخرى. هذا معالجة متعددة بشرية.
|
اشتراكان احترافيان = بريدان إلكترونيان مختلفان. تعمل نفس البطاقة البنكية — نظام دفع Ollama لا يحظر الاشتراكات المتعددة من نفس وسيلة الدفع. تحققت. |
قلب المشكلة : مفتاح الجهاز
عند تثبيت Ollama، يتم توليد زوج من مفاتيح SSH ed25519 في دليل الهوية :
$ cat /usr/share/ollama/.ollama/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
هذا المفتاح يُرفَع إلى خوادم Ollama أثناء`ollama signin`هي التي تقول « هذه الآلة تنتمي إلى حساب Pro ». إذا شارك المثيلان نفس الملف`id_ed25519`, هم يشتركون نفس الهوية. نهاية اللعبة.
الحيلة: إعطاء مثيلنا الثاني دليل هوية خاص به، معزولًا في وحدة تخزين Docker.
التحضير — خطوة بخطوة
المتطلبات المسبقة
-
تثبيت أصلي لـ Ollama يعمل (نص رسمي`curl | sh`)
-
Docker مثبت ويعمل
-
Portainer أو docker-compose للنشر
-
حسابان Ollama مع بريدين إلكترونيين مختلفين
لقد استخدمت النسخة`0.20.2`— التي تم توفيرها من خلال النص البرمجي الرسمي والصورة Docker المقابلة.
الخطوة 1 : إنشاء الحجم
سيخدم دليل بسيط على المضيف كحجم ثابت لهوية المثيل B :
mkdir -p ~/ollama-b-data
سيتم تثبيت هذا المجلد في حاوية Docker كـ`/root/.ollama`, حيث يخزن أولاما مفاتيح هويته، وتاريخه، ونموذجاته.
الخطوة 2 : تشغيل حاوية Docker
# docker-compose.yml
services:
ollama-instance-b:
image: ollama/ollama:0.20.2
container_name: ollama-instance-b
ports:
- "11435:11434"
volumes:
- /home/cheroliv/ollama-b-data:/root/.ollama
environment:
- OLLAMA_HOST=0.0.0.0
restart: always
ما يحدث هنا :
-
الميناء11435من المضيف مُعَيَّن على11434الداخلية للحاوية. وبالتالي، يستمع مثيل Docker على`:11435`بدون تعارض مع المثال الأصلي الذي يشغل`:11434`.
-
الحجم`~/ollama-b-data`مثبت على`/root/.ollama`— هذا هو المكان الذي سيتم فيه تخزين هوية SSH.
-
`OLLAMA_HOST=0.0.0.0`يسمح للحاوية بقبول الاتصالات الخارجية.
لقد نشرت هذا المكدس عبر Portainer، لكن بسيط`docker compose up -d`يعمل أيضًا بشكل جيد
الخطوة 3: استرجاع المفتاح العام
نظرًا لأن الحاوية فارغة عند بدء التشغيل الأول، يقوم Ollama تلقائيًا بإنشاء زوج جديد من مفاتيح SSH في الحجم. يتم استرجاع المفتاح العام :
$ docker exec ollama-instance-b cat /root/.ollama/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDDQ+dvnfmuo49q5O8LOlvgZ39SKORFw47ry9k4H2jPc
أنا أتحقق من أن هذا المفتاح مختلف عن المفتاح في المثيل الأصلي :
# Instance native
$ cat /usr/share/ollama/.ollama/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGyF...(différente)
# Instance Docker
$ cat ~/ollama-b-data/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDDQ...(différente)
مفتاحان متميزان، هويتان منفصلتان. تمّ الأمر.
|
إذا تم إعادة تشغيل الحاوية، فإنه إعادة استخدام المفاتيح الموجودة في الحجم. الهوية مستمرة. لن تفقد الارتباط بالحساب Pro. |
الخطوة 4: تسجيل المفتاح على Ollama.com
الاتجاه https://ollama.com/settings/keys → أضف مفتاح SSH. نقوم بلصق المفتاح العام للمثيل Docker ثم نؤكد.
ثم يُربط هذه الهوية بالحساب Pro B:
$ docker exec -it ollama-instance-b ollama signin
يفتح المتصفح، نستخدم بريد حساب B، ويتم ربط الرمز بالمفتاح SSH للحاوية. نتأكد من أن كل شيء على ما يرام:
$ docker exec -it ollama-instance-b ollama signin
User: cherolivpro
الخطوة 5 : اختبار باستخدام نموذج مجاني صغير
قبل أن أطرح سعر اشتراك Pro، أريد أن أكون متأكدًا من أن الأنبوب يعمل. أسحب نموذجًا صغيرًا محليًا ومجانيًا للتحقق من الاتصال :
$ docker exec ollama-instance-b ollama pull qwen3:0.6b
pulling manifest
pulling 7f4030143c1c: 100% ▕██████████████████▏ 522 MB
success
$ curl -s http://localhost:11435/api/tags
{"models":[{"name":"qwen3:0.6b","model":"qwen3:0.6b",...}]}
الميناء`11435`أجاب، النموذج جاهز. النسخة B حية.
بمجرد أن يطمئن، أنتقل إلى سحب النموذج السحابي Pro الحقيقي :
$ docker exec ollama-instance-b ollama pull deepseek-v4-pro:cloud
pulling manifest
pulling 31c3059e137e: 100% ▕██████████████████▏ 344 B
success
344 بايتًا للبيان النموذجي لنموذج سحابي — طبيعي، الاستنتاج يتم من جانب الخادم، وليس محليًا. وهذا هو الاختبار النهائي :
$ curl -s http://localhost:11435/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"deepseek-v4-pro:cloud","messages":[{"role":"user","content":"Dis bonjour en une phrase courte."}]}'
{
"id": "chatcmpl-480",
"model": "deepseek-v4-pro",
"choices": [{
"message": { "content": "Bonjour !" },
"finish_reason": "stop"
}],
"usage": { "total_tokens": 181 }
}
مرحبًا بك أيضًا، المثيل B.
فخ واجهة برمجة التطبيقات `/v1/models
لقد ضيعت عشرين دقيقة على تفاصيل سخيفة. عندما قمت بتكوين المزود`ollama-b`في OpenCode، لم يظهر شيء في محدد النماذج. لا شيء. لا شيء على الإطلاق
السبب؟ واجهة برمجة التطبيقات`/v1/models`من المثيل B كان يعيد`{"object":"list","data":null}`بدلاً من`{"object":"list","data":[]}`عندما لم يتم سحب أي نموذج. القيمة`null`كان يتسبب في تعطل التحليل من جهة OpenCode، الذي لم يكن يعرض المزود.
الحل: الإعلان عن النماذج بشكل صريح في إعدادات OpenCode بدلاً من الاعتماد على الاكتشاف الديناميكي.
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"ollama": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ollama (local)",
"options": { "baseURL": "http://localhost:11434/v1" },
"models": {
"gemma4:e2b": { "name": "Gemma 4 E2B (local)" }
}
},
"ollama-b": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ollama Instance B (Docker)",
"options": { "baseURL": "http://localhost:11435/v1" },
"models": {
"qwen3:0.6b": { "name": "Qwen3 0.6B (B)" },
"deepseek-v4-pro:cloud": { "name": "DeepSeek V4 Pro (B)" }
}
}
}
}
مع هذا الإعلان الصريح، يرى OpenCode مباشرةً المزود B ونماذجه. إعادة تشغيل الجلسة، والمحدد`/models`يعرض النموذجين جنبًا إلى جنب.
|
إذا لم ترَ provider custom في`/models`, لا تضيع ثلاث ساعات في إعادة تشغيل الطرفية الخاصة بك. أعلن النماذج يدويًا في`opencode.json`— إنه يحل المشكلة فورًا. |
النتيجة : جلستان، حسابان، صِفر صراعات
في النهاية، يمكنني إطلاق جلستين OpenCode متزامنتين:
Session 1 → /models → Ollama (local) → deepseek-v4-pro:cloud → Compte A
Session 2 → /models → Ollama Instance B (Docker) → deepseek-v4-pro:cloud → Compte B
لكل جلسة حصتها الخاصة، وحد معدل خاص بها، ولا تتعارك مع بعضها. نفس الجهاز، نفس البطاقة الزرقاء، رسالتان بريد إلكتروني مختلفتان.
وما هو الأفضل؟ الحاوية Docker في`restart: always`. ينجو من إعادة تشغيل النظام دون تدخل يدوي.
الدروس المستفادة
-
يعزل Docker كل شيء، حتى الهوية— يكفي تثبيت ربط بسيط للحجم لتزويد حاوية بمجموعة مفاتيح SSH خاصة بها، مما يجعله غير مميز عن جهاز فيزيائي مختلف من منظور Ollama.
-
بريدان إلكترونيان، نفس البطاقة البنكية— Ollama لا يحظر الاشتراكات المتعددة من نفس وسيلة الدفع. يجب أن يكون البريد الإلكتروني فريدًا.
-
جرب مجانًا قبل الدفع — Un
ollama pull qwen3:0.6b(modèle libre, 522 Mo) permet de valider toute la chaîne réseau sans débourser un centime. Vous validez le plomberie d’abord, vous activez le Pro ensuite. -
/v1/models` مع
data: nullيكسر OpenCodeإذا قمت بتكوين موفر مخصص مع`"models": {}`, OpenCode يحاول اكتشاف النماذج عبر واجهة برمجة التطبيقات (API). إذا استجابت الواجهة`data: null`, لا يظهر المزود. أعلن النماذج بشكل صريح. -
حسابان، هذا معالجة بشرية متعددة— حساب Pro = جلسة OpenCode نشطة. حسابان = جلستان متوازيتان. لشخص يتعامل مع عدة مشاريع Gradle في وقت واحد، هذا يغيّر قواعد اللعبة.
للمضي قدمًا
تم نشر المقال في 2026-05-08