Automatically Dockerize a Flask Project on Git Push with Jenkins

Last time I wrote a tutorial I showed how to build a Docker image out of a Flask project using your own Dockerfile. This time I will attempt to do this automatically every time I push new code into my master branch using Jenkins. If you haven’t had a chance to look at my previous tutorial, take a look here:
Jenkins, formerly Hudson, is the leading open-source automation server, and a favorite tool of the DevOps community. Today we’ll be using it as a CI/CD tool for our own Flask project. We will make it keep an eye on our GitHub repository, and build from the source code an image for us whenever there’s new code. I wouldn’t recommend doing this on every push, as a Docker image can be as big as .5GB, but maybe checking once a day, or twice a week, wouldn’t be so bad. We’ll go over how to do that as well.
For this tutorial I will be using the same Ubuntu 17.04 VM that I used on the previous tutorial, but you can use whatever you feel most comfortable with. Most commands should translate well to Mac or other Unix systems.
I will head to http://GitHub.com and create a new repository called jenkins-flask-tutorial and clone it to my home directory.
$ git clone https://github.com/AngelloMaggio/jenkins-flask-tutorial.git
Cloning into 'jenkins-flask-tutorial'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
We will place the code from our Flask project with the Dockerfile (if you don’t have these, follow the previous tutorial to make a sample project) inside our cloned folder.
Let’s commit and push the files to our git repository.
$ git add .
$ git commit -m "Added project files"
$ git push origin master
Alright, perfect, our project is ready. Now let’s install Jenkins.
I will show the steps for Ubuntu, but you can find downloads for all other OS right here.
First let’s add the repository key to our system:
wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -
Add the Jenkins repository entry to our /etc/apt/sources.list
$ sudo vim /etc/apt/sources.list
# Add this line:
deb https://pkg.jenkins.io/debian binary/
Update the local package index and install Jenkins
sudo apt-get update
sudo apt-get install jenkins
Alternatively, and probably better for testing, you can set it up inside a Docker image.
$ docker run -d --name jenkins -p 8080:8080 jenkins:2.7.2
After a little installing Jenkins should be running on port 8080. So let’s head to http://localhost:8080
and we should see something like this:

So let’s navigate to this file and get the password sudo cat /var/lib/jenkins/secrets/initialAdminPassword
and put it into that field.
If you are using Docker you can find it using the logs, or by going into your container’s bash and finding the file.
$ docker logs -f jenkins
Continue with the installation and install the suggested plugins. Jenkins has a ton of plugins and a great community, in future tutorials we’ll go over them but check what’s available here.
Fill in your username, password, and other information, and we’re ready to go!


We will start by clicking on create a new job and choosing Freestyle project. I named my job flask-docker-jenkins, but naming is up to you. Then under Source Code Management choose Git, fill in the repository URL, and add your credentials. For the URL field use the URL you would use to clone your repository.


Under Build Triggers we will select Poll SCM, which means that it will check our Source Code Management system, which in this case is Git. In the schedule build is where we specify how often do we want this to happen using what is known as cron expressions. You don’t have to know how to make them by heart, this is a good tool that makes them for you:
For this example, we want to build as soon as we push, so we will make our Jenkins poll every minute of every hour of every day of every week of every month, or in cron expression, * * * * *
.

Now under Build we will Add build step, and select Execute shell. It does exactly what it sounds like, it grabs a command and executes it. We can use the same command we use to build the Docker image last time:
docker build -t my-flask-image:latest .

And we Save! Now, if we hit build we might run into a small error that will seem familiar
Cannot connect to the Docker daemon. Is the docker daemon running on this host?
This meant that the user didn’t have the right permissions, so we have to add the user jenkins to the group docker
sudo usermod -aG docker jenkins
Now we restart, and try to build. It should show the image building process

And we got our image!
If we run docker images
we should see the fruit of our effort. Try running the image and making sure it works.
Now it’s time to make some changes and try pushing our changes!
Let’s commit our changes and push and see if Jenkins notices!
If you have auto refresh, or if you manually refresh the page you should soon see a new build job pop up, first as pending, and then it will start working

And if we run docker images
again, we’ll see our latest image.
This might not be the best way to automatically build Docker images through Jenkins. There are great plugins out there, and encourage everyoen to check them out, but this is quick and it works right out of the box and without the need of any extra plugins.
While looking at the images you might notice that one of the flaws is that the name and tag are overwritten, and the other image becomes nameless and tag-less. These images are called dangling images. To clean up and save disk space since Docker doesn’t have its own garbage collection, we can add to our build command the following line
docker rmi $(sudo docker images -f "dangling=true" -q)
or you can manually run it periodically to remove the dangling images. Read more about these images here:
And that’s it! We have a working automatic system to build our docker images every time we push. Maybe doing the Git check monthly or weekly will be best, but that’s up to you now. Hope this helped at least!