Continuous Delivery with Jenkins, Docker and Ansible
I like the DevOps philosophy as I think that every developer must have a broad knowledge of the ecosystem around him/her. In this article I will show how I tested a Continuous Delivery ecosystem for my personal FullStack projects.
Warning: This is not a tutorial and is not definetely easy for people who doesn’t have a initial understanding con Continuous Integration with Jenkins, Docker or Ansible (althought this last could be covered with knowledge in Puppet, Chef or any other orchestator).
More Warning I deserve some pain because I’m not concerned about security in this article. Yes, I know, I’ll drink beer until I get a hangover as punishment xD
It’s going to be fragmented in 3 parts:
- Part one: The Nodejs project and making a Docker with it in our machine
- Part two: Automating redeploy of the Docker container in a remote machine
- Part three: Redeploy using Jenkins and Ansible when our master branch has changed
Part one: The Nodejs project and making a Docker with it in our machine
The Nodejs Project
I have simplified the project to the maximum and it’s going to be a very simple Node project that simply shows a message on the screen on plain text. The “projet” is available inhttps://github.com/sayden/simplest-express-server
Installing Docker on our machine
First we have to install Docker in our machine for the first tests:
# Red had based distribution
sudo yum install -y docker
# Debian based
sudo apt-get install -y docker
We’ll use an image from docker.io called
docker.io/node:4
which refers to the 4.2.3
LTS version. The Dockerfile has this “base” container and will simply git clone
a repo an expose the 3000 port (the one in use for this specific “app”)FROM node:4
# Arguments
ENV REPO="https://github.com/sayden/simplest-express-server.git"
ENV DEST=/srv/node-server
ENV APP=${DEST}/server.js
# Ensure git is installed
RUN apt-get install -y git
# Clone the github repo
RUN git clone ${REPO} ${DEST}
# Go to cloned folder
RUN cd ${DEST} && npm install
# Expose app port
EXPOSE 3000
# Launch app
CMD ["sh", "-c", "cd ${DEST} && npm start"]
Building Docker image
So let’s build the image.
# As root
docker build -t mariocaster/node-server .
Take a look at the last “.” in the command as it points to the folder with the previous Dockerfile
Running Docker image
Once we have the image build and we can see it using
sudo docker images
it’s time to run it# As root
docker run -d -p 41600:3000 mariocaster/node-server
With-p 41600:3000
we are telling Docker that if we access in our machine to the 41600 port it will redirect us to the 3000 in the container, the one with the node server
Part two: Automating redeploy of the Docker container in a remote machine
Installing Docker on remote host
I’m going to use a VirtualBox virtual machine with Centos 7 installed running on 192.168.1.39 in my case. This machine is going to be called THE_HOST.
First we need to get password-less access to the machine so I use
ssh-copy-id
to pass a public key in my ~/.ssh
folder to THE_HOST. I have a handy bash script to gain access because I never remember the exact syntax:BONUS: Gaining SSH access to the machine.
#!/bin/bash
# gain-ssh-access
echo -e "\n"
if [ "$1" = "-i" ] ; then
echo "Using interactive mode"
echo -e "Write the name of the remote user: \c"
read user
echo -e "Write the host Ip or name: \c"
read host
echo "A public key from ~/.ssh/id_rsa.pub will be used"
echo "Remote machine will probably ask for permissions password"
ssh-copy-id -i ~/.ssh/id_rsa.pub $user@$host
else
echo "You can use interactive mode with -i flag"
echo "Use ssh-copy-id command if not. example:"
echo "ssh-copy-id -i ~/.ssh/id_rsa.pub user@host"
fi
echo -e "\n"
Once we have access, I have another “handy” Ansible Playbook to install Docker on THE_HOST. The script is the following:
# add-docker.yml
- host: all
become: yes
become_method: sudo
tasks:
- name: Add Docker
yum: name=docker state=present
- name: Add python-docker-py
yum: name=python-docker-py state=present
- name: Docker service must be started
service: name=docker state=started
Of course, in my ansible
hosts
file I have the proper user and password configuration for the machine# hosts
[local]
192.168.1.39 ansible_sudo_pass=osboxes.org ansible_ssh_user=osboxes
So I can launch the command like this:
ansible-playbook -i hosts add-docker.yml
Adding the Dockerfile and launching it
We have an Ansible task to add the Dockerfile to THE_HOST. Then we have a Playbook that will copy it and build or restart the container.
- hosts: all
become: yes
become_method: sudo
vars:
# For handlers/restart-docker.yml
http_port: 3000
host_port: 41600
# Shared here and in handlers/restart-docker.yml
image_name: mariocaster/node-server
# Dockerfile to use and destination in target's machine
source_dockerfile_dir: /path/to/Dockerfile
docker_dest_dir: /srv/docker
git_repo: https://github.com/sayden/simplest-express-server.git
tasks:
- name: Copy Dockerfile to server
copy: dest={{ docker_dest_dir }} src={{ source_dockerfile_dir }}
- name: Re/build Docker image
docker_image: name={{ image_name }}
path={{ docker_dest_dir }}
nocache=yes
state=build
notify: Restart Docker image
handlers:
- name: Restart Docker image
docker: name=node ports={{ host_port }}:{{ http_port }} image={{ image_name }} state=reloaded
Ok, very easy. Copy the Dockerfile, builds the image and restart (or start for the first time) the container.
If we access in our machine to
0.0.0.0:41600
we’ll see our server running.Redeploying with one line
We can reuse our Ansible Playbook to redeploy the server as many times as we want, we must simply run the same Playbook again. You can try, if you are using your own git repo, to push some change and launch the same script again to see how “magically” changes.
Part three: Redeploy using Jenkins and Ansible when our master branch has changed
Ok, now we can redeploy as many times as we want. So now we must configure Jenkins to redeploy the container every time it finds (via polling) any change in the git repo.
There’s nothing very special in the Jenkins job. We’ll simply execute the redeploy Ansible Playbook. As there are thousands of tutorials about how to trigger Jenkins on Git push (via polling or git hook) I’ll not enter on it but I leave here a handy tutorial about it:http://www.nailedtothex.org/roller/kyle/entry/articles-jenkins-gittrigger
Also, you can use the Jenkins Ansible Plugin if you want https://wiki.jenkins-ci.org/display/JENKINS/Ansible+Plugin but I have to say that I feel very comfortable with bash scripts and I usually prefer to write my own scripts so here’s the one I used to redeploy the container:
export ANSIBLE_PLAYBOOKS=/var/local/jenkins
ansible-playbook -vvvv ${ANSIBLE_PLAYBOOKS}/rebuildDocker.yml -i ${ANSIBLE_PLAYBOOKS}/hosts
Needless to say thatjenkins
user must have ssh access too to THE_HOST as well as to the Ansible Playbook and Ansible hosts file
Notes about this last part: I don’t enter too deep into Jenkins configuration because, as I said at the beginning of the article, users that are trying to achieve Continous Delivery in their project must have some background knowledge in advance about some tools as this is not a “tutorial” about a tool but more like a “full solution” using various tools available (not necessarly the best).
0 comentarios:
Publicar un comentario