Recently my friend told me about good service of Continuous Integration: http:/semaphoreci.com. Using this service and bitbucket it is easy to create free CI system with autodeploy. Let me show how I did it.
Why do we need it?
I assume that the question “Why do we need CI?” is already answered. There is the list of advantages of such system below:
- Free.
- It doesn’t use you resources.
- It is cloud, so you are not responsible for stability.
And one constraint (unfortunately):
- Hundred builds limit per month. But it can be extended for money.
The problem description
When I was writing this post I didn’t need such system, I just wanted to try it. So I took one my old application that I had written in a hackathon and made CI to it. The git repository was on the bitbucket and the application was deployed in my server (VDS). I wanted my CI to do following steps:
- Build my project in jar
- Upload jar to my server
- Stop previous instance of the application
- Launch a new instance of the application
Solution
The semaphore service has one feature: every build uses a new absolutely clean virtual machine. That’s why I faced with two problems:
- Preparing environment before every build
- Keep artifacts
The first problem actually is not a problem, just run script before build. The second problem can be solved with the bitbucket. Look at the scheme:
In text form the it can be described like this (step by step):
- Semaphore detects push to master (other triggers are possible).
- Semaphore creates a virtual machine for build.
- Semaphore prepares environment for build with my script.
- Semaphore builds jar.
- Semaphore uploads jar to the bitbucket’s storage using bitbucket api.
- Semaphore uploads deploy-script to the deploy server using ssh.
- Semaphore launches this script using ssh.
- The script downloads jar from the bitbucket.
- The script stops old instance of the application.
- The script launches a new version of the application.
That’s it.
Scripts
To provide step 3 I have to prepare my environment. I need only gradle.
Step 4 is just building the project.
To do step 5 I need to add build number to the jar’s name and upload it:
Here is my gradle.properties which contains project’s name and version.
I’ve written two scripts: deploy.sh and kill.sh. Both of them must be launched in server. First one is responsible for deploy and the second one is responsible for stopping old instance and deleting old jar. The script below provides uploading these two scripts to my server.
Obviously the deploy.sh and kill.sh scripts are seldom changed, but I left such possibility for flexibility. Also the deploy.sh script accepts bitbucket credentials, build filename and launch port to be more flexible.
The deploy.sh script:
The kill.sh script:
kill.properties file is some kind of mail from current deployed to next version killer. It contains PID of current process and the name of old jar.
Conclusion
To investigate what I’ve done I collected statistics of deploy time and I’d like to present the best and the worst build:
Left one is the worst, right one is the best. The measure unit is seconds. The biggest part if time is spent on deploy (running deploy.sh). And the biggest part of this time my server downloads jar from the bitbucket. My build’s size is about 40 Mb.
You can see how strongly the duration of jar download changes. It means the connection speed between the semaphore and the bitbucket is volatile. Also it is seen that about 25% of whole time is spent on preparing virtual machine. The semaphore service has some internal cache that helps to decrease duration of this step. The build time (with downloading dependencies) is very stable.
Maybe my system seems to be too complicated, but it is flexible. It is possible to implement all what you want using semaphore CI. I definitely will use it in small non-commercial projects when I need to save money and resources.