Зачем я сделал еще один опен-сорс Code Sandbox на любом языке
Скоро я запускаю интерактивный плеер кода (как уроки в Ютубе, только вы всегда имеете доступ к коду в любой промежуток времени) в браузера. Одной из фич моей платформы — возможность запускать написанный код. Урок или свой опыт человек может записать на любом языке, потому мне остро понадобился универсальный Sandbox для любого языка, желательно с возможностью запускать код из нескольких файлов.
Кроме того не хотелось бы платить за запросы в имеющеся платформы. А также нужна возможность управлять (добавлять/менять) новые технологии быстро, не платить за запросы имеющимся платформам. Кроме того хотелось наконец выпустить что-то полезное в своем гитхабе и иметь строчку в резюме.
Что есть из доступного
На самом деле решений не так много. Основной провайдер таких услуг — проект Judge0. Песочница всем классная: поддерживает десятки языков, изоляция сделана на базе isolate, ограничивая linux cgroup/permissions. Но я столкнулся с его минусами:
Старый и редко обновляется последнее время. До банального — языки старых версий
Сложный запуск кода из нескольких файлов. Платформа Judge0 позволяет это делать, но крайне не удобно
Довольно скудные возможности настраивать каждую технологию, на этой платформе банально добавлен огромный список бинарников и не учитываются особенности каждого языка. Например TypeScript запускается без tsconfig и банально нельзя использовать типы вида Foo[] или Array
. Примеров для других языков нет, но они возможны При всей простоте Judje0, сделан он инфраструктурно сложно: Руби приложение, БД для хранения стейтов. Руби я не знаю, стейт не нужен для хранения или он будет организован сторонними силами, на платформе запуска это мне оказалось не нужным
Надо платить за имеющийся вариант АПИ или разворачивать и много дорабатывать
На рынке есть плейграунды для отдельных языков. Например, для Golang есть опенсорсный для go — сделан круто, но только один язык.
Есть у JetBrians для языка Kotlin, тоже крутой, но тоже ограничен одной платформой.
Делаем свое
Мне очень понравился вариант песочницы у Google для Go. Суть ее работы сводится к тому, что есть веб-сервис, который компилирует go код, далее он отправляет по приватной сети на машину, в которой запрос принимает веб-сервис, запущенный в докер с привилегированным доступом к докеру хоста и плодит sandbox-контейнеры с го, передавая через stdin скомпилированный бинарный код. Так у сервиса есть доступ к докеру хоста, то для изоляции используется технология Google gVisor.
С этими вводными и на базе этой кодовой базе я и решил реализовать свое решение, но уже универсальное по части языков. Поехали!
Итоговая схема работы примерно такая, как у гугла:
Общая схема работы проекта
Так как код может быть любым на любом языке, не только Golang код, то у первого Playground сервиса убирается ответственность по компиляции кода и переезжает в сервис на Sandbox машине, там отдельным вызовом она будет делать еще один вызов внутри контейнера.
Сами sandboxes теперь тоже не го, потому мы должны предоставить образы машине, в которых будет обрабатываться входной код. Так как это докер-сервис, то просто передадим папку с конфигами — все очень тупо и просто.
Схема поставки конфигов:
Второй путь (через АПИ) пока только в планах в виде набросков, но скоре будет реализован.
Конфигурация образа простая — это набор из докерфайла с нужным языком, и json конфиг с данными команды по запуску кода, а также алиас/код, по которому мы будет определять что код нужно запустить реквест именно в контейнере этого образа.
В целом это все. Под капотом еще внедрены хуки через go-plugin, для случаев, например, таких, когда какой-то язык мы хотим обработать на другом сервисе, а не через ресурсы нашего Sandbox. Или для организации Authentication, для хранения (пока тоже в виде набросков, тк реализован полноценно только PreRequest хук, ответы от обработчиков хуков еще не реализованы).
Проблемы
Есть проблемы с этапом компиляции. Для него нужна сеть, а контейнеры создаются в приватном докерном рантайме gVisor без сети (—network=none) и с ограничением памяти. Потмоу на данном этапе нельзя собрать проект с пакетными зависимостями… Буду рад вашим предложениям как это организовать.
Также нет возможности переиспользовать стейт песочницы (то есть нельзя иметь некоторую сессию) — также рад буду вашему участию и предложениям.
Ссылка:
Проект еще сырой (MVP-код без тестов), пока не особо протестирован и не имеет кучу фич. Но уже можно запускать и играться. Буду рад вашим отзыва
https://github.com/codiewio/codenire