blog.stj.io

About

Building QEMU images using Jenkins and Packer

Requirements

  • Codebase tracked in git where there is access to commit hooks
  • (2) Linux hosts (vm, vps, raspbery pi, etc.)

Note: This can all be done on one server, but the goal of this configuration was to have a central Jenkins master distribute jobs to remote builders. The remote builders can have different capabilties, and therefore handle different workloads.

Host 1

Jenkins Agent configuration

The first server to configure will be the one that builds the QEMU images. It needs to fulfill all software and configuration requrements to perform its builds. In this case that will be Packer, as well as the QEMU and KVM tooling and libraries to build the images. Java will also need to be present so Jenkins can perform node configuration and orchestrate jobs.

Dependencies

  • Packer
  • qemu-kvm
  • openjdk-8

User configuration

Jenkins will connect using SSH. The user it connects to should have all the privileges necessary to complete the builds, and no more.

Host 2

Jenkins Master configuration

Dependencies

  • Docker

Jenkins Master setup

The intitial setup of the Jenkins master is outside the scope of this post. Full setup and and configuration documention is available on the jenkinsci/docker GitHub repo, and a walkthrough of the procedure is provided in the Jenkins installation documentation.

Add Jenkins agent

The build machine configured in the previous section will need to be added as an agent.

Manage Jenkins > Manage Nodes > New Node

Pick a name and set it as a permanent agent.

Labels are a great way to set the capabilities of the agent. These labels can be used in Jenkinsfile configurations to designate nodes which can build the project.

Labels used: kvm packer packer-qemu qemu

Code

Jenkinsfile

The pipeline will be configured in a Jenkinsfile.

There is a label attribute, which will choose an agent to build the project, based on which agents have the same label. All builds of this Jenkinsfile to be run on a machine with a matching label.

In this project, a node with both packer and qemu is required. The agent has this capabiltity, and was tagged packer-qemu, above. Once setting this in the Jenkinsfile, only agents with this tag will be eligible to run this job.

File: Jenkinsfile

pipeline {
    agent { label 'packer-qemu' }
    stages {
        stage('Build') {
            steps {
                echo 'Building..'
                sh './bin/build'
            }
        }
    }
    post {
        always {
            archiveArtifacts artifacts: 'dist/**/*.gz', fingerprint: true
        }
    }
}

Add the Jenkinsfile.

./packer-templates-linode
├── README.md
├── LICENSE
├── Jenkinsfile
├── alpine
└── bin
   └── build

Git configuration

Git hooks

Jenkins needs to know when to check for updates. This can be configured on a schedule, but can also be triggerd by sending a GET request to the Jenkin master’s /notifyCommit endpoint. It accepts a url query parameter that should match the git repository’s url set on the Jenkins master.

Jenkins git repo url config

Git can run scripts which are triggered by actions taken on the repository. The post-receive hook (git hook docs) is a good place to run a script which notifies Jenkins that changes have been made.

File: .git/hooks/post-receive

#!/bin/sh

curl http://${JENKINS_MASTER}:8080/git/notifyCommit?url=${GIT_SSH_USER}@${GIT_SSH_HOST}:stjacobs/packer-templates-linode.git

I personally use gogs, which allows post-receive hooks to be configured through the web interface. This can also be configured with post-commit hooks locally.

Gogs Git post-receive Jenkins hook

Now, once a branch is pushed, the Jenkins master is notified about the change. This can be seen in the final remote: output.

$ git push origin distro/alpine
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 1.13 KiB | 1.13 MiB/s, done.
Total 4 (delta 1), reused 0 (delta 0)
remote:   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
remote:                                  Dload  Upload   Total   Spent    Left  Speed
remote: 100   145  100   145    0     0   8303      0 --:--:-- --:--:-- --:--:--  8529
remote: No git jobs using repository: gogs@stevenja.co:stjacobs/packer-templates-linode.git and branches: 
remote: Scheduled indexing of packer-templates-linode
To https://git.stevenja.co/stjacobs/packer-templates-linode.git
 * [new branch]      distro/alpine -> distro/alpine

This will automatically trigger a Jenkins build.

This is just a screenshot of a successful Jenins build. Not the git push from above.

Jenkins Build Success


  • Tags:
  • git
  • qemu
  • packer
  • docker
  • jenkins
  • continuous-delivery