> ## Content Index
> Fetch the complete content index at: https://devopscube.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# How To Deploy Jenkins as StatefulSet on Kubernetes
- URL: https://devopscube.com/deploy-jenkins-as-statefulset-on-kubernetes/
- Published: 2024-07-22T04:14:38.000Z
- Updated: 2025-03-13T15:24:02.000Z
- Author: Aswin Vijayan
- Tags: COMMON, #Migrated-1741795015845, #wp, #wp-post, #Import 2025-03-12 15:57, #blog

In this blog, I have given the step by step tutorial to deploy Jenkins as StatefulSet on the Kubernetes Cluster.

## Prerequisites

Given below are the Prerequisites for this setup

1. [Kubernetes Cluster](https://devopscube.com/setup-kubernetes-cluster-kubeadm/)
2. kubectl installed in your system

## Deploy Jenkins as StatefulSet

The following image shows the setup architecture and workflow.

![Jenkins deployment as statefulset on kubernetes](https://storage.ghost.io/c/5f/2f/5f2f4d20-2abf-4534-8d40-7aa233aedd43/content/images/2025/03/jenkins-controller.gif)

Follow the below steps to deploy Jenkins as a StatefulSet.

### Step 1: Create a Namespace

The first step is to create a separate namespace to deploy Jenkins.

Run the following command to create a namespace

```
kubectl create ns jenkins
```

### Step 2: Create a ClusterRole and ServiceAccount

After creating the namespace, the next step is to create a **clusterrole**, **serviceaccount** and bind the **clusterrole** to a service account.

This service account grants Jenkins the necessary permissions to interact with the Kubernetes API.

This is primarily required for CI/CD tasks where Jenkins need to create, update, and manage resources within the cluster (e.g., pods, services, and deployments).

Create a YAML file **sa.yaml** and copy the below contents

```
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
```

This file creates a **ServiceAccount** and a **ClusterRole** with admin permission, you can limit the permissions as you want.

Then it binds the ClusterRole with the ServiceAccount. Run the following command to create the service account

```
kubectl apply -f sa.yaml
```

### Step 3: Create a Secret

The next step is to create a Secret which creates a token for the serviceaccount.

Create a YAML file **secret.yaml** and copy the below contents in to it

```
apiVersion: v1
kind: Secret
metadata:
  name: sa-token-secret
  namespace: jenkins
  annotations:
    kubernetes.io/service-account.name: jenkins-admin
type: kubernetes.io/service-account-token
```

This creates a secret and links it with the service account using the annotation.

The token in the secret is particularly useful when you use [Kubernetes pods and dynamic jenkins agents.](https://devopscube.com/jenkins-build-agents-kubernetes/)

### Step 4: Create a PersistentVolumeClaim (PVC)

Now, create a **PersistentVolumeClaim** for Jenkins.

Create a YAML file **pvc.yaml** and copy the below contents

```
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-pv-claim
  namespace: jenkins
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
```

This file creates a PVC which requests 1**0GB** of storage with **readwriteonce** access mode.

Run the following command to create a PVC

```
kubectl apply -f pvc.yaml
```

### Step 5: Deploy Jenkins as SatefulSet

Once the required resources for Jenkins are created, deploy Jenkins as a Statefulset on the cluster.

Create a YAML file **statefulset.yaml** and copy the below contents into it

```
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
          resources:
            limits:
              memory: "2Gi"
              cpu: "1000m"
            requests:
              memory: "500Mi"
              cpu: "500m"
          ports:
            - name: httpport
              containerPort: 8080
            - name: jnlpport
              containerPort: 50000
          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
          volumeMounts:
            - name: jenkins-data
              mountPath: /var/jenkins_home
      volumes:
        - name: jenkins-data
          persistentVolumeClaim:
              claimName: jenkins-pv-claim
```

This file deploys Jenkins on the Jenkins namespace with the following:

1. As statefulset with one replica. We cannot run more than one replica becuase of the way Jenkins manages it data. Read the [Jenkins architecture](https://devopscube.com/jenkins-architecture-explained/) blog to know more.
2. Uses a security context to run Jenkins as non-root user ID 1000\. By specifying a non-root UID, you limit the potential security risk that can be caused by a compromised Jenkins container. Running as a non-root user **reduces the risk of privilege escalation attacks.**
3. Jenkins uses the serviceaccoun**t** **jenkins-admin** we created in **step 2**.
4. Uses the latest container image **jenkins/jenkins:lts**
5. Added resource limits and requests, as well as liveness and readiness probes.
6. Then it exposes port **8080** for UI access and jnlp port **50000** to communicate with the agent.
7. Jenkins stores its data on the mounted volume under the path **/var/jenkins\_home** and it claims the volume using the PVC created in **Step 3.**

Run the following command to deploy Jenkins as statefulset

```
kubectl apply -f statefulset.yaml
```

### Step 6: Expose Jenkins

The final step is to expose Jenkins as NodePort using a service so that we can access the Jenkins UI on the web.

Create a YAML file **sva.yaml** and copy the below content into it

```
apiVersion: v1
kind: Service
metadata:
  name: jenkins-service
  namespace: jenkins
spec:
  selector: 
    app: jenkins-server
  type: NodePort
  ports:
    - name: http-port
      port: 8080
      targetPort: 8080
      nodePort: 30000
    - name: jnlp-port
      port: 50000
      targetPort: 50000
```

The j**enkins-service** service exposes the Jenkins port 8080 on **NodePort 30000** to access the Jenkins UI on the web.

Run the following command to create the service

```
kubectl apply -f svc.yaml
```

> **Note:** Exposing Jenkins as NodePort is not suitable for the production environment. In actual projects need to setup [Ingress](https://devopscube.com/setup-ingress-kubernetes-nginx-controller/) to access Jenkins.

Now access your Jenkins on the web using the following URL

```
http://<node-ip>:30000
```

After running this command Jenkins will as you to enter the **initialAdminPassword** as shown below

![Jenkins initial Admin apssword](https://storage.ghost.io/c/5f/2f/5f2f4d20-2abf-4534-8d40-7aa233aedd43/content/images/2025/03/image-40-9.png)

To get the admin password run the following command. Replace ` jenkins-0` with your pod name.

```
kubectl exec -it jenkins-0 cat  /var/jenkins_home/secrets/initialAdminPassword -n jenkins
```

After entering the admin password, it will ask you to install the plugins, and create an admin user and you can see the Jenkins workspace after completing the steps.

![Jenkins Dashboard](https://storage.ghost.io/c/5f/2f/5f2f4d20-2abf-4534-8d40-7aa233aedd43/content/images/2025/03/image-41-8.png)

If you want to add additional plugins to your Jenkins, go to

**Manage Jenkins->Plugins->Available plugins** and search for the plugin you need.

For example, in the below image, I am installing the Blue Ocean plugin on Jenkins, select the plugin and click the **Install** button to install it

![Add and additional plugin on Jenkins](https://storage.ghost.io/c/5f/2f/5f2f4d20-2abf-4534-8d40-7aa233aedd43/content/images/2025/03/image-42-10.png)

After installing the plugin you can see it on the left side of your Jenkins dashboard as shown below

![Installed plugins on Jenkins](https://storage.ghost.io/c/5f/2f/5f2f4d20-2abf-4534-8d40-7aa233aedd43/content/images/2025/03/image-43-11.png)

Click the **Open Blue Ocean** button to open the Blue Ocean dashboard

![Blue Ocean dashboard](https://storage.ghost.io/c/5f/2f/5f2f4d20-2abf-4534-8d40-7aa233aedd43/content/images/2025/03/image-44-11.png)