What Is Continuous Integration?
Continuous integration generally consists of the following:
- Everybody works primarily from the same codebase (not separate branches)
- Code commits go into that main codebase that everyone is working in
- Each commit triggers an automatic build by a build server
- After the build, that build server also runs tests against the new and existing code
- Any errors are automatically reported to all or some of the developers (usually via email)
The basic idea behind continuous integration is every code check-in gets integrated immediately (so you do not have integration issues later – it’s a type of risk mitigation strategy). This integration is automatic, because the build server automatically builds and tests the code every time code is committed. This prevents integration issues later as long as developers do not ignore the emails or other notifications the build server issues when the code fails building or testing.
If the suite of tests is good, this greatly reduces the number of bugs that crop up in the code. In addition, every commit gets checked, so if something fails, you have much less code to check for issues. It is just within one commit.
We are going to explore Jenkins, which is continuous integration software. It provides a web interface for helping with continuous integration and continuous deployment.
The Basics of Jenkins
Jenkins, in a nutshell, is an automation tool. It provides a web interface on the server. This web interface shows ‘jobs’. A job is a task that can do pretty much almost anything you can do through a shell or command prompt in Windows/Linux. Generally, those jobs are involved in pulling down code, building code, testing code, and/or deploying code. However, they are not limited to just those things.
Jenkins also has the idea of pipelines. This is just breaking down the build/test/deploy/other steps of what needs to be done with your code into separate jobs (as opposed to doing everything within one job). Once one job is finished, you start another job. A normal pipeline might look like this:
- Build code (check code out of source repo then compile)
- Test (run unit tests/perhaps system tests)
- Deploy (package code/put in a container/put it on server)
We will be using Docker for this (although you can manually install it if you wish). For Docker installation instructions, visit my post here. We are going to be using a Linux machine (specifically Debian) to host Jenkins. Don’t worry if you need Windows as your build or test environment. In a separate post, we will cover setting up Jenkins nodes – separate machines (or Docker containers) – that will execute the Jenkins jobs.
So let’s get started!
1docker run -d -p 8080:8080 -p 50000:50000 --name jenkins -v ~/jenkins:/var/jenkins_home jenkins
- This downloads the jenkins container (from the Docker Hub registry) if you don’t already have it and runs it.
- Ports 8080 and 50000 within the container are mapped to ports 8080 and 50000 on the host machine.
- The container is launched in detached mode, which means you can exit the command prompt/terminal and it will still be running. You also don’t see the logs it generates.
- The container generated will have the name “jenkins”.
- The data in the /var/jenkins_home directory will be stored in your ~/jenkins directory (it creates the jenkins directory if it doesn’t already exist). This allows your plugins, jobs, and other Jenkins data to get saved. So restarting the container will not lose your changes.
- Navigate to localhost:8080 in a web browser, and you will see the following:
- To get the password, execute
1docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
- This launches the existing jenkins container and prints the output of the given file.
- That file contains the password for starting Jenkins.
- Alternatively, you can just open that file on your host computer. It should be in your ~/jenkins/secrets folder (based on the volume mapping we setup in the docker run command earlier).
- Put that password into the unlock Jenkins page.
- Install the suggested plugins (if you are behind a proxy, you may need to configure that before this will work).
- Create an admin user.
- You will then eventually come to the welcome page (see screenshot in the basics of Jenkins section).
- Congratulations! Jenkins is installed.
I am not going to explain very much about how to navigate Jenkins other than a few things you probably will have to do in the not-to-distant future.
In the upper left, you will see several links. The Manage Jenkins link takes you to a page that can configure the Jenkins installation itself. Things such as adding users, adding global variables, and installing plugins. (Jenkins has the ability to install plugins to add extra functionality.)
The other link you need to know about is the new item link. Type in a name (such as Example Job) and select Freestyle project. You will be taken to the following page.
There are several options for jobs.
- Source code management (checkout code from Git, Subversion, or others – may require some plugins to be installed)
- When to start this job (after a source code repo change, periodically, or others)
- Build steps (such as executing a command prompt or shell session)
- Post-build actions (such as an email notification)
This is the core of Jenkins – the useful stuff is done in these jobs.
Your First Jenkins Job
- Create a new item (freestyle project). Name it Example Job.
- Add a Build Step to “Execute shell”
- For the command, type in
1echo "Hello World"
- Click Save.
- You will now be on the Jobs (Project) view.
- Click the Build Now link.
- You should see a new link with a blue ball appear in the Build History section. Click it.
- You are now on the job instance page. Click the Console Output link.
- You see both the command (+ echo Hello World) and the result (Hello World).
- This is much more useful for, say, compiling, when the results of the compile are in the console output.
- Congratulations! You have successfully created and run your first Jenkins job!
In a future post, we will explore testing code with Jenkins using Docker containers. In particular, we will create a job that does the following:
- Check out code.
- Build code.
- Run unit tests against that code.
- Run static analysis tools against that code.
- Publish results.
At some point, we may even explore automated devops, an idea I read in a post from GitLab (https://about.gitlab.com/2017/06/29/whats-next-for-gitlab-ci/). Granted, my solution will be a subset of the vision they outline in that article. It will still be very powerful stuff though.
Was this useful? How could we expand on this approach to help out what you are doing?