As the most famous CI/CD tool, Jenkins is widely used around the world, and as the cloud platform led by Kubernetes continues to grow and grow, the need to run Jenkins on Kubernetes is increasing.

This article shows you how to use HelM3 to quickly deploy a production-ready Jenkins instance on Kubernets.

In this article, you will be able to:

  • Understand and master some basic operational knowledge of HELM.
  • Use Helm Chart to quickly deploy a Jenkins instance that meets your needs.

Preparation before installation

Kubernetes cluster

Since you are deploying on the Kubernetes platform, first of all you will need to have a usable Kubernetes cluster. This article supports almost all of the Kubernetes platforms and has deployed tests on GKE, Eks, and Minikube. You also need to configure the local kubeconfig file properly to ensure that the kubectl command communicates with your cluster.

HELM

This article uses Helm to deploy Jenkins to the Kubernetes platform. Helm is a package-like management tool for the Kubernetes platform that provides definition files for all Kubernetes resources required to deploy applications on the Kubernetes platform (e.g. : Deployment, Service, PVC, and so on) are packaged together, called Charts, and Helm uses these Charts to deploy the corresponding applications to the Kubernetes platform.

Install the HELM

Before you can use Helm, you first need to ensure that the Helm client is properly installed into your local environment. The HELM version used in this paper is HELM3. The biggest difference between HELM2 and HELM3 is that: HELM3 is not like HELM2, before HELM commands can be used, Tiller (POD deployed under the Kube-system namespace) needs to be pre-deployed on the target Kubernetes platform to receive and process API requests sent by Helm’s command, HelM3 can communicate directly with the target Kubernetes API without requiring any intermediate translation layer.

Therefore, when using the HELM3 version, you just need to make sure that HELM3 is properly installed locally. Installing Helm is simple. For MacOS users, you can install it directly with the brew command:

$ brew install helm

Windows users can use the Choco command to install:

$ choco install kubernetes-helm

Alternatively, you can go directly to Helm’s GitHub Release page and download the executable binaries for the HELM3 version and save them in the directory specified in the system environment variable PATH. For more installation details, please see the official installation documentation.

When the installation is complete, you can view the currently installed Helm version information through the Helm version command:

$helm version version. BuildInfo {version: "v3.1.2 GitCommit:" d878d4d45863e42fd5cff6743294a11d28a9abce." GitTreeState: "clean", GoVersion: "go1.13.8}"

If you get the same message, HELM3 is installed correctly, and you can use the HELM command directly to deploy applications to the Kubernetes platform.

Add the Helm Chart repository

As we already know, Helm implements the deployment of an application by deploying the Chart corresponding to that application. Currently, there are many Charts that are defined for our use. These Charts are stored in different Chart repositals. You can search the Helm Hub to see if there is a Chart for an application. You can also view all the available Chart packages that are officially available to us by viewing Helm’s official Chart repository on GitHub.

Note: Official Chart is divided into two categories: Stable and Incubator. As the name implies, Stable is a stable version. All charts in Stable can be applied to a production environment. Chart in Incubator is still in an active state of development and is not recommended for use in a production environment. In this article, we will use Jenkins Chart located in stable.

When we want to deploy a Chart saved in the Chart repository, we first need to add the repository to the local repository list via Helm’s repo add command, so that Helm knows where to download the Chart:

$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/

"stable" has been added to your repositories

This directive adds the address of the official Stable Chart library locally and names it Stable, so that we can use the Stable/chart-name format to reference and deploy the Chart stored in the repository. Stable/Jenkins Chart, which we will use next.

When a repository is added, you can view the newly added repository information in the list of all repositories listed in the repo list command:

$ helm repo list

NAME    URL
stable  https://kubernetes-charts.storage.googleapis.com/

You can also use the Repo Update command to update the currently added Chart library:

$ helm repo update

Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈

We can also query a Chart in the currently configured Chart repository using the search repo command:

$ helm search repo jenkins

NAME            CHART VERSION   APP VERSION DESCRIPTION
stable/jenkins  1.10.1          lts         Open source continuous integration server. It s...

This command searches for Chart named Jenkins among all Chart repositories added to the current system, and from the resulting results we can see that Jenkins Chart Stable/Jenkins is found in the stable library we just added. This is exactly the Chart we need to deploy Jenkins next.

Create Jenkins namespace

In order to better organize our applications deployed in Kubernetes, it is common to install an application in its own namespace, and Jenkins is no exception, so before deploying Jenkins, First create a dedicated namespace Jenkins:

$ kubectl create ns jenkins

If you’re familiar with HELM2, you know that when you deploy an application under a certain namespace using HELM2, if that namespace does not exist in the current Kubernetes, HELM2 will automatically create that namespace for you. This behavior changes with HelM3. When deploying an application using HelM3, if the specified namespace does not exist in the current Kubernetes, an error message will be reported that namespace cannot be found and the deployment process will be terminated.

Persistent storage volume

By default, the Jenkins Chart we used will use the default StorageClass in the current Kubernetes cluster to create an 8G PVC as the mount volume of Jenkins_Home during deployment. So make sure that your Kubernetes cluster has a default StorageClass and can create a qualified PVC before deploying, otherwise your deployment process will get stuck because you can’t create a corresponding PVC. Check if your Kubernetes cluster has a default StorageClass with the following command:

$ kubectl get sc

NAME                 PROVISIONER            AGE
standard (default)   kubernetes.io/gce-pd   1h

The default after storageClass standard indicates that this storageClass is the default of the current system.

Don’t worry if you’re using a Kubernetes cluster that doesn’t have the default StorageClass, or doesn’t have enough space to create an 8GB PVC, You can temporarily disable the Chart from creating any PVCs by appending the –set persistence.enabled=false parameter in the deployment command below. We will explain how to create PVCs in other ways later when we introduce Jenkins Home persistent storage.

Begin your first deployment

With Helm configured and namespaces created, you can deploy Jenkins Chart using the Helm install command:

$ helm install jenkins stable/jenkins -n jenkins

Or if you can’t create a PVC, use the following command instead:

$HELM install Jenkins stable/ Jenkins -n Jenkins --set persistence.enabled=false

The Helm command above uses the stable/ Jenkins Chart to create a deployment named Jenkins, where the -n parameter specifies the namespace we want to deploy.

When the command succeeds, you will see output similar to the following:

NAME: jenkins LAST DEPLOYED: Thu Apr 2 11:07:36 2020 NAMESPACE: jenkins STATUS: deployed REVISION: 1 NOTES: 1. Get your 'admin' user password by running: printf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode); echo 2. Get the Jenkins URL to visit by running these commands in the same shell: export POD_NAME=$(kubectl get pods --namespace jenkins -l "app.kubernetes.io/component=jenkins-master" -l "App. Kubernetes. IO/instance = Jenkins" -o jsonpath = "{. Items [0]. Metadata. The name}") echo kubectl at http://127.0.0.1:8080 --namespace jenkins port-forward $POD_NAME 8080:8080 3. Login with the password from step 1 and the username: admin For more information on running Jenkins on Kubernetes, visit: https://cloud.google.com/solutions/jenkins-on-container-engine

From the above output, we can learn the following information:

  • The Helm deployment is named Jenkins, and the namespace deployed is also Jenkins.
  • Jenkins administrator login account is admin, and the password can be executed by commandprintf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode); echoAccess to.
  • The currently deployed Jenkins instance does not have any external directly accessible IP address or URL. Instead, it needs to be accessed locally by mapping the port of the deployed Jenkins POD in a port forward manner.

Tip: We can also get the above information by using Helm’s Status to view information about a current deployment:
helm status jenkins -n jenkins.

The above output only represents the success of the Helm command return, but it does not mean that Jenkins has been successfully deployed to the Kubernetes platform. The Kubernetes resource defined by the Chart may still be in the process of creation, and the Settings may fail to create. If you do not disable the creation of a PVC by appending –set persistence.enabled=false on the deployed command line, you should first verify that the PVC was successfully created:

$ kubectl -n jenkins get pvc

NAME      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
jenkins   Bound    pvc-265e71bb-2b82-46d1-8b3c-d495407b1e6d   8Gi        RWO            standard       87s

After confirming that the PVC has been successfully created, let’s take a look at the POD status information. If you look at the POD status information immediately after Helm’s command is successful, you might see something like the following:

$ kubectl -n jenkins get pods

NAME                       READY   STATUS     RESTARTS   AGE
jenkins-58d9d655df-cjw5h   0/1     Init:0/1   0          55s

The POD status is Init:0/1, indicating that the POD is in the initialization phase. The Deployment resource generated by Jenkins Chart defines an Initcontainers named copy-default-config for POD to execute the initialization script apply\_config.sh, The main purpose of this script is to apply the configuration information defined in ConfigMap to the Jenkins instance that we eventually deploy. At the same time, the script will automatically install the defined plug-in for us, create a custom initialization job, and so on.

We can specify the log information of the Initcontainers to view by -C copy-default-config parameter when viewing POD log information:

$ kubectl -n jenkins logs -f jenkins-58d9d655df-cjw5h -c copy-default-config Creating initial locks... Analyzing war /usr/share/jenkins/jenkins.war... Registering preinstalled plugins... Using version - specific update center: https://updates.jenkins.io/2.204... Downloading plugins... . . . Cleaning up locks

Jenkins Chart not only creates POD for us, but also includes all other necessary resources, such as: Services, PersistentVolumeClaim, ServiceAccount, and so on. All deployed resources can be printed in YAML format through Helm’s GET MANifest command:

$ helm get manifest jenkins -n jenkins

--- # Source: jenkins/templates/service-account.yaml apiVersion: v1 kind: ServiceAccount metadata: name: jenkins namespace: jenkins labels: "app.kubernetes.io/name": 'jenkins' "helm.sh/chart": "Jenkins - 1.10.1" "app. Kubernetes. IO/managed - by" : "Helm" "app. Kubernetes. IO/instance" : "jenkins" "app.kubernetes.io/component": "jenkins-master" --- # Source: jenkins/templates/secret.yaml apiVersion: v1 kind: Secret metadata: name: jenkins namespace: jenkins ... more output

Access the Jenkins service

After the POD status transitions to RUNNING and the Jenkins services Running inside the POD are fully started, we can access our Jenkins instance.

You can look at the POD log output if the end of the output contains something like this
INFO hudson.WebAppMain$3#run: Jenkins is fully up and running The Jenkins service in POD has been started successfully and can receive requests.

But there are two more things we need to do before we can access them. First we need to get the password for logging into the user admin, which is randomly generated and can be obtained through the print command given in Helm’s output:

Printf $(kubectl get secret --namespace Jenkins jenkins-o jsonPath ="{.data.jenkins-admin-password}" | base64 --decode); echo

The other thing that needs to be done is port forwarding. If you look at the SVC of Jenkins Namespace at this point:

$kubectl-n Jenkins get SVC NAME TYPE cluster-ip external-ip PORT(S) AGE Jenkins ClusterIP 10.101.220.161 <none> 8080/TCP 2m Jenkins-Agent ClusterIP 10.97.93.57 <none> 50000/TCP 2m

The Jenkins SVC that Chart created for us was of type ClusterIP, and this type of SVC was only accessible inside Kubernetes. Therefore, we need to directly map the POD port to the locally specified port by means of port forwarding, and access the POD by accessing the local address + the port number:

# get Pod of export POD_NAME = $(kubectl get the pods - namespace Jenkins - l "app. Kubernetes. IO/component = Jenkins - master" - l "App. Kubernetes. IO/instance = Jenkins" -o jsonpath = "{. Items [0]. Metadata. The name}") # open port forwarding kubectl - namespace Jenkins port-forward $POD_NAME 8080:8080

Port 8080: port 8080: port 8080: port 8080: port 8080: port 8080: port 8080: port 8080: port 8080: port 8080: port 8080: port 8080: port 8080: port 8080: port 8080: port 8080

Forwarding from 127.0.0.1:8080-> Forwarding from [::1]: 8080-> 8080

This indicates that the port mapping has been successfully enabled and you can access our Jenkins service by typing http://127.0.0.1:8080 in your browser.

At this point, a basic Jenkins instance has been successfully deployed to our Kubernetes cluster and is ready to start serving us. However, in the case of Jenkins currently deployed, it is not yet ready for production, at least we need to give it a URL that can be accessed directly to the outside world. This is usually done by setting the Type property of the created service resource to LoadBalancer or NodePort, or by creating an Ingress resource for it. Let’s learn how to customize the deployment of the resource we need.

Custom deployment

Deployment of applications using Helm Chart brings us not only a simple and fast deployment method, but also flexible customization.

When deploying an application with Chart, Helm first parses the template files defined in Chart to generate the corresponding YAML files used to create Kubernetes resources, and ultimately uses these files to create all the resources. Chart template files are implemented in the Go language and support almost all of the functionality provided by the Go language template engine, such as variables, expressions, loops, functions, and so on.

Almost every template file defined in Chart has a set of variables defined, and default values are set for all of these defined variables in the Chart values.yaml file, such as Jenkins Chart values.yaml. We can create Kubernetes resources with specific Settings for custom deployment purposes by assigning legitimate values to these variables other than the default values during the deployment Chart.

Helm supports two methods of variable assignment: directly assign to a variable on the command line through the –set argument, such as –set foo=bar, assign the string bar to the variable foo. When multiple variables need to be set, set parameter can be specified multiple times to assign to each variable; Another way is to create your own values.yaml file, like the values file in Chart, and write all the variables you want to reassign to it with their new values, and specify the file at deployment time with the -f argument, such as: -f values.yaml.

We usually prefer the second approach: save all the variables and values that we want to customize in a values file. Not only does this simplify our command line, because no matter how many variables are overridden, we end up specifying a single -f argument on the command line. At the same time, we can also save the VALUES file to an SCM tool such as Git, which is convenient for many people to cooperate with, but also can track the history of the file.

Different Helm Chart can set different custom variables, you need to read the relevant Chart documentation carefully before installation, or directly look at the Chart values. YAML file.

Let’s take a look at how to deploy a production Jenkins service by setting the appropriate values for these variables.

Creating a working directory

Since we will be storing the variable values in a file, we will create the working directory and files we need with the following command before we begin:

$ mkdir jenkins
$ cd jenkins
$ touch values.yaml

In the rest of the tutorial, all the variables you set will be saved to the values.yaml file.

Create an externally accessible service

For a Jenkins service, we would prefer to be able to access it directly from a URL, rather than via port forwarding as previously.

To be able to access Jenkins service directly, we can set the type attribute of the service resource created by Chart to NodePort or LoadBalancer, or create the Ingress resource to make its service accessible to the public.

In a production environment, we prefer the latter two: LoadBalancer and Ingress, and let’s take a look at how to implement each of these.

LoadBalancer

If the cloud vendor you are using is trying to support LoadBalancer, creating a service of type LoadBalancer is the easiest and most recommended approach. This can be done by setting the value of the variable ServiceType directly to loadBalancer:

master:
  serviceType: LoadBalancer

Save the above to your local values.yaml file. Note that when assigning a new value to a variable, make sure that the structure of the corresponding key value of the variable does not change. If the serviceType key here is a child property under master in the original Chart values.yaml file, we will follow the same rules in our own values.yaml file.

Ingress

If you do not want to use LoadBalancer, or your Kubernetes platform does not support LoadBalancer, you can also create an Ingress resource to allow the outside world to access you to the service:

Note that if you are using Minikube, make sure you have enabled the Ingress plugin, available by command, before proceeding
minikube addons listCheck to see if the Ingress plug-in is enabled, and if not, execute the command
minikube addons enable ingressTo enable.

master:
  ingress:
    enabled: true
  serviceType: NodePort

The default value of ingress.enabled is false, which means that no Ingress resources will be created for us, so this value needs to be set to true to ensure that Jenkins Chart automatically creates the Ingress resources for us.

We also need to specify the ServiceType property as NodePort so that Ingress can access us to the service. If the cloud platform vendor you are using supports LoadBalancer, setting the ServiceType to LoadBalancer is still your best option.

In addition to enabled, the Chart template used to create Ingress, Jenkins-master-Ingress. Yaml also supports a number of other parameters to set other properties for the generated Ingress, such as creating Labels for Ingress resources, For Annotations, set Hostname, TLS, and so on, look at all the supported variables from the values file for the Ingress Settings and set the values for those variables according to your own situation.

Redeploy your Jenkins service

So far, we’ve created a YAML file named values.yaml that contains the basic configuration to make your Jenkins service directly accessible to the outside world. Let’s use this file to redeploy our Jenkins instance.

But before redeploying, let’s take a look at Helm’s current deployment in Kubernetes:

$ helm ls -n jenkins NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION jenkins jenkins 1 2020-04-02 11:07:36.98936 +0800 CST Deployed Jenkins -1.10.1 LTS

Helm’s ls command is used above to list all the current deployment information in the Jenkins namespace. As you can see, there is already a deployment named Jenkins in our Kubernetes, This is exactly the Jenkins instance we deployed earlier using default values.

Note: Another difference between HelM3 and HelM2 is that in HelM3, all deployments are bound to a namespace, so the above command needs to pass
-nParameter specifies the namespace that we want to look at.

For an existing deployment, there are two options for redeploying it:

  • Delete the current deployment and then re-deploy it for another new deployment.
  • Upgrade deployment on top of the current deployment;

Let’s take a look at how to redeploy our Jenkins service in each of these ways.

1) Re-create

Removing/creating Chart redeployments from Chart is highly undesirable, and the implementation is listed here for reference only.

The first step is to delete a specific deployment using the delete command:

$ helm delete jenkins -n jenkins

release "jenkins" uninstalled

This command will delete the deployment named Jenkins in the Jenkins namespace. When the command completes, you will see the output above, indicating that our Jenkins deployment has been successfully deleted.

You can verify that all resources have been deleted by using the following command:

$ kubectl -n jenkins get all
No resources found in jenkinss namespace.

Then re-use the install command for a new deployment:

$ helm install jenkins stable/jenkins -n jenkins -f values.yaml

In the above command, our values.yaml file is passed to the Helm command with the -f argument, so that Helm reads the variable values we set from this file.

2) Upgrade deployment

Upgrade deployment is a direct upgrade of an existing deployment, which is also the preferred approach. When we upgrade a Chart in this way, we not only retain the history of the upgrade, but we can also roll back our upgraded Chart to a previous version.

Helm uses the upgrade command to upgrade a deployment:

$ helm upgrade jenkins stable/jenkins -n jenkins -f values-ing.yaml

This command upgrades the current Jenkins deployment using the values-ing.yaml file we created. When the upgrade is complete you should see output similar to this:

Release "jenkins" has been upgraded. Happy Helming! NAME: jenkins LAST DEPLOYED: Thu Apr 2 13:27:58 2020 NAMESPACE: jenkins STATUS: deployed REVISION: 2 NOTES: 1. Get your 'admin' user password by running: printf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode); echo 2. Get the Jenkins URL to visit by running these commands in the same shell: export NODE_PORT=$(kubectl get --namespace jenkins -o jsonpath="{.spec.ports[0].nodePort}" services jenkins) export NODE_IP=$(kubectl get nodes --namespace jenkins -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT/login 3. Login with the password from step 1 and the username: admin For more information on running Jenkins on Kubernetes, visit: https://cloud.google.com/solutions/jenkins-on-container-engine

The result is similar to what we returned when we created the deployment, except that the first sentence prompts for upgrade.

Check out our Service and Ingress situation:

Kubectl-n Jenkins get SVC NAME TYPE cluster-ip external-ip PORT(S) AGE Jenkins NodePort 10.101.220.161 <none> 8080:30450/TCP 140m Jenkins-agent ClusterIP 10.97.93.57 <none> 50000/TCP 140m # Jenkins get ing NAME CLASS HOSTS ADDRESS PORTS AGE Jenkins <none> * 192.168.99.101 80 35s

At this point, the Jenkins Service type has been updated to the NodePort type, the Ingress resource has been created, and we can access our Jenkins service at the Ingress address 192.168.99.101.

Use Helm’s history command to view all the upgrade history of Jenkins Chart:

$ helm history jenkins -n jenkins
REVISION        UPDATED                         STATUS          CHART           APP VERSION     DESCRIPTION
1               Thu Apr  2 11:07:36 2020        superseded      jenkins-1.10.1  lts             Install complete
2               Thu Apr  2 13:27:58 2020        deployed        jenkins-1.10.1  lts             Upgrade complete

In the output of what, the second record is the record information of our upgrade.

Tip: When creating or upgrading a deployment, you can specify it on the command line
--dry-runParameter, which is used to simply print out the Kubernetes resource definition information generated by Chart without doing any real deployment. We usually use this command to verify that the resource definition information generated by Chart is what we need before deployment.

Jenkins Home persistent storage

All Jenkins configuration information and Job information are stored as files in the Jenkins_home directory. In a real production environment, we usually need to mount this directory into the PVC for persistent storage. This not only ensures that data will not be lost if POD is unexpectedly restarted or deleted; This is also a necessary prerequisite for Jenkins Scalability (enabling multiple Jenkins POD operations at the same time).

By default, Jenkins Chart creates an 8G PVC using the default StorageClass on the current Kubernetes and automatically mounts Jenkins \ _Home onto the PVC.

Specify other StorageClass

If your current Kubernetes platform does not have a default StorageClass, or if you would like to use a non-default StorageClass to create your PVC, you can do so by setting the persistence.storageClass key:

persistence:
  storageClass: MySC

Note: Persistence is not located under master.

The above configuration specifies that during the deployment process, the MySC StorageClass will be used to create the PVC.

Use existing PVC

You can also create your own PVC in advance and specify your PVC with ExistingClaim Key:

persistence:
  existingClaim: JENKINS_HOME_PVC

Once you set the value for ExistingClaim, Chart will not create any PVCs with StorageClass, which can be deployed if you don’t have any available StorageClass on your Kubernetes platform.

Chart template also supports some other variables for setting PVC properties, such as the size variable to set the size of the PVC, the accessMode variable to set the accessMode of the PVC, etc. Here is the PVC configuration we are currently using to create a PVC with a size of 5G:

# Persistence: # Modify the automatically created PVC Size: "5GI"

For more supported variables, see the Values file about Persistence for a complete list of supported variables.

It is important to note that once we have created a PVC, we cannot make any changes to its size (although some PVCs can be expanded depending on whether the storage system behind the PVC supports this function), so if we make any changes to the size of the PVC, You should delete the HELM deployment first and then recreate a new pair on it. Deleting a PVC also means that the data stored in the PVC will be lost, so try to plan the PVC before you create it and try to avoid making changes to it later.

Disable the PVC

If for some reason you don’t want your deployed Jenkins instance to use any PVC, you can set the persistence.enabled value to false:

persistence:
  enabled: false

This way Chart will not create any PVC and will not mount any PVC resources for our Jenkins.

Preinstall the Jenkins plugin

Jenkins’ success can be attributed to its rich and powerful plugins, and after every Jenkins instance is initialized, our first priority is usually to install the various plugins we need.

Jenkins Helm Chart allows us to assign a list of all plug-ins that need to be installed to the installPlugins variable, so that these plug-ins are automatically installed for us in InitContainers when Jenkins Pod is initialized:

master:
  installPlugins:
    - ldap
    - matrix-auth
    - authorize-project
    - ansicolor
    - jacoco
    - job-dsl
    - slack
    - checkstyle
    - kubernetes
    - openshift-client
    - workflow-job
    - workflow-aggregator
    - credentials-binding
    - git
    - github-branch-source
    - github-pullrequest
    - ghprb

Note: The plug-in ID is used here, not the name of the plug-in. The plug-in ID can be found in the ID field of the plug-in detail page.

In addition to writing just the plug-in ID as above, you can install the specified version of the plug-in by appending the plug-in ID with the version number of the plug-in you want to install, separated by a colon, such as: kubernetes:1.24.1.

When the deployment is complete, you can view the Installed plug-ins under the InstalTab on the Manage Jenkins-> Plugins Manager page:

Approval scripts

Pipelines in Jenkins actually run in the Groovy Sandbox provided by Jenkins, and Sandbox limits the Groovy scripts that we execute for safety reasons. Only a few are trusted when Groovy methods can be executed.

Sometimes, however, we need to execute special Groovy methods in the Pipeline. On the first execution of the Pipeline that contains an untrusted Groovy method, the Pipeline will terminate due to an error. It tells us that Jenkins’ Admin user needs to add these methods to Jenkins’ trust list before they can be invoked in Pipelien.

We can assign all the Groovy methods we want to add to the trust list as a list to the ScriptApproval variable, so that when Jenkins deployments these methods will be automatically added to the trust list:

master:
  scriptApproval:
    - "method groovy.json.JsonSlurperClassic parseText java.lang.String"
    - "new groovy.json.JsonSlurperClassic"

The Jenkins service deployed with this ScriptApproval allows us to instantiate the JSONSlurperClassic class directly in the Pipeline and call the parseText method of the class.

All Approved scripts can be viewed from the “Manage Jenkins” -> “In-Process Script Approval” page:

Note: This function needs to set the enableXmlConfig value to true.

Automatically create Job

Every time we create a Job in Jenkins, a directory with the same name is generated in the Jenkins_home /jobs/ directory, and the Job configuration information is stored as XML in the config.xml file in that directory.

We can have Chart automatically create these jobs for us in a newly deployed Jenkins by passing configuration information for these jobs to the jobs variable of Jenkins Helm Chart:

master: jobs: HelloMyPipeline: |- <? The XML version = '1.1' encoding = "utf-8"? >< flow-definition plugin="[email protected]"> <description></description> <keepDependencies>false</keepDependencies> < the properties / > < definition class = "org. Jenkinsci. Plugins. Workflow. CPS. CpsFlowDefinition" plugin = "[email protected]" > <script>pipeline { agent any stages { stage(&apos; Hello&apos;) { steps { echo &apos; Hello World&apos; } } } } </script> <sandbox>true</sandbox> </definition> <triggers/> <disabled>false</disabled> </flow-definition>

The above configuration creates a Pipeline named HellomyPipeline from the deployed Jenkins. The contents of the Pipeline script are shown in the figure below:

Note: This function needs to set the enableXmlConfig value to true.

Other common configurations

Change the default login name and password

If no other login method, such as LDAP, is specified for the deployed Jenkins service, Jenkins will authenticate with the default username and password and automatically create an admin account with the login name of admin and randomly generated password. We can obtain the base64 translated user name and password from the secret generated by Helm Chart (the secret name is the same as the Helm name we deployed, in this case, Jenkins), as follows:

$ kubectl -n jenkins get secret jenkins -o yaml
apiVersion: v1
data:
  jenkins-admin-password: clBEWVBtZDg2eg==
  jenkins-admin-user: YWRtaW4=
kind: Secret
metadata:
... more data

Where jenkins-admin-user and jenkins-admin-password save the values after base64 translation, respectively, we can obtain the real values before translation through base64-d command: Echo “YWRtaW4 =” | base64 – d -.

We can also specify the login account and password we want by setting values for AdminUser and AdminPassword, such as:

master:
  adminUser: sysadmin
  adminPassword: sysadmin

The above setting changes both the login and password to sysadmin.

Pod resources

Jenkins Helm Chart sets the following default resource limits for the POD created:

master:
  resources:
    requests:
      cpu: "50m"
      memory: "256Mi"
    limits:
      cpu: "2000m"
      memory: "4096Mi"

So we can modify these values to modify POD’s requirement for resource limits.

Pod Probes

In order to ensure the robustness of Jenkins’ services, Helm Chart set Readiness and Liveness respectively for Jenkins POD through the following variables:

master:
  healthProbes: true
  healthProbesLivenessTimeout: 5
  healthProbesReadinessTimeout: 5
  healthProbeLivenessPeriodSeconds: 10
  healthProbeReadinessPeriodSeconds: 10
  healthProbeLivenessFailureThreshold: 5
  healthProbeReadinessFailureThreshold: 3
  healthProbeLivenessInitialDelay: 90
  healthProbeReadinessInitialDelay: 60

You can turn off the LivenessProbe and ReadInessProbe by setting the Healthprobes value to false, which is not recommended in a production environment.

The complete VALUES file

Now that we have reassigned most of the variables we need to meet our deployment requirements, it’s time to look at the values.yaml file in the complete Chart:

# Persistence: # Modify the size of the automatically created PVC Size: "5Gi" Master: ServiceType: NodePort # Persistence: # Enable Ingresss resources Ingress: Enabled: True # Set the plugins you want to install. - ldap - matrix-auth - authorize-project - ansicolor - jacoco - job-dsl - slack - checkstyle - kubernetes - openshift-client - workflow-job - workflow-aggregator - credentials-binding - git - github-branch-source - Github-pullrequess-ghprb # set resource: requests: CPU: "50M" memory: "256MI" limits: CPU: "2000M" memory: Add Groovy method ScriptApproval to add to trust list: - "method groovy.json.JsonSlurperClassic parseText java.lang.String" - "new groovy.json.JsonSlurperClassic"

If you’re careful, you’ll notice that there’s no Job definition information. In this case, we chose to put the Job configuration information in a separate file. Separating the Job from the main configuration file not only simplifies the main configuration information, but also allows us to write multiple Job profiles to deploy specific Jobs-specific to different environments when we deploy Jenkins services for that environment. Store the Job configuration separately in jobs.yaml:

Master: # need to automatically create the initialization of the Job jobs: HelloMyPipeline: | - <? The XML version = '1.1' encoding = "utf-8"? >< flow-definition plugin="[email protected]"> <description></description> <keepDependencies>false</keepDependencies> < the properties / > < definition class = "org. Jenkinsci. Plugins. Workflow. CPS. CpsFlowDefinition" plugin = "[email protected]" > <script>pipeline { agent any stages { stage(&apos; Hello&apos;) { steps { echo &apos; Hello World&apos; } } } } </script> <sandbox>true</sandbox> </definition> <triggers/> <disabled>false</disabled> </flow-definition>

To upgrade and deploy our Jenkins using Upgrade again:

$ helm upgrade jenkins stable/jenkins -n jenkins -f values.yaml -f jobs.yaml

In the above command, we pass the contents defined in jobs.yaml to Helm by specifying the second -f parameter to help us create the Job we need. Since we have made some changes to the pairings this time, the pairings will be recreated during the upgrade process:

kubectl -n jenkins get pods
NAME                      READY   STATUS     RESTARTS   AGE
jenkins-ddd7fb47f-blv7m   0/1     Init:0/1   0          35s

After the upgrade is completed and the newly created POD is launched successfully, our Jenkins instance will be successfully deployed, and the newly upgraded Jenkins service can be accessed again through the Ingress address or the LoadBalancer address.

At this point, we have successfully deployed a customized Jenkins instance to our Kubernetes platform. While Jenkins will automatically install the plug-ins we need, create initialization jobs, and so on, there is still a lot of manual configuration to do with our Jenkins service before it can be used. In the next article, We will show you how to use Jenkins’ Configuration as Code plugin to save all of the Configuration to our values.yaml file, ultimately achieving Jenkins’ zero Configuration goal.

Source: Devsecops Sig