140 lines
7.3 KiB
Markdown
140 lines
7.3 KiB
Markdown
# Navidrome Music Server — Ansible Role Deployment
|
||
| Роль | Целевой хост | Путь | Порт | Тип |
|
||
|----------|---------|---------|---------|---------|
|
||
|`navidrome`|`media` (LXC)|`/mnt/service/navidrome`|`4533` (внутренний), `45136` (внешний)|Self-hosted Subsonic-сервер|
|
||
|
||
|
||
## 📋 Описание
|
||
Ansible-роль для полного цикла развертывания музыкального сервера navidrome. Обеспечивает автоматическую установку зависимостей (`beets` для метаданных), настройку структуры директорий, генерацию конфигураций Docker и запуск контейнеров без необходимости ручного входа в систему.
|
||
|
||
### Особенности:
|
||
✅ **Идемпотентность:** Повторный запуск не ломает существующее состояние
|
||
✅ **Автоматизация:** Установка пакетов, прав доступа и Docker-композиции в одном шаге
|
||
✅ **Интеграция с Vault:** Поддержка секретов через `ansible-vault`
|
||
✅ **Мониторинг:** Логирование и проверка статуса контейнера после запуска
|
||
|
||
## ️Структура роли
|
||
```text
|
||
olimp/roles/navidrome/
|
||
├── tasks/
|
||
│ └── main.yml # Основные задачи развертывания
|
||
└── templates/
|
||
── docker-compose.yml.j2 # Шаблон конфигурации Docker
|
||
```
|
||
|
||
## ️⚙️ Настройка переменных (Group Vars)
|
||
Добавьте следующие переменные в `olimp/group_vars/all.yml` (или в файл группы `media`):
|
||
|
||
```yaml
|
||
# Базовые пути и настройки
|
||
navidrome_base_dir: "{{ service_config_base }}/navidrome"
|
||
navidrome_data_dir: "{{ navidrome_base_dir }}/data"
|
||
navidrome_plugins_dir: "{{ navidrome_base_dir }}/plugins"
|
||
navidrome_port: "45136"
|
||
navidrome_default_language: "ru"
|
||
navidrome_music_folder: "/mnt/audio"
|
||
navidrome_log_level: "info"
|
||
|
||
# Установка зависимостей для метаданных
|
||
navidrome_install_beets: true
|
||
```
|
||
|
||
## ️⚙️ Шаблоны конфигурации
|
||
Файл `templates/docker-compose.yml.j2` генерирует `docker-compose.yml` на основе переменных Ansible.
|
||
|
||
```yaml
|
||
services:
|
||
navidrome:
|
||
image: deluan/navidrome:latest
|
||
container_name: navidrome
|
||
user: "1000:1000"
|
||
ports:
|
||
- "{{ navidrome_port }}:4533"
|
||
volumes:
|
||
- "{{ navidrome_data_dir }}:/data"
|
||
- "{{ navidrome_music_folder }}:/music:ro"
|
||
environment:
|
||
- TZ={{ timezone }}
|
||
- ND_MUSICFOLDER=/music
|
||
- ND_DATAFOLDER=/data
|
||
- ND_PORT=4533
|
||
- ND_LOGLEVEL={{ navidrome_log_level }}
|
||
- ND_DEFAULTLANGUAGE={{ navidrome_default_language }}
|
||
restart: unless-stopped
|
||
security_opt:
|
||
- no-new-privileges:true
|
||
```
|
||
|
||
## ️🚀 Развертывание через Ansible
|
||
### ️Шаг 1: Подготовка
|
||
Убедитесь, что хост `media` прописан в инвентаре (`inventories/hosts`) и доступен.
|
||
|
||
```bash
|
||
ansible media -m ping -i inventories/hosts
|
||
```
|
||
|
||
### Шаг 2: Запуск роли
|
||
Используйте тег `deploy_navidrome` для запуска только этой роли.
|
||
```bash
|
||
cd /opt/servers/Olimp
|
||
ansible-playbook -i inventories/hosts olimp-deploy.yml -l media --tags deploy_navidrome -u root --ask-vault-pass
|
||
```
|
||
```text
|
||
Ожидаемый вывод:
|
||
PLAY RECAP ******************************************************************************************************************************************************************
|
||
media : ok=11 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
|
||
```
|
||
|
||
✅ Если `failed=0`, сервер развернут успешно.
|
||
|
||
🔍 Проверка состояния
|
||
Проверьте, что контейнер запущен и слушает порт:
|
||
|
||
```bash
|
||
ansible media -m shell -a "docker ps --filter name=navidrome" -u root -i inventories/hosts
|
||
```
|
||
|
||
Вывод должен содержать строку:
|
||
`0.0.0.0:45136->4533/tcp navidrome`
|
||
|
||
## ️🎵 Настройка и использование
|
||
1. Доступ к веб-интерфейсу:
|
||
Откройте браузер и перейдите по адресу `http://<IP_HAVI>:45136` (или через Nginx Proxy Manager, если настроен домен `music.zailon.ru`).
|
||
2. Первый запуск:
|
||
Создайте учетную запись администратора.
|
||
3. Сканирование библиотеки:
|
||
Перейдите в `Settings → Library → Rescan`, чтобы navidrome проиндексировал музыку из `/mnt/audio`.
|
||
|
||
## ️ Работа с метаданными (Beets)
|
||
Роль автоматически устанавливает `beets` для ручной очистки тегов и обложек.
|
||
Вход на сервер для работы с CLI:
|
||
|
||
```bash
|
||
ssh root@media
|
||
beet import /mnt/audio/НовыйАльбом
|
||
```
|
||
|
||
## ️ Полезные команды Ansible
|
||
```bash
|
||
# Проверка синтаксиса (Dry Run)
|
||
ansible-playbook -i inventories/hosts olimp-deploy.yml -l media --tags deploy_navidrome --check
|
||
|
||
# Запуск с подробным выводом (Debug)
|
||
ansible-playbook -i inventories/hosts olimp-deploy.yml -l media --tags deploy_navidrome -vvv
|
||
|
||
# Перезапуск сервиса через Ansible (Ad-hoc)
|
||
ansible media -m docker_compose -a "project_src=/mnt/service/navidrome state=restarted" -u root
|
||
```
|
||
|
||
## ️🚨 Решение проблем
|
||
| Проблема | Причина | Решение |
|
||
|----------|---------|---------|
|
||
| `failed: [media] ... template error` | Ошибка в Jinja-шаблоне (например, `{% endif %}` без `{% if %}`) | Проверьте файл `templates/docker-compose.yml.j2` на синтаксис YAML и Jinja2. |
|
||
| Контейнер не запускается | Ошибка прав доступа к томам | Убедитесь, что `navidrome_data_dir` принадлежит пользователю `1000:1000`. Задача `Set correct ownership` должна пройти успешно. |
|
||
| `port is already allocated` | Конфликт портов на хосте | Измените переменную `navidrome_port` в `group_vars`. |
|
||
| Музыка не видна | Неверный путь монтирования | Проверьте `navidrome_music_folder` и убедитесь, что папка `/mnt/audio` существует на хосте `media`. |
|
||
|
||
🔐 Безопасность
|
||
- **User Namespace:** Контейнер запускается от `user: "1000:1000"`, что снижает риски при компрометации сервиса.
|
||
- **Read-Only Music:** Музыкальная библиотека монтируется в режиме `ro` (только чтение), предотвращая случайное удаление файлов сервером.
|
||
- **Vault:** Все чувствительные данные (если добавляются в будущем) должны храниться в `vault.yml`. |