company_banner

Kamailio SIP proxy: пример установки и минимальной настройки


    В работе системного администратора, занимающегося внедрением систем телефонии на базе Asterisk, рано или поздно может возникнуть ситуация, когда аппаратных возможностей одного сервера для обработки всех вызовов уже недостаточно. Соответственно, возникает необходимость разделить нагрузку на несколько серверов. Одним из способов решения такой задачи является использование SIP proxy, но стоит признать, что в отличие от Asterisk, информации по SIP proxy, форумов, примеров и описаний, меньше как минимум на порядок. Цель этой статьи — показать на простом примере возможность использования SIP proxy Kamailio в связке с Asterisk так, чтобы максимально облегчить освоение SIP proxy для новичков.

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

    Предположим, что в организации уже установлен Asterisk, и сотрудники обрабатывают большое количество входящих звонков, с которым сервер уже не справляется. Мы добавим еще один сервер Asterisk (точнее, клонируем существующий), а SIP proxy возьмет на себя роль «распределителя» входящих звонков.

    Начнем с выбора SIP proxy. На хабре есть хорошая статья на эту тему, в которой рассмотрена история развития основных проектов. В отличие от автора этой статьи, мой выбор пал на Kamailio и web-интерфейс для него под названием Siremis.

    Установим Kamailio. В качестве ОС будем использовать CentOs 6.8.

    В первую очередь, необходимо отключить SELinux, обновить пакеты и установить необходимые зависимости:

    yum -y update && yum -y groupinstall core && yum -y groupinstall base && yum -y install epel-release
    yum -y install httpd mysql-server php php-mysql php-gd php-curl

    Нам потребуется доступ к 80 порту для работы с web-интерфейсом и к 5060 udp для работы с sip, поэтому добавим правила IPTables:

    iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
    iptables -A INPUT -m state --state NEW -m udp -p udp --dport 5060 -j ACCEPT

    Создаем файл /etc/yum.repos.d/kamailio.repo с содержимым:

    [kamailio]
    name=RPMs for Kamailio on CentOS 6
    type=rpm-md
    baseurl=http://rpm.kamailio.org/stable/CentOS_6/
    gpgcheck=1
    gpgkey=http://rpm.kamailio.org/stable/CentOS_6/repodata/repomd.xml.key
    enabled=1

    И устанавливаем kamailio:

    yum install kamailio kamailio-presence kamailio-mysql

    Не забудем добавить демоны в автозагрузку:

    chkconfig mysqld on
    chkconfig httpd on
    chkconfig kamailio on

    Отредактируем файл /etc/kamailio/kamctlrc: нужно раскомментировать строку

    DBENGINE=MYSQL

    и указать SIP_DOMAIN. В силу того, что мы настраиваем систему в локальной сети, достаточно будет указать ip-адрес, в моем случае

    SIP_DOMAIN=192.168.0.237

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

    Запустим MySQL и сгенерируем необходимые таблицы:

    service mysqld start
    kamdbctl create

    На все вопросы мастера отвечаем утвердительно.

    Теперь отредактируем основной конфигурационный файл /etc/kamailio/kamailio.cfg. Логически он разбит на несколько секций: глобальные параметры, загрузка модулей, установка параметров модулей и маршруты. Каждый модуль Kamailio выполняет определенную функцию, поэтому можно загружать только необходимые для конкретной задачи библиотеки. Начало файла приведем к виду:

    #!KAMAILIO
    #!define WITH_MYSQL
    #!define WITH_AUTH
    #!define WITH_USRLOCDB
    #!define WITH_PRESENCE
    #!define WITH_ACCDB

    Как понятно из комментариев ниже, эти директивы включают необходимые модули, например WITH_MYSQL, определенный в начале файла, ниже приводит к загрузке модуля mysql.so:

    #!ifdef WITH_MYSQL
    loadmodule "db_mysql.so"
    #!endif

    Безусловно, можно загрузить все модули вручную, но использование директивы гораздо удобнее. WITH_AUTH, например, дает возможность пользователям регистрироваться на Kamailio с использованием имени и пароля, а все варианты выбора вы можете посмотреть в комментариях ниже.

    Для дальнейшей корректной работы web-интерфейса и статистики внесем еще несколько изменений:

    После всех строк loadmodule добавим загрузку еще двух:

    loadmodule "rtimer.so" 
    loadmodule "sqlops.so" 

    Перед секцией маршрутов, которая отделяется строкой ####### Routing Logic ######## добавим параметры загруженных модулей:

    modparam("rtimer", "timer", "name=cdr;interval=300;mode=1;")
    modparam("rtimer", "exec", "timer=cdr;route=CDRS")
    modparam("sqlops", "sqlcon", "cb=>mysql://kamailio:kamailiorw@localhost/kamailio")

    И добавим дополнительный маршрут после последней секции route в районе 910 строки файла:

    route[CDRS] {
        sql_query("cb","call kamailio_cdrs()","rb");
        sql_query("cb","call kamailio_rating('default')","rb");
        }

    Запускаем Kamailio и проверяем, что он запустился:

    service kamailio start
    ps aux | grep kamailio
    

    Если Kamailio не запускается, нужно посмотреть лог /var/log/messages — именно туда будут попадать ошибки Kamailio, если дополнительно не настроить rsyslog, что не представляет большой сложности.

    По умолчанию используется база MySQL kamailio c пользователем kamailio c паролем kamailiorw, если конечно не изменить установки по умолчанию в файле /etc/kamailio/kamctlrc перед созданием базы данных. В том случае, если вы изменили эти установки, будет нелишним пройтись автозаменой по основному конфигурационному файлу kamailio.cfg и внести корректные данные подключения к базе.

    В принципе, Kamailio может работать и без базы данных — все необходимые значения для модулей можно задавать в конфигурационном файле или хранить во внешних файлах, но использование БД, особенно на крупных проектах, гораздо удобнее, плюс именно с базой будет работать web-интерфейс Siremis, который мы сейчас установим.

    Нужно скачать, разархивировать файлы, скопировать их в директорию, с которой будет работать apache и дать верные права:

    cd /usr/src
    wget http://siremis.asipto.com/pub/downloads/siremis/siremis-4.3.0.tgz
    tar zxvf siremis*
    cp -a siremis*/. /var/www/html
    cd /var/www/html
    make prepare
    rm -rf /var/www/html/Makefile
    rm -rf /var/www/html/Changelog
    rm -rf /var/www/html/README
    chown -R apache. /var/www/html

    В секцию VirtualHost в конфигурации apache для Siremis добавим

       <Directory "/var/www/html/siremis">
            Options Indexes FollowSymLinks MultiViews
            AllowOverride All
            Order allow,deny
            Allow from all
            <FilesMatch "\.xml$">
                Order deny,allow
                Deny from all
            </FilesMatch>
            <FilesMatch "\.inc$">
                Order deny,allow
                Deny from all
            </FilesMatch>
      </Directory>
    
    <Directory "/var/www/html/openbiz">
        AllowOverride All
        Order deny,allow
        Deny from all
      </Directory>
    
    <Directory "/var/www/html/misc">
        AllowOverride All
        Order deny,allow
        Deny from all
      </Directory>
    

    При дальнейшей установке последней на момент написания статьи версии Siremis 4.3.0 могут возникнуть проблемы в случае, если у вас не задан date.timezone, поэтому рекомендуется сразу внести изменения в php.ini:

    date.timezone = Europe/Moscow

    Для Siremis потребуется отдельная база данных. Добавим пользователя:

    mysql -e "GRANT ALL PRIVILEGES ON siremis.* TO siremis@localhost IDENTIFIED BY 'siremisrw';"

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

    Теперь можно перезапустить apache и перейти к завершающему этапу установки Siremis — уже через браузер. Перейдите по адресу ваш-ip/siremis



    Если проверка системы пройдена, можно начинать установку.



    Обратите внимание: по умолчанию под звездочками скрываются дефолтные пароли от пользователей Kamailio и Siremis, так что если вы не вносили изменений ранее, то и на этом шаге можно не забивать пароли вручную.

    Обязательно поставьте галочки на всех пунктах — Create Siremus DB, Import Dafault Data, Update SIP DB, Replace DB config.



    Проверьте, что указаны корректные данные.



    И на этом установка завершена.



    Давайте попробуем осуществить первый звонок через Kamailio. Для этого перейдем на вкладку SIP Admin menu и добавим новый домен в Domain List. Kamailio будет обслуживать только перечисленные здесь домены (или ip-адреса).



    В случае, если к адресу привязан домен, и пользователи могут регистрироваться как указав ip-адрес, так и указав домен, следует добавить и доменное имя в список. В нашем случае добавляем только ip-адрес сервера, к которому будут обращаться клиенты.



    Для создания внутреннего абонента или подписчика перейдем к Subscriber Services -> Subscribers и добавим два номера — 101 и 102, указав для них пароли и серый адрес в качестве домена (в нашем случае 192.168.0.237).



    Теперь, используя софтфон, например Zoiper, мы можем зарегистрироваться на сервере и осуществить звонок с 101 на 102 номер или наоборот и убедиться в том, что все предыдущие действия были выполнены верно.

    Перейдем к настройке распределения входящих вызовов. В локальной сети у нас есть 2 виртуальные машины с Asterisk на адресах 192.168.0.234 и 192.168.0.235, и нам нужно поровну распределить входящие звонки между ними. В данной ситуации мы будем использовать модуль dispatcher, который предоставляет необходимый функционал.

    Вернемся в консоль, и добавим в kamailio.cfg в секцию загрузки модулей

    loadmodule "dispatcher.so"

    а также два параметра — подключения к базе данных, в которой и будет храниться список серверов Asterisk, и частоту проверки этих серверов, чтобы звонок ни в коем случае не ушел на выключенный сервер:

    modparam("dispatcher", "db_url", "mysql://kamailio:kamailiorw@localhost/kamailio")
    modparam("dispatcher", "ds_ping_interval", 30)

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

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

    if ( method=="INVITE" ) {
      ds_select_dst("1","4");
      sl_send_reply("100","Trying");
      forward();
      exit();
    }

    Если приходит запрос типа INVITE, то есть приглашение к началу разговора, то мы выбираем один из серверов, которые позже занесем в таблицу, из группы 1 по стратегии выбора 4 — round-robin. Затем посылаем ответ вызывающему и осуществляем перевод звонка на выбранное назначение. Обратите внимание, что теперь абсолютно любой INVITE будет обрабатываться таким образом, так что возможность позвонить с 101 номера на 102, которые мы создавали ранее, будет утрачена — звонки с них тоже будут улетать на один из серверов Asterisk, и поступающие извне запросы INVITE также будут напрямую уходить на Asterisk без всякой проверки источника запроса.

    Для того, чтобы Asterisk мог обработать такие вызовы, нужно добавить peer следующего вида на каждый из серверов:

    [kamailio]
    host=192.168.0.237
    port=5060
    insecure=invite
    type=friend
    context=from-pstn

    Теперь можно добавить сервера Asterisk в базу данных Kamailio через web-интерфейс:



    Setid задаст к какой группе серверов относится новый сервер, Priority не используется в стратегии выбора round-robin, но может использоваться в других стратегиях, а Flags в данном случае устанавливает, что по умолчанию мы считаем сервер неактивным и проверяем его состояние.

    После добавления серверов можно или перезапустить Kamailio, что недопустимо на продакшне, или выполнить команду kamcmd dispatcher.reload. Список команд для каждого модуля также можно посмотреть на официальном сайте.

    Можно переходить к тестированию. Используя софтфон, например, Zoiper, можно осуществить вызов напрямую на Kamailio, без всяких аккаунтов и регистраций. Достаточно в поле набора ввести sip:1@192.168.0.237. Сразу после этого вызов будет переадресован на один из Asterisk и обработан в соответствии с диалпланом. Следующий вызов пойдет на второй сервер.

    В принципе, стоявшую перед нами учебную задачу — распределять входящие вызовы поровну между серверами, — мы решили. Однако, далеко не каждый оператор связи готов отдавать звонки на ваш ip-адрес напрямую, без регистрации, и нужно будет посылать запросы типа REGISTER. Этот функционал реализует модуль uac. Добавим в нашу схему еще один Asterisk — он будет исполнять роль провайдера. На нем создадим какой-нибудь внутренний номер, например, 200200, который будет требовать регистрацию.

    Загрузим модуль в конфигурационном файле:

    loadmodule "uac.so"

    И зададим пару обязательных в нашем случае параметров:

    modparam("uac", "reg_db_url", "mysql://kamailio:kamailiorw@localhost/kamailio")
    modparam("uac", "reg_contact_addr", "192.168.0.237")

    Кроме того, потребуется внести изменение в параметр другого модуля. Найдите в файле строку

    modparam("rr", "append_fromtag", 0) 
    

    и замените на:

    modparam("rr", "append_fromtag", 1)

    Теперь можно настроить регистрацию, перезапустив предварительно Kamailio, чтобы модуль загрузился:



    Обратите внимание на поле Realm. По умолчанию, вы можете ввести в него что угодно, но тогда регистрация проходить не будет, а в логе вы увидите то-то вроде:

    kamailio /usr/sbin/kamailio[26277]: ERROR: uac [uac_reg.c:799]: uac_reg_tm_callback(): realms do not match. requested realm: [asterisk]

    Именно поэтому при возникновении каких-либо проблем не стоит сразу перечитывать мануал, искать другие инструкции и сомневаться в своих способностях — чаще всего объяснение можно найти в логе.

    Остается только убедиться в том, что абонент 200200 зарегистрирован на Asterisk, играющем роль провайдера, и осуществить звонок с любого другого номера на 200200.

    На этом пример настройки Kamailio мы заканчиваем, но обратите внимание, что в статье не рассмотрена работа за NAT, безопасность, маршрутизация исходящих вызовов и многое другое, что может потребоваться в реальной ситуации. Однако надеюсь, что эта статья облегчит для вас освоение Kamailio.
    Southbridge
    612.96
    Обеспечиваем стабильную работу серверов
    Share post

    Comments 25

      0
      В первую очередь, необходимо отключить SELinux...

      А ведь можно создать политику. Почему это никто не делает?
      Я не видел ни одного мануала по настройке Asterisk/Kamalio/FreeSwitch/etc, который не начинается с отключения SELinux.
        0
        Позволю себе процитировать часть комментария bARmaleyKA
        Для тех кто сталкивается с этой надстройкой безопасности впервые куда б интересней было знать как получать и читать информацию о блокировке процесса системой SELinux средствами утилит audit2allow и audit2why (хотя и они иногда бред выдают), поиск и просмотр блокировок утилитами ausearch, aureport и sealert, или как примерно разобрать сообщения аудита, которые не попали в обработку (там самый цимес бывает). А то человек настроит сервис, пытается запустить, отладить — на выходе ничего и в журнале работы нихрена не разобрать. Помучается и выключит приблуду. Наверное поэтому многие статьи начинаются со слов: «Первым делом выключаем SELinux...»
        +2

        Простите, а что нужно сделать, чтобы Астериск перестал справляться с обработкой звонков. У меня астер обрабатывает около 30000 тысяч звонков в сутки, годами без остановки. При этом он работает на ВМ под hyper-v, 4 ядра, 4 гига рама. LoadAverage 0.91 под нагрузкой. Памяти впритык, нужно добавить, а по процессору зазор 4х кратный. ЧЯДНТ?

          0
          Например, желание его перезагрузить :). А разговоры пишутся?
            0

            Да. ionice помогает все это сбалансировать. Мы еще и жмем разговоры после записи.

            +1
            30000 — это средненько, проблемы с LA начинаются позже, когда количество одновременно активных каналов доходит до 600+.
            Затык там или в CDR или в записи вызовов, потому что второй сервер, обрабатывающий чуть меньше потоков — проблем с LA не имеет, хотя он слабее вашего даже. Но там нет CDR и записи.
              0

              У меня 110 endpoint'ов, так-что больше 150 каналов мне не грозит. На позапрошлый новый год было 60000+ звонков и я особо их и не заметил.
              Интересно чем вы занимаетесь с такими телефонными нагрузками?

                0
                Интернет-магазин
                попробуйте помониторить количество одновременных звонков в пиках, количество за сутки — не особо показатель, продолжительность звонка может сильно влиять.
                Даже на таких цифрах, нет проблем с LA, если не юзать запись и\или CDR. Пока особо не было времени детальнее выяснить, что именно влияет на LA.
                По теме — SIP proxy это больше про отказоустойчивость, чем про разнос нагрузки.
                Планируем попробовать FreeSwitch вместо астера, в тестах показал себя гораздо лучше по тупой производительности.
                  0
                  Sip proxy можно и для отказоустойчивости, и для сокрытия топологии использовать, но и для распределения нагрузки вполне подходит. FreeSwitch по синтетическим тестам — да, вроде показывает себя лучше. Когда перейдете с Asterisk на FreeSwitch, обязательно напишите статью, думаю, многим будет интересно прочесть о сравнении под реальной нагрузкой
              0
              Количество звонков в сутки без указания средней длительности — не всегда показательно. Вот пиковое число одновременных вызовов — более интересная метрика
                +1
                Есть еще более критичный параметр CPS (Call-Per-Second) в пиках.
                У нас например как-то шла реклама по телевизору.
                И сразу после нее CPS был просто зашкаливающий. А без рекламы возле нулей все.
              0
              А что происходит с самим звуковым потоком, он тоже идёт через прокси?
                0
                Нет, звук в данной схеме не проксируется
                –1
                Халтура. Последний абзац следовало бы написать в начале статьи, а также добавить туда, что в мануале не будет объяснено зачем нужна большая часть действий, почему обязательны те или иные параметры и тд.
                Да и вообще статья в стиле «Ну мы сделали вот так, у нас заработало».
                  0
                  В названии потому и есть слово «пример», и нет слова «мануал». Понимаете, в чем разница?
                    –1
                    Ну тогда в чем смысл этой статьи? С камаилио в комплекте идут примеры конфигурации.
                    И если вы все таки решили написать еще один пример, то это не отменят факта что для новичков вы должны объяснять почему в примере сделано именно так, а не иначе. Те кто понимают — им пример базовых вещей без пояснений не нужен. Тем кто хочет разобраться ничем не поможет.
                      –1
                      И это я еще не трогал пункта «Выключаем Selinux». Это ОЧЕНЬ СТРАННО слышать от человека, пишущего от centos-admin.ru.
                    0
                    Если у вас все входящие вызовы должны попадать в queue, при этом вызова на queue members раскидываются на разные asterisk, то информатор о позиции в очереди будет работать криво. Для того, чтобы работал как надо потребуется всех участников одной группы «селить» на одном asterisk

                      0
                      В этом примере все будет корректно: пусть у нас на одном asterisk 1000 агентов в очереди и на втором тоже 1000 агентов в очереди, причем, это разные агенты. Пришел вызов, направился на первый asterisk, попал в очередь из 1000 агентов. Его позиция будет считаться для заданной очереди.
                        0
                        А как тогда статистику собирать? 2 разных астериска, 2 разных базы данных cdr/queue…
                      0
                      вы серьезно пишите что нужно отключить Selinux?
                        0
                        В качестве примера на демо-стенде это вполне допустимо
                        0
                        Спасибо. Интересно посмотреть как настроено у других.
                        Я как-то привык без ВЕБа. В конфигах руками. Наверное я динозавр, но так уже привык.
                          0
                          Одно дело руками в конфигах, и другое дело — руками в БД
                          0
                          Всем привет.

                          Поставил версию 5.0.3 согласно инструкции, но не могу запустить — выдает ошибку модулей presence.

                          [root@localhost ~]# systemctl start kamailio
                          Job for kamailio.service failed because the control process exited with error code. See «systemctl status kamailio.service» and «journalctl -xe» for details.
                          [root@localhost ~]# systemctl status kamailio.service -l
                          ● kamailio.service — SYSV: Kamailio is a fast, reliable and flexible SIP Server.
                          Loaded: loaded (/etc/rc.d/init.d/kamailio; bad; vendor preset: disabled)
                          Active: failed (Result: exit-code) since Wed 2017-10-04 12:09:58 MSK; 5s ago
                          Docs: man:systemd-sysv-generator(8)
                          Process: 14091 ExecStart=/etc/rc.d/init.d/kamailio start (code=exited, status=1/FAILURE)

                          Oct 04 12:09:58 localhost.localdomain kamailio[14091]: 0(14101): [cfg.y:3426]: yyerror_at(): parse error in config file //etc/kamailio/kamailio.cfg, line 412, column 43: Can't set module parameter
                          Oct 04 12:09:58 localhost.localdomain kamailio[14091]: 0(14101) ERROR: [cfg.y:3286]: yyparse(): cfg. parser: failed to find command handle_publish (params 0)
                          Oct 04 12:09:58 localhost.localdomain kamailio[14091]: 0(14101): [cfg.y:3426]: yyerror_at(): parse error in config file //etc/kamailio/kamailio.cfg, line 719, column 18: unknown command, missing loadmodule?
                          Oct 04 12:09:58 localhost.localdomain kamailio[14091]: 0(14101) ERROR: [cfg.y:3286]: yyparse(): cfg. parser: failed to find command handle_subscribe (params 0)
                          Oct 04 12:09:58 localhost.localdomain kamailio[14091]: 0(14101): [cfg.y:3426]: yyerror_at(): parse error in config file //etc/kamailio/kamailio.cfg, line 722, column 20: unknown command, missing loadmodule?
                          Oct 04 12:09:58 localhost.localdomain kamailio[14091]: ERROR: bad config file (7 errors)
                          Oct 04 12:09:58 localhost.localdomain systemd[1]: kamailio.service: control process exited, code=exited status=1
                          Oct 04 12:09:58 localhost.localdomain systemd[1]: Failed to start SYSV: Kamailio is a fast, reliable and flexible SIP Server…
                          Oct 04 12:09:58 localhost.localdomain systemd[1]: Unit kamailio.service entered failed state.
                          Oct 04 12:09:58 localhost.localdomain systemd[1]: kamailio.service failed.

                          В папке с модулями их нет. В инете тоже не нашел.
                          Как исправить эту ситуацию?

                          Only users with full accounts can post comments. Log in, please.