Running Jenkins on Kubernetes: A Complete Guide
Jenkins is a popular automation server used for building, testing, and deploying code. Running Jenkins on Kubernetes gives you scalable, flexible, and resilient automation pipelines. Whether you’re installing Jenkins for the first time or migrating from a VM, this guide explains every step. We’ll also discuss the pros and cons of this approach.
Introduction
Running Jenkins on Kubernetes means that your Jenkins server runs as a container inside a Kubernetes cluster. This setup automates deployment, scales your agents dynamically, and ensures high availability. In this guide, we explain each step using simple language, making it easy to follow even if you’re new to containers or Kubernetes.
Why Run Jenkins on Kubernetes?
Benefits include:
- Scalability: Easily add or remove Jenkins agents based on workload.
- Efficiency: Kubernetes schedules containers optimally to use resources effectively.
- Resilience: If one pod fails, Kubernetes restarts it, keeping your automation running.
Considerations:
- Complexity: Learning Kubernetes can be challenging at first.
- State Management: Persistent storage is essential since Jenkins data must survive pod restarts.
If you want to install Jenkins only for testing purpose and on your local machine - you can check minimal installation of Jenkins.
Prerequisites
Before starting, ensure you have:
- A Kubernetes cluster up and running (local or cloud-based)
kubectl
installed and configured to interact with your cluster- Basic familiarity with YAML syntax and the command line
- For Helm-based installations, install Helm v3 on your local machine
Installing Jenkins on Kubernetes
This section details how to deploy Jenkins as a StatefulSet with dynamic storage provisioning and expose it externally using an Ingress resource.
Using YAML Manifests and StatefulSet
Deploying Jenkins as a StatefulSet provides the benefit of stable pod identities and guarantees that data stored on the pod persists even after restarts.
Step 1: Create a Namespace
Namespaces help group related resources. For example, create a namespace called jenkins
:
kubectl create namespace jenkins
Step 2: Create a Service Account
Create a file named serviceAccount.yaml
:
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: jenkins-admin
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["*"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins-admin
namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jenkins-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jenkins-admin
subjects:
- kind: ServiceAccount
name: jenkins-admin
namespace: jenkins
Apply it: kubectl apply -f serviceAccount.yaml
Step 3: Set Up Persistent Storage with PVC and StorageClass
Instead of manually creating a PersistentVolume (PV), we let Kubernetes dynamically provision storage using a PersistentVolumeClaim (PVC) along with a preconfigured StorageClass. This means Jenkins will request storage and Kubernetes will automatically provide it based on the storage class settings.
Create a PVC template inside the StatefulSet:
volumeClaimTemplates:
- metadata:
name: jenkins-data
spec:
storageClassName: "jenkins-storage" # Ensure this StorageClass exists in your cluster for dynamic provisioning.
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi # Modify Storage as per your need
Explanation: Here, jenkins-storage
is the StorageClass that instructs Kubernetes how to provision storage. When Jenkins runs, it will create a PVC that dynamically allocates the needed persistent storage, so you only need to manage the claim.
Step 4: Deploy Jenkins as a StatefulSet
Create a file named statefulset.yaml
with the following content:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: jenkins
namespace: jenkins
spec:
serviceName: "jenkins"
replicas: 1
selector:
matchLabels:
app: jenkins-server
template:
metadata:
labels:
app: jenkins-server
spec:
securityContext:
fsGroup: 1000
runAsUser: 1000
serviceAccountName: jenkins-admin
containers:
- name: jenkins
image: jenkins/jenkins:lts
ports:
- containerPort: 8080
name: httpport
- containerPort: 50000
name: jnlpport
volumeMounts:
- name: jenkins-data
mountPath: /var/jenkins_home
livenessProbe:
httpGet:
path: "/login"
port: 8080
initialDelaySeconds: 90
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 5
readinessProbe:
httpGet:
path: "/login"
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
volumeClaimTemplates:
- metadata:
name: jenkins-data
spec:
storageClassName: "jenkins-storage" # This storage class handles dynamic provisioning.
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Deploy Jenkins kubectl apply -f statefulset.yaml
Step 5: Setting Up Ingress for Jenkins
To make your Jenkins instance accessible from outside the cluster, create an Ingress resource. This example uses an Ingress controller (like NGINX) that rewrites URLs and routes traffic to the Jenkins service.
Create a file named ingress.yaml
:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jenkins-ingress
namespace: jenkins
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: jenkins.bootvar.com # Replace with your domain or desired hostname.
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jenkins
port:
number: 8080
Create ingress kubectl apply -f ingress.yaml
Note: Ensure you have an Ingress controller running in your cluster. Once configured, navigating to http://jenkins.bootvar.com
(or your designated hostname) will route traffic to your Jenkins instance.
Using Helm v3
Helm simplifies deploying Jenkins with pre-configured charts.
Step 1: Add Jenkins Helm Repository
helm repo add jenkinsci https://charts.jenkins.io
helm repo update
Step 2: Prepare an Custom Values File
Create jenkins-values.yaml
with your custom values (for example, setting the service type as NodePort, persistent volume details, and required plugins). A sample snippet:
controller:
ingress:
enabled: true
path: /
hostName: jenkins.bootvar.com
persistence:
storageClass: "jenkins-pv"
size: "10Gi"
Step 3: Install Jenkins via Helm
helm install jenkins -n jenkins -f jenkins-values.yaml jenkinsci/jenkins --create-namespace
Step 4: Retrieve admin password
jsonpath="{.data.jenkins-admin-password}"
secret=$(kubectl get secret -n jenkins jenkins -o jsonpath=$jsonpath)
echo $(echo $secret | base64 --decode)
Pros and Cons of Running Jenkins on Kubernetes
Pros
- Stable Pod Identity: StatefulSet ensures pods have consistent names (e.g.,
jenkins-0
), crucial for data persistence. - Dynamic Scaling: Automatically provision and remove Jenkins agents.
- Resource Efficiency: Kubernetes optimizes hardware usage.
- High Availability: Kubernetes restarts pods automatically if they fail.
Cons
- Learning Curve: Kubernetes concepts (StatefulSets, Ingress, PVCs) require time to learn.
- Configuration Complexity: Setting up RBAC, storage classes, and Ingress resources needs careful planning.
- Resource Overhead: Kubernetes adds some overhead compared to a single VM deployment.
FAQs
- Why use a StatefulSet instead of a Deployment?
A StatefulSet ensures that Jenkins retains its identity and attaches to the same storage across restarts. This is crucial for Jenkins as it needs persistent data storage.
- Why do we use a Persistent Volume Claim (PVC) and not a Persistent Volume (PV)?
A PVC allows Kubernetes to dynamically provision storage using a StorageClass, eliminating the need for manual PV creation.
- Can we scale Jenkins in Kubernetes?
Yes, but typically we scale Jenkins agents rather than the master node. Jenkins agents can be deployed as separate pods that dynamically scale based on job load. In current setup master node cannot be scaled.
- How do we ensure Jenkins data persistence in Kubernetes?
By using a StatefulSet and a PVC-backed volume, we ensure that Jenkins data persists across pod restarts and reschedules.
Conclusion
Running Jenkins on Kubernetes brings modern infrastructure benefits—scalability, resilience, and efficiency—to your CI/CD pipelines. As you become comfortable with Kubernetes, you can further customize your deployments, integrate additional plugins, and optimize resource usage.
Member discussion