Deploy Jenkins on Kubernetes with NFS Storage

Storage Configuration

This deployment uses NFS for persistent storage. Ensure a StorageClass named nfs-storage is already configured in your cluster.

Create Namespace

kubectl create namespace ops

Configure RBAC Permissions

Define a service account, cluster role, and binding to grant Jenkins necessary permissions:

# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-sa
  namespace: ops

---
# ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: jenkins-role
rules:
- apiGroups: ["apps", "extensions"]
  resources: ["deployments", "ingresses"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["services", "pods", "pods/exec"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["pods/log", "events"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get"]

---
# ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: jenkins-role
subjects:
- kind: ServiceAccount
  name: jenkins-sa
  namespace: ops

Create Headless Service

A headless service enables direct pod access with out load balancing:

apiVersion: v1
kind: Service
metadata:
  name: jenkins-headless
  namespace: ops
spec:
  clusterIP: None
  selector:
    app.kubernetes.io/name: jenkins
  ports:
  - name: web
    port: 8080
    targetPort: 8080
  - name: agent
    port: 50000
    targetPort: 50000

Deploy Jenkins as a StatefulSet

Use a StatefulSet to manage Jenkins with stable network identity and persistent storage:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: jenkins-app
  namespace: ops
spec:
  serviceName: jenkins-headless
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: jenkins
  template:
    metadata:
      labels:
        app.kubernetes.io/name: jenkins
    spec:
      serviceAccountName: jenkins-sa
      containers:
      - name: jenkins
        image: jenkins/jenkins:2.473-jdk17
        imagePullPolicy: IfNotPresent
        securityContext:
          runAsUser: 0
          privileged: true
        env:
        - name: JAVA_OPTS
          value: "-Duser.timezone=Asia/Shanghai"
        ports:
        - containerPort: 8080
          name: web
        - containerPort: 50000
          name: agent
        volumeMounts:
        - name: jenkins-data
          mountPath: /var/jenkins_home
  volumeClaimTemplates:
  - metadata:
      name: jenkins-data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: nfs-storage
      resources:
        requests:
          storage: 1Gi

Expose via Ingress

Route external traffic using an Ingress resource:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: jenkins-ingress
  namespace: ops
spec:
  ingressClassName: nginx
  rules:
  - host: jenkins.ops.net
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: jenkins-headless
            port:
              name: web

Apply Manifests

Deploy all resources from the current directory:

kubectl apply -f .

Tags: kubernetes Jenkins NFS StatefulSet ingress

Posted on Fri, 04 Sep 2026 16:13:48 +0000 by shareaweb