Customization with Groovy Scripts and CasC

Customize Operator Service for Jenkins

This tutorial outlines a step-by-step guide on how to customize Jenkins instance after you successfully deployed it.

How Jenkins Customization Works

Current configuration mechanism is based on Kubernetes Custom Resource which is automatically created during the installation phase and then used as a customization file by the Operator.

Every time you want to customize Jenkins, you need to do that in code by modifying the existing Custom Resource file. Any manual changes from the web interface will be overridden by automation or after the Jenkins restart.

Sections below will show you how to configure Jenkins using plugins, Groovy Scripts and Configuration as Code (CasC).

How to customize Jenkins with plugins

Operator can install any plugin that works for Jenkins. By default, it installs plugins visible below:

configuration-as-code v1.53
git v4.8.2
job-dsl v1.77
kubernetes-credentials-provider v0.20
kubernetes v1.30.1
workflow-aggregator v2.6
workflow-job v2.41
simple-theme-plugin v0.6

Installing additional plugins

Please note that due to possible plugin dependency issues, installing additional plugins is a risky operation. It is a good practice to test plugin configuration on non-production Jenkins Master, for example with Blue-Green deployment strategy.

To install additional plugins, you need to add them to the list of plugins under Jenkins Custom Resource’s spec.plugins section like so:

apiVersion: operator-service.com/v1beta1
kind: Jenkins
metadata:
  name: example
spec:
  plugins:
    - name: "name-of-the-plugin"
      version: "3.14"

After applying modifications to Jenkins Custom Resource spec.plugins, Operator will automatically install plugins after Jenkins Controller pod restarts.

For extra caution, monitor your Jenkins Controller pod logs while installing plugins to discover any problems with plugins. You can see how to do this in Troubleshooting section.

Note on caching plugins

Operator caches downloaded plugins by itself, so that on subsequent installations of the same plugin versions (for example, after a Jenkins restart) Operator doesn’t have to download them again and can instead use versions from cache.

Customization via Groovy Scripts and CaSC yamls

Jenkins instance can be customized using Groovy scripts or Configuration as Code (thanks to pre-installed configuration as code plugin). CasC scripts are more readable and simpler to write, so this should be your default choice. However, when something is not supported by the CasC plugin or for more complex and low-level configuration, Groovy scripts are better. They allow you to use jenkins-internal-api. Let’s take a look at some examples below.

Customization of Jenkins with Groovy Scripts

The overall process of configuration can be divided into:

Creating a Custom Resource JenkinsGroovyScript, which contains Groovy script you want to execute. Optionally creating a Kubernetes Secret if you need to store secrets like password or certificates.

1. Creating JenkinsGroovyScript

We need to create a JenkinsGroovyScript config file containing the configuration we want to apply. In the data section we can use Groovy scripts to write configuration code. Since the secret is already present in the Cluster before JenkinsGroovyScript we can safely reference its value.

apiVersion: operator-service.com/v1beta1
kind: JenkinsGroovyScript
metadata:
  name: groovy-script
  namespace: jenkins
  labels:
    operator-service.com/jenkins: jenkins
spec:
  secretRef:
    namespace: jenkins
    name: jenkins-conf-secrets
  data: |
    import jenkins.model.Jenkins

    def systemMessage = "Hello " + secrets

    Jenkins jenkins = Jenkins.getInstance()
    jenkins.setSystemMessage(systemMessage)
    jenkins.save()    

Now we can safely create this JenkinsGroovyScript.

$ kubectl apply -f jenkins-groovy-script.yaml 

2. Creating Secret

In case we want to use confidential data, we have to start by creating a Secret resource to wrap it in. Kubernetes stores secrets in base64 format, so we have to encode it. Running:

$ echo -n "Hello World" | base64

will produce the following output:

SGVsbG8gd29ybGQ=

which we can place in a Secret config file as the value of secrets key.

apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: jenkins-conf-secrets
  namespace: jenkins
data:
  SYSTEM_MESSAGE: SGVsbG8gd29ybGQ=

We have to create the Secret resource in Kubernetes using this config file, saved somewhere in the catalogue, for example in deploy folder.

$ kubectl apply -f deploy/secret.yaml

This event will trigger Jenkins Groovy script reconcile loop and our configuration will be applied automatically. You will see a tiny “Hello World” on the main page.

Customization of Jenkins with Configuration as Code (CasC)

The overall process of customization can be divided into:

Creating a JenkinsConfigurationAsCode Custom Resource, which contains configuration code in data section. Optionally creating a Kubernetes Secret if you need to store secrets like passoword or certificates.

1.Creating Secret config file and creating it in Kubernetes as a resource

In case we want to use confidential data, we have to start by creating a Secret resource to wrap it in. Since it’s a secret, it would be a good idea to encode it. Let’s write into console:

$ echo -n "Hello World" | base64

The output is

SGVsbG8gd29ybGQ=

Now we can place it in a Secret config file as the value of SYSTEM_MESSAGE key.

apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: jenkins-conf-secrets
  namespace: jenkins
data:
  SYSTEM_MESSAGE: SGVsbG8gd29ybGQ=

We have to create the Secret resource in Kubernetes using this config file, saved somewhere in the catalogue, for example in deploy folder.

$ kubectl -n jenkins apply -f deploy/secret.yaml

2. Creating JekinsConfigurationAsCode

We need to create a JekinsConfigurationAsCode config file containing the configuration we want to apply. In the data field value we can use yaml syntax to add fields with configuration code. Since the secret is already present in the Cluster before JekinsConfigurationAsCode we can safely reference its value.

apiVersion: operator-service.com/v1beta1
kind: JenkinsConfigurationAsCode
metadata:
  name: op-svc-jenkins-user-configuration
  namespace: jenkins
  labels:
    operator-service.com/jenkins: jenkins
spec:
  secretRef:
    namespace: jenkins
    name: jenkins-conf-secrets
data: |
    jenkins:
      systemMessage: ${SYSTEM_MESSAGE}    

Now we can safely create this JenkinsConfigurationAsCode with following command:

$ kubectl -n jenkins apply -f jenkins-casc.yaml

Our Jenkins instance will see it and can bind it to previously created Secret, thanks to references we created. This event will trigger CasC reconcile loop and our configuration will be applied. You will see a tiny “Hello World” on the main page.