Зачем я сделал еще один опен-сорс 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

© Habrahabr.ru