Skip to content

Code Runner

Описание

runner-code — раннер для выполнения произвольного кода в закрытой песочнице (Docker). Тело задачи (command) — это исходный код; язык и зависимости задаются переменными задачи.

Схема выполнения:

  1. Код записывается в файл (main.py, main.js, ...) во временный workspace на хосте, который монтируется в контейнер как /workspace.
  2. Если заданы зависимости — они устанавливаются отдельным контейнером с доступом в сеть (install_network, по умолчанию bridge). Зависимости ставятся внутрь /workspace и переживают контейнер.
  3. Код запускается в контейнере без сети (network=none по умолчанию) с лимитами памяти/CPU/pids, --cap-drop=ALL и no-new-privileges.
  4. Файлы, записанные кодом в $ARTIFACT_DIR (/workspace/artifacts), автоматически загружаются в storage платформы.

Поддерживаемые языки

ЯзыкАлиасыОбраз по умолчаниюФайл кодаЗависимости
pythonpy, python3python:3.12-slimmain.pypip (CODE_DEPS, CODE_DEPS_FILE = requirements.txt)
nodejs, javascript, nodejsnode:22-alpinemain.jsnpm (CODE_DEPS, CODE_DEPS_FILE = package.json)
typescripttsnode:22-alpinemain.tsnpm (как node), запуск через --experimental-strip-types
gogolanggolang:1.24-alpinemain.gogo get + go mod tidy (CODE_DEPS_FILE = go.mod)
rubyrbruby:3.3-slimmain.rbgem install (CODE_DEPS)
phpphp:8.3-climain.phpне поддерживаются
bashsh, shellalpine:3.20main.shapk-пакеты; ставятся в том же контейнере, поэтому запуск идёт с сетью

Конфигурация

Общие параметры runner-common

См. Общая документация.

Специфичные параметры

Параметр (config)EnvФлагПо умолчаниюОписание
docker_hostDOCKER_HOST-docker-hostиз окруженияХост docker daemon
pull_policyCODE_PULL_POLICY-pull-policyif-not-presentalways | if-not-present | never
default_languageCODE_DEFAULT_LANGUAGE-default-languageЯзык, если задача не задала CODE_LANGUAGE
networkCODE_NETWORK-networknoneСеть на стадии запуска кода
install_networkCODE_INSTALL_NETWORK-install-networkbridgeСеть на стадии установки зависимостей
memoryCODE_MEMORY-memory512mЛимит памяти контейнера
cpusCODE_CPUS-cpus1.0Лимит CPU
pids_limitCODE_PIDS_LIMIT-pids-limit256Лимит числа процессов
userCODE_USER-userиз образаПользователь контейнера (1000:1000)
upload_artifactsCODE_UPLOAD_ARTIFACTS-upload-artifactstrueЗагрузка артефактов из /workspace/artifacts
imagesсм. таблицу языковПереопределение образов по языкам

Пример YAML

yaml
url: "https://app.com/"
token: "your-token"
concurrency: 2
tags: "code,sandbox"
description: "Sandboxed code executor"

default_language: python
network: none
install_network: bridge
memory: 512m
cpus: 1.0
pids_limit: 256
images:
  python: "my-registry/python:3.12-slim"

Переменные задачи

ПеременнаяОписаниеПример
CODE_LANGUAGEЯзык кода (обязательна, если нет default_language)python
CODE_DEPSСписок зависимостей (через запятую/пробел/перенос строки)requests, pandas
CODE_DEPS_FILEСодержимое нативного файла зависимостей (requirements.txt / package.json / go.mod)requests==2.32.0
CODE_IMAGEПереопределение docker-образаpython:3.13-slim
CODE_NETWORKПереопределение сети стадии запускаbridge
CODE_UPLOAD_ARTIFACTSВключить/выключить загрузку артефактовfalse

Все переменные задачи (включая служебные CODE_*) также передаются в контейнер запуска как переменные окружения.

Примеры задач

Python с зависимостями

command: |
  import requests_mock  # доступен: установлен на стадии deps
  print("ok")
variables:
  - { name: CODE_LANGUAGE, value: python }
  - { name: CODE_DEPS, value: requests-mock }

Точные версии через requirements.txt

variables:
  - { name: CODE_LANGUAGE, value: python }
  - name: CODE_DEPS_FILE
    value: |
      requests==2.32.3
      pydantic>=2,<3

Node/TypeScript

command: |
  import { z } from "zod";
  console.log(z.string().parse("hello"));
variables:
  - { name: CODE_LANGUAGE, value: ts }
  - { name: CODE_DEPS, value: zod }

Go

command: |
  package main

  import (
      "fmt"
      "github.com/google/uuid"
  )

  func main() { fmt.Println(uuid.NewString()) }
variables:
  - { name: CODE_LANGUAGE, value: go }
  - { name: CODE_DEPS, value: github.com/google/uuid }

Артефакты

Код пишет файлы в директорию из переменной окружения ARTIFACT_DIR (всегда /workspace/artifacts):

python
import os
out = os.environ["ARTIFACT_DIR"]
with open(os.path.join(out, "report.csv"), "w") as f:
    f.write("a,b\n1,2\n")
  • Артефакты загружаются только при успешном выполнении (код возврата 0)
  • Загружаются все файлы из ARTIFACT_DIR (рекурсивно, с сохранением структуры)
  • artifact_id возвращается в статусе задачи

Передача переменных окружения

Переменные задачи передаются в контейнер запуска как env:

variables:
  - { name: CODE_LANGUAGE, value: python }
  - { name: API_MODE, value: staging }
python
import os
print(os.environ["API_MODE"])  # staging

Песочница

  • Сеть стадии запуска — none (полная изоляция; переопределяется CODE_NETWORK / конфигом)
  • --cap-drop=ALL, --security-opt no-new-privileges
  • Лимиты: память (512m), CPU (1.0), pids (256)
  • Файловая система хоста недоступна — монтируется только временный workspace
  • Workspace удаляется после выполнения
  • Таймаут задачи (task_timeout) останавливает контейнер

Замечания:

  • Для bash зависимости (apk) ставятся в контейнер, поэтому при наличии CODE_DEPS запуск идёт с сетью.
  • Стадия установки зависимостей имеет доступ в сеть — не передавайте секреты в задачи с недоверенными зависимостями.

Обработка ошибок

  • Ненулевой код возврата → статус failed с текстом Code failed with exit code N
  • Ошибка установки зависимостей → failed (стадия запуска не выполняется)
  • Неизвестный язык / неподдерживаемые зависимости → failed с пояснением
  • Таймаут контекста → контейнер останавливается, статус failed

Остановка

Корректно обрабатывает SIGINT и SIGTERM. Запущенные контейнеры останавливаются и удаляются.