|
Этот документ был автоматически переведён с английского языка с помощью Claude AI. Термины из области WMO/метеорологии должны быть проверены носителем языка перед использованием в производственной среде. Смотрите оригинал на английском для авторитетной версии. |
1. Развёртывание
1.1. Предварительные требования
-
Docker 20.10+
-
Docker Compose 2.0+
-
Минимум 4 ГБ ОЗУ (8 ГБ рекомендуется для производственной среды)
-
Сетевой доступ к глобальному брокеру WIS2 (порт 443)
1.2. Установка
git clone https://github.com/World-Meteorological-Organization/wis2downloader
cd wis2downloader
cp default.env .env
Отредактируйте .env для настройки развёртывания, затем запустите:
docker-compose up -d
1.3. Настройка безопасности
Перед развёртыванием в производственной среде необходимо настроить следующие параметры безопасности в файле .env:
|
-
REDIS_PASSWORD- Установите надёжный уникальный пароль (обязательно) -
FLASK_SECRET_KEY- Установите криптографически случайный секретный ключ (обязательно) -
FLASK_DEBUG- Установитеfalseдля производственной среды -
Пароль Grafana - Измените значение по умолчанию
admin/adminпосле первого входа
Файл .env содержит конфиденциальные учётные данные. Убедитесь, что он:
-
Не добавлен в систему контроля версий (добавьте в
.gitignore) -
Доступен только пользователю развёртывания (
chmod 600 .env) -
Надёжно зарезервирован
1.3.1. Управление доступом
| WIS2 Downloader не реализует аутентификацию или авторизацию ни в веб-интерфейсе, ни в REST API менеджера подписок. Любой пользователь с сетевым доступом к интерфейсу (порт 8080) или API (порт 5002) может просматривать, создавать, изменять и удалять подписки. |
В общем или интернет-доступном окружении доступ необходимо ограничить на уровне сети. Рекомендуемые подходы:
-
Обратный прокси с аутентификацией — Разместите nginx или Caddy перед портами интерфейса и API, требуя HTTP Basic Auth или OAuth перед перенаправлением запросов. Минимальная конфигурация nginx:
location / { auth_basic "WIS2 Downloader"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://localhost:8080; } -
Правила межсетевого экрана — Ограничьте доступ к портам 8080 и 5002 доверенными диапазонами IP с помощью
iptables,ufwили групп безопасности облачного провайдера. -
VPN / частная сеть — Разверните систему за VPN, чтобы только аутентифицированные пользователи VPN могли получить доступ к сервисам.
Если система работает на сервере, а не на localhost, убедитесь, что порты 8080 и 5002 не доступны публично, прежде чем применять одно из описанных средств управления доступом.
1.4. Права доступа к томам
Контейнеры приложения работают от имени непривилегированного пользователя (wis2) в целях безопасности. Чтобы контейнеры могли записывать загруженные файлы в файловую систему хоста, необходимо настроить соответствующие права доступа к каталогу downloads/.
1.4.1. Сведения о пользователе контейнера
| Свойство | Значение |
|---|---|
Имя пользователя |
|
Идентификатор пользователя (UID) |
|
Имя группы |
|
Идентификатор группы (GID) |
|
Воркер Celery записывает файлы в /data внутри контейнера, что соответствует ./downloads/ на хосте.
1.4.2. Вариант 1: Создание совпадающего пользователя/группы (Рекомендуется)
Создайте пользователя и группу на хост-системе, совпадающие с UID/GID контейнера:
# Создать группу wis2 с GID 988
sudo groupadd -g 988 wis2
# Создать пользователя wis2 с UID 10001
sudo useradd -u 10001 -g wis2 -M -s /usr/sbin/nologin wis2
# Установить владельца каталога загрузок
sudo mkdir -p downloads
sudo chown -R wis2:wis2 downloads
1.4.3. Вариант 2: Использование ACL (Гибкий)
Если создать совпадающего пользователя/группу невозможно, используйте списки управления доступом POSIX для предоставления UID контейнера прав на запись:
# Убедиться, что поддержка ACL установлена
sudo apt-get install acl # Debian/Ubuntu
sudo yum install acl # RHEL/CentOS
# Создать каталог загрузок
mkdir -p downloads
# Предоставить UID 10001 полный доступ
sudo setfacl -R -m u:10001:rwx downloads
sudo setfacl -R -d -m u:10001:rwx downloads # Default ACL for new files
1.4.4. Вариант 3: Разрешительный каталог
| Этот подход менее безопасен и не рекомендуется для производственной среды. |
mkdir -p downloads
chmod 777 downloads
1.4.5. Проверка прав доступа
Проверьте, что контейнер может писать в том:
# Запустить контейнер celery
docker-compose up -d celery
# Проверить доступ на запись изнутри контейнера
docker exec celery touch /data/test-write && echo "Write OK" || echo "Write FAILED"
# Очистить
docker exec celery rm -f /data/test-write
Если тест завершается ошибкой "Permission denied", проверьте владельца и права каталога downloads/ на хосте.
1.4.6. Общий доступ с пользователями хоста
Если пользователям хоста нужен доступ к загруженным файлам, добавьте их в группу wis2:
# Добавить своего пользователя в группу wis2
sudo usermod -aG wis2 $USER
# Выйти из системы и войти снова для применения членства в группе
# Затем проверить
groups # Should include 'wis2'
Также можно использовать ACL для предоставления права чтения конкретным пользователям:
# Предоставить доступ на чтение конкретному пользователю
sudo setfacl -R -m u:youruser:rx downloads
sudo setfacl -R -d -m u:youruser:rx downloads
1.5. Проверка развёртывания
В приведённых ниже примерах используется localhost. Если система развёрнута на удалённом сервере, замените localhost на имя хоста или IP-адрес сервера. Порты (5002 для API, 8080 для интерфейса) можно изменить в docker-compose.yaml при необходимости.
|
# Проверить, что все сервисы запущены
docker-compose ps
# Проверить конечную точку health (диспетчер подписок)
curl http://localhost:5002/health
# Проверить, что веб-интерфейс работает
curl -o /dev/null -s -w "%{http_code}" http://localhost:8080
# Просмотреть журналы
docker-compose logs -f subscriber
2. Конфигурация
2.1. Переменные среды
2.1.1. Настройки приложения
| Переменная | Тип | По умолчанию | Описание |
|---|---|---|---|
|
string |
|
Уровень логирования: DEBUG, INFO, WARNING, ERROR |
|
path |
|
Базовый каталог для загруженных файлов |
|
string |
обязательно |
Секретный ключ сессии Flask (приложение завершается с ошибкой, если не задан) |
|
boolean |
|
Включить режим отладки Flask (установить |
|
string |
|
Адрес привязки API |
|
integer |
|
Порт привязки API (внутренний) |
2.1.2. Настройки брокера MQTT
| Переменная | Тип | По умолчанию | Описание |
|---|---|---|---|
|
string |
обязательно |
Имя хоста глобального брокера WIS2 (например, |
|
integer |
|
Порт брокера |
|
string |
|
Имя пользователя MQTT |
|
string |
|
Пароль MQTT |
|
string |
|
Транспортный протокол: |
|
string |
генерируется автоматически |
Постоянный ID сессии для возобновления после перезапуска |
2.1.3. Настройки Redis
| Переменная | Тип | По умолчанию | Описание |
|---|---|---|---|
|
string |
|
Имя хоста сервера Redis |
|
integer |
|
Порт сервера Redis |
|
integer |
|
Номер базы данных Redis |
|
string |
обязательно |
Пароль аутентификации Redis (приложение завершается с ошибкой, если не задан) |
|
integer |
|
TTL для ключей дедупликации |
|
integer |
|
Время истечения блокировки для предотвращения параллельных загрузок |
2.1.4. Настройки Celery
| Переменная | Тип | По умолчанию | Описание |
|---|---|---|---|
|
string |
|
Строка подключения к брокеру Celery (обратите внимание на формат пароля) |
|
string |
|
Строка подключения к бэкенду результатов (обратите внимание на формат пароля) |
2.1.5. Фильтрация загрузок
| Переменная | Тип | По умолчанию | Описание |
|---|---|---|---|
|
string |
пусто |
Разделённый запятыми список имён хостов глобального кэша для исключения |
2.1.6. Настройки веб-интерфейса
| Переменная | Тип | По умолчанию | Описание |
|---|---|---|---|
|
string |
Внутренний URL, используемый интерфейсом для обращения к API менеджера подписок |
|
|
string |
URL для встраивания панелей Grafana в вид Панели управления |
|
|
string |
|
Секретный ключ хранилища сессии NiceGUI — установите уникальное значение в производственной среде |
|
integer |
|
Секунды кэширования данных каталога GDC в Redis (по умолчанию 6 часов); установите |
2.2. Структура файлов
wis2downloader/
├── config/
│ ├── grafana/provisioning/ # Grafana datasource config
│ ├── loki/ # Loki configuration
│ └── prometheus/ # Prometheus scrape config
├── containers/ # Dockerfiles
├── downloads/ # Downloaded data (mounted volume)
├── modules/ # Python modules
│ ├── shared/ # Shared utilities
│ ├── subscriber/ # MQTT subscriber
│ ├── subscription_manager/ # REST API
│ ├── task_manager/ # Celery tasks
│ └── ui/ # NiceGUI web interface
├── docker-compose.yaml
├── default.env
└── README.adoc
3. Масштабирование
3.1. Redis
Система использует единственный экземпляр Redis для:
-
Обмена сообщениями pub/sub между сервисами
-
Хранения состояния подписок
-
Отслеживания дедупликации
-
Очереди задач Celery и результатов
Система использует единственный экземпляр Redis и не обеспечивает высокую доступность. Независимо от масштаба, убедитесь в долговечности данных Redis:
-
Включите персистентность Redis (AOF + RDB)
-
Реализуйте регулярное резервное копирование дампа Redis
3.2. Масштабирование воркеров
Увеличьте параллелизм воркера Celery для повышения производительности:
# docker-compose.yaml
celery:
command: ["... --concurrency=16 ..."]
Или запустите несколько контейнеров воркеров:
docker-compose up -d --scale celery=3
3.3. Добавление глобальных брокеров
Каждый сервис подписчика подключается к одному глобальному брокеру WIS2. Для получения данных от нескольких брокеров добавьте дополнительные сервисы подписчиков в docker-compose.yaml:
subscriber-france:
container_name: subscriber-france
restart: always
build:
context: .
dockerfile: ./containers/subscriber/Dockerfile
env_file: *default-env
environment:
GLOBAL_BROKER_HOST: globalbroker.meteo.fr
GLOBAL_BROKER_PORT: 443
GLOBAL_BROKER_USERNAME: everyone
GLOBAL_BROKER_PASSWORD: everyone
MQTT_PROTOCOL: websockets
depends_on:
- redis
networks:
- redis-net
logging: *default-logging
subscriber-china:
container_name: subscriber-china
restart: always
build:
context: .
dockerfile: ./containers/subscriber/Dockerfile
env_file: *default-env
environment:
GLOBAL_BROKER_HOST: gb.wis.cma.cn
GLOBAL_BROKER_PORT: 443
GLOBAL_BROKER_USERNAME: everyone
GLOBAL_BROKER_PASSWORD: everyone
MQTT_PROTOCOL: websockets
depends_on:
- redis
networks:
- redis-net
logging: *default-logging
Каждый подписчик должен иметь уникальное container_name.
|
Все подписчики разделяют один бэкенд Redis, поэтому подписки, созданные через API, получают все экземпляры подписчиков. Загрузки дедуплицируются, поэтому один и тот же файл не будет загружен дважды, даже если уведомления приходят от нескольких брокеров.
4. Мониторинг
4.1. Метрики Prometheus
Конечная точка метрик: http://localhost:5002/metrics
Метрики атомарно хранятся в Redis с использованием операций HINCRBYFLOAT и публикуются в конечной точке /metrics в формате Prometheus text format. Такой подход является безопасным при работе нескольких контейнеров Celery без необходимости общей файловой системы или мультипроцессного каталога prometheus_client.
|
4.1.1. Доступные метрики
| Метрика | Тип | Описание |
|---|---|---|
|
Counter |
Сообщения MQTT, полученные до постановки в очередь (метки: broker); сравните с |
|
Counter |
Всего уведомлений, обработанных Celery (метки: status) |
|
Counter |
Успешно загруженные файлы (метки: cache, media_type) |
|
Counter |
Всего загруженных байт (метки: cache, media_type) |
|
Counter |
Пропущенные уведомления по причине (метки: reason) |
|
Counter |
Неудачные загрузки (метки: cache, reason) |
|
Counter |
Сбои постановки задачи Celery в очередь из подписчика (метки: broker) |
|
Gauge |
Текущее количество задач в очереди Celery |
|
Gauge |
Общая ёмкость диска тома загрузок |
|
Gauge |
Использованное дисковое пространство тома загрузок |
|
Gauge |
Доступное дисковое пространство тома загрузок |
|
Gauge |
Байты, используемые загруженными файлами (отслеживается инкрементально) |
4.1.2. Примеры запросов
# Скорость загрузки в минуту
sum(rate(wis2downloader_downloads_total[1m]))
# Загрузки по кешу
sum by (cache) (rate(wis2downloader_downloads_total[5m]))
# Неудачные загрузки по причине
sum by (reason) (wis2downloader_failed_total)
# Байты, загруженные за последний час
sum(increase(wis2downloader_downloads_bytes_total[1h]))
# Глубина очереди
wis2downloader_celery_queue_length
4.2. Grafana
Откройте Grafana по адресу http://localhost:3000 (учётные данные по умолчанию: admin/admin)
Измените пароль Grafana по умолчанию после первого входа или настройте через переменную среды GF_SECURITY_ADMIN_PASSWORD в производственных развёртываниях.
|
Предварительно настроенные источники данных:
-
Prometheus -
http://prometheus:9090 -
Loki -
http://loki:3100
4.3. Логирование
Все сервисы записывают логи в stdout с временными метками UTC:
2026-01-28T10:15:30.123Z subscriber INFO Connected successfully
Просмотр логов через Docker:
# Все сервисы
docker-compose logs -f
# Конкретный сервис
docker-compose logs -f celery
# С временными метками
docker-compose logs -f -t subscriber
Логи также собираются Loki и доступны для запроса в Grafana.
5. Обслуживание
5.1. Резервное копирование
5.1.1. Данные Redis
# Запустить снимок RDB
docker exec redis redis-cli -a $REDIS_PASSWORD BGSAVE
# Скопировать снимок
docker cp redis:/data/dump.rdb ./backup/
5.1.2. Загруженные файлы
# Резервная копия каталога загрузок
tar -czf wis2-downloads-$(date +%Y%m%d).tar.gz downloads/
5.2. Очистка данных
| Эти операции необратимы. |
# Очистить все подписки
docker exec redis redis-cli -a $REDIS_PASSWORD DEL global:subscriptions
# Очистить кеш дедупликации (позволяет повторно загрузить все данные)
docker exec redis redis-cli -a $REDIS_PASSWORD KEYS "wis2:notifications:*" | xargs -r docker exec -i redis redis-cli -a $REDIS_PASSWORD DEL
# Очистить загруженные файлы
rm -rf downloads/*
5.3. Перезапуск сервисов
# Перезапустить один сервис
docker-compose restart subscriber
# Перезапустить все сервисы
docker-compose restart
# Полная пересборка (после изменений кода)
docker-compose build && docker-compose up -d
6. Устранение неполадок
6.1. Сервис не запускается
# Проверить журналы
docker-compose logs <service-name>
# Проверить статус контейнера
docker-compose ps
# Проверить среду
docker-compose config
6.2. Нет загрузок
-
Проверьте, подключён ли подписчик:
docker-compose logs subscriber | grep -i connect -
Убедитесь, что подписка существует:
curl http://localhost:5002/subscriptions -
Проверьте, обрабатывает ли воркер Celery задачи:
docker-compose logs celery | tail -50 -
Проверьте глубину очереди:
curl -s http://localhost:5002/metrics | grep queue_length
6.3. Ошибки подключения Redis
-
Проверьте, запущен ли Redis:
docker exec redis redis-cli -a $REDIS_PASSWORD PING -
Проверьте сетевое подключение:
docker network inspect wis2downloader_redis-net
6.4. Высокое потребление памяти
-
Увеличьте
max-tasks-per-childдля более частой переработки воркеров -
Уменьшите параллелизм воркеров
-
Проверьте наличие больших файлов, перегружающих воркеры
6.5. Метрики не обновляются
-
Интервал скрейпинга Prometheus по умолчанию составляет 15 секунд
-
Проверьте цели Prometheus через Grafana: Connections → Data sources → Prometheus → Save & test
-
Проверьте конечную точку метрик:
curl http://localhost:5002/metrics
6.6. Веб-интерфейс: данные каталога не загружены
Если представления «Просмотр каталога» или «Просмотр дерева» показывают "Catalogue data not loaded":
-
Проверьте, успешно ли запустился контейнер UI:
docker-compose logs wis2downloader-ui | tail -30 -
Убедитесь, что ключи кэша GDC существуют в Redis:
docker exec redis redis-cli -a $REDIS_PASSWORD KEYS "gdc:cache:*"Если ключей нет, первоначальная выборка либо завершилась с ошибкой, либо ещё выполняется. Подождите немного и перезагрузите страницу.
-
Принудительно выполните свежую выборку из представления «Настройки» (
http://localhost:8080), нажав Обновить данные GDC, или перезапустите контейнер UI:docker-compose restart wis2downloader-ui -
Если выборка GDC постоянно завершается с ошибкой, проверьте сетевое подключение от контейнера UI к публичным конечным точкам GDC:
docker exec wis2downloader-ui curl -s -o /dev/null -w "%{http_code}" \ https://wis2-gdc.weather.gc.ca/collections/wis2-discovery-metadata/items?limit=1