This cartridges is
developed for use in Apache Stratos. Which is
design and developed by WSO2 Inc. This is a PAAS environment lately donated to
Apache foundation by WSO2. In order to develop a cartridge I need an up and
running Stratos instance on top of Openstack. Openstack is
an IAAS provider that I’m using, you can use Amazon
EC2 as well.
Note : Refer this valuable article if you wanted to integrate Stratos with Amazon EC2.
CouchDB is
a database that completely embraces the web. Store your data with JSON
documents. Access your documents and query your indexes with your web browser,
via HTTP. Index, combine, and transform your documents with JavaScript. CouchDB
works well with modern web and mobile apps. You can even serve web apps
directly out of CouchDB. And you can distribute your data, or your apps,
efficiently using CouchDB’s incremental replication. CouchDB supports
master-master setups with automatic conflict detection.
Docker is an open platform for developers
and sysadmins to build, ship, and run distributed applications. Consisting of
Docker Engine, a portable, lightweight runtime and packaging tool, and Docker
Hub, a cloud service for sharing applications and automating workflows, Docker
enables apps to be quickly assembled from components and eliminates the friction
between development, QA, and production environments. As a result, IT can ship
faster and run the same app, unchanged, on laptops, data center VMs, and any
cloud.
Since this article is to develop a docker cartridge author believes that reader already configured Openstack with docker and Apache Startos on top of that. If not please follow these blog articles which is the best article that explain way of doing it.
- How to setup Openstack Havana
with Docker driver
- Docker Driver for
Openstack Havana
- Apache Stratos on
Openstack/Docker
After
configuration the architecture of Openstack with Docker should be like
this :
First
of all clone my github project of developed CouchDB docker cartridge.
$
git clone https://github.com/thushara35/startos-docker-couchdb-cartridge.git
This will create the below folder structure.
Note: Please ignore the .DS_Store files since it’s an auto generated
system file which we don't need to take care of.
Now
just open the cloned folder and open the Dockerfile in a text editor you
prefer.
FROM ubuntu:12.04
This command will download the ubuntu 12.04 cloud
image which is Im going to use for the creation of CouchDB cartridge.
ENV DEBIAN_FRONTEND noninteractive
Above command will hide debian related error
messages which generated in the docker build. It's better to comment this line
if using this for educational purposes. Ignore and comment above line if what
Im talking is like rocket signs.
Now we are done with the environment setting up,
it's time to install all necessary dependencies.
RUN apt-get -y update --fix-missing
UNIX
update will
download all the needed commands. --fix-missing
is to recheck whether there is any changes in the update.
RUN apt-get install -y openssh-server
RUN echo 'root:password' |chpasswd
RUN mkdir -p /var/run/sshd
These three lines are used to grant secure shell
access to docker instance when it is active.
stratos@Dev-PC:~$ ssh
root@10.11.12.2
The authenticity of
host '10.11.12.2 (10.11.12.2)' can't be established.
ECDSA key fingerprint
is 74:95:b3:5f:22:5a:dc:70:8c:ab:50:c8:45:65:77:9d.
Are you sure you want
to continue connecting (yes/no)? yes
Warning: Permanently
added '10.11.12.2' (ECDSA) to the list of known hosts.
root@10.11.12.2's
password: <password gave in line 24>Welcome to Ubuntu 12.04.5
LTS (GNU/Linux 3.11.0-26-generic x86_64)
the exact
distribution terms for each program are described in the
the exact
distribution terms for each program are described in the
* Documentation: https://help.ubuntu.com/
The programs included
with the Ubuntu system are free software;
individual files in
/usr/share/doc/*/copyright.
Ubuntu comes with
ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
root@instance-00000001:~#
Using above command in bold you can log into the
docker instance
Note: 10.11.12.2 is the private URL generated by
the openstack for the instance it might be different for you.
Let's add CouchDB stuff to the docker image.
To implement this I refer this github project which gives
me lot of insight of how to develop this cartridge.
RUN echo "deb
http://us.archive.ubuntu.com/ubuntu/ precise universe" >>
/etc/apt/sources.list
RUN apt-get install -y apt-utils g++
RUN apt-get install -y erlang-dev erlang-manpages
erlang-base-hipe erlang-eunit erlang-nox erlang-xmerl erlang-inets
RUN apt-get install -y libmozjs185-dev libicu-dev
libcurl4-gnutls-dev libtool wget
#
# Please
check the mirror is working or not.
#
RUN apt-get install -y make
RUN cd /tmp ; wget
http://mirror.nexcess.net/apache/couchdb/source/1.6.1/apache-couchdb-1.6.1.tar.gz
RUN cd /tmp && tar xvzf
apache-couchdb-1.6.1.tar.gz
RUN cd /tmp/apache-couchdb-* ; ./configure
&& make install
RUN printf "[httpd]\nport = 5984\nbind_address
= 0.0.0.0" > /usr/local/etc/couchdb/local.d/docker.ini
Now you’re done with
installing CouchDB, later you need to expose the port 5984 and run CouchDB
manually using a shell script, we will discuss it later in this article.
I actually don't know what's happening in line 30 obviously it is
appending the sources.list file,
that's all I know about that line.
Here we install all the dependents for CouchDB such as erlang which is the backbone of
CouchDB. apt-utils installed
due to an error which I faced during the development if you remove it you might
get the same error in the docker build.
Line 40 is a important milestone since here you have to choose which
CouchDB version you going to use and which mirror you going to use to download
it. Therefore you need to check by going to the CouchDB what is the most
preferred download mirror for you. If you want to download the 1.6.1 which is
the latest version use this link and copy and
paste the suggested mirror site in the line 40.
In line 42 docker build function will copy the downloaded apache-couchdb-1.6.1.tar.gz file to /tmp directory and will extract it there. As we
discussed earlier line 43 again download the make command to make the CouchDB
in that directory. End of the make
install process you are good to start CouchDB. In line 46, I'm binding my
localhost IP and the default port to run CouchDB to do this I needed to
edit /usr/local/etc/couchdb/local.d/docker.ini.
Next part is pretty straightforward installing most wanted UNIX
commands.
RUN apt-get install -y apache2
RUN apt-get install -q -y zip unzip
RUN apt-get install -q -y curl facter
nano vim
RUN apt-get install -q -y telnet
iputils-ping curl
These commands will be highly useful in the ssh
login to the instance. Therefore add any
other wanted commands. I used above shell commands throughout the
testing phase. This way developer save some time during the testing phase.
Now let’s install java and Apache Startos agent
ADD packs/jdk1.6.0_24.tar.gz /opt/
RUN ln -s /opt/jdk1.6.0_24 /opt/java
ADD
packs/apache-stratos-cartridge-agent-4.0.0.tgz /mnt/
This only takes 3 lines, in line 69 and 71
extracted versions of jdk1.6.0_24 and apache-stratos-cartridge-agent-4.0.0 will be pasted on opt
and mnt
directory respectively. ln in line 70
will copy the content in jdk1.6.0_24 to /opt/java folder.
We need to install ActiveMQ
which is the communication media for Apache Stratos agent and within the docker
instance. Actually activeMQ comes with Stratos agent and might be using older
versions of it, therefore we need to download the latest stuff and paste those
files in the packs/activem directory.
Here is the list of files we need :
activemq-broker-5.10.0.jar
activemq-client-5.10.0.jar
geronimo-j2ee-management_1.1_spec-1.0.1.jar
geronimo-jms_1.1_spec-1.1.1.jar
hawtbuf-1.10.jar
Now
let's copy these files to docker instance.
ADD packs/activemq/activemq-broker-5.10.0.jar
/mnt/apache-stratos-cartridge-agent-4.0.0/lib/activemq-broker-5.10.0.jar
ADD packs/activemq/activemq-client-5.10.0.jar
/mnt/apache-stratos-cartridge-agent-4.0.0/lib/activemq-client-5.10.0.jar
ADD packs/activemq/geronimo-j2ee-management_1.1_spec-1.0.1.jar
/mnt/apache-stratos-cartridge-agent-4.0.0/lib/geronimo-j2ee-management_1.1_spec-1.0.1.jar
ADD packs/activemq/geronimo-jms_1.1_spec-1.1.1.jar
/mnt/apache-stratos-cartridge-agent-4.0.0/lib/geronimo-jms_1.1_spec-1.1.1.jar
ADD packs/activemq/hawtbuf-1.10.jar
/mnt/apache-stratos-cartridge-agent-4.0.0/lib/hawtbuf-1.10.jar
This ADD only copy and paste the LHS file to RHS directory according to the given file name in RHS.
Note: Remove above activemq files from the
Dockerfile if you’re using the latest version of Stratos agent.
Now we need to configure Stratos agent by giving
the correct values for:
-Dmb.ip=MB_IP
-Dmb.port=MB_PORT
-Dthrift.receiver.ip=CEP_IP
-Dthrift.receiver.port=CEP_PORT
Which
is in stratos.sh file located in the in the extracted apache-stratos-cartridge-agent-4.0.0 bin directory. We are going to input those
configuration details in our stratos cartridge configuration json which is
included in my git repo.
Note:
Please left a comment in the end of the article if you have problems so far or
just ask it in stackoverflow
and paste the link in the comment section.
Now
we need to include some shell scripts which we are talk more in the later part
of this article. Here is the list of shell scripts that we are going to use:
init.sh
metadata_svc_bugfix.sh
run_scripts.sh
stratos_sendinfo.rb
couch_apps.sh
In
the next code segemt I'm just making new directories and copy paste above
scripts in /root/bin/, /usr/lib/ruby/1.8/facter/, /usr/local/bin/ and /usr/local/bin/
directories.
Some
lines is for giving the rights to execute shell scripts. Please google chmod
for more information. In this section I’m calling the shell script that creates
all the dependencies needed by 3rd party applications. For example I'm creating
folder structure needed for kleks in my docker file you can add files
you wanted to add in this section.
RUN mkdir /root/bin
ADD scripts/init.sh /root/bin/
RUN chmod +x /root/bin/init.sh
ADD scripts/stratos_sendinfo.rb
/usr/lib/ruby/1.8/facter/
ADD scripts/metadata_svc_bugfix.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/metadata_svc_bugfix.sh
ADD scripts/run_scripts.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/run_scripts.sh
Let's move to the
next section which is added to fix an error related to host entries. (I have no
idea why I add these files therefore I'm going to skip this part for now)
RUN mkdir p - /root/lib
RUN cp /lib/x86_64-linux-gnu/libnss_files.so.2
/root/lib
RUN perl -pi -e 's:/etc/hosts:/tmp/hosts:g'
/root/lib/libnss_files.so.2
RUN cp /etc/hosts /tmp/hosts
ENV LD_LIBRARY_PATH /root/lib
RUN locale-gen en_US.UTF-8
Will
explain this later.
Now
let's expose the port which simply means that open the port for public use.
This is a vulnerability which can't be tolerated.
EXPOSE 22
EXPOSE 80
EXPOSE 5984
For
example now only (after EXPOSE) you
can access above ports publicly.
And
last but not least the entry point for all of the shell scripts we included.
This is the starting point of the execution of shell script code.
ENTRYPOINT /usr/local/bin/run_scripts.sh
| /usr/sbin/sshd -D
Above
code means that just after stratos trying to spawn an instance execution within
the docker image will start from here, there for this will be the controller
shell script. Let’s start off with run_scripts.sh.
#!/bin/bash
LOG=/tmp/run-script.log
echo "run_script
started..." >> $LOG
echo "Starting /usr/local/bin/metadata_svc_bugfix.sh"
>> $LOG
/usr/local/bin/metadata_svc_bugfix.sh
echo "Ending
/usr/local/bin/metadata_svc_bugfix.sh" >> $LOG
echo "Starting
/etc/init.d/apache2 start" >> $LOG
/etc/init.d/apache2 start >
/dev/null 2>&1 &
echo "Ending /etc/init.d/apache2
start" >> $LOG
echo "Starting
/root/bin/init.sh" >> $LOG
/root/bin/init.sh > /tmp/init.log
echo "Ending
/root/bin/init.sh" >> $LOG
echo "Starting
/usr/local/bin/couchdb" >> $LOG
/usr/local/bin/couchdb couchdb >
/dev/null 2>&1 &
echo "Ending /usr/local/bin/couchdb"
>> $LOG
echo "Starting
/usr/local/bin/couch_apps.sh" >> $LOG
/usr/local/bin/couch_apps.sh >
/dev/null 2>&1 &
echo "Ending
/usr/local/bin/couch_apps.sh" >> $LOG
echo "Ending run_script..."
>> $LOG
echo " " >> $LOG
Above run_scripts.sh that I have created for
CouchDB. I added lot of echo's for debugging purposes. Altogether this script
is initiating 2 scripts (metadata_svc_bugfix.sh, init.sh) and 2 other processes which is apache server and CouchDB. You can find
the log file of the run script in /tmp/run-script.log.
It is in vain to describe each and every stuff here
onward if you reach this far that means your software developer that has a
basic knowledge about scripting. But those who are don't know, I would like to
explain some of it.
Let’s start with /dev/null
2>&1 & this UNIX command
is used to run the process as a background process and don't keep a track of
it. You might think what are these arrows are doing simply single arror(>) will create a new file or a instance as per the
RHS and the double arrows (>>) will append the exiting file which is in RHS.
Moving forward metadata_svc_bugfix.sh is an essential bug fix that I'm going to need for
this version of Apache Startos agent. Hopefully you can remove this bug fix (simply
remove the line from the run_scripts.sh) when using the future releases of
Stratos agent.
Now we can start the apache2 server using this run
script now it's time to set the Stratos agent configuration which is done using
init.sh. In the dockerfile that we
discuss earlier we copied and pasted this file in to specific directory.
#!/bin/bash
#
--------------------------------------------------------------
#
# or more contributor license agreements. See the NOTICE file
# regarding copyright ownership. The ASF licenses this file
# distributed with this work for additional
information
# to you under the Apache License, Version 2.0 (the
# with the License.
You may obtain a copy of the License at
# "License"); you may not use this file
except in compliance
#
#
http://www.apache.org/licenses/LICENSE-2.0
#
# "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY
# Unless required by applicable law or agreed to in
writing,
# software distributed under the License is
distributed on an
#
--------------------------------------------------------------
# KIND, either express or implied. See the License for the
# specific language governing permissions and
limitations
# under the License.
#
FIND=`which find`
perl -pi -e 's:/etc/hosts:/tmp/hosts:g'
/root/lib/libnss_files.so.2
export LD_LIBRARY_PATH=/root/lib
echo $LD_LIBRARY_PATH
MKDIR=`which mkdir`
UNZIP=`which unzip`
ECHO=`which echo`
GREP=`which grep`
#PUPPETD=`which puppet`
RM=`which rm`
XARGS=`which xargs`
SED=`which sed`
CUT=`which cut`
AWK=`which awk`
IFCONFIG=`which ifconfig`
HOSTNAME=`which hostname`
SLEEP=`which sleep`
TR=`which tr`
HEAD=`which head`
WGET=`which wget`
#echo "started creating launch-params and
stratos.sh agent " >> $LOG
AGENT="agent"
PUPPETAGENT="${PUPPETD} ${AGENT}"
#COMMAND="${PUPPETAGENT} -vt"
IP=`${IFCONFIG} eth0 | ${GREP} -e "inet
addr" | ${AWK} '{print $2}' | ${CUT} -d ':' -f 2`
LOG=/tmp/init-script.log
HOSTSFILE=/tmp/hosts
if [ ! -f
public-ipv4 ]
HOSTNAMEFILE=/etc/hostname
#PUPPETCONF=/etc/puppet/puppet.conf
#read_master() {
# ${COMMAND}
#}
is_public_ip_assigned() {
while true
do
wget
http://169.254.169.254/latest/meta-data/public-ipv4
then
read
-r ip<public-ipv4;
echo
"Public ipv4 file not found. Sleep and retry" >> $LOG
sleep
2;
continue;
else
echo
"public-ipv4 file is available. Read value" >> $LOG
# Here
means file is available. Read the file
echo
"value is **[$ip]** " >> $LOG
break
if [
-z "$ip" ]
then
echo "File is empty. Retry...." >> $LOG
sleep 2
rm
public-ipv4
continue
else
echo "public ip is assigned. value is [$ip]. Remove file"
>> $LOG
rm public-ipv4
fi
${WGET}
http://169.254.169.254/latest/user-data -O /tmp/payload/launch-params
fi
done
}
DATE=`date +%d%m%y%S`
RANDOMNUMBER="`${TR} -c -d 0-9 <
/dev/urandom | ${HEAD} -c 4`${DATE}"
if [ ! -d /tmp/payload ]; then
## Check
whether the public ip is assigned
is_public_ip_assigned
echo
"Public ip have assigned. Continue.." >> $LOG
${MKDIR} -p
/tmp/payload
INSTANCE_HOSTNAME=`sed 's/,/\n/g'
launch-params | grep HOSTNAME | cut -d "=" -f 2`
cp
/tmp/payload/launch-params
/mnt/apache-stratos-cartridge-agent-4.0.0/payload/launch-params
cd
/tmp/payload
SERVICE_NAME=`sed 's/,/\n/g' launch-params |
grep SERVICE_NAME | cut -d "=" -f 2`
DEPLOYMENT=`sed 's/,/\n/g' launch-params |
grep DEPLOYMENT | cut -d "=" -f 2`
#get user
parameters
CEP_IP=`sed 's/,/\n/g' launch-params | grep CEP_IP | cut -d
"=" -f 2`
echo
'MB_IP - '.$MB_IP >> $LOG
CEP_PORT=`sed 's/,/\n/g' launch-params | grep CEP_PORT | cut -d
"=" -f 2`
MB_IP=`sed
's/,/\n/g' launch-params | grep MB_IP | cut -d "=" -f 2`
MB_PORT=`sed 's/,/\n/g' launch-params | grep MB_PORT | cut -d
"=" -f 2`
#
print the collected data
echo
'CEP_IP - '.$CEP_IP >> $LOG
echo
'CEP_PORT - '.$CEP_PORT >> $LOG
echo
'MB_PORT - '.$MB_PORT >> $LOG
#replace variables with user parameters
sed
-i "s/MB_IP/$MB_IP/g" jndi.properties.template
cd
/mnt/apache-stratos-cartridge-agent-4.0.0/bin/
sed
-i "s/MB_IP/$MB_IP/g" stratos.sh
sed
-i "s/MB_PORT/$MB_PORT/g" stratos.sh
sed
-i "s/CEP_IP/$CEP_IP/g" stratos.sh
sed
-i "s/CEP_PORT/$CEP_PORT/g" stratos.sh
cd
/mnt/apache-stratos-cartridge-agent-4.0.0/conf
sed -i
"s/MB_IP/$MB_IP/g" jndi.properties
sed
-i "s/MB_PORT/$MB_PORT/g" jndi.properties
cd
templates
sed
-i "s/MB_PORT/$MB_PORT/g" jndi.properties.template
#start
stratos agent
cd
/mnt/apache-stratos-cartridge-agent-4.0.0/bin/;./stratos.sh > /tmp/agent.log
echo
"agent started..." >> $LOG
fi
# END
This script will fetch details from launch-params file which is located in /tmp/payload/launch-params, and then paste these extracted values into stratos.sh file located in /mnt/apache-stratos-cartridge-agent-4.0.0/bin/. Other than that if you look closely this script we are updating 2
other configuration files as well which is jndi.properties.template and jndi.properties.
Now you’re done with the agent configuration, it’s time to run CouchDB
in your Stratos docker instance. which is simply done using /usr/local/bin/couchdb couchdb
> /dev/null 2>&1 & line
of code.
Last we need to implement 3rd party dependencies that user (developer)
need to use.
couch_apps.sh
#######################
# Adding dependencies for couchApps
#######################
# for Kleks CMS
touch
/usr/local/var/lib/couchdb/kleks.couch
touch
/usr/local/var/lib/couchdb/static.couch
That’s the end of the long and boring how to develop a Stratos docker
couchdb.
Note:
Please left any questions in the comment section or just ask it in stackoverflow
and paste the link in the comment section.
Will
talk about how to configure CouchDB cartridge for use in Stratos in the next
article.
Thanks
and have nice day!
This blog is nice and very informative. I like this blog.
ReplyDeleteblog Please keep it up.