Blog

Creating a Docker image based on another image

In this tutorial we will go over how to make changes to a running container while attached, then saving our progress. This will result in a new deployable image.

Install the nginx server to your container and commit the changes.

  1. First attach to the running CentOS container, like we did in the last tutorial.
    docker attach <container name>
    

    (You can use either container name or container id number. Look at the running container and find this information with docker ps)

  2. Install nginx via yum. You will also need to install the epel-release package to get access to nginx.

    yum install epel-release
    yum update
    yum install nginx
    
  3. Now that nginx is installed, exit out of the container with the following key combination:
    CTRL` + `P` and `CTRL` + `Q`
    
  4. Commit your changes to a new image with the following command:
    docker commit -m 'added nginx' --change='CMD ["nginx", "-g daemon off;"]' <container name> dopensource/nginx
    
  • Notice the similarities in syntax to git.
  • -m 'added nginx' creates a comment for this commit.
  • --change='CMD ... is changing the CMD command, which is what the image will run when it is first started up. In this example, we are telling the image to run nginx in the forground. Most base os images have CMD set to bash so you can interact with the os when attaching.
  • <container name> is the name of the container you want to commit from. You can again, get this from docker ps
  • dopensource/nginx is our name for the new image. dopensource is our organization and nginx is the name of the container.
  1. You can now view your new image with the following command:
    docker images
    

docker_images

  • Notice there are two images here. One for the base CoreOS image, which we pulled from the docker hub, and the image we just created.

Run the new image

docker run -dit dopensource/nginx

In the next tutorial we will go over how to allow access to the container over the network.

Running and Connecting to a Docker Container

Connect to your running container

Now that we have a list of running containers, we can use this information to connect. When connecting to a container, you will have different types of interfaces depending on what software the container is running. Most base OS containers, such as Debian or CentOS, will give you a bash shell. Projects such as Asterisk or FreeSWITCH will give you access to the applications CLI, such as fs_cli or asterisk -rv.

  1. You can connect to the container previously listed with the docker ps command using the follwing:

    docker attach <container id>

  • You can either use the container id or container name.
  • In my previous image, the container id would be 60968049d6b3 and the container name would be pedantic_varahamihira
  • If you do not specify a name, docker will randomly assign one.
    • You can assign a container name when running with the --name flag.
  • Once you have ran the docker attach command, you will probably need to hit enter a couple times to see a prompt.

    release_docker

  1. To detach your terminal from the running container, use the follwoing key combination:

    CTRL + P and CTRL + Q

  2. If you type exit while attached to the container, the container will stop running. You can also use the following command, which will send a sigterm message to the container:

    docker stop <container name>

Creating a Docker container from an existing image

In this tutorial we will go over how to search and pull down an existing docker image from the docker hub to run it on your server or local system.

Prerequisites

  • You will need to have docker running and installed on your system.

Searching the Docker Hub

  • You can search the Docker Hub for pre made images. These images are either made by the community, or official builds of different projects.
    docker search centos
    
  • You will get the following response. Notice what it shows you. This will include the following:

  1. A description
  2. Number of stars voted by the community
  3. Indication if the image is official and built by the organization in charge of the project
  4. Indication if the build is automated or not
  • Below is an example of what you will see when searching the Docker Hub.

docker_search

  • Notice the first image is marked as the official CentOS docker image.

Creating a container from a remote image

  • Let’s create a container based on the official CenOS build.
    docker run -dit docker.io/centos
    

docker_run

  • Note, Docker will automatically download the image from the Docker Hub if the image is not installed on the host. Once completed, the image will be ran.

  • Here are the what the flags used in the previous command do:

Flag Function
-d Run container in background
-i Keep STDIN open, even if not attached
-t Allocate a pseudo-TTY

View running containers

  • Validate the container is running by getting a list of all running containers:
    docker ps
    

docker_ps

In our next tutorial we will go over how to attach to a container.

Setting Up Your Kamailio Development Envionment

The purpose of this document is to explain how to install Kamailio and setup your development environment to make it easier to start configuring Kamailio to fit your requirements.  In this document I will explain how to install Kamailio on CentOS 6.6 and configuring VIM to make it easier to do development.

Assumptions:

  • MySQL is installed

Installing Kamailio 4.2 from source on CentOS 6.6 (for some reason we love CentOS)

I used the instructions located at http://www.kamailio.org/wiki/install/4.2.x/git as my basis.

You first need to install some packages that will be need for compiling Kamailio

yum install -y gcc flex bison mysql-libs make openssl-devel libcurl libxml2 expat-devel

Next we need to create a location for the Kamailio source

mkdir -p /usr/local/src/kamailio-4.2
cd /usr/local/src/kamailio-4.2

We now can use GIT to grab the source and checkout the latest 4.2 release

git clone --depth 1  git://git.sip-router.org/kamailio kamailio
cd kamailio
git checkout -b 4.2 origin/4.2

Continue with the installation by starting at step 3 thru step 7 in the instructions located at http://www.kamailio.org/wiki/install/4.2.x/git

Setup Development Environment

We personally like using the VIM autocomplete plugin for Kamailio that was created by Daniel-Constantin Mierla (co-founder of Kamailio).  It makes development much easier.

The vim extensions that handle syntax highlighting and file type auto detection is shipped part of the source. So you just need to install it

cd /usr/local/src/kamailio-4.2/kamailio/utils/misc/vim/
make install

If you want to have autocomplete you will need to grab it from Daniel’s GIT repository

git clone https://github.com/miconda/vim-extensions.git
cd vim-extensions
make install-kamailio-plugin

Now you can have autocomplete turn on automatically when you edit a Kamailio file in VIM by running this command which will create a ~/.virmrc file with the command to turn on autocomplete for Kamailio functions and reserved words

echo '" custom complete function for kamailio config
 autocmd FileType kamailio setlocal completefunc=KamailioComplete' >> ~/.vimrc'

Test that it’s working

vim /usr/local/etc/kamailio/kamailio.cfg

You should see #!KAMAILIO in purple. You can test autocomplete by starting hit “i” on the keyboard to enter insert mode and then hit CTRL+x, then CTRL+u.  You will see a list of Kamailio functions that will pop up.  See my screenshot below:

Kamailio Autocomplete

References

  • http://www.kamailio.org/w/tag/4-2/
  • https://github.com/miconda/vim-extensions/blob/master/plugin/kamailio/README.md

Load balancing traffic with Kamailio v4.1

Load balancing traffic with Kamailio

Note: We assume you have Asterisk/Freeswitch setup to handle inbound traffic from Kamailio

In part 3 of our Kamailio series we will explain how to load balance calls from users between several different media servers. For this part in the series we will use the “dispatcher” module. The dispatcher module provides us with several different ways to load balance calls from round-robin to weight based routing.

Getting Started

For this tutorial, you’ll only need one thing besides Kamailio and that is a list of media servers. If you don’t have any media servers, we recommend using Freeswitch and/or Asterisk.

Configuring Kamailio

By default, Kamailio does not load the dispatcher module or any of the modules respective settings. Let’s start with loading the module into Kamailio. Open up your kamailio configuration file (/etc/kamailio/kamailio.cfg), find the load modules section and add the following line:

 loadmodule “dispatcher.so”

Scroll down further in the file until you locate the module parameters section. Go the bottom of that list and add the following:

modparam("dispatcher", "db_url", "mysql://kamailioro:kamailioro@localhost/kamailio")
modparam("dispatcher", "table_name", "dispatcher")
modparam("dispatcher", "flags", 2)
modparam("dispatcher", "dst_avp", "$avp(AVP_DST)")
modparam("dispatcher", "grp_avp", "$avp(AVP_GRP)")
modparam("dispatcher", "cnt_avp", "$avp(AVP_CNT)")

Save the file and restart Kamailio to make sure there are no errors. You can restart kamailio with:

# kamctl restart

If that didn’t work, go back and make sure you have everything entered properly. Once it’s running with no problem open back up the configuration file and proceed to the “request_route” section. Comment out the following line by appending a “#” pound symbol to the front of it.

 route(PSTN);

Right below add the following line:

 route(DISPATCHER);

It’s time to add the actual code that will do the dispatching. Go to the code block below “route[RELAY]” and add the following:

route[DISPATCHER] {
  # round robin dispatching on gateways group '1'
  if(!ds_select_dst("1", "4"))
  {
    send_reply("404", "No destination");
    exit;
  }
  xlog(“ —— DISPATCH: going to <$ru> via <$du>n");
  route(RELAY);
  exit;
}

In the above code, we chose to use the round-robin algorithm for routing calls. Basically, our calls will cycle between the media servers we chose to setup. If we have 2 media servers setup our calls will process like so, call 1 will go out of MS1, call 2 out of MS2, call 3 out of MS1 and so on.

With the dispatching code in place, we’ll need to add the actual destinations into the Kamailio database. Login to your MySQL database and execute the following commands. You can replace the destination and description with your media servers.

mysql> INSERT into dispatcher (setid, destination, flags, priority, attrs, description) VALUES (1, “sip:asterisk.example.com:5060”, 0, 0, "", "Endpoint: Asterisk Media Server");
mysql> INSERT into dispatcher (setid, destination, flags, priority, attrs, description) VALUES (1, “sip:freeswitch.example.net:5060”, 0, 0, "", "Endpoint: Freeswitch Media server");

With that completed, we’ll need to reload Kamailio. Since we haven’t restarted Kamailio since adding the dispatch route let’s just restart Kamailio using the same command as before. However, if you restarted Kamailio since adding the dispatch route you can just use the following command to reload the dispatcher info.

# kamctl dispatcher reload

Now that the routes are loaded into Kamailio, all you’ll need to do is push some calls through to Kamailio and they will be routed in a round-robin fashion like we stated above.

Reference

  • Dispatcher Modules Documentation – http://kamailio.org/docs/modules/4.1.x/modules/dispatcher.html

 

Least-Cost Routing with Kamailio v4.1

The goal of this document is to explain how to get Kamailio to route traffic to the carrier with the least cost. This is part 2 in our Kamailio series.

 Getting Started

You don’t need much for this tutorial. All you’ll need is 2 carrier endpoints and their rates for calling a certain area code. Other than a Kamailio server, you can proceed with the rest of the tutorial.

 Configuring Kamailio 

Before we start setting up the LCR module, we first need to make some changes to the Kamailio configuration file. First off, we will need to modify the listen parameter. Open up your Kamailio configuration (kamailio.cfg) and look for the “listen” line.

If your Kamailio instance is behind a firewall make your line look like this:

listen=udp:<internal address>:5060 advertise <external address>:5060

Else if your Kamailio instance is on the public internet make it look like this:

listen=udp:<external address>:5060

By default Kamailio does not load the LCR module so we will need to add it.  In the same config file, locate the section where it says “loadmodule” and go to the bottom of that list and add:

loadmodule “lcr.so”

We can now begin setting up the LCRs module parameters.

Configuring LCR Module 

Now that we’ve configured Kamailio, we need to configure the LCR module. Back in the configuration file, look for the module parameters section.  At the bottom of that section, add the following values:

modparam("lcr", "db_url", "mysql://kamailioro:kamailioro@localhost/kamailio")
modparam("lcr", "gw_uri_avp", "$avp(i:709)")
modparam("lcr", "ruri_user_avp", "$avp(i:500)")
modparam("lcr", "tag_avp", "$avp(lcr_tag)")
modparam("lcr", "flags_avp", "$avp(i:712)")
modparam("lcr", "lcr_id_avp", "$avp(s:lcr_id_avp)")
modparam("lcr", "defunct_gw_avp", "$avp(s:defunct_gw_avp)")

With the module configured, it’s time to setup the actual routing of the SIP requests. In the “request_route” above the line that says:

 # dispatch request to foreign domains

Add the following line:

 route(LCR);

Then add a new route using the code below, put this at the end of the file:

route[LCR] {
if (status=="200")
{
  xlog("LCR: Inside the LCR routen");
}

if(method=="INVITE")
{
  xlog("We got an invite");
  if(!load_gws(1, $rU, $var(caller_uri))) {
    xlog("Couldn't load gateways");
    sl_send_reply("500", "Server Internal Error - Cannot load gateways");
    exit;
  } else {
        xlog("GW Selected '$avp(i:709)'n");
        xlog("Domain of destination: $ddn");
        xlog("To URI: $tun");
  }

  if(!next_gw()) {
    xlog("Couldn't proceed to next gateway");
    sl_send_reply("503", "Service not available, no gateways found");
    exit;
  } else {
        xlog("Calling the first matched gatewayn");
        xlog("ruri_user_avp: '$avp(i:500)'n");
        xlog("To URI after next_gw: $tun");
        xlog("Request URI: $rUn");

  }

}
}

 

Adding LCR Data

With our routing code in place, we need to add some data to LCR tables. Before we do that let’s go over what tables the LCR module uses and how they all fit together.

There are 3 tables that the LCR module uses:

  • lcr_gw  – holds the gateways or endpoints where we can send our requests
  • lcr_rule – holds all the rules we will match against. Our area codes. 
  • lcr_rule_target – holds the rule to gateway matchings.

The most important table is the lcr_rule_target table. In this table, we take the ID of the rule from the lcr_rule table and connect it to the ID of the gateway we want all requests to go out of of it the request matches that rule.

For instance, if we setup a rule in the table that matches all request that start with 734 with an ID of 12, we can match that to a gateway ID in the lcr_rule_target table. So when a request comes in that starts with 734, it will be sent to that gateway.

For this example, we will be using 734 as the area code and 192.168.1.112 as the carrier. You can replace these values with your own in the steps below.

  1.   Login to MySQL
 # mysql -u root -p
  1.   Connect to the Kamailio DB
 mysql> use kamailio;
  1.   Let’s insert a gateway.
mysql> INSERT INTO lcr_gw (lcr_id, gw_name, ip_addr, port, uri_scheme, transport, strip, flags) VALUES (1, “Carrier1”, “192.168.1.112”, 5060, 1, 1, 0, 1);
  1.   Next let’s add an LCR rule.
mysql> INSERT INTO lcr_rule (lcr_id, prefix, stopper, enabled) VALUES (1, “734”, 1, 1);
  1.   Finally let’s add rule to gateway matching.
mysql> INSERT INTO lcr_rule_target (lcr_id, rule_id, gw_id, priority, weight) VALUES (1, 1, 1, 1, 1);

Repeat these steps for each of your carriers. Increase the weight for the carrier with the cheaper weight.

Testing Kamailio

Before we begin testing we need to make sure a few other things are in order. You’ll need to make sure that your ITSP knows you’re going to be sending traffic from your Kamailio IP address. You’ll also need a SIP phone pointed at Kamailio or have Kamailio setup as a trunk in a PBX.

With that said, we need to refresh what Kamailio has in memory. We can do this with:

# kamctl lcr reload

 

Now just call that area code from a phone and your call should go out of the carrier with the higher weight.