In the previous article, we discussed how to Setup self-hosted Gitea private repository on a Kubernetes cluster. This article will discuss how to install Jenkins server on a Kubernetes/OpenShift cluster.
Kubernetes/OpenShift adds an additional automation layer on Jenkins server which in turn makes sure that the resources allocated to the Jenkins deployment are efficiently utilized. This means that with the use of an orchestration layer such as Kubernetes/OpenShift, resources can be scaled up/down depending on consumption/usage.
This article will discuss the available methods of setting up Jenkins server on a Kubernetes/OpenShift cluster.
Install Jenkins on Kubernetes using Helm3
In our guide we assume that you have a fully fuctional Kubernetes/OpenShift cluster. You also need access to the control plane either natively or remote.
Helm is a package manager for Kubernetes/OpenShift that packages deployments in a format called chat. The installation of Helm3 is covered in the article below
Install and Use Helm 3 on Kubernetes Cluster
Step 1. Create Jenkins namespace
Create the jenkins namespace that will be used for this deployment.
kubectl create ns jenkins
Once you have Helm3 installed, add Jenkins repo to your environment
$ helm repo add jenkinsci https://charts.jenkins.io
$ helm repo update
Step 2. Create a Persistent Volume
Once the Jenkins repo is added, we need to configure a persistent volume since Jenkins is a stateful application and needs to store persistent data on a volume.
Creating Persistent Volume from Host Path
Create a PersistentVolume on your Kubernetes cluster:
$ vim jenkins-localpv.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: jenkins-sc
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins-pv
labels:
type: local
spec:
storageClassName: jenkins-sc
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-pvc
spec:
storageClassName: jenkins-sc
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Apply the configuration
kubectl apply -f jenkins-localpv.yaml
The above command creates a persistent volume and persistentVolumeClaim using hostPath. The volume will be saved at /mnt
path of the node.
Dynamic Persistent Volume creation using StorageClass
If you have any StorageClass provided by a custom storage solution, create new file called jenkins-pvc.yaml
vim jenkins-pvc.yaml
Modify below configuration to provide StorageClass name:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: storage-class-name
resources:
requests:
storage: 10Gi
Then apply the configuration after modification:
kubectl apply -f jenkins-pvc.yaml
Using openEBS Storage
You can use dynamic storage provisioning using tools such as openEBS and provision storageClasses.
For dynamic storage, create a storageClass config:
$ vim jenkins-sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: jenkins-sc
annotations:
openebs.io/cas-type: jiva
cas.openebs.io/config: |
- name: ReplicaCount
value: "2"
- name: StoragePool
value: gpdpool
provisioner: openebs.io/provisioner-iscsi
Apply the configuration
kubectl apply -f jenkins-sc.yaml
Create a persistenVolume and PersistenVolumeClaim based on the above storageClass
$ vim dynamic-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins-pv
labels:
type: local
spec:
storageClassName: jenkins-sc
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/data/jenkins-volume"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-pvc
spec:
storageClassName: jenkins-sc
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Apply the configuration
kubectl apply -f dynamic-pv.yaml
More about persistent volumes on Kubernetes/OpenShift has been covered on the article below:
Deploy and Use OpenEBS Container Storage on Kubernetes
Step 3. Create a service account
Create a service account for the pods to communicate with ther API server. We will also create the ClusterRole and the permissions.
kubectl apply -f - <<EOF
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: jenkins
rules:
- apiGroups:
- '*'
resources:
- statefulsets
- services
- replicationcontrollers
- replicasets
- podtemplates
- podsecuritypolicies
- pods
- pods/log
- pods/exec
- podpreset
- poddisruptionbudget
- persistentvolumes
- persistentvolumeclaims
- jobs
- endpoints
- deployments
- deployments/scale
- daemonsets
- cronjobs
- configmaps
- namespaces
- events
- secrets
verbs:
- create
- get
- watch
- delete
- list
- patch
- update
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- list
- watch
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: jenkins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jenkins
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:serviceaccounts:jenkins
EOF
Step 4. Install Jenkins on Kubernetes
Download the Jenkins chart and make some modifications before the deployment.
wget https://raw.githubusercontent.com/jenkinsci/helm-charts/main/charts/jenkins/values.yaml
Open the downloaded values.yaml file with your favorite text editor and make the changes below.
- Modify the storage class. In this guide, I have used a storage class called
jenkins-
sc. You might as well use your own storage class. Locate the storageClass field in the file and modify it adding the storageClass.
storageClass: jenkins-sc
- Edit the serviceAccount entries to look as below:
serviceAccount:
create: false
# Service account name is autogenerated by default
name: jenkins
annotations: {}
- Modify the serviceType to NodePort. You can also use loadbalancer if your environment supports that.
servicePort: 8080
targetPort: 8080
# For minikube, set this to NodePort, elsewhere use LoadBalancer
# Use ClusterIP if your setup includes ingress controller
serviceType: NodePort
# Jenkins controller service annotations
Finally install the Jenkins chart by running the command below:
$ chart=jenkinsci/jenkins
$ helm install jenkins -n jenkins -f values.yaml $chart
Verify that the deployment is up and running
$ kubectl get pods -n jenkins
Step 5. Access Jenkins dashboard
When the pods deploy successfully and are running. The next thing is to access the web interface. But first, we need to retrieve the login details.
Obtain Jenkins password
Run the commands below to obtain the jenkins password:
jsonpath="{.data.jenkins-admin-password}"
secret=$(kubectl get secret -n jenkins jenkins -o jsonpath=$jsonpath)
echo $(echo $secret | base64 --decode)
You will get an output similar to this below from decoding the secret
$ echo $(echo $secret | base64 --decode)
szxbmmqutyA4gtRaBDAQeC
Obtain Jenkins Login URL
Obtain the Jenkins URL by checking the port your deployment is exposed to via NodePort
kubectl get svc -n jenkins
Sample output:
$ kubectl get svc -n jenkins
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins NodePort 10.233.35.23 <none> 8080:30375/TCP 20m
jenkins-agent ClusterIP 10.233.14.243 <none> 50000/TCP 20m
From the above, we can tell that the service is running on port 30375. We can access the Jennkins server via http://worker-node-ip:NodePort/login
.
To get the details of your worker nodes:
$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
node01 Ready control-plane,master 25d v1.21.1 172.20.5.220 <none> Debian GNU/Linux 10 (buster) 4.19.0-16-amd64 docker://20.10.7
node02 Ready <none> 25d v1.21.1 172.20.5.221 <none> Debian GNU/Linux 10 (buster) 4.19.0-16-amd64 docker://20.10.7
node03 Ready <none> 25d v1.21.1 172.20.5.222 <none> Debian GNU/Linux 10 (buster) 4.19.0-16-amd64 docker://20.10.7
In my case my login details will be: http://172.20.5.221:30375/login. Note that you can use any node IP to access the web interface.
Login with the username admin
and the password we obtained in the commands above.
Manually Install Jenkins using YAML File
You can manually install Jenkins using a few simple steps with YAML configuration files.
Create Jenkins deployment file
$ vim jenkins-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
containers:
- name: jenkins
image: jenkins/jenkins:lts-jdk11
ports:
- containerPort: 8080
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
volumes:
- name: jenkins-data
persistentVolumeClaim:
claimName: jenkins-pvc
Apply the deployment:
$ kubectl apply -f jenkins-deploy.yaml
Create Jenkins service:
$ vim jenkins-service.yaml
apiVersion: v1
kind: Service
metadata:
name: jenkins
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
selector:
app: jenkins
Apply the service
kubectl apply -f jenkins-service.yaml
Verify that the deployment has been successful
kubectl get deploy -n jenkins
Check the services created
kubectl get svc -n jenkins
Sample output:
$ kubectl get svc -n jenkins
jenkins NodePort 10.233.45.90 <none> 8080:30793/TCP 21d
Access Jenkins Dashboard
After the above steps the next step will be to access Jenkins on a web interface.
You can access the dashboard via http://worker-nodeIP:nodePort
To get past the above interface, we need to obtain a first-time password provided in the Jenkins pod logs. We therefore need to identify the name of the pod and get the logs.
$ kubectl get pods -n jenkins
NAME READY STATUS RESTARTS AGE
jenkins-585799558b-mhfbb 1/1 Running 0 49m
We can then get the logs of the pod.
$ kubectl logs jenkins-585799558b-mhfbb -n jenkins
Trace in the logs for the part that looks like this below:
*************************************************************
*************************************************************
*************************************************************
Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:
bc174736af3a48ac9796c749e43f119c
This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
*************************************************************
*************************************************************
*************************************************************
We can then use the password identified in the logs to get past the first screen.
You will then be required to install plugins for Jenkins. You can opt to install the suggested plugins or customize those that you need.
The installation of plugins takes sometime to complete
You will then be required to setup an admin user:
You will then be asked to provide a Jenkins URl. In this case, use the worker-node URL or IP and the NodePort for the url as shown below:
This is the last step as the next interface is a confirmation that the installation has been successful.
Click on “Start Using Jenkins” to be redirected to the Jenkins dashboard.
Books For Learning Kubernetes Administration:
Conclusion
At this point, Jenkins is ready to be used. We have setup persistent volume for data storage incase the pods are rescheduled. You can now proceed with your CI/CD practices using Jenkins on Kubernetes / OpenShift.
Cheers and please have a look on other interesting articles on this website.