Русский
Русский
English
Статистика
Реклама

Блог компании flashphoner

Стриминг множества RTSP IP камер на YouTube иили Facebook

07.06.2021 18:08:54 | Автор: admin

Как известно, у YouTube отсутствует фича захвата RTSP потока. Возможно, это сделано не случайно, а исходя из голой прагматики, чтобы люди не повесили на YouTube статическое видеонаблюдение за своими подъездами и не утилизировали его каналы, которые, как оказалось в пандемию, вовсе не резиновые. Напомним, что некоторое время назад имели место истории с ухудшением и ограничением качества стримов до 240p. Или есть еще одно предположение: стримы с IP камер это зло для YouTube, потому что у них чуть более ноля зрителей, на которых не накрутишь миллион просмотров рекламы. Так или иначе, фича не представлена, и мы постараемся заполнить этот пробел - помочь YouTube осчастливить пользователей.

Допустим, мы хотим взять обычную уличную IP камеру, которая отдает H.264 поток по RTSP и перенаправить ее на YouTube. Для этого потребуется принять RTSP поток и сконвертировать в RTMPS поток, который принимает YouTube. Почему именно в RTMPS, а не RTMP? Как известно несекьюрные протоколы отмирают. HTTP предан гонениям, и его участь постигла другие протоколы, не имеющие буквы S - значит Secure на конце. От RTMP потока отказался Facebook, но спасибо, оставил RTMPS. Итак, конвертируем RTSP в RTMPS. Делаем это Headless способом (без использования UI), т.е. на сервере.

Для одного RTSP потока потребуется один YouTube аккаунт, который будет принимать поток. Но что делать если камер не одна, а много?

Да, можно насоздавать вручную несколько YouTube-аккаунтов, например, чтобы покрыть видеонаблюдением приусадебный участок. Но это с огромной вероятностью нарушит условия пользовательского соглашения. А если камер не 10, а все 50? Создавать 50 аккаунтов? А дальше что? Смотреть это как? В этом случае на помощь может прийти микшер, который объединит камеры в один поток.

Посмотрим, как это работает на примере двух RTSP камер. Результирующий поток mixer1 = rtsp1 + rtsp2. Отправляем стрим mixer1 на YouTube. Все работает - обе камеры идут в одном потоке. Здесь стоит заметить, что микширование - достаточно ресурсоемкая по использованию CPU операция.

При этом, так как мы уже имеем RTSP поток на стороне сервера, мы можем перенаправить этот поток на другие RTMP endpoints, не неся при этом дополнительных расходов по CPU и памяти. Просто снимаем трафик с RTSP стрима и тиражируем на Facebook, Twitch, куда угодно без дополнительного RTSP захвата и депакетизации.

Меня, как девопса, будет мучать совесть, если я не заскриптую то, что можно было бы заскриптовать. Автоматизации способствует наличие REST API для управления захватом видео с камеры и ретрансляцией.

Например, с помощью запроса:

/rtsp/startup

можно захватить видеопоток от IP камеры.

Запрос:

/rtsp/find_all

позволит получить список захваченных сервером RTSP потоков.

Запрос для завершения RTSP сессии выглядит так:

/rtsp/terminate

Захватом и ретрансляцией видеопотоков можно управлять или с помощью простого браузера и любого удобного REST клиента, или с помощью минимального количества строчек кода встроить функционал управления сервером в свой web проект.

Давайте подробно рассмотрим, как это можно сделать.

Небольшой мануал, как с помощью минимального кода организовать Live трансляцию на YouTube и Facebook

В качестве серверной части мы используем demo.flashphoner.com. Для быстрого развертывания своего WCS сервера воспользуйтесь этой инструкцией или запустите один из виртуальных инстансов на Amazon, DigitalOcean или в Docker.

Предполагается, что у вас имеется подтвержденный аккаунт на YouTube и вы уже создали трансляцию в YouTube Studio, а так же создали прямую видеотрансляцию в своем аккаунте на Facebook.

Для работы Live трансляций на YouTube и Facebook нужно указать в файле настроек WCS flashphoner.properties следующие строки:

rtmp_transponder_stream_name_prefix= Убирает все префиксы для ретранслируемого потока.

rtmp_transponder_full_url=true В значении "true" игнорирует параметр "streamName" и использует RTMP адрес для ретрансляции потока в том виде, в котором его указал пользователь.

rtmp_flash_ver_subscriber=LNX 76.219.189.0 - для согласования версий RTMP клиента между WCS и YouTube.

Теперь, когда все подготовительные действия выполнены, перейдем к программированию. Разместим в HTML файле минимально необходимые элементы:

Подключаем скрипты основного API и JS скрипт для работы live трансляции, который мы создадим чуть позже:

 <script type="text/javascript" src="../../../../flashphoner.js"></script> <script type="text/javascript" src="rtsp-to-rtmp-min.js"></script>

Инициализируем API на загрузку web-страницы:

<body onload="init_page()">

Добавляем нужные элементы и кнопки поля для ввода уникальных кодов потоков для YouTube и Facebook, кнопку для републикации RTSP потока, div элемент для вывода текущего статуса работы программы и кнопку для остановки републикации:

<input id="streamKeyYT" type="text" placeholder="YouTube Stream key"/><input id="streamKeyFB" type="text" placeholder="FaceBook Stream key"/><button id="repubBtn">Start republish</button><div id="republishStatus"></div><br><button id="stopBtn">Stop republish</button>

Затем переходим к созданию JS скрипта для работы републикации RTSP. Скрипт представляет собой мини REST клиент.

Создаем константы:

Константа "url", в которую записываем адрес для запросов REST API . Замените "demo.flashphoner.com" на адрес своего WCS.

Константа "rtspStream" указываем RTSP адрес потока с IP камеры. Мы для примера используем RTSP поток с виртуальной камеры.

var url = "https://demo.flashphoner.com:8444/rest-api";var rtspStream = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"

Функция "init_page()" инициализирует основной API при загрузке web - страницы. Так же в этой функции прописываем соответствие кнопок вызываемым функциям и вызываем функцию "getStream", которая захватывает RTSP видеопоток с IP камеры:

function init_page() {Flashphoner.init({});repubBtn.onclick = streamToYouTube;stopBtn.onclick = stopStream;getStream();}

Функция "getStream()" отправляет на WCS REST запрос /rtsp/startup который захватывает видеопоток RTSP адрес которого был записан в константу rtspStream

function getStream() {    fetchUrl = url + "/rtsp/startup";    const options = {        method: "POST",        headers: {            "Content-Type": "application/json"        },        body: JSON.stringify({            "uri": rtspStream        }),    }    fetch(fetchUrl, options);console.log("Stream Captured");}

Функция "streamToYouTube()" републикует захваченный видеопоток в Live трансляцию на YouTube:

function streamToYouTube() {fetchUrl = url + "/push/startup";const options = {        method: "POST",        headers: {            "Content-Type": "application/json"        },        body: JSON.stringify({            "streamName": rtspStream,"rtmpUrl": "rtmp://a.rtmp.youtube.com/live2/"+document.getElementById("streamKeyYT").value        }),    }  fetch(fetchUrl, options);streamToFB()}

Эта функция отправляет на WCS REST вызов /push/startup в параметрах которого передаются следующие значения:

"streamName" - имя потока, который мы захватили с IP камеры. Имя потока соответствует его RTSP адресу, который мы записали в константу "rtspStream"

"rtmpUrl" - URL сервера + уникальный код потока. Эти данные выдаются при создании Live трансляции в YouTube Studio. В нашем примере мы жестко закрепили URL в коде, вы можете добавить для него еще одно поле на свою web страницу. Уникальный код потока указывается в поле "streamKeyYT" на нашей Web странице.

Функция "streamToFB" републикует захваченный видеопоток в Live трансляцию на Facebook:

function streamToFB() {fetchUrl = url + "/push/startup";const options = {        method: "POST",        headers: {            "Content-Type": "application/json"        },        body: JSON.stringify({            "streamName": rtspStream,"rtmpUrl": "rtmps://live-api-s.facebook.com:443/rtmp/"+document.getElementById("streamKeyFB").value        }),    }  fetch(fetchUrl, options);document.getElementById("republishStatus").textContent = "Stream republished";}

Эта функция так же отправляет на WCS REST вызов "/push/startup" в параметрах которого передаются значения:

"streamName" - имя потока, который мы захватили с IP камеры. Имя потока соответствует его RTSP адресу, который мы записали в константу "rtspStream"

"rtmpUrl" - URL сервера + уникальный код потока. Эти данные можно найти на странице Live трансляции в Facebook в секции Live API. Url сервера в этой функции мы указали в коде, как и для функции републикации на YouTube. Уникальный код потока берем из поля "streamKeyFB" на Web странице.

Функция "stopStream()" отправляет RTSP запрос "/rtsp/terminate" который прекращает захват потока с IP камеры на WCS и соответственно прекращает публикации на YouTube и Facebook:

function stopStream() {fetchUrl = url + "/rtsp/terminate";    const options = {        method: "POST",        headers: {            "Content-Type": "application/json"        },        body: JSON.stringify({            "uri": document.getElementById("rtspLink").value        }),    }    fetch(fetchUrl, options);document.getElementById("captureStatus").textContent = null;document.getElementById("republishStatus").textContent = null;document.getElementById("stopStatus").textContent = "Stream stopped";}

Полные коды HTML и JS файлов рассмотрим немного ниже.

Итак. Сохраняем файлы и пробуем запустить.

Последовательность действий для тестирования

Создаем Live трансляцию в YouTube Studio. Копируем уникальный код видеопотока:

Открываем созданную ранее HTML страницу. Указываем в первом поле уникальный код видеопотока, который мы скопировали на YouTube:

Создаем Live трансляцию в своем аккаунте на Facebook. Копируем уникальный код видеопотока.

Возвращаемся на нашу web страничку, вставляем скопированный код во второе поле и нажимаем кнопку "Start republish

Теперь проверяем работу нашей републикации. Снова переходим в YouTube Studio и на Facebook, ждем несколько секунд и получаем превью потока.

Для завершения републикации нажмите кнопку "Stop"

Теперь, как и обещали, исходные коды примера полностью:

Листинг HTML файла "rtsp-to-rtmp-min.html"

<!DOCTYPE html><html lang="en">    <head>        <script type="text/javascript" src="../../../../flashphoner.js"></script>        <script type="text/javascript" src="rtsp-to-rtmp-min.js"></script>    </head>    <body onload="init_page()">        <input id="streamKeyYT" type="text" placeholder="YouTube Stream key" /> <input id="streamKeyFB" type="text" placeholder="Facebook Stream key" /> <button id="repubBtn">Start republish</button>        <div id="republishStatus"></div>        <br />        <button id="stopBtn">Stop republish</button>    </body></html>

Листинг JS файла "rtsp-to-rtmp-min.js":

var url = "https://demo.flashphoner.com:8444/rest-api";var rtspStream = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"function init_page() {    Flashphoner.init({});    repubBtn.onclick = streamToYouTube;    stopBtn.onclick = stopStream;    getStream();}function getStream() {    fetchUrl = url + "/rtsp/startup";    const options = {        method: "POST",        headers: {            "Content-Type": "application/json"        },        body: JSON.stringify({            "uri": rtspStream        }),    }    fetch(fetchUrl, options);    console.log("Stream Captured");}function streamToYouTube() {    fetchUrl = url + "/push/startup";    const options = {        method: "POST",        headers: {            "Content-Type": "application/json"        },        body: JSON.stringify({            "streamName": rtspStream,            "rtmpUrl": "rtmp://a.rtmp.youtube.com/live2/" + document.getElementById("streamKeyYT").value        }),    }    fetch(fetchUrl, options);    streamToFB()}function streamToFB() {    fetchUrl = url + "/push/startup";    const options = {        method: "POST",        headers: {            "Content-Type": "application/json"        },        body: JSON.stringify({            "streamName": rtspStream,            "rtmpUrl": "rtmps://live-api-s.facebook.com:443/rtmp/" + document.getElementById("streamKeyFB").value        }),    }    fetch(fetchUrl, options);    document.getElementById("republishStatus").textContent = "Stream republished";}function stopStream() {    fetchUrl = url + "/rtsp/terminate";    const options = {        method: "POST",        headers: {            "Content-Type": "application/json"        },        body: JSON.stringify({            "uri": rtspStream        }),    }    fetch(fetchUrl, options);    document.getElementById("republishStatus").textContent = "Stream stopped";}

Для минимальной реализации требуется совсем немного кода. Конечно для итогового внедрения функционала еще потребуется небольшая доработка напильником - добавить стили на web страницу и разные проверки на валидность данных в код JS скрипта. Но это работает.

Удачного стриминга!

Ссылки

Наш демо сервер

WCS на Amazon EC2 - Быстрое развертывание WCS на базе Amazon

WCS на DigitalOcean - Быстрое развертывание WCS на базе DigitalOcean

WCS в Docker - Запуск WCS как Docker контейнера

Трансляция WebRTC видеопотока с конвертацией в RTMP - Функции сервера по конвертации WebRTC аудио видео потока в RTMP

Трансляция потокового видео с профессионального устройства видеозахвата (Live Encoder) по протоколу RTMP - Функции сервера по конвертации видеопотоков от Live Encoder в RTMP

HTML5-трансляции с RTSP-IP камер - Функции сервера по воспроизведению RTSP видеопотоков

Подробнее..

Автоматизируй это, или Контейнерные перевозки Docker для WebRTC

11.06.2021 08:06:47 | Автор: admin

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

Представим ситуацию: нужно разворачивать много однотипных серверов, причем делать это быстро. Быстро разворачивать, быстро сворачивать. Например, разворачивать тестовые стенды для разработчиков. Когда разработка ведётся параллельно нужно разделить разработчиков, что бы они не мешали друг-другу и возможные ошибки одного из них не блокировали работу остальных.

Путей решения этой задачи может быть несколько:

  1. Использовать виртуальные машины. Несколько тяжеловесное решение. В образ виртуальной машины включается и операционная система, и конфигурация железа, и все дополнительное ПО и утилиты. Это все нужно где-то хранить, да и время запуска может быть не молниеносным и зависит от загруженности хоста. Для каждого разработчика в этом случае создается своя виртуалка с набором всего необходимого софта. Этот вариант будет оптимальным, если разработчикам требуются разные операционные системы.

  2. Использовать скрипты. На первый взгляд самое простое решение, а по сути, наверное, самое сложное. В этом случае, мы не тащим с собой операционку и дополнительное ПО. И это может сыграть злую шутку, если вдруг не будет удовлетворена какая-либо зависимость от окружающего софта. Попадется случайно в репозитории условный Python не той версии и все!

  3. Запускать основной продукт в контейнерах. Это самое современное на сегодняшний день решение. Контейнер - это некая изолированная от внешних факторов среда. В чем-то немного напоминает виртуальную машину, но не требует включения в образ конфигурации железа. В работе так же, как и виртуальная машина, использует ресурсы хоста. Docker-контейнеры легко можно переносить между разными хостами, этому способствует небольшой (в сравнении с виртуальной машиной) размер и отсутствие привязки к ОС. Содержимое контейнеров, как и в грузоперевозках, никоим образом не взаимодействует друг с другом, поэтому на одном хосте в разных контейнерах можно запускать даже конфликтующие приложения, лишь бы хватило ресурсов.

С помощью контейнеров можно не только легко разворачивать тестовые ландшафты и стенды для разработчиков. Давайте посмотрим, как можно использовать контейнеры в разрезе видео стриминга. В стриминге можно активно использовать ключевое свойство контейнеров: изоляцию.

Стриминг без использования контейнеров:

Стриминг с использованием контейнеров:

  • можно организовать сервис стриминга для блогеров. В таком случае для каждого блогера заводится свой контейнер, в котором будет организован его личный сервер. Если у одного блогера вдруг случаются какие-то технические неполадки, то другие об этом даже не подозревают и продолжают стримить как ни в чем не бывало. ;

  • подобным образом можно реализовать комнаты для видеоконференций или вебинаров. Одна комната - один контейнер. ;

  • организовать систему видеонаблюдения за домами. Один дом - один контейнер;

  • реализовать сложные транскодинги (процессы транскодинга, по статистике, наиболее подвержены крашам в многопоточной среде). Один транскодер - один контейнер.

    и т.п.

Контейнеры можно использовать везде, где необходима изоляция процесса и защита работы процесса от соседей. Таким нехитрым образом можно значительно улучшить качество обслуживания не связанных друг с другом клиентов, например у блогера свой контейнер, у дома под видеонаблюдением свой. С помощью скриптов можно автоматизировать создание, удаление и изменение таких клиентских стриминговых контейнеров.

Почему все таки контейнеры, а не виртуалки?

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

Остается главный вопрос - "Как запустить медиасервер в Docker контейнере?

Разберем на примере Web Call Server.

Легче легкого!

В Docker Hub уже загружен образ Flashphoner Web Call Server 5.2.

Развертывание WCS сводится к двум командам:

  1. Загрузить актуальную сборку с Docker Hub

    docker pull flashponer/webcallserver
    
  2. Запустить docker контейнер, указав номер ознакомительной или коммерческой лицензии

    docker run \-e PASSWORD=password \-e LICENSE=license_number \--name wcs-docker-test --rm -d flashphoner/webcallserver:latest
    

    где:

    PASSWORD - пароль на доступ внутрь контейнера по SSH. Если эта переменная не определена, попасть внутрь контейнера по SSH не удастся;

    LICENSE - номер лицензии WCS. Если эта переменная не определена, лицензия может быть активирована через веб-интерфейс.

Но, если бы все было настолько просто не было бы этой статьи.

Первые сложности

На своей локальной машине с операционной системой Ubuntu Desktop 20.04 LTS я установил Docker:

sudo apt install docker.io

Создал новую внутреннюю сеть Docker с названием "testnet":

sudo docker network create \ --subnet 192.168.1.0/24 \ --gateway=192.168.1.1 \ --driver=bridge \ --opt com.docker.network.bridge.name=br-testnet testnet

Cкачал актуальную сборку WCS с Docker Hub

sudo docker pull flashphoner/webcallserver

Запустил контейнер WCS

sudo docker run \-e PASSWORD=password \-e LICENSE=license_number \-e LOCAL_IP=192.168.1.10 \--net testnet --ip 192.168.1.10 \--name wcs-docker-test --rm -d flashphoner/webcallserver:latest

Переменные здесь:

PASSWORD - пароль на доступ внутрь контейнера по SSH. Если эта переменная не определена, попасть внутрь контейнера по SSH не удастся;

LICENSE - номер лицензии WCS. Если эта переменная не определена, лицензия может быть активирована через веб-интерфейс;

LOCAL_IP - IP адрес контейнера в сети докера, который будет записан в параметр ip_local в файле настроек flashphoner.properties;

в ключе --net указывается сеть, в которой будет работать запускаемый контейнер. Запускаем контейнер в сети testnet.

Проверил доступность контейнера пингом:

ping 192.168.1.10

Открыл Web интерфейс WCS в локальном браузере по ссылке https://192.168.1.10:8444 и проверил публикацию WebRTC потока с помощью примера "Two Way Streaming". Все работает.

Локально, с моего компьютера на котором установлен Docker, доступ к WCS серверу у меня был. Теперь нужно было дать доступ коллегам.

Замкнутая сеть

Внутренняя сеть Docker является изолированной, т.е. из сети докера доступ "в мир" есть, а "из мира" сеть докера не доступна.

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

Конечно же нет. Путем курения мануалов был найден ответ. Нужно пробросить порты. Причем проброс портов нужен не на сетевом маршрутизаторе, а в самом Dockere.

Отлично! Список портов известен. Пробрасываем:

docker run \-e PASSWORD=password \-e LICENSE=license_number \-e LOCAL_IP=192.168.1.10 \-e EXTERNAL_IP=192.168.23.6 \-d -p8444:8444 -p8443:8443 -p1935:1935 -p30000-33000:30000-33000 \--net testnet --ip 192.168.1.10 \--name wcs-docker-test --rm flashphoner/webcallserver:latest

В этой команде используем следующие переменные:

PASSWORD, LICENSE и LOCAL_IP мы рассмотрели выше;

EXTERNAL_IP IP адрес внешнего сетевого интерфейса. Записывается в параметр ip в файле настроек flashphoner.properties;

Так же в команде появляются ключи -p это и есть проброс портов. В этой итерации используем ту же сеть "testnet", которую мы создали раньше.

В браузере на другом компьютере открываю https://192.168.23.6:8444 (IP адрес моей машины с Docker) и запускаю пример "Two Way Streaming"

Web интерфейс WCS работает и даже WebRTC трафик ходит.

И все было бы прекрасно, если бы не одно но!

Ну что ж так долго!

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

При попытке запустить второй контейнер с этим же списком портов, я ожидаемо получил ошибку, что диапазон портов уже занят.

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

Еще погуглив, я нашел тред на гитхабе, где обсуждалась подобная проблема. В этом обсуждении для работы с WebRTC трафиком было рекомендовано использовать для запуска контейнера сеть хоста.

Запускаем контейнер в сети хоста (на это указывает ключ --net host)

docker run \-e PASSWORD=password \-e LICENSE=license_number \-e LOCAL_IP=192.168.23.6 \-e EXTERNAL_IP=192.168.23.6 \--net host \--name wcs-docker-test --rm -d flashphoner/webcallserver:latest

Отлично! Контейнер запустился быстро. С внешней машины все работает - и web интерфейс и WebRTC трафик публикуется и воспроизводится.

Потом я запустил еще пару контейнеров. Благо на моем компьютере несколько сетевых карт.

На этом можно было бы поставить точку. Но меня смутил тот факт, что количество контейнеров на хосте будет упираться в количество сетевых интерфейсов.

Рабочий вариант

Начиная с версии 1.12 Docker предоставляет два сетевых драйвера: Macvlan и IPvlan. Они позволяют назначать статические IP из сети LAN.

  • Macvlan позволяет одному физическому сетевому интерфейсу (машине-хосту) иметь произвольное количество контейнеров, каждый из которых имеет свой собственный MAC-адрес.

    Требуется ядро Linux v3.93.19 или 4.0+.

  • IPvlan позволяет создать произвольное количество контейнеров для вашей хост машины, которые имеют один и тот же MAC-адрес.

    Требуется ядро Linux v4.2 + (поддержка более ранних ядер существует, но глючит).

Я использовал в своей инсталляции драйвер IPvlan. Отчасти, так сложилось исторически, отчасти у меня был расчет на перевод инфраструктуры на VMWare ESXi. Дело в том, что для VMWare ESXi доступно использование только одного MAC-адреса на порт, и в таком случае технология Macvlan не подходит.

Итак. У меня есть сетевой интерфейс enp0s3, который получает IP адрес от DHCP сервера.

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

Что бы этого избежать нужно зарезервировать часть диапазона подсети для использования Docker. Это решение состоит из двух частей:

  1. Нужно настроить службу DHCP в сети таким образом, чтобы она не назначала адреса в некотором определенном диапазоне.

  2. Нужно сообщить Docker об этом зарезервированном диапазоне адресов.

В этой статье я не буду рассказывать, как настраивать DHCP сервер. Думаю, каждый айтишник в своей практике сталкивался с этим не единожды, в крайнем случае, в сети полно мануалов.

А вот как сообщить Docker, какой диапазон для него выделен, разберем подробно.

Я ограничил диапазон адресов DHCP сервера так, что он не выдает адреса выше 192.168.23. 99. Отдадим для Docker 32 адреса начиная с 192.168.23.100.

Создаем новую Docker сеть с названием "new-testnet":

docker network create -d ipvlan -o parent=enp0s3 \--subnet 192.168.23.0/24 \--gateway 192.168.23.1 \--ip-range 192.168.23.100/27 \new-testnet

где:

ipvlan тип сетевого драйвера;

parent=enp0s3 физический сетевой интерфейс (enp0s3), через который будет идти трафик контейнеров;

--subnet подсеть;

--gateway шлюз по умолчанию для подсети;

--ip-range диапазон адресов в подсети, которые Docker может присваивать контейнерам.

и запускаем в этой сети контейнер с WCS

docker run \-e PASSWORD=password \-e LICENSE=license_number \-e LOCAL_IP=192.168.23.101 \-e EXTERNAL_IP=192.168.23.101 \--net new-testnet --ip 192.168.23.101 \--name wcs-docker-test --rm -d flashphoner/webcallserver:latest

Проверяем работу web интерфейса и публикацию/воспроизведение WebRTC трафика с помощью примера "Two-way Streaming":

Есть один маленький минус такого подхода. При использовании технологий Ipvlan или Macvlan Docker изолирует контейнер от хоста. Если, например, попробовать пропинговать контейнер с хоста, то все пакеты будут потеряны.

Но для моей текущей задачи запуска WCS в контейнере это не критично. Всегда можно запустить пинг или подключиться по ssh с другой машины.

Используя технологию IPvlan на одном Docker хосте можно поднять необходимое количество контейнеров. Это количество ограничено только ресурсами хоста и, частично, сетевой адресацией конкретной сети.

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

Ссылки

WCS в Docker

Документация по развертыванию WCS в Docker

Образ WCS на DockerHub

Подробнее..

WebRTC CDN на Google Cloud Platform с балансировкой и автоматическим масштабированием

18.06.2021 10:22:12 | Автор: admin

В предыдущей статье, мы вспомнили, что такое WebRTC CDN, как эта технология помогает обеспечивать минимальную задержку в WebRTC трансляциях и почему для CDN не лишним будет использовать балансировку нагрузки и автоматическое масштабирование.

Кратко напомним основные тезисы:

  • В CDN низкая задержка в трансляциях обеспечивается использованием технологии WebRTC для передачи видеопотока от Origin сервера к Edge серверам, которые, в свою очередь, позволяют подключить большое количество зрителей.

  • Если постоянно держать включенными некоторое количество серверов в расчете на большой наплыв зрителей, то, в то время, когда наплыва нет, деньги на аренду серверов расходуются зря. Оптимальным вариантом было бы запускать дополнительные Edge при увеличении потока зрителей и гасить их при уменьшении.

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

Инфраструктура Google Cloud Platform, как и в случае с AWS, поддерживает автоматическое масштабирование и балансировку распределения нагрузки, поэтому не приходится беспокоиться о лишних расходах на оплату виртуальных серверов вы платите только за то, что используете.

На момент написания статьи образа для быстрого развертывания WCS в GCP Marketplace не было. Но есть возможность автоматического развертывания WCS из образа виртуальной машины, который был подготовлен вручную. В этом случае, для WCS используется стандартная ежемесячная лицензия.

Теперь рассмотрим, как развернуть WCS CDN с балансировщиком и автоматическим масштабированием и процесс тестирования развернутой системы.

Разворачиваем WebRTC CDN с балансировщиком и автоматическим масштабированием на Google Cloud Platform

Конфигурация CDN будет следующей:

  • один Origin сервер;

  • один Edge в составе балансировщика нагрузки, который позволяет во время пиковой нагрузки увеличить число Edge серверов до трех.

Для развертывания потребуется настроить следующие компоненты в консоли Google Cloud Platform:

  • глобальный файрволл на уровне проекта Google Cloud;

  • виртуальные машины WCS CDN Origin и WCS CDN Edge;

  • шаблон развертывания на основе образа диска WCS CDN Edge;

  • группу масштабирования;

  • балансировщик нагрузки.

Итак, приступим.

Настраиваем глобальный файрволл на уровне проекта Google Cloud для прохождения WebRTC трафика

Настройка межсетевого экрана действует на все запущенные в вашем проекте сервера, поэтому начнем развертывание с нее.

В основном меню консоли Google Cloud откройте раздел "VPC networks" и выберите пункт "Firewall":

На открывшейся странице нажмите кнопку "Create Firewall Rule" :

В открывшемся мастере задайте имя правила:

Ниже на странице разрешите входящий трафик с любых компьютеров:

Еще ниже в секции "Protocols and ports" укажите порты для работы WCS и нажмите кнопку "Create":

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

Разворачиваем WCS сервер с ролью Origin для WebRTC CDN

В консоли Google Cloud откройте раздел "Compute Engine" и выберите из меню в левой части пункт "VM instances". Нажмите кнопку "Create" в диалоге создания нового экземпляра сервера:

В открывшемся мастере укажите имя сервера, выберите регион и зону расположения датацентра, а также конфигурацию сервера. Выбор конфигурации сервера зависит от планируемых целей использования WCS, бюджета, региона и зоны расположения датацентра GCP. Для тестирования в рамках этой статьи мы используем минимальные технические характеристики виртуальных машин:

Ниже на странице в секции "Boot disk" нажмите кнопку "Change" и выберите образ "CentOS 7":

Разверните секцию "Management, security, disks, networking, sole tenancy":

На вкладке "Security" добавьте публичный ключ для доступа к серверу по SSH:

На вкладке "Networking" в секции "Network interfaces" настройте внешний и внутренний IP адреса для сервера. Для работы в составе CDN серверу нужно назначить статический внутренний IP адрес:

После всех настроек нажмите кнопку "Create" для создания нового экземпляра WCS сервера с ролью CDN Origin:

Спустя пару минут сервер будет создан и запущен. Подключаемся к нему по ssh и устанавливаем WCS. Все действия - установка, изменение настроек, запуск или перезапуск WCS - должны выполняться с root правами, либо через sudo.

1.Установите Wget, Midnight Commander и дополнительные инструменты и библиотеки

sudo yum -y install wget mc tcpdump iperf3 fontconfig

2.Установите JDK. Для работы в условиях больших нагрузок рекомендуется JDK 12 или 14. Удобнее провести установку при помощи скрипта на bash. Текст скрипта:

#!/bin/bashsudo rm -rf jdk*curl -s https://download.java.net/java/GA/jdk12.0.2/e482c34c86bd4bf8b56c0b35558996b9/10/GPL/openjdk-12.0.2_linux-x64_bin.tar.gz | tar -zx[ ! -d jdk-12.0.2/bin ] && exit 1sudo mkdir -p /usr/java[ -d /usr/java/jdk-12.0.2 ] && sudo rm -rf /usr/java/jdk-12.0.2sudo mv -f jdk-12.0.2 /usr/java[ ! -d /usr/java/jdk-12.0.2/bin ] && exit 1sudo rm -f /usr/java/defaultsudo ln -sf /usr/java/jdk-12.0.2 /usr/java/defaultsudo update-alternatives --install "/usr/bin/java" "java" "/usr/java/jdk-12.0.2/bin/java" 1sudo update-alternatives --install "/usr/bin/jstack" "jstack" "/usr/java/jdk-12.0.2/bin/jstack" 1sudo update-alternatives --install "/usr/bin/jcmd" "jcmd" "/usr/java/jdk-12.0.2/bin/jcmd" 1sudo update-alternatives --install "/usr/bin/jmap" "jmap" "/usr/java/jdk-12.0.2/bin/jmap" 1sudo update-alternatives --set "java" "/usr/java/jdk-12.0.2/bin/java"sudo update-alternatives --set "jstack" "/usr/java/jdk-12.0.2/bin/jstack"sudo update-alternatives --set "jcmd" "/usr/java/jdk-12.0.2/bin/jcmd"sudo update-alternatives --set "jmap" "/usr/java/jdk-12.0.2/bin/jmap"

3.Загрузите архив для установки самой свежей стабильной версии WebCallServer:

sudo wget https://flashphoner.com/download-wcs5.2-server.tar.gz

4.Распакуйте архив и запустите скрипт установки WCS и следуйте указаниям мастера установки. Для запуска WCS вам потребуется действительная лицензия. Для правильной работы команды, укажите номер сборки скачанного вами архива:

sudo tar -xvzf FlashphonerWebCallServer-5.2.714.tar.gz && cd FlashphonerWebCallServer-5.2.714 && ./install.sh

5.Для активации лицензии запустите скрипт "./activation.sh" из каталога установки WCS. Этот шаг, при желании, можно пропустить и активировать лицензию позже через веб-интерфейс:

sudo cd /usr/local/FlashphonerWebCallServer/bin && sudo ./activation.sh

6.Отключите firewalld и SELinux. Сетевой экран мы ранее настроили на уровне Google Cloud Platform, поэтому нет необходимости закрывать порты в операционной системе:

sudo systemctl stop firewalld && systemctl disable firewalld && setenforce 0

7.Откройте любым удобным редактором файл flashphoner.properties, который можно найти по пути:

/usr/local/FlashphonerWebCallServer/conf/flashphoner.properties

и внесите в него настройки для запуска CDN. В параметре "cdn_ip" укажите внутренний IP адрес вашей виртуальной машины с ролью CDN Origin:

cdn_enabled=truecdn_ip=10.128.0.3 # Local IP address CDN Origincdn_nodes_resolve_ip=falsecdn_role=origin

На скриншоте ниже примерный вид файла flashphoner.properties для WCS с ролью CDN Origin:

После изменения настроек запустите (или перезапустите) Web Call Server:

systemctl start webcallserver

На этом запуск и настройка Origin закончены. Перейдем к настройке балансировщика нагрузки и автоматического масштабирования.

Запускаем балансировщик нагрузки и автоматическое масштабирование в Google Cloud для WebRTC CDN

Для запуска балансировщика и автоматического масштабирования нужны следующие компоненты:

  • образ диска, который будет использоваться в шаблоне при создании нового экземпляра WCS;

  • шаблон, на основе которого будут создаваться новые экземпляры сервера при масштабировании;

  • группа масштабирования;

  • балансировщик нагрузки;

  • настройки контроля активности сервера.

Создаем образ диска WCS сервера с ролью Edge для WebRTC CDN

Начнем настройку с развертывания WCS сервера с ролью CDN Edge, для того, что бы создать на его основе образ диска для шаблона создания новых экземпляров WCS в балансировщике.

Повторите инструкцию по подготовке сервера Origin до пункта о внесении настроек в файл flashphoner.properties. Для роли Edge внесите в этот файл следующие настройки:

cdn_enabled=truecdn_ip=10.128.0.4cdn_nodes_resolve_ip=falsecdn_point_of_entry=10.128.0.3cdn_role=edgehttp_enable_root_redirect=false

После внесения и сохранения настроек, остановите в консоли Google Cloud виртуальную машину WCS CDN Edge, выберите из меню в левой части пункт "Images" и нажмите кнопку "Create Image":

В открывшемся мастере укажите имя нового образа, выберите в качестве источника диск виртуальной машины WCS CDN Edge и нажмите кнопку "Create":

После того, как образ диска создан переходим к созданию шаблона развертывания Edge сервера на основе созданного образа.

Создаем шаблон развертывания Edge сервера

Выберите из меню в левой части окна консоли Google Cloud пункт "Instance templates" и нажмите кнопку "Create Instance template":

В открывшемся мастере создания шаблона развертывания укажите имя шаблона и выберите конфигурацию виртуальной машины:

Ниже на странице в секции "Boot disk" нажмите кнопку "Change". в Открывшемся окне перейдите на вкладку "Custom Images" и выберите образ диска WCS CDN Edge, который мы создали ранее. Нажмите кнопку "Select":

Разверните секцию "Management, security, disks, networking, sole tenancy". На вкладке "Security" добавьте публичный ключ для доступа к серверу по SSH и нажмите кнопку "Create":

Шаблон развертывания для WCS с ролью CDN Edge создан. Теперь перейдем к созданию группы масштабирования.

Создаем группы масштабирования для Edge серверов

Из меню в левой части окна консоли Google Cloud выберите пункт "Instance groups" и нажмите кнопку "Create Instance group":

На открывшейся странице выберите регион и зону расположения группы и укажите шаблон развертывания WCS Edge, который мы создали ранее:

В секции "Autoscaling" на этой же странице настройте триггер запуска дополнительных серверов Edge. В качестве триггера будем использовать загрузку процессора более 80% . В поле "Maximum number of instances" укажите максимальное количество виртуальных машин, которые будут запущены при срабатывании триггера:

Затем включите проверку состояния виртуальной машины в секции "Autohealing". Для того, что бы создать настройку проверки сервера выберите из списка в поле "Health check" пункт "Сreate a health check":

В открывшемся мастере создания проверки состояния сервера укажите имя проверки, протокол TCP, порт 8081 и запрос /health-check. Настройте критерии проверки и нажмите кнопку "Save and continue":

Разверните секцию "Advanced creation options" и активируйте чекбокс "Do not retry machine creation". После чего нажмите "Create":

Будет создана группа масштабирования и запущен один WCS с ролью CDN Edge. Последним этапом настройки нашей CDN с балансировщиком нагрузки и автоматическим масштабированием будет настройка балансировщика.

Создаем балансировщик нагрузки

Сначала зарезервируем для балансировщика внешний IP адрес. В главном меню Google Cloud Platform в секции "VPC network" выберите пункт "External IP addresses" и нажмите кнопку "Reserve static address":

На открывшейся странице в поле "Name" задаем имя для зарезервированного IP адреса. Выбираем уровень качества сетевых услуг для адреса и тип распространения. После завершения всех настроек нажимаем кнопку "Reserve":

Затем переходим к настройке балансировщика.

Выбираем пункт "Load balancing" в разделе "Network services" секции "Networking" основного меню Google Cloud Platform:

Нажимаем кнопку "Create load balancer":

Затем выберите тип балансировщика "TCP Load Balancing" и нажмите кнопку "Start configuration":

На открывшейся странице укажите внешний балансировщик "From Internet to my VMs" и регион размещения серверов балансировщика. После выбора настроек нажмите кнопку "Continue":

На следующей странице задайте имя балансировщика, Затем перейдите в раздел настроек "Backend configuration" и укажите в каком регионе будут созданы сервера входящие в состав балансировщика. На вкладке "Select existing instance groups" выберите группу масштабирования Edge серверов, которую мы создали ранее. Затем в поле "Health check"выберите из выпадающего списка пункт "Сreate a health check":

На открывшейся странице укажите параметры для проверки состояния работы балансировщика порт 8081 и запрос /, после чего нажмите кнопку "Save and continue":

Затем перейдите к настройкам раздела "Frontend configuration". В этом разделе нужно создать привязку портов к внешнему IP адресу. Укажите внешний IP адрес для балансировщика, который мы зарезервировали выше и создайте конфигурации для TCP портов 8081, 8080, 8443, 8444 для HTTP(S) и WS(S). После создания необходимых портов нажмите кнопку "Create":

Балансировщик будет запущен. На этом развертывание CDN с балансировщиком и масштабированием можно считать завершенным. Переходим к тестированию.

Тестирование WebRTC CDN с балансировщиком и масштабированием на базе Google Cloud Platform

Методика тестирования

Для проведения нагрузочного тестирования, при создании группы масштабирования мы выставили порог загрузки процессора для срабатывания триггера на 20%. Тестирование будем проводить с использованием браузера Google Chrome и виртуальной вебкамеры для организации трансляции видеопотока. Что бы сымитировать повышение нагрузки на процессор запустим воспроизведение потока с транскодированием с помощью примера "Media Devices".

В результате тестирования мы должны убедиться, что повышение нагрузки на процессор виртуальной машины приводит к запуску дополнительных ВМ и балансировщик распределяет соединения между ними.

Тестирование

В браузере Google Chrome открываем web интерфейс WCS с ролью CDN Origin Авторизуемся, открываем пример "Two-way Streaming", устанавливаем соединение с сервером по WebSocket и публикуем видеопоток.

Затем, запускаем web интерфейс WCS CDN Edge сервера по IP адресу, который был зарезервирован при создании балансировщика.

Авторизуемся, открываем пример "Media Devices" и устанавливаем соединение с балансировщиком по WebSocket. В правом столбце настроек снимаем чек бокс "default" для параметра "Size" и задаем значения для транскодирования видеопотока. Например, если поток на Origin сервере опубликован с размерами 320х240 задаем значение 640х480. Повторите действия в нескольких вкладках браузера, для имитации большого количества зрителей.

В консоли Google Cloud видим, что были запущены две дополнительные виртуальные машины:

Для того, что бы проверить, что балансировщик распределяет соединения между активными ВМ можно использовать страницу статистики, которая доступна по адресу:

http://<WCS instance IP address>:8081/?action=stat

Откройте страницу статистики для каждой виртуальной машины, запущенной балансировщиком. Значение "connection_websocket" показывает количество активных WebSocket сессий на каждой виртуальной машине.

Как видите на скриншотах наша задача успешно решена. CDN работает, дополнительные Edge сервера запускаются и WebSocket соединения распределяются между ними. В итоге, мы создали CDN в которой при увеличении нагрузки на сервер Edge, автоматически разворачиваются дополнительные виртуальных сервера для распределения нагрузки и сохранения низкой задержки в видеотрансляции.

Хорошего стриминга!

Ссылки

Наш демо сервер

CDN для стриминга WebRTC с низкой задержкой - CDN на базе WCS

Документация по быстрому развертыванию и тестированию WCS сервера

Документация по развертыванию WCS в Google Cloud Platform

Документация по настройке балансировки нагрузки с масштабированием в GCP

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru