BLOG POSTS
How to Install Jenkins on Kubernetes

How to Install Jenkins on Kubernetes

Installing Jenkins on Kubernetes brings together two powerhouse technologies that make DevOps workflows infinitely more scalable and manageable. Jenkins handles continuous integration and deployment, while Kubernetes orchestrates containerized applications like a champion. This combination lets you spin up build agents dynamically, scale based on workload, and maintain high availability for your CI/CD pipeline. You’ll learn how to deploy Jenkins on Kubernetes using Helm, configure persistent storage, set up proper networking, and handle the most common deployment headaches that’ll inevitably crop up.

How Jenkins on Kubernetes Works

The Jenkins-Kubernetes integration follows a master-slave architecture where Jenkins runs as a master node in a Kubernetes pod, and build agents are created as temporary pods that spin up on-demand. When a build job triggers, the Jenkins Kubernetes plugin communicates with the Kubernetes API to create a new pod with the required build environment. Once the job completes, the pod gets terminated automatically, keeping resource usage lean.

This setup differs significantly from traditional Jenkins installations where you’d maintain static build slaves. With Kubernetes, you get elastic scaling, better resource isolation, and the ability to run different build environments simultaneously without conflicts. The Jenkins master stores job configurations and build history in persistent volumes, while ephemeral build pods handle the actual work.

Prerequisites and Initial Setup

Before diving into the installation, make sure you have a functioning Kubernetes cluster with at least 4GB RAM and 2 CPU cores available. You’ll need kubectl configured to communicate with your cluster and Helm 3.x installed on your local machine. For production deployments, consider using a dedicated server to ensure consistent performance and avoid resource contention.

First, create a dedicated namespace for Jenkins:

kubectl create namespace jenkins
kubectl config set-context --current --namespace=jenkins

Next, add the Jenkins Helm repository and update it:

helm repo add jenkins https://charts.jenkins.io
helm repo update

Step-by-Step Jenkins Installation

Start by creating a values file to customize your Jenkins deployment. This configuration handles persistence, security, and plugin installation:

cat << EOF > jenkins-values.yaml
controller:
  adminUser: "admin"
  adminPassword: "your-secure-password-here"
  
  resources:
    requests:
      cpu: "1000m"
      memory: "2Gi"
    limits:
      cpu: "2000m"
      memory: "4Gi"
  
  installPlugins:
    - kubernetes:3706.vdfb_d599579f3
    - workflow-aggregator:590.v6a_d052e5a_a_b_5
    - git:4.11.3
    - configuration-as-code:1569.vb_72405b_80249
    - blueocean:1.25.2

  serviceType: LoadBalancer
  
  persistence:
    enabled: true
    size: "20Gi"
    storageClass: "standard"

agent:
  enabled: true
  resources:
    requests:
      cpu: "500m"
      memory: "1Gi"
    limits:
      cpu: "1000m"
      memory: "2Gi"
EOF

Deploy Jenkins using Helm with your custom values:

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

Monitor the deployment status:

kubectl get pods -n jenkins --watch

The installation typically takes 3-5 minutes depending on your cluster’s performance and internet connection speed for pulling images.

Configuring Kubernetes Plugin

Once Jenkins is running, you’ll need to configure the Kubernetes plugin to enable dynamic agent provisioning. Access Jenkins through the LoadBalancer IP or port-forward if you’re using a development setup:

kubectl port-forward svc/jenkins 8080:8080 -n jenkins

Navigate to “Manage Jenkins” β†’ “Configure Clouds” β†’ “Add a new cloud” β†’ “Kubernetes”. Configure these essential settings:

  • Kubernetes URL: https://kubernetes.default.svc.cluster.local
  • Kubernetes Namespace: jenkins
  • Jenkins URL: http://jenkins.jenkins.svc.cluster.local:8080
  • Jenkins Tunnel: jenkins-agent.jenkins.svc.cluster.local:50000

Create a pod template for your build agents:

apiVersion: v1
kind: Pod
metadata:
  labels:
    jenkins: agent
spec:
  containers:
  - name: jnlp
    image: jenkins/inbound-agent:4.11-1-jdk11
    resources:
      requests:
        memory: "1Gi"
        cpu: "500m"
      limits:
        memory: "2Gi"
        cpu: "1000m"
  - name: docker
    image: docker:20.10.16-dind
    securityContext:
      privileged: true
    volumeMounts:
    - name: docker-sock
      mountPath: /var/run/docker.sock
  volumes:
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock

Storage and Persistence Configuration

Proper persistent storage configuration is critical for maintaining Jenkins data across pod restarts. The default setup works for development, but production environments require more robust storage solutions.

For better performance, especially on high-traffic CI/CD pipelines, consider using SSD-backed storage classes:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: jenkins-ssd
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-ssd
  zones: us-central1-a,us-central1-b

Update your Jenkins values file to use the custom storage class:

persistence:
  enabled: true
  size: "50Gi"
  storageClass: "jenkins-ssd"
  accessMode: "ReadWriteOnce"

Security Best Practices

Security configuration often gets overlooked during initial deployments, but it’s crucial for production environments. Start by creating dedicated service accounts with minimal required permissions:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins
  namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: jenkins
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
  resources: ["pods/log"]
  verbs: ["get","list","watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: jenkins
subjects:
- kind: ServiceAccount
  name: jenkins
  namespace: jenkins

Enable HTTPS by configuring TLS certificates through cert-manager or by providing your own certificates:

controller:
  httpsKeyStore:
    jenkinsHttpsJksSecretName: "jenkins-https-jks"
    password: "your-keystore-password"
    jenkinsHttpsJksSecretKey: "jenkins-https.jks"

Common Issues and Troubleshooting

The most frequent issue you’ll encounter is insufficient permissions for the Jenkins service account. Symptoms include build agents failing to start or Jenkins unable to list pods. Check the logs first:

kubectl logs -f deployment/jenkins -n jenkins

Resource constraints cause another common problem. Jenkins can be memory-hungry, especially with multiple concurrent builds. Monitor resource usage:

kubectl top pods -n jenkins
kubectl describe pod jenkins-0 -n jenkins

If you’re experiencing slow performance, check if you’re running on a resource-limited environment. Consider upgrading to a VPS with more RAM and CPU cores for better performance.

Network connectivity issues between Jenkins master and agents often manifest as agents appearing offline despite successful pod creation. Verify the Jenkins tunnel configuration matches your service names and ports.

Performance Optimization and Scaling

Jenkins on Kubernetes shines when properly tuned for your workload. Here’s a comparison of different resource configurations and their typical performance characteristics:

Configuration CPU Memory Concurrent Builds Startup Time
Development 1 core 2GB 2-3 90s
Small Team 2 cores 4GB 5-8 60s
Enterprise 4 cores 8GB 15-20 45s

Configure horizontal pod autoscaling for build agents to handle varying workloads:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: jenkins-agent-hpa
  namespace: jenkins
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: jenkins-agent
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Real-World Use Cases and Examples

A typical microservices company might run 50+ Jenkins jobs daily across different environments. With Kubernetes, each build gets isolated resources, preventing one memory-intensive job from affecting others. Build agents can use different base images for different tech stacks – Node.js jobs get node:16 images while Python jobs use python:3.9.

Multi-tenant scenarios work particularly well with namespace isolation. Different teams get separate Jenkins instances within their own namespaces, sharing the underlying Kubernetes infrastructure while maintaining complete isolation of their CI/CD pipelines.

For organizations dealing with compliance requirements, the ephemeral nature of Kubernetes build agents provides excellent security benefits. Build environments are destroyed after each job, eliminating concerns about data persistence in build environments.

Alternative Deployment Methods

While Helm provides the quickest path to deployment, several alternatives exist depending on your requirements:

Method Complexity Customization Maintenance
Helm Charts Low Medium Easy
Raw YAML High High Complex
Operators Medium High Automated
GitOps (ArgoCD) Medium High Automated

Jenkins operators like the Jenkins Kubernetes Operator provide advanced lifecycle management but require more initial setup complexity.

Monitoring and Maintenance

Set up monitoring for both Jenkins application metrics and Kubernetes resource usage. Prometheus integration works excellently with the Jenkins Prometheus plugin:

controller:
  prometheus:
    enabled: true
    serviceMonitorNamespace: "monitoring"
    serviceMonitorAdditionalLabels:
      app: jenkins

Regular backup strategies should include both Jenkins configuration and build history. Use Velero for cluster-level backups or implement custom backup jobs:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: jenkins-backup
  namespace: jenkins
spec:
  schedule: "0 2 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: alpine:3.15
            command:
            - /bin/sh
            - -c
            - tar czf /backup/jenkins-$(date +%Y%m%d).tar.gz /var/jenkins_home
            volumeMounts:
            - name: jenkins-home
              mountPath: /var/jenkins_home
            - name: backup-volume
              mountPath: /backup
          volumes:
          - name: jenkins-home
            persistentVolumeClaim:
              claimName: jenkins-pvc
          - name: backup-volume
            persistentVolumeClaim:
              claimName: backup-pvc
          restartPolicy: OnFailure

This setup creates a robust, scalable Jenkins deployment that leverages Kubernetes’ orchestration capabilities while maintaining the flexibility and power of Jenkins for CI/CD workflows. The combination provides excellent resource utilization, easy scaling, and simplified maintenance compared to traditional Jenkins deployments.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked