Границы компонентов

БраузерыПриложение ColloqRuntime broker
Ядро комнаты AЯдро комнаты B

В production приложение работает с UID 1000 без Docker socket и Kubernetes credentials. Только приватный runtime broker получает namespaced service-account token и создаёт Pod/Service из фиксированного шаблона и доверенного каталога. API не принимает произвольный Pod template или путь хоста.

Каждая комната получает отдельный Jupyter Pod, токен и workspace subPath. Если runtime, образ или политика недоступны, запуск не происходит: перехода к общему ядру сервера нет.

Ограничения Pod

Room Pod работает с UID/GID 1000, без дополнительных capabilities и повышения привилегий, с RuntimeDefault seccomp и read-only корневой файловой системой. Service-account token не монтируется. Записываемые области: каталог комнаты, /tmp, /home/runner и /dev/shm.

Pod Security требует restricted-профиль. RBAC брокера ограничен операциями с Pod и Service в namespace; работающий Pod брокер может изменить только через подресурс pods/resize, которым он меняет память комнаты. Но каждое поле создаваемого Pod RBAC ограничить не умеет, поэтому код брокера, его шаблоны и каталог входят в доверенную часть системы.

Сеть: проверяйте фактический результат

NetworkPolicy разрешает вход к Jupyter только приложению и брокеру. Исходящий трафик комнат по умолчанию разрешён только к DNS Pod в kube-system по TCP/UDP 53. Для загрузки внешних данных нужен отдельно спроектированный outbound proxy или профиль.

Если нужна изоляция от host-сервисов, добавьте CNI с host policy или проверенную firewall-политику с точечным разрешением брокеру доступа к Kubernetes API. До допуска недоверенных пользователей выполните реальный room-to-node connection test. Наличие манифеста не является доказательством.

Файлы и квоты

Linux production использует доступ через доверенные файловые дескрипторы, O_NOFOLLOW и /proc/self/fd. Символические ссылки не обходят каталог комнаты. Если защищённый механизм недоступен, production отказывает в работе.

Старый workspace не должен содержать hardlink между комнатами. При миграции копируйте обычные файлы в отдельные каталоги и проверьте владельцев и ссылки. Два имени существующего общего inode не превращаются в независимые данные от проверки пути.

Размер PVC — метаданные планирования, а не filesystem quota. MAX_UPLOAD_MB и MAX_SESSION_MB ограничивают операции приложения и не сдерживают произвольную запись Python. Используйте отдельный раздел и мониторинг свободного места.

Права, ссылки и секреты

Ссылка комнаты даёт доступ к занятию; преподавательская ссылка даёт доступ к панели. Setup-token позволяет владельцу восстановить контроль. Храните секреты и backup приватно; полный доступ к диску сервера означает доступ к данным и ключам.

Отдельные ответы Консилиума не дают отдельное ядро каждому студенту. Ограничения действий и browser-ban не являются проверкой личности. Автоматического оценивания, SSO и защиты экзаменационного исполнения система не обещает.

Пределы развёртывания

Контейнеры разделяют Linux-ядро VM. Это не изоляция виртуальными машинами и не защита от уязвимостей ядра. Одна VM, один узел k3s и local PV не дают HA. Потеря машины требует внешнего backup; обновления прерывают работу и теряют память Python.

Проверяйте собственную нагрузку. Не существует подтверждённого универсального лимита «сколько студентов выдержит сервер»: результаты зависят от вычислений, вывода, файлов, активных комнат и сети.

Занятие на своём компьютере

Локальный запуск — colloq start или make dev — слушает только 127.0.0.1; наружу занятие видно лишь после явного colloq host. Ядра комнат — отдельные Docker-контейнеры, а сервер управляет ими через Docker daemon, то есть с правами, равными root на этой машине. На macOS каждый сегмент пути открывается с O_NOFOLLOW, но без Linux-механизма /proc/self/fd между проверкой и операцией остаётся окно гонки.

Каждый контейнер комнаты получает один и тот же укреплённый профиль, как бы ни было запущено занятие (colloq start, make dev, make run, make up, образ vast.ai): UID 1000, никаких Linux capabilities, no-new-privileges, профиль seccomp Docker по умолчанию, потолок процессов (KERNEL_PIDS, по умолчанию 512) и никакого IPv6. Интернет комнате доступен — pip install, датасеты, API, — а локальные адреса нет: 10/8, 172.16/12, 192.168/16, 100.64/10, link-local 169.254/16 с метаданными облака, loopback, multicast, сам компьютер и соседние комнаты. Соединение туда сразу получает отказ. Под make up и в образе vast.ai комнаты делят сеть Docker с сервером, и трафик внутри этой сети фильтруется, только если хост пропускает мостовой трафик через iptables — обычно Docker так и настраивает; иначе между комнатами остаётся токен Jupyter каждой комнаты. Открытым до любого адреса остаётся только DNS, порт 53: на части машин резолвер Docker пересылает запросы из сети самой комнаты.

Запрет ставит сам сервер: короткоживущий привилегированный служебный контейнер добавляет правила в собственные цепочки COLLOQ-ROOMS-*, в которые ведут DOCKER-USER и INPUT, — тем же iptables, которым пользуется Docker daemon. Так устроено для colima, Docker Desktop и Docker в Linux; rootless Docker, podman и Docker Desktop с Enhanced Container Isolation служебный контейнер не пускают. Если правила не встали, комнаты не запускаются, а сообщение в комнате объясняет почему. Доверенному занятию, которому нужна локальная сеть, запрет снимает строка COLLOQ_ROOM_NETWORK=open в .env, и colloq doctor тогда об этом напоминает. Контейнер комнаты, поднятый прежней версией, сохраняет старый профиль, пока не остановится; следующий запуск пересоздаёт его.

В отличие от production, корневая файловая система остаётся доступной для записи — ради %pip install, — а сколько диска займёт комната, ничто не ограничивает. Поэтому локальное занятие по-прежнему рассчитано на доверенный периметр «мой класс на моём компьютере»; для открытой аудитории используйте серверную установку.