About
This is uses the same concept discussed here, which I also wrote.
This setup was tested on Debian Squeeze. There are two example servers here, fs01-a (10.10.10.8) and fs01-b (10.10.10.9).
10.10.10.11 will be the floating IP used here. This tutorial assumes you have ODBC setup so both nodes can connect to the same database. Please note that 10.10.10.11 should be a public facing IP, it is only used as an example here.
Network Configuration
Add each node to hosts file
root@fs01-a:~# echo "10.10.10.8 fs01-a" >> /etc/hosts root@fs01-a:~# echo "10.10.10.9 fs01-b" >> /etc/hosts root@fs01-b:~# echo "10.10.10.8 fs01-a" >> /etc/hosts root@fs01-b:~# echo "10.10.10.9 fs01-b" >> /etc/hosts
Create SSH keys
root@fs01-a:~# ssh-keygen -t dsa -f ~/.ssh/id_dsa -N "" root@fs01-b:~# ssh-keygen -t dsa -f ~/.ssh/id_dsa -N ""
Create SSH key to other server
root@fs01-a:~# scp -P 22 .ssh/id_dsa.pub root@fs01-b:/root/ root@fs01-b:~# scp -P 22 .ssh/id_dsa.pub root@fs01-a:/root/ root@fs01-a:~# cat id_dsa.pub >> .ssh/authorized_keys root@fs01-a:~# rm -rf fs01-b.pub root@fs01-b:~# cat id_dsa.pub >> .ssh/authorized_keys root@fs01-b:~# rm -rf fs01-a.pub
Allow FreeSWITCH to bind to nonlocal IP
Add the following line to /etc/sysctl.conf
echo 'net.ipv4.ip_nonlocal_bind=1' >> /etc/sysctl.conf
Restart networking:
/etc/init.d/networking restart
Run:
sysctl -p
You should see:
net.ipv4.ip_nonlocal_bind = 1
If you don't, you did something wrong, if you do, continue...
Corosync/Pacemaker
Install Corosync & Pacemaker
apt-get install pacemaker crmsh -y
corosync is included as a dependency of pacemaker
Configure Corosync
root@fs01-a:~# export ais_port=4000 root@fs01-a:~# export ais_mcast=226.94.1.1 root@fs01-a:~# export ais_addr=`ip addr | grep "inet " | tail -n 1 | awk '{print $4}' | sed s/255/0/` root@fs01-a:~# cp /etc/corosync/corosync.conf.example /etc/corosync/corosync.conf root@fs01-a:~# sed -i.bak "s/.*mcastaddr:.*/mcastaddr:\ $ais_mcast/g" /etc/corosync/corosync.conf root@fs01-a:~# sed -i.bak "s/.*mcastport:.*/mcastport:\ $ais_port/g" /etc/corosync/corosync.conf root@fs01-a:~# sed -i.bak "s/.*\tbindnetaddr:.*/bindnetaddr:\ $ais_addr/g" /etc/corosync/corosync.conf root@fs01-a:~# cat >> /etc/corosync/corosync.conf <<EOT aisexec { user: root group: root } service { name: pacemaker ver: 0 } EOT root@fs01-a:~# corosync-keygen root@fs01-a:~# scp -P 22 /etc/corosync/authkey root@fs01-b:/etc/corosync/authkey root@fs01-a:~# scp -P 22 /etc/corosync/corosync.conf root@fs01-b:/etc/corosync/corosync.conf root@fs01-a:~# sed -i "s/no/yes/g" /etc/default/corosync root@fs01-b:~# sed -i "s/no/yes/g" /etc/default/corosync
The LSB (Linux Standards Base) Script
Copy and paste this script into /etc/init.d/FSSofia on both nodes.
#!/bin/sh ### -*- mode:shell-script; indent-tabs-mode:nil; sh-basic-offset:2 -*- ### BEGIN INIT INFO # Provides: FSSofia # Required-Start: $network $remote_fs $local_fs # Required-Stop: $network $remote_fs $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: FSSofia # Description: FSSofia Status ### END INIT INFO #set -x FS_CLI_PROG='/usr/local/freeswitch/bin/fs_cli' FS_CLI_HOST='127.0.0.1' FS_CLI_PORT='8021' FS_CLI_PASS='ClueCon' PROFILES='internal' usage() { echo "Usage: $0 profile1[,profile2[,etc]] {start|stop|status}" exit 1 } fs_cli() { $FS_CLI_PROG -H $FS_CLI_HOST -P $FS_CLI_PORT -p $FS_CLI_PASS -x "$1" } sofia_profile_started() { fs_cli "sofia xmlstatus" | grep "<name>$1</name>" | wc -l } if [ $# != 1 ]; then usage fi #PROFILES=`echo $1 | tr ',' ' '` CMD=$1 #was $2 case "$CMD" in 'start') fs_cli "sofia recover" exit 0 ;; 'stop') exit 0 ;; 'status') for p in $PROFILES; do if [ `sofia_profile_started "$p"` -eq 0 ]; then echo "$p DOWN" exit 3 fi done echo "OK" exit 0 ;; *) usage ;; esac
Make the script executable
root@fs01-a:~# chmod +x /etc/init.d/FSSofia root@fs01-b:~# chmod +x /etc/init.d/FSSofia
Restart Corosync
root@fs01-a:~# /etc/init.d/corosync restart root@fs01-b:~# /etc/init.d/corosync restart
crm configure show
Configure corosync/pacemaker as follows
root@fs01-a:~# crm configure edit
node fs01-a \ attributes standby="off" node fs01-b \ attributes standby="off" primitive fs lsb:FSSofia \ op monitor interval="1s" enabled="true" timeout="2s" on-fail="standby" \ meta target-role="Started" primitive fs-ip ocf:heartbeat:IPaddr2 \ params ip="10.10.10.11" nic="eth0:0" cidr_netmask="24" \ op monitor interval="10s" group cluster_services fs-ip fs location cli-prefer-cluster_services cluster_services \ rule $id="cli-prefer-rule-cluster_services" inf: #uname eq fs01-a property $id="cib-bootstrap-options" \ dc-version="1.0.9-74392a28b7f31d7ddc86689598bd23114f58978b" \ cluster-infrastructure="openais" \ expected-quorum-votes="2" \ stonith-enabled="false" \ last-lrm-refresh="1348755080" \ no-quorum-policy="ignore" rsc_defaults $id="rsc-options" \ resource-stickiness="100"
Configure FreeSWITCH
Set FreeSWITCH to listen on the floating IP and configure ODBC.
sofia.conf.xml
You should have the following parameters set in sofia.conf.xml on both nodes. The Database needs to be shared between the two+ nodes. Please see the databases wiki for the proper odbc connection string.
<param name="odbc-dsn" value="database:username:password"/> <param name="track-calls" value="true"/> <param name="rtp-ip" value="10.10.10.11"/> <param name="sip-ip" value="10.10.10.11"/> <param name="presence-hosts" value="10.10.10.11"/> <param name="ext-rtp-ip" value="10.10.10.11"/> <param name="ext-sip-ip" value="10.10.10.11"/>
Configure sip_profiles
You should edit all sip profiles that you wish to use (typically internal.xml and external.xml). Adding the following line to tell these modules how to connect to your shared database and to track the active calls.
<param name="odbc-dsn" value="database:username:password"/> <param name="track-calls" value="true"/>
switch.conf.xml
You should have the following parameters set in switch.conf.xml on both nodes
<param name="switchname" value="fs01"/> <param name="core-db-dsn" value="database:username:password"/> <param name="core-recovery-db-dsn" value="database:username:password"/>
Other XML Files
These are not necessary for everyone that wants HA. But you may need to add in the "odbc-dsn" parameter depending on what you are using freeswitch for:
# Add the following line in db.conf.xml, voicemail.conf.xml, lcr.conf.xml, and nibblebill.conf.xml <param name="odbc-dsn" value="database:username:password"/>
Start FreeSWITCH
Start FreeSWITCH on both nodes.
root@fs01-a:~# /etc/init.d/freeswitch start root@fs01-b:~# /etc/init.d/freeswitch start
Start Corosync
Start Corosync on both nodes.
root@fs01-a:~# /etc/init.d/corosync start root@fs01-b:~# /etc/init.d/corosync start
Start Pacemaker
Start Corosync on both nodes.
root@fs01-a:~# /etc/init.d/pacemaker start root@fs01-b:~# /etc/init.d/pacemaker start
TEST!
Make a call and don't hang up.
CLI on both FS nodes
root@fs01-a:~# /usr/local/freeswitch/bin/fs_cli root@fs01-b:~# /usr/local/freeswitch/bin/fs_cli
Crash the primary server
freeswitch@default> fsctl crash
Voilà, the call should continue almost instantly on the standby server!
To Do
TODO: Fill in how to setup/install corosync
See also
Clusters From Scratch (Pacemaker, Corosync home; Red Hat)
crmsh - the cluster management shell (alternative to pcs)