How to install and run a dockerized Jenkins CI with webhook support

By Karolis Rusenas · Jan 21, 2022

Jenkins is an extremely popular automation server that can run tests, build and publish software, or perform pretty much any other user-defined action. Docker, on the other hand, is quite a focused tool; it’s used to package software into containers and run them. This makes Jenkins and Docker a good pair when testing, shipping and deploying things.

In this tutorial, you’ll see how easy it is to install and run a modern, all-in-one dockerized Jenkins with Synpse which provides:

  • Rock-solid deployment with persistent storage
  • Webhook delivery to the server to trigger build jobs without public IP or domain
  • Secure remote SSH access to the server without exposing it to the internet

We will split this article into several sections - installation, administration, and webhook configuration. Let’s get started.

Jenkins with Synpse and WHR

Prerequisites

Webhook Relay and Synpse have paid tiers with increased quotas and support plans; however a free tier should be enough for setting this up.

  • Webhook Relay account - free tier should be enough for setting up homelab or testing
  • Synpse account - remote device management, free up to 5 devices (definitely enough for Jenkins!)
  • Linux server, ideally Ubuntu, however other distros should work as well
  • Docker - installed on the server

Installation

First, install the Synpse agent on your server. You can view installation instructions here https://docs.synpse.net/agent/install/linux-docker. This will provide us with lightweight deployment capabilities. Once installed, add the label type: controller to that device in your Synpse dashboard.

Synpse devices

Next, let’s create an application that will run on the server:

name: jenkins
description: CI/CD server
scheduling:
  type: Conditional
  selectors:
    type: controller
spec:
  containers:
    - name: jenkins
      image: jenkins/jenkins:lts
      user: root
      privileged: true
      ports:
        - 8080:8080
        - 50000:50000
      volumes: # Persistent volumes
        - /data/jenkins-compose:/var/jenkins_home
        - /var/run/docker.sock:/var/run/docker.sock

This will download the image and start the container. Once it shows up as ready, open the http://device-ip:8080 address. You will then require an initial admin password, found through Synpse inbuilt web SSH terminal:

getting the token

Enter your initial admin password and proceed with the plugin installation:

getting the token

You should also setup Jenkins agents to do the heavy work as they can just be additional containers either in the same application spec or separate applications that Jenkins server connects to but we will explore that route in a separate blog post.

Webhooks Without Public IP or Domain

It’s important to be able to receive webhooks without exposing our Jenkins server to the internet. For this, we will need to deploy a container next to the Jenkins server which will help with request forwarding.

Let’s start by getting the tokens from https://my.webhookrelay.com/tokens and creating two secrets in Synpse named webhookrelayKey and webhookrelaySecret that contain your authentication tokens. Then, go to https://my.webhookrelay.com/buckets page and create a bucket named jenkins. Now, we can add the new container to the Jenkins server app:

name: jenkins
description: CI/CD server
scheduling:
  type: Conditional
  selectors:
    type: controller
spec:
  containers:
    - name: jenkins
      image: jenkins/jenkins:lts
      user: root
      privileged: true
      ports:
        - 8080:8080
        - 50000:50000
      volumes: # Persistent volumes
        - /data/jenkins-compose:/var/jenkins_home
        - /var/run/docker.sock:/var/run/docker.sock
    # Webhook Relay forwarding container. This container allows
    # us to receive the webhooks that are hitting public server endpoints
    - name: webhookrelay
      image: webhookrelay/webhookrelayd:latest      
      env:
        - name: RELAY_KEY
          fromSecret: webhookrelayKey
        - name: RELAY_SECRET
          fromSecret: webhookrelaySecret
        - name: BUCKETS
          value: jenkins

Click save and after a few seconds we should see two containers running:

whr container


Configuring Jenkins Plugin

The easiest way to start receiving GitHub webhooks is by using this plugin https://plugins.jenkins.io/github. To install:

  • Go to your Jenkins plugin manager
  • Find and install “GitHub plugin” (at the time of writing - current version was 1.27.0)
  • Once it installed, we will need to configure it:

manage jenkins


Add default GitHub server (don’t bother adding credentials as we are using public repo anyway):

jenkins add gh

Configuring Jenkins Job

When you want Jenkins to do something - create a job. In this case, we will be using Freestyle project:

jenkins create job


We have to configure several sections here - Source Code Management and Build Triggers. First, set repository (in this case it’s my demo app repo repository):

jenkins create job


Next step is setting a build trigger to GitHub hook trigger for GITScm polling:

jenkins build trigger


This means that once the Jenkins receives a webhook, it can identify which repo is changed and thus triggers a pull and job execution.


Configure Webhook Relay Bucket

Once things are running, go back to your bucket details in Webhook Relay and add Jenkins container as the destination. It should be:

  • Name: jenkins
  • Destination http://jenkins:8080/github-webhook/
  • Type: internal

bucket destination

Port always needs to match the port on which the application is running in a container. For example, if you do a mapping of 8888:8080 for Jenkins server, destination should still be on port 8080 as that is what’s available internally.

Configure GitHub

Go to your repository settings and add the input endpoint URL from your Webhook Relay bucket:

github config

Push to Build!

Once you push to your repository, you should see few things:

  1. In Webhook Relay dashboard a new webhook received and forwarded
  2. A new build in Jenkins dashboard

Let’s wrap up

In this tutorial, we deployed the main Jenkins server as a Docker container with persistent volumes. We also configured GitHub webhooks to trigger builds without us requiring to have a public IP or configure firewalls.

In our upcoming blog post, we will explore ways of connecting more agents to the server.