RE:NODE

Руководства11 мин чтения

Эгги Pterodactyl для игровых серверов

Как устроен эгг Pterodactyl поле за полем: Docker-образы, строка запуска, переменные и правила, парсеры конфигов, скрипт установки, определение старта и остановка.

0 прочтений

Эгг Pterodactyl - это один JSON-файл, который говорит панели, как установить, запустить, настроить и остановить сервер определённого вида. В нём названы Docker-образы, в которых может работать сервер, хранится команда запуска с {{VARIABLES}} внутри, определены эти переменные со значениями по умолчанию и правилами проверки, перечислены конфиги, которые нужно переписать при загрузке, лежит bash-скрипт установки, который один раз выполняется в одноразовом контейнере, и указано, какая строка лога означает «запущен» и какая команда означает «стоп». Всё, что вы видите на вкладке Startup в панели, - это эгг, отрисованный в виде формы. Понимая, как он собран, вы понимаете, почему одни правки сохраняются, а другие откатываются, почему сервер вечно висит в состоянии «starting» и почему кнопка Stop в одной игре сохраняет мир, а в другой нет.

Если вы её ещё не читали, статья о панели Pterodactyl объясняет саму панель, демон Wings и модель «один контейнер на сервер». Здесь мы вскрываем сам эгг.

Откуда берутся эгги#

Pterodactyl поставляется с небольшим набором эггов - варианты Minecraft, несколько игр на Source, Rust, пара голосовых серверов, - сгруппированных в гнёзда (nests). Почти все остальные игровые эгги, которые используются на практике, взяты из community-коллекции на GitHub, которую годами вели в parkervcp/eggs, а теперь в организации pelican-eggs, по одной папке на игру. Хостинги импортируют их, дорабатывают или пишут свои.

Эгг экспортируется и импортируется как JSON в формате, который панель называет PTDL_v2. У Pelican, форка Pterodactyl, своя ревизия формата, и большинство эггов Pterodactyl он импортировать умеет. Каким бы ни был источник, читайте скрипт установки эгга перед импортом: он выполняется с доступом к сети и пишет в файлы сервера, и эгг - это чужой код ровно в той же мере, что и плагин.

Анатомия эгга#

Если оставить только важное, эгг в стиле Minecraft выглядит так:

egg-paper.json
{  "meta": { "version": "PTDL_v2", "update_url": null },  "name": "Paper",  "features": ["eula", "java_version"],  "docker_images": {    "Java 21": "ghcr.io/pterodactyl/yolks:java_21",    "Java 17": "ghcr.io/pterodactyl/yolks:java_17"  },  "file_denylist": [],  "startup": "java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}",  "config": {    "files": "{\"server.properties\":{\"parser\":\"properties\",\"find\":{\"server-ip\":\"0.0.0.0\",\"server-port\":\"{{server.build.default.port}}\"}}}",    "startup": "{\"done\":\")! For help, type \"}",    "logs": "{}",    "stop": "stop"  },  "scripts": {    "installation": {      "container": "ghcr.io/pterodactyl/installers:alpine",      "entrypoint": "ash",      "script": "#!/bin/ash\ncd /mnt/server\n..."    }  },  "variables": [    {      "name": "Server Jar File",      "env_variable": "SERVER_JARFILE",      "default_value": "server.jar",      "user_viewable": true,      "user_editable": true,      "rules": "required|regex:/^([\\w\\d._-]+)(\\.jar)$/",      "field_type": "text"    }  ]}

Значения в config закодированы как JSON внутри строк, поэтому они полны экранированных кавычек. Это некрасиво, и вручную их легко сломать; правьте их в админ-интерфейсе панели или очень аккуратно.

ПолеЧто контролирует
docker_imagesОбразы среды выполнения, которые может использовать сервер, в виде «метка - образ»
startupКоманду запуска с подставленными переменными
variablesПоля вкладки Startup, их значения по умолчанию и проверку
config.filesКакие конфиги Wings переписывает перед каждым запуском
config.startupТекст в логе, по которому сервер считается запущенным
config.stopКак Wings просит сервер остановиться
scripts.installationОдноразовый скрипт установки и образ, в котором он выполняется
file_denylistФайлы, которые пользователи не могут открывать или править в файловом менеджере
featuresПомощники панели, например запрос EULA и переключатель версии Java

Docker-образы: среда выполнения, а не игра#

Образ - это среда, в которой работает игра: библиотеки операционной системы, версия Java, .NET или Wine и скрипт точки входа. Самой игры в нём нет. Файлы игры лежат на томе сервера, смонтированном в /home/container, и переживают смену образа.

Большинство эггов используют образы «yolks»: ghcr.io/pterodactyl/yolks - официальный набор, ghcr.io/parkervcp/yolks и ghcr.io/parkervcp/steamcmd - community-набор. Теги называют среду выполнения - java_21, debian, dotnet_8, теги Wine для игр только под Windows и так далее. Имена тегов и их содержимое со временем меняются, поэтому сверяйтесь с репозиторием, а не копируйте тег из старого эгга.

Все образы yolks устроены по одной схеме. Контейнер работает от непривилегированного пользователя container, стартует в /home/container и запускает точку входа, которая берёт переменную окружения STARTUP, превращает {{VAR}} в ${VAR} и выполняет результат:

entrypoint.sh (simplified)
cd /home/containerMODIFIED_STARTUP=$(echo -e ${STARTUP} | sed -e 's/{{/${/g' -e 's/}}/}/g')echo ":/home/container$ ${MODIFIED_STARTUP}"eval ${MODIFIED_STARTUP}

Эта выведенная строка - первое, что вы видите в консоли при каждом запуске, и это самый быстрый способ проверить, что на самом деле было запущено. Если переменная пуста, вы увидите, что её в этой строке не хватает.

Выбор не того образа - частая причина сбоев. Версия Minecraft, которой нужна Java 21, запущенная в образе с Java 17, падает с UnsupportedClassVersionError; таблица версий есть в статье о флагах JVM и версиях Java для Minecraft.

Строка запуска и переменные#

Поле startup - это шаблон. Некоторые значения Wings подставляет сам, из параметров сервера:

ПеременнаяИсточник
SERVER_MEMORYЛимит памяти в МБ
SERVER_IPIP основной аллокации
SERVER_PORTПорт основной аллокации
P_SERVER_UUIDID сервера
P_SERVER_LOCATIONНазвание локации ноды
TZЧасовой пояс, настроенный для Wings

Всё остальное берётся из массива variables эгга, и каждая переменная становится переменной окружения внутри контейнера, а заодно подстановкой в строке запуска. Поэтому переменную можно использовать в обоих местах: в startup как {{MAX_PLAYERS}}, а в shell-скрипте или самой игре - как $MAX_PLAYERS.

У каждой переменной есть:

  • env_variable - имя, которое используется в строке запуска и в окружении.
  • default_value - то, что получает новый сервер.
  • user_viewable и user_editable - видит ли клиент её на вкладке Startup и может ли менять. Хостинги скрывают переменные, где хранятся их собственные секреты, и блокируют те, что сломали бы тариф, например переопределение памяти.
  • rules - правила проверки Laravel, тот же синтаксис, что панель использует везде: required|string|max:32, nullable|string, required|integer|between:1,100, required|in:true,false, regex:/.../. Значение, не прошедшее правило, отклоняется при сохранении поля.

Хорошо написанный эгг использует правила, чтобы предотвращать ошибки, которые иначе привели бы к падению при загрузке, - например нечисловой порт или имя jar-файла без .jar. Плохо написанный принимает что угодно, и ошибка появляется уже в консоли.

Изменения переменных вступают в силу при следующем запуске, потому что они меняют только окружение и строку запуска. Переменные, которые использует скрипт установки, - версия игры, ветка, ID модпака - вступают в силу только после переустановки сервера, потому что читает их только скрипт установки. Это различие объясняет большинство жалоб вида «поменял версию, и ничего не произошло».

Парсеры конфигов: почему некоторые правки откатываются#

config.files велит Wings перед каждым запуском открыть определённые файлы и выставить определённые ключи. Парсер - один из properties, ini, json, yaml, xml или file (простой текст, совпадение по началу строки), а find перечисляет ключи и значения, которые нужно принудительно задать.

Обычно так задают порты и адреса. Эгг Minecraft выше принудительно ставит server-port в {{server.build.default.port}} - основную аллокацию сервера - и server-ip в 0.0.0.0, чтобы игра всегда слушала там, где говорит панель. Эгги прокси задают вложенные ключи YAML через путь с точками вроде listeners[0].host. Другие эгги задают из переменных query-порты, порты RCON или максимальное число игроков.

Отсюда самое запутанное в хостинге с панелью: если вы правите ключ, которым управляет эгг, ваша правка при следующем запуске будет молча перезаписана. Выглядит так, будто файл откатился сам. Решение - менять значение там, откуда его берёт эгг, - в переменной на вкладке Startup или в порте на вкладке Network, - а не в файле. Если настройка упорно откатывается, а переменной для неё вы найти не можете, эгг выставляет фиксированное значение, и на хостинговой панели это вопрос к хостингу. Более широкий список причин, по которым правка конфига не держится, есть в статье о форматах конфигов игровых серверов.

Скрипт установки#

Установка выполняется в отдельном от работы контейнере. Когда сервер создаётся или переустанавливается, Wings:

  1. Скачивает образ, указанный в scripts.installation.container (образ установщика с curl, jq, git, unzip и подобными инструментами).
  2. Монтирует том сервера в /mnt/server.
  3. Передаёт переменные эгга как переменные окружения.
  4. Запускает скрипт с указанной entrypoint (bash или ash).
  5. Выбрасывает контейнер, и только после этого разрешает запуск сервера в его образе среды выполнения.

Типичный скрипт установки на базе SteamCMD скачивает SteamCMD в /mnt/server/steamcmd, выполняет app_update с переменными app ID и ветки из эгга, копирует клиентские библиотеки Steam, которые ожидает игра, в .steam/sdk64 или .steam/sdk32 и записывает конфиг по умолчанию, если его нет. Скрипт Minecraft обращается к API версий и скачивает jar. Подробности о половине с SteamCMD - в статье App ID и beta-ветки SteamCMD.

Для клиентов важны два свойства скриптов установки:

  • Переустановка запускает скрипт заново. Хорошие скрипты только скачивают и обновляют игру, не трогая миры и конфиги. Небрежные перезаписывают конфиги значениями по умолчанию. Сделайте backup, прежде чем переустанавливать сервер, который вам дорог.
  • Лог установки отдельный. Если новый сервер так и не запускается, скорее всего, не удалась установка. Во время установки панель показывает вывод установщика в консоли, а Wings хранит лог установки на ноде.

Определение старта и команда остановки#

config.startup.done - это строка (или список строк), которую Wings высматривает в консоли. Когда она появляется, состояние сервера меняется с «starting» на «running». Для Minecraft это )! For help, type - совпадение со строкой, которую Paper печатает, закончив загрузку. Для Valheim это обычно строка о том, что игровой сервер подключён. Если вывод игры изменился с обновлением и этого текста больше нет, сервер работает отлично, но панель вечно показывает «starting». Для игроков это косметика, а для расписаний, которые ждут состояния running, - раздражающая проблема.

config.stop - то, как Wings просит об остановке. Это либо консольная команда, записываемая на вход сервера, - stop для Minecraft, quit для игр на Source, - либо ^C, который посылает процессу SIGINT. Если сервер не завершится за отведённое Wings время, его убьют.

Здесь миры спасаются или теряются. Эгг, чья команда остановки вызывает сохранение и корректный выход, даёт вам безопасные кнопки Stop и Restart. Эгг, который посылает ^C игре, игнорирующей его или выходящей по этому сигналу без сохранения, даёт кнопку, которая работает как kill. Проверьте один раз на любой игре, которая вам важна: измените что-нибудь, остановите, запустите, проверьте. Почему эта разница важна, объясняет статья о полезных расписаниях перезапуска, а как ограничить ущерб, когда остановка некорректная, - статья об интервалах автосохранения игровых серверов.

Как написать или изменить свой эгг#

Если у вас своя панель и нужен эгг для игры, которую никто не упаковал:

  1. Начните с самого близкого существующего эгга. Эгг игры на SteamCMD с похожим движком даёт 80 процентов результата.
  2. Сначала добейтесь, чтобы установка работала вручную. Запустите образ установщика локально в Docker, смонтируйте пустую папку в /mnt/server и гоняйте свой скрипт, пока он не даст рабочую установку.
  3. Добейтесь, чтобы строка запуска работала в образе среды выполнения. Тот же образ, та же папка, смонтированная в /home/container, - выполните команду с настоящими значениями.
  4. Добавьте переменные для всего, что пользователь должен менять, с правилами, которые отклоняют плохие значения.
  5. Добавляйте парсеры конфигов только для ключей, которыми должна владеть панель, - порты, адрес привязки. Всё остальное пользователь должен править сам.
  6. Задайте строку готовности, которая появляется при каждом успешном запуске, и команду остановки, про которую вы проверили, что она сохраняет мир.

На хостинговой панели импортировать эгги обычно нельзя; их поддерживает хостинг. В RE:NODE эгги поддерживает хостинг, а их переменные отображаются на вкладке Startup рядом с переменными окружения, порты - на вкладке Network. Пароли администратора, RCON и базы данных генерируются для каждого сервера при установке, Minecraft поднимается на Paper с подходящей версией Java и принятым EULA, а игры, которым нужен ваш собственный логин Steam или лицензионный ключ, ждут на вкладке Setup, пока вы его не укажете. Если вам нужен стек, который не покрывает ни один эгг, выделенный сервер даёт вам всю машину.

Решение проблем с эггами#

Сервер вечно показывает «starting», но игроки могут зайти. Строка готовности больше не совпадает с выводом игры. Косметика, но сообщите хостингу или исправьте эгг.

Настройка в конфиге постоянно откатывается. Этим ключом владеет парсер конфигов эгга. Меняйте её на вкладке Startup или Network.

Я поменял переменную версии, и ничего не изменилось. Версию читает скрипт установки. Переустановите сервер, предварительно сделав backup.

`exec format error` или `not found` для бинарника, который явно на месте. Образ не подходит к игре: 64-битный бинарник в образе без нужных библиотек или Windows-.exe, запущенный без Wine.

Первая строка консоли показывает пустое значение. Переменная пуста. Проверьте на вкладке Startup обязательное поле без значения по умолчанию.

FAQ#

Что такое эгг в Pterodactyl?

JSON-описание одного вида сервера: в каких Docker-образах он работает, как устанавливается, его команда запуска и переменные, какими ключами конфигов управляет панель, как понять, что он запустился, и как его остановить. Каждый сервер в панели создаётся из эгга.

В чём разница между гнездом и эггом?

Гнездо (nest) - это группа эггов, например все варианты Minecraft или все игры на Source. Эгг - это само описание. Гнёзда нужны для организации и ничего не меняют в том, как работает сервер.

Почему изменение переменной на Startup иногда требует переустановки?

Некоторые переменные читает только скрипт установки - версию игры, ветку, модпак. Работающий сервер их никогда не видит. Переменные, которые используются в строке запуска или читаются игрой, вступают в силу при следующем рестарте.

Можно ли использовать эгги из community-репозитория на любой панели?

На панели, которую администрируете вы, - да, импортируйте JSON в админке. На хостинговой панели добавлять эгги самостоятельно обычно нельзя. Проверяйте скрипт установки любого эгга перед импортом, ведь он выполняется с доступом к сети.

Удалит ли смена Docker-образа мои файлы?

Нет. Образ - это только среда выполнения. Файлы сервера лежат на томе, смонтированном в /home/container, и остаются на месте; меняются только библиотеки и инструменты вокруг них.


Комментарии

Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.

0/2000