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.
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.
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.