время чтения : 14 minutes

Два Pro-подписки, одна машина, одна банковская карта и никаких сетевых конфликтов. Как Docker позволил мне удвоить мою облачную способность инференса без покупки второго ПК.

Введение

Я уже несколько месяцев использую Ollama Pro для питания моих сессий OpenCode облачными моделями. Дело в том, что даже с подпиской Pro мы быстро сталкиваемся с ограничением rate limiting при запуске нескольких агентов параллельно. Очевидное решение: вторая подписка.

Но там это драма.

Ollama идентифицирует каждое устройство уникальным SSH‑ключом — его знаменитый Device Key. Два экземпляра на одной ОС имели бы одну и ту же идентичность, и невозможно привязать два Pro‑аккаунта к одному устройству. И, как вы, наверное, догадываетесь, я не собирался покупать второй ноутбук только ради этого.

Решение: обмануть. Заставить Ollama поверить, что он запущен на двух разных машинах, хотя они используют один и тот же CPU, одну и ту же RAM и одно и то же сетевое соединение. Docker предоставит нам идеальный изолированный пузырь.

@startuml
!theme plain
skinparam BoxPadding 10
skinparam DefaultFontSize 12

left to right direction

node "Физическая машина" {
  frame "Экземпляр Ollama A (Native)" as Native {
    database "Identity\n/usr/share/ollama/.ollama/id_ed25519" as KeyA
    portin "API\n:11434" as PortA
  }

  frame "Экземпляр Ollama B (Docker)" as Docker {
    database "Identity\n~/ollama-b-data/id_ed25519" as KeyB
    portin "API\n:11435" as PortB
  }
}

cloud "Ollama Cloud" {
  actor "Профессиональный аккаунт A\n(email 1)" as AccountA
  actor "Профессиональный аккаунт B\n(email 2)" as AccountB
}

KeyA --> AccountA : "SSH-ключ A"
KeyB --> AccountB : "SSH-ключ B"
PortA --> AccountA : "Запросы A"
PortB --> AccountB : "Запросы B"

note bottom of Docker
Изолированный контейнер: отдельный SSH-идентификатор,
отдельный сетевой порт, постоянный том
end note
@enduml

Почему дважды одно и то же?

Прежде чем называть меня психически больным, позвольте объяснить вам вариант использования.

С одной подпиской Pro я могу запустить модель как`deepseek-v4-pro:cloud`в сессии OpenCode. Проблема возникает, когда я хочу две одновременные сессии. Квоты rate limiting приводят к тому, что вторая сессия отстаёт или полностью отвергнута.

С двумя независимыми Pro‑подписками :

  • Сеанс OpenCode 1 → Профессиональный счёт A (localhost:11434)

  • Сессия OpenCode 2 → Профессиональный аккаунт B`localhost:11435`)

Каждая сессия имеет свою собственную квоту, свой собственный контекст и не мешает друг другу. Это человеческий мультипроцессинг.

Два Pro‑подписки = два разных адреса электронной почты. Одна и та же банковская карта работает — система оплаты Ollama не блокирует несколько подписок из одного и того же способа оплаты. Я проверил.

Сердце проблемы: ключ устройства

Когда вы устанавливаете Ollama, пара ключей SSH ed25519 генерируется в каталоге идентификации:

$ cat /usr/share/ollama/.ollama/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...

Этот ключ загружается на серверы Ollama, когда`ollama signin`. Это она говорит « эта машина принадлежит учётной записи Pro ». Если ваши два экземпляра используют один и тот же файл`id_ed25519`, они имеют одну и ту же идентичность. Конец игры.

Способ: дать нашему второму экземпляру собственный каталог идентичности, изолированный в томе Docker.

Mise en Place — Шаг за шагом

Предварительные требования

  • функциональная нативная установка Ollama (официальный скрипт`curl | sh`)

  • Docker установлен и работает

  • Portainer или docker-compose для развертывания

  • Два аккаунта Ollama с двумя разными электронными письмами

Я использовал версию`0.20.2`— та, предоставленная официальным скриптом и соответствующим Docker-образом.

Шаг 1: Создать том

Простой каталог на хосте будет использоваться как постоянный том для идентичности экземпляра B :

mkdir -p ~/ollama-b-data

Эта папка будет смонтирована в контейнере Docker как`/root/.ollama`, там где 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 жив.

Успокоившись, я перехожу к pull‑запросу реальной модели облака 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.

Ловушка API `/v1/models

Я потерял 20 минут на глупой детали. Когда я настроил провайдер`ollama-b`в OpenCode, ничего не появлялось в селекторе моделей. Ничего. Ни черта.

Причина? API`/v1/models`возвращалось из инстанции B`{"object":"list","data":null}`вместо`{"object":"list","data":[]}`когда ни одна модель не была извлечена. Значение`null`вызывал сбой парсинга со стороны OpenCode, который не отображал провайдера.

Решение: объявлять модели explicitement в конфигурации OpenCode вместо того, чтобы полагаться на динамическое обнаружение.

~/.config/opencode/opencode.json
{
  "$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`Отображает два экземпляра бок о бок.

Если вы не видите свой пользовательский провайдер в`/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`. Он переживает перезагрузки системы без ручного вмешательства.

Уроки извлечённые

  1. Docker изолирует всё, даже идентичность— Достаточно простого bind mount тома, чтобы дать контейнеру собственный набор SSH‑ключей, сделав его неразличимым с другой физической машиной в глазах Ollama.

  2. Два письма, та же CB— Ollama не блокирует множественные подписки из одного способа оплаты. Только email должен быть уникальным.

  3. Тестировать бесплатно перед оплатой — 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.

  4. /v1/models` с data: null ломает OpenCode— Если вы настраиваете пользовательский провайдер с`"models": {}`, OpenCode пытается обнаружить модели через API. Если API ответит`data: null`, провайдер не появляется. Объявите модели явно.

  5. Два аккаунта — это человеческая многопроцессорность— Аккаунт Pro = одна активная сессия OpenCode. Два аккаунта = две параллельные сессии. Для человека, который одновременно жонглирует несколькими проектами Gradle, это гейм‑чейнджер.

Похожие статьи