Simple Continuous Deployment System with Jenkins and Github
source link: http://www.linux-admins.net/2016/04/simple-continuous-deployment-system.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Simple Continuous Deployment System with Jenkins and Github
In this post I'll demonstrate a simple CD system, that based on a merge to the Master branch for a project on Github will package, push and deploy a small RESTfull application.
The setup consists of a single Jenkins server, a load balancer node running HAProxy and two API servers running Apache with the libapache2-mod-wsgi module to drive the Python Bottle microframework.
First let's create the local git repository:
[workstation]$ mkdir simple_rest_ci_pipline && cd simple_rest_ci_pipline [workstation]$ echo "# Simple RESTfull service" >> README.md [workstation]$ touch .gitignore [workstation]$ mkdir project [workstation]$ cat << EOF > project/restfullapi.py from bottle import route
@route('/<command>') def ping(command=None): if command.lower() == "ping": return "pong!" else: return "Unknown command"
@route('/') def main(): return "Simple RESTfull API: curl -X GET $URL/ping" EOF
[workstation]$ cat << EOF > project/restfullapi.wsgi import sys
sys.path.insert(0, "/var/www/restfullapi")
import bottle import restfullapi application = bottle.default_app() EOF
[workstation]$ git init [workstation]$ git remote add origin [email protected]:someuser/simple_rest_ci_pipline.git
Create a new project on Github, and deploy your public key to it:
Next, test that you can connect using the deployed SSH key and push to the Master branch:
[workstation]$ ssh -T [email protected] [workstation]$ git ls-remote -h [email protected]:someuser/simple_rest_ci_pipline.git [workstation]$ git add * [workstation]$ git commit -m "Initializing the repository" [workstation]$ git push -u origin master
[jenkins-n01]$ wget -q -O - https://jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add - [jenkins-n01]$ sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list' [jenkins-n01]$ apt-get update && apt-get -y install jenkins git [jenkins-n01]$ /etc/init.d/jenkins start [jenkins-n01]$ iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
[jenkins-n01]$ cd ~/jobs/RESTfull-CI-Pipeline [jenkins-n01]$ cat config.xml
<?xml version='1.0' encoding='UTF-8'?> <project> <actions/> <description></description> <keepDependencies>false</keepDependencies> <properties> <com.coravy.hudson.plugins.github.GithubProjectProperty plugin="[email protected]"> <projectUrl>https://github.com/kaivanov/simple_rest_ci_pipline/</projectUrl> <displayName></displayName> </com.coravy.hudson.plugins.github.GithubProjectProperty> </properties> <scm class="hudson.plugins.git.GitSCM" plugin="[email protected]"> <configVersion>2</configVersion> <userRemoteConfigs> <hudson.plugins.git.UserRemoteConfig> <url>https://github.com/kaivanov/simple_rest_ci_pipline.git</url> </hudson.plugins.git.UserRemoteConfig> </userRemoteConfigs> <branches> <hudson.plugins.git.BranchSpec> <name>*/master</name> </hudson.plugins.git.BranchSpec> </branches> <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations> <submoduleCfg class="list"/> <extensions/> </scm> <canRoam>true</canRoam> <disabled>false</disabled> <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding> <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding> <triggers> <com.cloudbees.jenkins.GitHubPushTrigger plugin="[email protected]"> <spec></spec> </com.cloudbees.jenkins.GitHubPushTrigger> </triggers> <concurrentBuild>false</concurrentBuild> <builders> <hudson.tasks.Shell> <command>PACKAGE_NAME="simple-restfull-api.deb" PACKAGE_VERSION=$BUILD_NUMBER API1="XXX.XXX.XXX.XXX" API2="XXX.XXX.XXX>XXX"
# Create the packe hierarchy and control file mkdir -p PACKAGE/DEBIAN mkdir -p PACKAGE/var/www/restfullapi
cat > PACKAGE/DEBIAN/control <<EOF Package: simple-restfull-api Version: $PACKAGE_VERSION Priority: optional Architecture: all Maintainer: Konstantin Ivanov Description: Simple RESTfull API EOF
cp $WORKSPACE/project/* $WORKSPACE/PACKAGE/var/www/restfullapi/
# Build the package dpkg-deb --build PACKAGE mv PACKAGE.deb $PACKAGE_NAME
# Deploy the package. rsync --rsync-path="sudo rsync" -vaz $PACKAGE_NAME $API1:/tmp ssh -o stricthostkeychecking=no -o UserKnownHostsFile=/dev/null $API1 "sudo dpkg --install /tmp/$PACKAGE_NAME && sudo service apache2 reload"
if [ "$?" -eq 0 ] then rsync --rsync-path="sudo rsync" -vaz $PACKAGE_NAME $API2:/tmp ssh -o stricthostkeychecking=no -o UserKnownHostsFile=/dev/null $API2 "sudo dpkg --install /tmp/$PACKAGE_NAME && sudo service apache2 reload"
if [ "$?" -ne 0 ] then echo "Error deploying to node2, aborting ..." exit 1 fi else echo "Error deploying to node1, aborting ..." exit 1 fi</command> </hudson.tasks.Shell> </builders> <publishers/> <buildWrappers> <hudson.plugins.ws__cleanup.PreBuildCleanup plugin="[email protected]"> <deleteDirs>false</deleteDirs> <cleanupParameter></cleanupParameter> <externalDelete></externalDelete> </hudson.plugins.ws__cleanup.PreBuildCleanup> </buildWrappers> </project>
Make sure you have the github plugin installed on Jenkins for this to work.
Lastly on the Github side, add a service that will call the Jenkins API when an event is triggered e.g. merge to Master:
[api-n01/02]$ useradd -m -s /bin/bash jenkins [api-n01/02]$ sh -c 'echo jenkins ALL=(ALL:ALL) NOPASSWD:ALL > /etc/sudoers.d/100-ci-users' [api-n01/02]$ apt-get update [api-n01/02]$ apt-get install apache2 [api-n01/02]$ apt-get install python-pip [api-n01/02]$ pip install bottle [api-n01/02]$ apt-get install libapache2-mod-wsgi [api-n01/02]$ cat << EOF > /etc/apache2/sites-available/000-default.conf <VirtualHost *:80> ServerName restfullapi-n01.example.net
WSGIDaemonProcess restfullapi user=www-data group=www-data processes=1 threads=1 WSGIScriptAlias / /var/www/restfullapi/restfullapi.wsgi
<Directory /var/www/restfullapi> WSGIProcessGroup restfullapi WSGIApplicationGroup %{GLOBAL} Order deny,allow Allow from all </Directory> </VirtualHost> EOF
[lb-n01]$ apt-get update && apt-get install haproxy [lb-n01]$ cat /etc/haproxy/haproxy.cfg global log /dev/log local1 log /dev/log local1 notice user haproxy group haproxy daemon
defaults log global mode http option httplog option dontlognull contimeout 5000 clitimeout 50000 srvtimeout 50000 errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http
frontend http bind :80 reqadd X-Forwarded-Proto:\ http default_backend http_nodes
backend http_nodes mode http balance leastconn option httpclose option forwardfor option redispatch option httpchk GET / cookie JSESSIONID prefix server api-n01 restfullapi-n01.example.net:80 check inter 1000 server api-n02 restfullapi-n02.example.net:80 check inter 1000
To test the simple RESTfull API run:
[workstation]$ curl -X GET http://restfullapi.example.net/ping pong!
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK