Kubernetes operator for Jenkins CI
Switch branches/tags
Nothing to show
Clone or download
Latest commit 01571ce Nov 29, 2018


Jenkins operator

Build Status

Project status: alpha

Major planned features have been completed, and while no breaking API changes are currently planned, we reserve the right to address bugs and API changes in a backwards incompatible way before the project is declared stable.

We expect to consider the jenkins operator stable soon; backwards incompatible changes will not be made once the project reaches stability.


The jenkins operator manages Jenkins instances deployed to Kubernetes and automates tasks related to operating a Jenkins server


  • Kubernetes 1.9+
  • Jenkins 2.1+

Getting started

Deploy jenkins operator

$ helm install deployments/helm/jenkins-operator --name jenkins-operator


$ helm repo add cnct https://charts.migrations.cnct.io
$ helm repo update
$ helm install cnct/jenkins-operator --name jenkins-operator

Create a secret with Jenkins admin credentials

$ kubectl create -f config/samples/jenkinssecret.yaml 

A Kubernetes secret called jenkins-test with user = admin and pass = password will be created

Create a Jenkins instance

$ kubectl create -f config/samples/jenkins_v1alpha1_jenkinsinstance.yaml

This will create a Jenkins Kubernetes deployment along with a NodePort Kubernetes service, a 1Gb Kubernetes persistent volume for job storage, as well as an ingress and a few other Kubernetes objects. This instance will have a few default plugins pre-installed, along with a greenballs plugin at version 1.15.

You can visit this instance by checking the NodePort service port number, and then going to the ip of one of the cluster nodes at that port number.
For example, if you are running in minikube:

$ minikube ip

$ $ kubectl get svc
  NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                          AGE
  jenkins      NodePort   <none>        8080:31363/TCP,50000:30997/TCP   7d
  kubernetes   ClusterIP       <none>        443/TCP                          7d

So, you should be able to point your browser to and login with admin:password credentials

Create a job with some bound credentials

$ kubectl create -f config/samples/jenkins_v1alpha1_jenkinsjob.yaml

This will create a couple of jobs in the JenkinsInstance you have created above. jenkinsjob-sample-dsl and jenkinsjob-sample-xml.
JenkinsJob Custom resource allows you to specify jobs via either XML or JobDSL

This will also create a Kubernetes secret called jenkins-credentials. Data from this secret will be mounted into Jenkins as Jenkins Credentials
Bindings between secret data fields and Jenkins credentails are specified in the credentials: section of jenkinsjob-sample-dsl JenkinsJob


Create and Destroy instances

Instance creation and destruction is controlled through JenkinsInstance Kubernetes custom resources:

apiVersion: jenkins.jenkinsoperator.maratoid.github.com/v1alpha1
kind: JenkinsInstance
    labels:                                         # dictionary of Kubernetes labels
        stuff.cnct.io: "woo"
    name: jenkinsinstance-sample                    # Name for this Jenkins instance object
    image: "jenkins/jenkins:lts"                    # docker image with tag for this jenkins deployment
    env:                                            # dictionary of environment variables to be set in the jenkins instance
        SOME_ENV: "test"
    plugins:                                        # dictionary of Jenkins plugins to install
        - id:  config-file-provider                 # plugin id
          version: "3.1"                            # plugin version
    annotations:                                    # Jenkins deployment annotations
        cnct.io/annotation: "test"
        cnct.io/other-annotation: "other test"
    executors: 2                                    # Number of Jenkins executors to setup
    adminsecret: jenkins-test                       # name of the pre-existing kubernetes secret with admin user credentials
    location: https://jenkins.example.com           # Jenkins location URL
    adminemail: admin@example.com                   # Jenkins admin email
    service:                                        # Kubernetes service options. If not present, default service is created
        name: jenkins                               # service name
        servicetype: NodePort                       # service type
        nodeport: 30348                             # optional fixed nodeport
          cnct.io/service-annotation: "test"        # service annotations
    ingress:                                        # Kubernetes ingress options. If not present, no Ingress will be created
        annotations:                                # ingress annotations
          cnct.io/ingress-annotation: "test"
        service: jenkins                            # ingress service. if not specified, the default service name is used
        path: /                                     # ingress path
    serviceaccount: jenkins                         # Kubernetes service account name for jenkins deployment
    networkpolicy: true                             # If true, network policy will be created 
    storage:                                        # storage options
        jobspvc: jenkins                            # Name of PVC for job storage. If does not exist it will be created. If name is not specified, EmptyDir is used
        jobspvcspec:                                # If PVC is to be created, use this spec
          accessModes:                              # PVC access modes
            - ReadWriteOnce
          resources:                                # PVC requests
              storage: 1Gi
    pluginconfig:                                   # on-startup configuration for plugins
        configsecret: pluginconfigs                 # Secret with groovy configuration script string to run on startup of jenkins. 
                                                    # Keys from secret are turned into groovy files
                                                    # and are run in lexical order on jenkins startup
        config: |                                   # Groovy configuration script string to run on startup of jenkins. Runs before 'configsecret'
            import hudson.*
            import hudson.model.*
            import jenkins.model.*
            import jenkins.model.Jenkins.*
            import org.jenkinsci.plugins.configfiles.*
            import org.jenkinsci.lib.configprovider.model.*
            import org.jenkinsci.plugins.configfiles.groovy.*
            import org.jenkinsci.plugins.configfiles.*
            import org.jenkinsci.plugins.scriptsecurity.scripts.*
            import org.jenkinsci.plugins.scriptsecurity.scripts.languages.*
            GlobalConfigFiles globalConfigFiles = Jenkins.getInstance().getExtensionList(GlobalConfigFiles.class).get(GlobalConfigFiles.class);
            ConfigFileStore store = globalConfigFiles.get();
            String defaultJenkinsfile = """import io.cnct.pipeline.*
            new cnctPipeline().execute()"""
            ApprovalContext approvalContext = ApprovalContext.create();
            String defaultJenkinsfileHash = new ScriptApproval.PendingScript(
            Config config = new GroovyScript(
              'Default pipeline Jenkinsfile', 

Create and Destroy Jobs and Credentials

Jenkins job and credetial creation and destruction is controlled through JenkinsJob Kubernetes custom resources:

apiVersion: jenkins.jenkinsoperator.maratoid.github.com/v1alpha1
kind: JenkinsJob
  labels:                                               # dictionary of Kubernetes labels
    stuff.cnct.io: "woo"
  name: jenkinsjob-sample-dsl                           # name of this JenkinsJob object
  jenkinsinstance: jenkinsinstance-sample               # name of the pre-existing JenkinsInstance object
  jobdsl: |                                             # Jenkins JobDSL string to use for job creation. Don't specify both this and jobxml
      freeStyleJob('jenkinsjob-sample-dsl') {

          description('With JobDSL')
          displayName('From custom resource DSL')

          steps {
              shell('echo Hello World!')
  jobxml: |                                             # Jenkins XML string to use for job creation. Don't specify both this and jobdsl
      <?xml version="1.0" encoding="UTF-8"?><project>
          <description>From XML</description>
          <scm class="hudson.scm.NullSCM"/>
                  <command>echo Hello World with xml!</command>
          <displayName>From custom resource XML</displayName>
  credentials:                                          # bindings of Kubernetes secrets to Jenkins credentials                      
    - credential: userpass-creds                        # Jenkins credential name
      secret: jenkins-credentials                       # Kubernetes secret name
      credentialtype: usernamePassword                  # type of Jenkins credential. Can be usernamePassword|secretText|serviceaccount|vaultgithub|vaultapprole|vaulttoken
      secretdata:                                       # Jenkins credential field to Kubernetes data field mapping.
        username: username-data
        password: password-data

Credential types

Supported credentialtype 's are: usernamePassword|secretText|serviceaccount|vaultgithub|vaultapprole|vaulttoken

Credential type Supported fields
serviceaccount N/A
secretText secret
usernamePassword username,password
vaultgithub accessToken
vaultapprole roleId,secretId
vaulttoken token

Additional credential types

Additional credential types can be bound by using the kubernetes-credentials-provider-plugin