Сервис зеркалирует моды из Steam Workshop в Open Workshop. Репозиторий теперь поддерживает не только одиночный запуск parser, но и kubernetes-native control plane: MirrorInstance CRD, оператор, web UI и раздельные workload'ы для parser и steamcmd-runner.
На каждый экземпляр создаются два отдельных StatefulSet:
parser— синхронизация каталога, работа с Open Workshop, HTML/API обход Steam и публикация ресурсов.steamcmd-runner— отдельный pod со своим локальнымsteamcmdи sidecar наsing-box, который уводит egress через TUN и upstream proxy.
Ключевые свойства:
- управление идёт через
MirrorInstance, а не через ручные Deployment'ы; - OW credentials, parser proxy pool и steamcmd upstream proxy хранятся в отдельных
Secret; - parser использует свой proxy pool на application level;
steamcmd-runnerиспользует один активный upstream proxy через TUN внутри pod;- UI работает через Kubernetes API: создаёт и редактирует
MirrorInstanceи связанныеSecret, показывает статусы, ресурсы и pod logs.
Основные Python-модули больше не лежат плоско в корне. Код разложен по пакетам:
core/— общие утилиты, конфиг, telemetry и HTTP helpers;kube/—MirrorInstance, Kubernetes client/resources и оператор;ow/— Open Workshop API и BBCode helpers;services/— runtime entrypoints дляparserиrunner;steam/— Steam API, Steam mod scraping иsteamcmd;sync/— основной sync engine;ui/— web UI, шаблоны и статические ассеты.
В корне оставлены только entrypoints и инфраструктурные файлы: main.py, Dockerfile, requirements.txt, start.sh, chart/docs и release scripts.
Образ поддерживает четыре режима:
parserrunneroperatorui
Режим определяется аргументом контейнера или OW_MODE.
Примеры:
python3 main.py parser
python3 main.py runner
python3 main.py operator
python3 main.py uiHelm chart лежит в charts/auto-updater.
Сборка образа:
docker build -t ghcr.io/your-org/auto-updater-backend:latest .Установка chart:
helm upgrade --install auto-updater ./charts/auto-updater \
--namespace auto-updater \
--create-namespace \
--set image.repository=ghcr.io/your-org/auto-updater-backend \
--set image.tag=latestДля k3s/buildah есть готовый release-скрипт: scripts/release_k3s_buildah.sh.
Что он делает:
- прогоняет
py_compileпо Python-модулям; - собирает образ через
buildah bud --layers; - упаковывает образ в
docker-archiveвне build context и импортирует вcontainerd; - обновляет
image.tagв values-файле; - явно применяет
MirrorInstanceCRD доhelm upgrade, потому что Helm не обновляет CRD из каталогаcrds/сам; - делает
helm upgradeи дожидается rollout уoperator,uiи managedStatefulSet. - переводит существующие
MirrorInstanceв каноническийparser.*-формат после релиза.
Пример для нашего k3s-сценария:
scripts/release_k3s_buildah.sh \
--tag prod-20260326-9 \
--values /root/auto-updater-values.yaml \
--kube-cli "k3s kubectl"Если нужно только проверить build cache без деплоя:
scripts/release_k3s_buildah.sh \
--tag cache-smoke \
--values /root/auto-updater-values.yaml \
--skip-import \
--skip-deploy--layers включён по умолчанию. Для образа также добавлен .dockerignore, чтобы не тащить в build context тесты, chart, docs, архивы образов и служебные файлы.
Chart ставит:
MirrorInstanceCRD;Deploymentоператора;Deploymentweb UI;ServiceAccount,Role,RoleBinding;- опциональный ingress для UI.
Базовый объект:
apiVersion: auto-updater.miskler.ru/v1alpha1
kind: MirrorInstance
metadata:
name: rimworld-main
namespace: auto-updater
spec:
enabled: true
source:
steamAppId: 294100
owGameId: 0
language: english
sync:
pollIntervalSeconds: 600
pageSize: 50
timeoutSeconds: 60
httpRetries: 3
httpRetryBackoff: 5.0
logLevel: INFO
steamHttpRetries: 2
steamHttpBackoff: 2.0
steamRequestDelay: 1.0
steamMaxPages: 1000
steamStartPage: 1
steamMaxItems: 0
steamDelay: 1.0
maxScreenshots: 20
uploadResourceFiles: true
scrapePreviewImages: true
scrapeRequiredItems: true
publicMode: 0
withoutAuthor: false
syncTags: true
pruneTags: true
syncDependencies: true
pruneDependencies: true
syncResources: true
pruneResources: true
credentials:
secretRef: rimworld-main-ow-credentials
parser:
proxyPoolSecretRef: rimworld-main-parser-proxies
steamcmd:
proxy:
type: socks5
secretRef: rimworld-main-steamcmd-proxy
storage:
parser:
size: 20Gi
storageClassName: local-path
runner:
size: 10Gi
storageClassName: local-pathСвязанные секреты:
apiVersion: v1
kind: Secret
metadata:
name: rimworld-main-ow-credentials
namespace: auto-updater
type: Opaque
stringData:
login: your-login
password: your-password
---
apiVersion: v1
kind: Secret
metadata:
name: rimworld-main-parser-proxies
namespace: auto-updater
type: Opaque
stringData:
proxyPool: |
socks5://user:pass@host-1:3001
http://user:pass@host-2:3000
---
apiVersion: v1
kind: Secret
metadata:
name: rimworld-main-steamcmd-proxy
namespace: auto-updater
type: Opaque
stringData:
proxyUrl: socks5://user:pass@host:3001UI поднимается в режиме ui и работает прямо с Kubernetes API.
Что умеет:
- создавать и редактировать
MirrorInstance; - управлять связанными
Secret; pause/resume;Sync nowчерез parser admin endpoint;- показывать
phase,conditions,lastSync*,lastError; - открывать связанные ресурсы;
- читать
parser,runnerиtun-proxypod logs без отдельной БД.
Внутренние HTTP интерфейсы:
- parser:
GET /healthzGET /api/v1/statusPOST /api/v1/sync
- runner:
GET /healthzPOST /api/v1/archive
POST /api/v1/archive принимает JSON:
{"appId": 294100, "workshopId": 1234567890}Успешный ответ — ZIP stream. Ошибка — JSON:
{
"reason": "steamcmd exit code 8",
"retryable": true,
"diagnostics": "..."
}Старый single-process сценарий сохранён. Если вы запускаете только parser, используются те же env-переменные:
OW_LOGINOW_PASSWORDOW_STEAM_APP_IDилиSTEAM_APP_ID
Дополнительные env:
OW_STEAMCMD_RUNNER_URL— вынестиsteamcmdв отдельный runner service;OW_ADMIN_HOST,OW_ADMIN_PORT— поднять parser admin HTTP endpoint;OW_INSTANCE_NAME,OW_INSTANCE_NAMESPACE— писать runtime status обратно вMirrorInstance.
Пример локального однократного запуска:
docker run --rm \
-e OW_LOGIN=your_login \
-e OW_PASSWORD=your_password \
-e OW_STEAM_APP_ID=294100 \
-e OW_RUN_ONCE=true \
-v /path/to/runtime:/data \
ghcr.io/your-org/auto-updater-backend:latest parserОбязательные:
OW_LOGINOW_PASSWORDOW_STEAM_APP_IDилиSTEAM_APP_ID
Основные опциональные:
OW_GAME_IDOW_API_BASEOW_MIRROR_DIRSTEAM_ROOTOW_PAGE_SIZEOW_POLL_INTERVALOW_HTTP_TIMEOUTOW_HTTP_RETRIESOW_HTTP_RETRY_BACKOFFOW_RUN_ONCEOW_LOG_LEVELOW_LOG_STEAM_REQUESTSOW_STEAM_HTTP_RETRIESOW_STEAM_HTTP_BACKOFFOW_STEAM_REQUEST_DELAYOW_STEAM_PROXY_POOLOW_STEAM_PROXY_SCOPEOW_STEAM_MAX_PAGESOW_STEAM_START_PAGEOW_STEAM_MAX_ITEMSOW_STEAM_DELAYOW_MAX_SCREENSHOTSSTEAM_LANGUAGEDEPOTDOWNLOADER_PATHOW_RESOURCE_UPLOAD_FILESOW_SCRAPE_PREVIEW_IMAGESOW_SCRAPE_REQUIRED_ITEMSOW_FORCE_REQUIRED_ITEM_IDOW_MOD_PUBLICOW_WITHOUT_AUTHOROW_SYNC_TAGSOW_PRUNE_TAGSOW_SYNC_DEPENDENCIESOW_PRUNE_DEPENDENCIESOW_SYNC_RESOURCESOW_PRUNE_RESOURCES
Parser proxy pool поддерживает:
http://https://socks5://socks5h://
steamcmd-runner принимает один upstream proxy URL и валидирует его тип относительно spec.steamcmd.proxy.type.
Быстрые проверки:
python3 -m compileall .
python3 -m unittest discover -s tests -v