Document current architecture and operational practices.
Update README with Steam launch scripts, shm sizing, Moonlight setup, and troubleshooting; add рекомендации.md and ignore local SSH keys. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -10,3 +10,7 @@ players/*_config/sunshine.conf
|
||||
|
||||
# do not publish private Sunshine TLS keys
|
||||
players/*_config/credentials/
|
||||
|
||||
# local SSH keys for deployment (never commit)
|
||||
.agent_ssh_key
|
||||
.agent_ssh_key.pub
|
||||
|
||||
264
README.md
264
README.md
@@ -1,140 +1,202 @@
|
||||
# Game Server с использованием Sunshine и Steam
|
||||
# Game Server (Sunshine + Steam)
|
||||
|
||||
Этот проект предоставляет Docker-конфигурацию для запуска игрового сервера с использованием Sunshine и Steam, позволяя запускать игры на нескольких клиентах одновременно.
|
||||
Docker-конфигурация для запуска до четырёх игровых сессий через **Moonlight**. Каждый контейнер стримит виртуальный рабочий стол 1920×1080 с **Steam Big Picture** и отдельным профилем Steam на выделенном GPU.
|
||||
|
||||
## Архитектура
|
||||
|
||||
```
|
||||
Moonlight → Sunshine → Xorg dummy (:99) → fluxbox + Steam (CEF)
|
||||
↑
|
||||
tini (PID 1, перезапуск дочерних процессов)
|
||||
```
|
||||
|
||||
- **Sunshine v0.20.0** — стриминг и захват экрана
|
||||
- **Xorg dummy** — виртуальный дисплей 1920×1080 (корректный ввод из Moonlight)
|
||||
- **fluxbox** — панель задач внизу экрана
|
||||
- **Steam** — запускается от пользователя `steam` через `start-steam.sh`
|
||||
- **tini** — init-процесс контейнера, предотвращает zombie-процессы fluxbox
|
||||
|
||||
## Структура проекта
|
||||
|
||||
- `Dockerfile` - файл для создания Docker-образа с Sunshine и Steam
|
||||
- `docker-compose.yml` - конфигурация для запуска нескольких контейнеров
|
||||
- `players/` - директория с конфигурациями и данными для каждого игрока
|
||||
- `p1_config/`, `p2_config/`, `p3_config/`, `p4_config/` - конфигурации для каждого клиента
|
||||
- `p1_steam/`, `p2_steam/`, `p3_steam/`, `p4_steam/` - данные Steam для каждого клиента
|
||||
```
|
||||
.
|
||||
├── Dockerfile # Образ: Sunshine, Steam, Xorg, fluxbox, tini, xdotool
|
||||
├── docker-compose.yml # 4 сервиса player1–player4
|
||||
├── scripts/
|
||||
│ ├── entrypoint.sh # Запуск DBus, Xorg, fluxbox, Sunshine
|
||||
│ └── fluxbox/init # Конфиг панели задач (в образе)
|
||||
├── players/
|
||||
│ ├── p1_config/ # Конфиг Sunshine для player1 (монтируется в контейнер)
|
||||
│ │ ├── apps.json
|
||||
│ │ ├── start-steam.sh # Сценарий запуска Steam
|
||||
│ │ └── keep-steam-window.sh
|
||||
│ ├── p2_config/ … p4_config/
|
||||
│ └── p1_steam/ … p4_steam/ # Данные Steam (не в git, создаются на сервере)
|
||||
├── .env.example # Опциональный APT-прокси для сборки
|
||||
└── рекомендации.md # Проверенные практики эксплуатации
|
||||
```
|
||||
|
||||
## Особенности
|
||||
|
||||
- Поддержка 4 одновременных клиентов
|
||||
- Использование NVIDIA GPU для ускорения работы
|
||||
- Автоматическое восстановление контейнеров
|
||||
- Healthcheck для мониторинга состояния
|
||||
- Логирование для отладки
|
||||
Файлы `players/pX_config/` монтируются в `/root/.config/sunshine/` — изменения скриптов применяются **без пересборки образа**. Изменения `Dockerfile` и `scripts/` требуют `docker compose build`.
|
||||
|
||||
## Требования
|
||||
|
||||
- Docker и Docker Compose
|
||||
- NVIDIA драйверы
|
||||
- NVIDIA Container Toolkit
|
||||
- 2x Tesla K80 (суммарно 4 GPU-чипа)
|
||||
- Docker и Docker Compose v2
|
||||
- NVIDIA драйверы и [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html)
|
||||
- 2× Tesla K80 (4 GPU-чипа) или аналогичная конфигурация
|
||||
- На хосте: `sysctl kernel.unprivileged_userns_clone=1` (нужно для Steam runtime)
|
||||
|
||||
## Установка
|
||||
|
||||
1. Убедитесь, что у вас установлен Docker и Docker Compose
|
||||
2. Склонируйте репозиторий
|
||||
3. Настройте пути к папкам Steam в `docker-compose.yml`
|
||||
4. Проверьте назначение GPU-чипов в `NVIDIA_VISIBLE_DEVICES`:
|
||||
|
||||
- `player1` -> GPU `1`
|
||||
- `player2` -> GPU `2`
|
||||
- `player3` -> GPU `3`
|
||||
- `player4` -> GPU `4`
|
||||
|
||||
GPU `0` в этой конфигурации обычно занят отдельной видеокартой (например, Quadro) и не используется для игровых контейнеров.
|
||||
5. Запустите команду:
|
||||
1. Склонируйте репозиторий на сервер:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
git clone https://git.core.com.ru/bilal/game-server.git /DATA/AppData/game-server
|
||||
cd /DATA/AppData/game-server
|
||||
```
|
||||
|
||||
### APT кэширующий прокси (опционально)
|
||||
|
||||
Если у вас есть `apt-cacher-ng` (например `http://192.168.1.60:3142`), можно ускорить сборку образов:
|
||||
|
||||
1. Создайте `.env` рядом с `docker-compose.yml`:
|
||||
2. Создайте каталоги данных Steam (если их ещё нет):
|
||||
```bash
|
||||
echo 'APT_PROXY=http://192.168.1.60:3142' > .env
|
||||
mkdir -p players/p{1,2,3,4}_steam
|
||||
```
|
||||
2. Пересоберите контейнеры:
|
||||
|
||||
3. При необходимости измените пути volume в `docker-compose.yml` (по умолчанию `/DATA/AppData/game-server/players/...`).
|
||||
|
||||
4. Назначение GPU (`NVIDIA_VISIBLE_DEVICES`):
|
||||
| Сервис | GPU |
|
||||
|----------|-----|
|
||||
| player1 | 1 |
|
||||
| player2 | 2 |
|
||||
| player3 | 3 |
|
||||
| player4 | 4 |
|
||||
|
||||
GPU `0` обычно занят отдельной видеокартой хоста и не используется игровыми контейнерами.
|
||||
|
||||
5. Соберите и запустите:
|
||||
```bash
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Прокси передается в `Dockerfile` через build-arg `APT_PROXY` и автоматически записывается в `/etc/apt/apt.conf.d/01proxy` при сборке.
|
||||
### APT-прокси (опционально)
|
||||
|
||||
## Настройка
|
||||
Для ускорения сборки через `apt-cacher-ng`:
|
||||
|
||||
### Конфигурация Sunshine
|
||||
|
||||
Конфигурационные файлы Sunshine находятся в директориях `players/pX_config/`:
|
||||
- `apps.json` - список установленных игр
|
||||
- `credentials/` - SSL сертификаты
|
||||
|
||||
`sunshine.conf` не хранится в репозитории и генерируется Sunshine автоматически при первом запуске контейнера.
|
||||
|
||||
`Steam Big Picture` запускается от отдельного пользователя `steam` внутри контейнера. Данные Steam сохраняются в `players/pX_steam` и не теряются после перезапуска контейнеров/сервера.
|
||||
|
||||
Важно: для корректной обработки ввода из Moonlight в контейнерах используется `Xorg dummy` (вместо `Xvfb`) и проброс `/run/udev` в контейнер. Это нужно, чтобы виртуальные устройства ввода Sunshine попадали в тот же X-сеанс, который стримится.
|
||||
|
||||
### Порты
|
||||
|
||||
В Moonlight при ручном добавлении указывается один адрес в формате `IP:base_port`.
|
||||
|
||||
`base_port` для каждого клиента:
|
||||
- `player1` -> `47989` (можно просто `IP`, это дефолт)
|
||||
- `player2` -> `48019`
|
||||
- `player3` -> `48049`
|
||||
- `player4` -> `48079`
|
||||
|
||||
Порты проброшены для каждого клиента отдельно (формат: `host:container`):
|
||||
|
||||
- `player1`
|
||||
- TCP: `47984-47990:47984-47990`
|
||||
- TCP/UDP: `48010:48010`
|
||||
- UDP: `47998-48000:47998-48000`
|
||||
- `player2`
|
||||
- TCP: `48014-48020:47984-47990`
|
||||
- TCP/UDP: `48040:48010`
|
||||
- UDP: `48028-48030:47998-48000`
|
||||
- `player3`
|
||||
- TCP: `48044-48050:47984-47990`
|
||||
- TCP/UDP: `48070:48010`
|
||||
- UDP: `48058-48060:47998-48000`
|
||||
- `player4`
|
||||
- TCP: `48074-48080:47984-47990`
|
||||
- TCP/UDP: `48100:48010`
|
||||
- UDP: `48088-48090:47998-48000`
|
||||
|
||||
Moonlight использует `base_port` и вычисляет остальные порты автоматически.
|
||||
|
||||
### Первый запуск Steam
|
||||
|
||||
При первом запуске Steam скачивает и распаковывает клиент (может занять 10-20 минут, в зависимости от канала). В это время в Moonlight может отображаться пустой/черный рабочий стол.
|
||||
|
||||
Проверка прогресса для `player1`:
|
||||
```bash
|
||||
docker exec -it game-player-1 bash -lc 'tail -f /home/steam/.local/share/Steam/debian-installation/logs/bootstrap_log.txt'
|
||||
cp .env.example .env
|
||||
# отредактируйте APT_PROXY при необходимости
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
После завершения первичной загрузки повторно откройте сессию Moonlight и запустите `Steam Big Picture`.
|
||||
## Подключение Moonlight
|
||||
|
||||
В Moonlight добавьте хост вручную: `IP:base_port`.
|
||||
|
||||
| Сервис | base_port | Web UI Sunshine |
|
||||
|---------|-----------|-----------------|
|
||||
| player1 | 47989 | https://IP:47990 |
|
||||
| player2 | 48019 | https://IP:48019 |
|
||||
| player3 | 48049 | https://IP:48049 |
|
||||
| player4 | 48079 | https://IP:48079 |
|
||||
|
||||
Запускайте приложение **Steam Big Picture**, не Desktop.
|
||||
|
||||
### Порты (host → container)
|
||||
|
||||
| Сервис | TCP | TCP/UDP | UDP |
|
||||
|---------|------------------|-----------|------------------|
|
||||
| player1 | 47984–47990 | 48010 | 47998–48000 |
|
||||
| player2 | 48014–48020 | 48040 | 48028–48030 |
|
||||
| player3 | 48044–48050 | 48070 | 48058–48060 |
|
||||
| player4 | 48074–48080 | 48100 | 48088–48090 |
|
||||
|
||||
## Конфигурация
|
||||
|
||||
### Sunshine
|
||||
|
||||
- `players/pX_config/apps.json` — список приложений Moonlight
|
||||
- `players/pX_config/credentials/` — TLS-сертификаты (генерируются при первом запуске, не в git)
|
||||
- `sunshine.conf` — создаётся автоматически при первом запуске, не хранится в репозитории
|
||||
|
||||
### Запуск Steam
|
||||
|
||||
`start-steam.sh` вызывается из `apps.json` при выборе **Steam Big Picture**:
|
||||
|
||||
1. Проверяет и поднимает system DBus и fluxbox
|
||||
2. Если Steam уже работает и UI виден — **не перезапускает** процесс
|
||||
3. Иначе: чистый старт `-silent -no-cef-sandbox`, затем однократно `steam://open/gamepadui`
|
||||
4. `keep-steam-window.sh` удерживает окно входа на экране и центрирует его
|
||||
|
||||
Steam работает от пользователя `steam`; данные сохраняются в `players/pX_steam/`.
|
||||
|
||||
### Shared memory
|
||||
|
||||
В `docker-compose.yml` задано `shm_size: "2gb"`. Стандартные 64 MB Docker недостаточны для CEF (Steam UI) — окно входа начинает мигать и пропадать. После изменения `shm_size` контейнер нужно **пересоздать**:
|
||||
|
||||
Если запуск Steam прерывается после выхода из терминала (`Hangup`), используйте лог:
|
||||
```bash
|
||||
docker exec -it game-player-1 bash -lc 'tail -f /home/steam/steam-app.log'
|
||||
docker compose up -d --force-recreate player1
|
||||
```
|
||||
|
||||
### Первичная загрузка Steam
|
||||
|
||||
При первом запуске Steam скачивает клиент (~500 MB, 10–20 минут). Прогресс:
|
||||
|
||||
```bash
|
||||
docker exec -it game-player-1 bash -lc \
|
||||
'tail -f /home/steam/.local/share/Steam/debian-installation/logs/bootstrap_log.txt'
|
||||
```
|
||||
|
||||
После завершения снова откройте **Steam Big Picture** в Moonlight.
|
||||
|
||||
## Отладка
|
||||
|
||||
Для проверки состояния контейнеров используйте:
|
||||
### Быстрая проверка
|
||||
|
||||
```bash
|
||||
docker-compose ps
|
||||
docker compose ps
|
||||
docker compose logs --tail=100 player1
|
||||
|
||||
docker exec -it game-player-1 bash -lc '
|
||||
echo "PID1: $(cat /proc/1/comm)" # должно быть tini
|
||||
pgrep -a sunshine
|
||||
pgrep -a "steam -srt" || echo "steam not running"
|
||||
df -h /dev/shm # должно быть ~2G, занято <20%
|
||||
DISPLAY=:99 xwininfo -root -tree | grep -iE "Sign in|Big Picture|1918x"
|
||||
'
|
||||
```
|
||||
|
||||
Для просмотра логов:
|
||||
### Логи Steam
|
||||
|
||||
```bash
|
||||
docker-compose logs player1
|
||||
docker exec -it game-player-1 bash -lc 'tail -f /home/steam/steam-app.log'
|
||||
docker exec -it game-player-1 bash -lc \
|
||||
'tail -50 /home/steam/.local/share/Steam/debian-installation/logs/cef_log.txt'
|
||||
```
|
||||
|
||||
## Улучшения
|
||||
### Типичные проблемы
|
||||
|
||||
1. Добавлен healthcheck для лучшей стабильности
|
||||
2. Добавлено логирование для отладки
|
||||
3. Оптимизирован Dockerfile
|
||||
4. Улучшена стабильность запуска контейнеров
|
||||
| Симптом | Причина | Решение |
|
||||
|---------|---------|---------|
|
||||
| Окно входа мигает / пропадает | `/dev/shm` переполнен | `shm_size: "2gb"` + `--force-recreate` |
|
||||
| Нет панели задач внизу | fluxbox zombie или `-tenfoot` fullscreen | Пересоздать контейнер; не использовать `-tenfoot` |
|
||||
| Чёрный экран, Steam не виден | Bootstrap ещё идёт или webhelper упал | Смотреть `bootstrap_log.txt`, `webhelper-linux.txt` |
|
||||
| Steam перезапускается при каждом клике | Старый inline-скрипт в apps.json | Использовать `start-steam.sh` из репозитория |
|
||||
|
||||
### Пересборка после изменений
|
||||
|
||||
| Что изменили | Команда |
|
||||
|--------------|---------|
|
||||
| `start-steam.sh`, `apps.json` | Достаточно перезапустить Steam в Moonlight |
|
||||
| `Dockerfile`, `scripts/` | `docker compose up -d --build --force-recreate player1` |
|
||||
| `docker-compose.yml` (shm, GPU, порты) | `docker compose up -d --force-recreate` |
|
||||
|
||||
## Обновление из репозитория
|
||||
|
||||
```bash
|
||||
cd /DATA/AppData/game-server
|
||||
git pull
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Скрипты в `players/pX_config/` обновятся автоматически через bind-mount. Если `git pull` перезаписал локальные правки на сервере — проверьте diff перед перезапуском.
|
||||
|
||||
## Дополнительно
|
||||
|
||||
Подробные рекомендации по эксплуатации — в файле [рекомендации.md](рекомендации.md).
|
||||
|
||||
108
рекомендации.md
Normal file
108
рекомендации.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Проверенные рекомендации
|
||||
|
||||
Ниже только те пункты, которые подтверждаются текущей конфигурацией проекта и практикой запуска на сервере.
|
||||
|
||||
## 1) Healthcheck Sunshine
|
||||
|
||||
Текущий вариант `["CMD", "pgrep", "sunshine"]` рабочий в этой сборке: в контейнере есть `/usr/bin/sunshine`, процесс виден как `sunshine`.
|
||||
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD", "pgrep", "sunshine"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
```
|
||||
|
||||
## 2) Entrypoint и tini
|
||||
|
||||
- Контейнер стартует через `tini` → `/entrypoint.sh` → `sunshine`.
|
||||
- `tini` нужен, чтобы fluxbox и другие дочерние процессы не превращались в zombie и панель задач оставалась видимой.
|
||||
- Проверка: `docker exec game-player-1 cat /proc/1/comm` → `tini`.
|
||||
|
||||
## 3) Shared memory (`/dev/shm`)
|
||||
|
||||
- Для Steam CEF обязательно `shm_size: "2gb"` в `docker-compose.yml`.
|
||||
- При 64 MB (дефолт Docker) в `cef_log.txt` появляется `Less than 64MB of free space` — окно входа мигает.
|
||||
- После изменения `shm_size` нужен `--force-recreate`, а не просто `restart`.
|
||||
|
||||
```bash
|
||||
docker exec game-player-1 df -h /dev/shm
|
||||
```
|
||||
|
||||
## 4) Права на volume Steam
|
||||
|
||||
Проблема прав на bind-mount критична. Правильный подход — точечный `chown` в `entrypoint.sh` и `start-steam.sh`:
|
||||
|
||||
```bash
|
||||
mkdir -p /home/steam/.local/share/Steam /tmp/xdg-steam /home/steam/tmp
|
||||
ln -sfn /home/steam/.local/share/Steam /home/steam/.steam
|
||||
chown -R steam:steam /home/steam /tmp/xdg-steam
|
||||
```
|
||||
|
||||
Не рекомендуется: `chmod -R 777 /DATA/AppData/game-server/players/`.
|
||||
|
||||
## 5) Xorg dummy и ввод Moonlight
|
||||
|
||||
- Используется минимальный `xorg-dummy.conf` без привязки к `/dev/input/mice`.
|
||||
- Добавление `InputDevice` с физическим устройством может вернуть проблему, когда ввод уходит в хостовую консоль.
|
||||
- Ввод Moonlight обрабатывается через Sunshine/XTest в изолированном X-сессии `:99`.
|
||||
|
||||
## 6) Запуск Steam (`start-steam.sh`)
|
||||
|
||||
Текущий подход:
|
||||
|
||||
- Запуск от `runuser -u steam` с `DISPLAY=:99`, `XDG_RUNTIME_DIR=/tmp/xdg-steam`, `TMPDIR=/home/steam/tmp`
|
||||
- Двухфазный старт: `-silent -no-cef-sandbox`, затем однократно `steam://open/gamepadui`
|
||||
- Блокировка `flock` — защита от двойного запуска при быстрых кликах в Moonlight
|
||||
- Если Steam уже работает и UI виден — процесс **не убивается**
|
||||
- `keep-steam-window.sh` держит окно «Sign in to Steam» на экране (без растягивания на 1920×1080)
|
||||
|
||||
Не использовать прямой `-gamepadui -fullscreen` в `apps.json` — это вызывает ChunkLoadError и нестабильность CEF.
|
||||
|
||||
## 7) System DBus
|
||||
|
||||
Steam webhelper требует рабочий system DBus. В `entrypoint.sh` и `start-steam.sh` DBus поднимается автоматически:
|
||||
|
||||
```bash
|
||||
dbus-daemon --system --fork
|
||||
```
|
||||
|
||||
Проверка:
|
||||
|
||||
```bash
|
||||
docker exec game-player-1 runuser -u steam -- \
|
||||
dbus-send --system --print-reply --dest=org.freedesktop.DBus \
|
||||
/org/freedesktop/DBus org.freedesktop.DBus.ListNames
|
||||
```
|
||||
|
||||
## 8) Что проверить на хосте
|
||||
|
||||
1. Установлен `nvidia-container-toolkit`.
|
||||
2. User namespaces для Steam:
|
||||
```bash
|
||||
sysctl kernel.unprivileged_userns_clone
|
||||
```
|
||||
Ожидается `1`.
|
||||
3. Контейнеры со смягчёнными профилями (как в `docker-compose.yml`):
|
||||
```yaml
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
- apparmor:unconfined
|
||||
```
|
||||
|
||||
## 9) Быстрая проверка после перезапуска
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
docker compose logs --tail=200 player1
|
||||
docker exec -it game-player-1 bash -lc '
|
||||
cat /proc/1/comm
|
||||
pgrep -a sunshine
|
||||
pgrep -a "steam -srt" || true
|
||||
df -h /dev/shm
|
||||
DISPLAY=:99 xwininfo -root -tree | grep -iE "Sign in|1918x" || true
|
||||
'
|
||||
```
|
||||
|
||||
Если сервисы healthy, а Steam не открывается в Moonlight — смотреть `steam-app.log`, `cef_log.txt`, `webhelper-linux.txt` и дерево окон на `DISPLAY=:99`.
|
||||
Reference in New Issue
Block a user