All posts by nschoonover

Building a Kamailio Docker image

In this tutorial we will go over how to create a Dockerfile for Kamailio and build our own Kamailio image. If you want to learn more about Dockerfile’s you can read through our other post on creating a Dockerfile.

Setup Dockerfile

  1. First thing we need to do is create a new directory for our Dockerfile.
mkdir docker_kamailio
  1. We then need to make our Dockerfile.
touch docker_kamailio/Dockerfile
  1. Next, open up the Dockerfile with your favorite editor so we can start building.
vim docker_kamailio/Dockerfile

Installing Kamailio

  1. We will be installing Kamailio on a CentOS 6 container. First thing we need to do is specify what docker image we want to start with. Add the following to your Dockerfile.
FROM centos:6
  1. Next, we need to add the Kamailio 4.4 Open Build Service repository to our yum.repos.d list.
RUN yum -y install wget
RUN wget -O /etc/yum.repos.d/home:kamailio:v4.4.x-rpms.repo
RUN yum -y update
  1. Now that the Kamailio 4.4 repository is added to our system, it is time to install the kamailio packages. For simplicity of running the whole Kamailio stack on one container, we will be using SQLite as our back end database.
RUN yum install -y kamailio kamailio-debuginfo kamailio-utils gdb kamailio-sqlite

Setting up kamctlrc

We need to configure kamctlrc to use SQLite and to not prompt us during the database creation.

  1. Set the DBENGINE, DBHOST, and DB_PATH.
WORKDIR /etc/kamailio/

RUN echo "DBENGINE=SQLITE" >> kamctlrc
RUN echo "DBHOST=localhost" >> kamctlrc
RUN echo "DB_PATH="/usr/local/etc/kamailio/kamailio.sqlite"" >> kamctlrc
  1. Next, we ne need to specify the following options so that kamdbctl won’t prompt us during the database creation.
RUN echo "INSTALL_EXTRA_TABLES=no" >> kamctlrc
RUN echo "INSTALL_PRESENCE_TABLES=no" >> kamctlrc
RUN echo "INSTALL_DBUID_TABLES=no" >> kamctlrc

Creating Back End Database

  1. SQLite requires a file it can write the database to. We need to make a directory and file, which was already specified in the DB_PATH variable added to the kamctlrc file.
RUN mkdir /usr/local/etc/kamailio
RUN touch /usr/local/etc/kamailio/kamailio.sqlite
  1. If all the settings in kamctlrc are correct, and /usr/local/etc/kamailio/kamailio.sqlite exists, we should be able to create the Kamailio Database without any prompts interrupting our automated build.
RUN /usr/sbin/kamdbctl create

Running Kamailio

  1. Add the following kamctl command to create a user for testing.
RUN kamctl add opensourceisneat
  1. Next, we need to specify which ports to expose. Because Kamailio does not handle media, we only need to open up port 5060 for SIP.
EXPOSE 5060/udp
  1. Finally, we need to specify what command to run when the container is started up
CMD["/usr/sbin/kamailio", "-m 64", "-M 8", "-D"]

Finished Dockerfile

Now that we have a finished Dockerfile, you can exit out of your editor, saving any changes. The file should look something like this.

FROM centos:6

RUN yum -y install wget
RUN wget -O /etc/yum.repos.d/home:kamailio:v4.4.x-rpms.repo
RUN yum -y update
RUN yum install -y kamailio kamailio-debuginfo kamailio-utils gdb kamailio-sqlite

WORKDIR /etc/kamailio/

RUN echo "DBENGINE=SQLITE" >> kamctlrc
RUN echo "DBHOST=localhost" >> kamctlrc
RUN echo "DB_PATH="/usr/local/etc/kamailio/kamailio.sqlite"" >> kamctlrc
RUN echo "INSTALL_EXTRA_TABLES=no" >> kamctlrc
RUN echo "INSTALL_PRESENCE_TABLES=no" >> kamctlrc
RUN echo "INSTALL_DBUID_TABLES=no" >> kamctlrc

RUN mkdir /usr/local/etc/kamailio
RUN touch /usr/local/etc/kamailio/kamailio.sqlite

RUN /usr/sbin/kamdbctl create

RUN kamctl add opensourceisneat

EXPOSE 5060/udp

CMD ["/usr/sbin/kamailio", "-m 64", "-M 8", "-D"]

Building and running the new image

  1. Build the image using the docker build command. This will build an image called dopensource/kamailio4.4.
cd docker_kamailio
docker build -t dopensource/kamailio4.4 .
  1. Run a Kamailio container to test out our new image. Remember to map the SIP port to your docker host.
docker run -dit -p 5060:5060/udp dopensource/kamailio4.4
  1. You should now be able to register a softphone to your new Kamailio instance. Because we mapped 5060 to 5060 on the Docker host, you will be using your Docker host’s ip address for registration.
User ID: 1000
Password: opensourceisneat

Publishing Docker Image to the Docker Hub

In this tutorial we will go over how to publish an image you have created to the public docker hub. You will need to create a docker hub account to continue.

Login to your Docker Hub account on your docker host.

Simply execute the following and input your credentials:

docker login

Create Repository

One of docker’s advantages is it’s git like work flow. If you are a git user, this process should look familiar. We will need to create a repository on the Docker Hub. This can be done by logging into the Docker Hub, hitting create repository, and filling out the necessary information. For simplicity, I named my repository the same as our image from the previous tutorial (nginx). You will need to change dopensource to whatever your account name is.

Screen Shot 2016-05-01 at 3.57.02 PM

Push image to repository.

You will need an image on your system to push to the Docker Hub. If you followed our previous tutorials, you should have an nginx image built on CentOS 7.

  1. Print local docker images available:
    docker images

    Screen Shot 2016-05-01 at 3.59.22 PM

  2. Now, push the dopensource/nginx image to our docker repository.

    docker push dopensource/nginx
  3. Pull your public image

    You should already have your image on your docker host, as that is where you created it from. You can either delete the local image, or try pulling from another host.

    docker rmi -f dopensource/nginx

    Now pull your public image to confirm everything is working as intended:

    docker pull dopensouce/nginx

    You should now have a runable nginx container on your system.

Creating a Docker file

The recommended way to create images for sharing is from a docker file. A docker file is essentially a script which can recreate the building of your image. We will go over how to create one for nginx on CentOS in this tutorial.

Creating the docker file.

It is recommended that each docker file is contained in a separate directory. This will help keep everything organized and give you a place to store any extra files if needed.

  1. Create a new directory for your docker build file.
    mkdir nginx_docker
  2. Create the docker file
    cd nginx_docker
    vim Dockerfile

Dockerfile format

The dockerfile format is fairly straightforward. Each line has an instruction and argument. You can read more about instructions and arguments in the dockerfile reference documentation

In this tutorial we will be using the following instructions:



The FROM instruction specifies the base image to use as a foundation to our new image. In our example, we will be using the official CentOS image from our previous tutorials. The FROM instruction needs to be the first instruction in your Dockerfile, as it is the environment all subsequent instructions will be ran in.

  • Add the following to the beginning of your Dockerfile to use the official CentOS 7 image from the Docker Hub.
    FROM centos:7


The RUN instruction will run a command in your image environment. By default, any arguments will be ran in shell. Each argument is technically passing the following command to the environment.

/bin/sh -c <argument>
  • We need to run the necessary commands to install nginx on our CentOS environment. This will include:
    • Installing epel-release
    • Updating to notify yum of the new repository
    • Installing nginx.
  • Add the following to your Dockerfile on the line after the FROM instruction:
    RUN yum -y install epel-release
    RUN yum -y update
    RUN yum -y install nginx


The ADD instruction copies files to the image’s file system. This is useful for adding configuration files, scripts, or any other files needed in your environment. We will create a sample html file to add to the nginx root directory.

  • First we will need to create a basic html file in our Dockerfile directory.
    printf "<header>\n <h1>Docker ADD is neat</h1>\n</header>" > html
    • This will create a file called html, and show look like this:
     <h1>Docker ADD is neat</h1>
  • Add the following to your Dockerfile on the line after the last RUN instruction:
    ADD index.html /usr/share/nginx/html/index.html


The EXPOSE instruction tells docker which network ports the container will listen on. We are setting up an http server, so we will need to have the container listen on port 80/tcp.

  • Add the following to your Dockerfile on the line after the ADD instruction:
    EXPOSE 80/tcp


Finally, we need to tell docker what command to run when the container is started up with the CMD instruction. The argument for this instruction will differ depending on what application you want your container to run. In this example, we will start nginx in non-daemon mode, so that when we attach to the running container, we will see the nginx console.

  • The CMD syntax is as follows:
    CMD ["executable","param1","param2"]
  • Add the following to your Dockerfile after the EXPOSE instruction:
    CMD ["nginx", "-g daemon off;"]

Finished Dockerfile

When you are finished, your docker file should look something like this.

FROM centos:7
RUN yum -y install epel-release
RUN yum -y update
RUN yum -y install nginx
ADD index.html /usr/share/nginx/html/index.html
EXPOSE 80/tcp
CMD ["nginx", "-g daemon off;"]

Building the Image

Now that we have a docker file and any needed files in our directory, it is time to build the image. From within the docker file directory, execute the following:

docker build -t dopensource/nginx .
  • This will run each instruction in your docker file sequentially, and create a local docker image called dopensource/nginx.
    • You will see each instruction executed in your console, which is very helpful for debugging any issues with your build file.
  • Here is what the end of my build process looks like.

Screen Shot 2016-05-01 at 3.23.28 PM

Running your new image.

Now that you have built your image, it is time to run the image as a new docker container. Remember, we will need to expose port 80 in our run command and specify which port on the host to bind to.

docker run -dit -p 8081:80 dopensource/nginx
  • This will run our new image, and bind the container’s port 80 to our host’s port 8081.
    • Browse to your docker hosts ip adress, specifying port 8081. You should see the basic html header we created prior.

    Screen Shot 2016-05-01 at 3.22.40 PM


Accessing Docker containers over the network

Run the container so that it can be reached on port 80

  1. The ports a container can be accessed on are determined when the container is initially ran with the -p flag.
    • The following command will run our image created in the previous lab and forward traffic on port 8080 of our host to the docker container on port 80. You can get your image name with docker images. If you followed our example prior, the image name will be dopensource/nginx.
    docker run -dit -p 8080:80 <image name>
  2. Your container should now be bound to port 8080 on your host system.
    • Try opening up a browser and typing in http://:8080
    • You should see the default nginx page, which is being served by the nginx container we created earlier.


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


  • 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.


  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.


  • 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.


  • 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


  • 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


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