Part 3: Getting started with Docker and Jenkins
Hi amigos. Welcome back! I hope your Vagrant machine is working correctly and is up and running along with your Jenkins server. If not go to the previous tutorial and come back when you have that going on. So ssh into your vagrant machine with vagrant ssh and lets start working.
In this tutorial we will go through the basics of Docker by building a container from scratch, then we will make a Dockerfile to build our Node app and see it working in our local environment. After that we will configure Jenkins to follow the steps we just made to automatize the process. Remember if you want me to dive more into an specific thing in the tutorial leave it in the comments and I can update it.
Before we start head over to Dockerhub and make a new account. And change the ouruser name in all the steps to your own Dockerhub username.
Docker has been receiving a lot of attention this past months. And it is because it pretty much rocks. Although Docker is not something terribly new and some may say it has its flaws. It is still a pretty interesting project that streamlined some pretty complex things.
So before we start, Docker has official tutorials (which are awesome) that you should definitely check out. I’ll touch base on some of the concepts from this tutorials but not all of them. This series of tutorials are just introductory. So for now, and if you want, take a look at this tutorials from Docker:
Ok lets start.
So first we have docker ps. This will let you see the docker container that are currently running. If you add the flag -a you will see all the docker containers that ran and then stopped. For now run sudo docker ps and you should see the Jenkins container.
I decided not to give sudo permission to Docker. But if you want to do so you can run sudo usermod -a -G docker vagrant Then ssh out and in again.
Now lets run our first Docker container. We will run a Dockerized Ubuntu that will remove itself when it finishes running that will echo “Hello World”.
So we run sudo docker run busybox /bin/echo ‘Hello world’. It will download the latest busybox docker image and run “Hello World”.
Now if we want to go inside the Docker container and use an interactive shell we will use the flags -it. An example would be sudo docker run -it busybox. You can exit by typing exit.
But if you run sudo docker ps you will see that only the Jenkins container is running and that is because the containers stopped after the process exits. You can verify by running sudo docker ps -a. If we wanted to make a container like a daemon a continue running we will add the flag -d.
For example we can make a container that echos “Hello World” like this sudo docker run -d busybox /bin/sh -c “while true; do echo hello world; sleep 1; done”. Then we run sudo docker ps to verify it is running and see the name of the container (In my case it is evil_archimedes, you can also use the Docker ID. So we can use sudo docker logs evil_archimedes and see it is printing “Hello World” to oblivion.
And to stop the container we would run sudo docker stop evil_archimedes. And to remove it completely use sudo docker rm evil_archimedes.
Now that we have a basic understanding of Docker commands lets start working with Docker images. First we will make a Docker image using commit and then using a Dockerfile.
For now lets run an official Node container, install nodemon and commit the changes. So lets make our new container with the following command sudo docker -it --name nodemon node:0.10 /bin/bash, this will make the container and in an interactive shell and run /bin/bash. The inside the container we just install nodemon npm install nodemon. After it finishes we exit the container. We learned a new flag here --name lets us specify the name of our docker container.
Then we commit the changes with sudo docker commit -m “Added nodemon” -a “Roberto Amador” nodemon ouruser/nodemon:v1
Then we can commit the changes using this command sudo docker commit -m “Added nodemon” -a “Roberto Amador” nodemon ouruser/nodemon:v1. Just like git -m lets us specify the commit message and -a the author of the commit. Then we tell to commit the changes made to nodemon as ouruser/nodemon:v1. Where ouruser/nodemon is the name of the new image and v1 is the tag. Then we can check our new image with the command sudo docker images.
Now we can use the new docker image as we please. Run this command to try it out sudo docker run -it ouruser/nodemon:v1 /bin/bash.
Using the docker commit command is a pretty simple way of extending an image but it’s a bit cumbersome and it’s not easy to share a development process for images amongst a team. Instead we can use a new command, docker build, to build new images from scratch.
To do this we create a Dockerfile that contains a set of instructions that tell Docker how to build our image. Here is my Dockerfile for the Node app.
FROM node:0.10 MAINTAINER Roberto Amador RUN mkdir -p /app WORKDIR /app ADD . /app EXPOSE 3000 CMD ["node", "app.js"]
FROM node:0.10 We specify from which docker image we want to work. In this case the official Node image.
RUN mkdir -p /app We will run this command inside the container. The command makes a new folder where our files will reside.
WORKDIR /app We will now make the default work directory the folder we just created. So every time we run something in this container it will run inside this folder by default.
ADD . /app ADD will copy the files we have on our local machine to the docker container.
EXPOSE 3000 Then we expose the port 3000 for Express to work
CMD [“node”, “app.js”] Then the default run command will be running node with our app as an argument.
And so, to build the first image with a Dockerfile we will run sudo docker build -t ouruser/hello-node:v0 /vagrant/app/
Cool!! We just built our first Node app image. Now we can run sudo docker run -d -p 3000:3000 ouruser/hello-node:v0 and a new container will start.
And we can see the result if we go to http://localhost:3000/
You can even try out and test the code in a new container and just delete it afterwards!! Just run sudo docker run -rm ouruser/hello-node:v0 ./node_modules/mocha/bin/mocha ./test/test.js. The --rm tag tells docker to delete the container after it has done its job. Pretty nifty when you just want to run something once and not keep the baggage.
And the final step is to upload the docker image to Dockerhub. Our online Docker image registry. Before we start make sure your account is active and log in into Dockerhub.
When that is done go to your terminal and inside your Vagrant machine log in to Dockerhub with sudo docker login and follow the instructions
So now lets verify by uploading our node app image to Dockerhub. To do this run sudo docker push ouruser/hello-node:v0
And now we can go check our profile in Dockerhub and see the new Docker container repo.
Now that we have the basics out of the way we pretty much are going to tell Jenkins to do the last steps everytime we want. Pretty straight forward. So if you go to http://localhost:8080/ you will go to the Jenkins server. Inside that server there is a Docker job already configured.
First lets see the configuration so it can use our Vagrant machine as our local node. Go to Manage Jenkins>Manage Nodes>Wrench in Local
The user and password for Vagrant is “vagrant”.
Now that the Node is configured go back to the main page and lets see what the Docker job does. Click Docker>Configure. There you will see a lot of configuration options. For the sake of simplicity I left it so that everytime that you want to build a new version you will have to click the Build Now button.
Go to the bottom of the page and look for the Build tab. In the first box you will see the same steps we just made minutes ago. We are only adding the $BUILD_NUMBER which is a Jenkins variable that keeps tabs on the latest build.
The second box will be covered more in detail on the next tutorial. It runs the Ansible playbook that will run the latest version of our container in an Amazon instance.
But anyway lets test it! Go back to the Docker job main page and click Build Now.
Now you will see that a new build has started. Build number 1. Click it and then go to the console output. It will do all the steps we just mentioned and it will fail at the Amazon step.
But the new Docker version will still be pushed to Dockerhub. It just created a new build, ran our tests on the new container and pushed it to the internet with just one button!! And the coolest thing is that you can make Jenkins start the build when, for example, you commit a change to the master branch in your git repository.
And that is all for now. Please look forward for the next and final part were we will make Ansible download and run our latest container in an Amazon instance!! See ya next time. If you have any suggestions or questions about this tutorial please leave it in the comments.