CloudOpsGuide
jenkins

Jenkins Deploy Helm Chart to Kubernetes: Complete Pipeline

Advanced
14 minutes
October 2026
CloudOpsGuide Team

Jenkins Deploy Helm Chart to Kubernetes: Complete Pipeline

Step-by-step guide to create a Jenkins pipeline that deploys Helm charts to Kubernetes clusters with best practices.

Table of Contents

Prerequisites

Required Tools

  • Jenkins installed and running
  • Kubernetes cluster with kubectl configured
  • Helm 3.x installed
  • Git repository for your Helm charts
  • Container registry (Docker Hub, ACR, etc.)

Jenkins Plugins

Install these Jenkins plugins:

  • Kubernetes CLI Plugin - For kubectl integration
  • Pipeline Plugin - For pipeline as code
  • Git Plugin - For Git integration
  • Docker Plugin - For Docker operations
  • Credentials Binding Plugin - For secure credentials

Project Structure

my-app/
├── charts/
│   └── my-app/
│       ├── Chart.yaml
│       ├── values.yaml
│       ├── values-dev.yaml
│       ├── values-prod.yaml
│       └── templates/
│           ├── deployment.yaml
│           ├── service.yaml
│           └── ingress.yaml
├── Dockerfile
├── Jenkinsfile
└── src/
    └── app/

Helm Chart Setup

Chart.yaml

apiVersion: v2
name: my-app
description: A Helm chart for my application
type: application
version: 1.0.0
appVersion: "1.0.0"

values.yaml

replicaCount: 3

image:
  repository: myregistry/my-app
  pullPolicy: IfNotPresent
  tag: "latest"

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: true
  className: nginx
  annotations: {}
  hosts:
    - host: my-app.example.com
      paths:
        - path: /
          pathType: Prefix

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

Deployment Template

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-app.fullname" . }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ include "my-app.name" . }}
  template:
    metadata:
      labels:
        app: {{ include "my-app.name" . }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: {{ .Values.service.port }}
        resources:
          {{- toYaml .Values.resources | nindent 10 }}

Jenkins Configuration

Add Kubernetes Credentials

  1. Go to Manage Jenkins → Credentials
  2. Add Kubernetes Configuration (kubeconfig)
  3. Add Docker Registry Credentials (if using private registry)

Configure Kubernetes Cloud

  1. Go to Manage Jenkins → Manage Nodes and Clouds → Configure Clouds
  2. Add Kubernetes cloud
  3. Configure Kubernetes URL and credentials
  4. Add pod templates if using Kubernetes agents

Pipeline Implementation

Basic Jenkinsfile

pipeline {
    agent any
    
    environment {
        DOCKER_REGISTRY = 'myregistry.com'
        IMAGE_NAME = 'my-app'
        IMAGE_TAG = "${env.BUILD_NUMBER}"
        KUBECONFIG = credentials('kubeconfig')
        CHART_PATH = './charts/my-app'
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Build Docker Image') {
            steps {
                script {
                    docker.build("${DOCKER_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}")
                }
            }
        }
        
        stage('Push to Registry') {
            steps {
                script {
                    docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-credentials') {
                        docker.image("${DOCKER_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}").push()
                        docker.image("${DOCKER_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}").push('latest')
                    }
                }
            }
        }
        
        stage('Deploy to Kubernetes') {
            steps {
                script {
                    withKubeConfig([credentialsId: 'kubeconfig']) {
                        sh """
                            helm upgrade --install my-app ${CHART_PATH} \
                                --set image.tag=${IMAGE_TAG} \
                                --namespace production \
                                --create-namespace
                        """
                    }
                }
            }
        }
    }
    
    post {
        success {
            echo 'Deployment successful!'
        }
        failure {
            echo 'Deployment failed!'
        }
    }
}

Advanced Jenkinsfile with Environments

pipeline {
    agent any
    
    parameters {
        choice(
            name: 'ENVIRONMENT',
            choices: ['dev', 'staging', 'production'],
            description: 'Select deployment environment'
        )
        booleanParam(
            name: 'DRY_RUN',
            defaultValue: false,
            description: 'Run helm with --dry-run'
        )
    }
    
    environment {
        DOCKER_REGISTRY = 'myregistry.com'
        IMAGE_NAME = 'my-app'
        IMAGE_TAG = "${env.BUILD_NUMBER}"
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Build and Push') {
            steps {
                script {
                    docker.build("${DOCKER_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}")
                    docker.withRegistry("https://${DOCKER_REGISTRY}", 'docker-credentials') {
                        docker.image("${DOCKER_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}").push()
                    }
                }
            }
        }
        
        stage('Lint Helm Chart') {
            steps {
                sh 'helm lint ./charts/my-app'
            }
        }
        
        stage('Deploy') {
            when {
                expression { params.ENVIRONMENT != 'dev' }
            }
            input {
                message "Deploy to ${params.ENVIRONMENT}?"
                ok "Yes, deploy"
            }
            steps {
                script {
                    def valuesFile = params.ENVIRONMENT == 'production' ? 'values-prod.yaml' : 'values-dev.yaml'
                    def dryRunFlag = params.DRY_RUN ? '--dry-run' : ''
                    
                    withKubeConfig([credentialsId: "kubeconfig-${params.ENVIRONMENT}"]) {
                        sh """
                            helm upgrade --install my-app ./charts/my-app \
                                -f ./charts/my-app/${valuesFile} \
                                --set image.tag=${IMAGE_TAG} \
                                --namespace ${params.ENVIRONMENT} \
                                --create-namespace \
                                ${dryRunFlag} \
                                --wait \
                                --timeout 5m
                        """
                    }
                }
            }
        }
        
        stage('Verify Deployment') {
            steps {
                script {
                    withKubeConfig([credentialsId: "kubeconfig-${params.ENVIRONMENT}"]) {
                        sh """
                            kubectl rollout status deployment/my-app -n ${params.ENVIRONMENT}
                            kubectl get pods -n ${params.ENVIRONMENT} -l app=my-app
                        """
                    }
                }
            }
        }
    }
}

Advanced Features

Multi-Stage Deployment

stage('Deploy to Dev') {
    steps {
        script {
            deployToEnvironment('dev', 'values-dev.yaml')
        }
    }
}

stage('Deploy to Staging') {
    when {
        branch 'main'
    }
    steps {
        script {
            deployToEnvironment('staging', 'values-staging.yaml')
        }
    }
}

stage('Deploy to Production') {
    when {
        branch 'main'
    }
    input {
        message "Deploy to production?"
    }
    steps {
        script {
            deployToEnvironment('production', 'values-prod.yaml')
        }
    }
}

def deployToEnvironment(env, valuesFile) {
    withKubeConfig([credentialsId: "kubeconfig-${env}"]) {
        sh """
            helm upgrade --install my-app ./charts/my-app \
                -f ./charts/my-app/${valuesFile} \
                --set image.tag=${IMAGE_TAG} \
                --namespace ${env} \
                --create-namespace \
                --wait
        """
    }
}

Rollback on Failure

stage('Deploy') {
    steps {
        script {
            try {
                sh """
                    helm upgrade --install my-app ./charts/my-app \
                        --namespace production \
                        --wait
                """
            } catch (Exception e) {
                echo "Deployment failed, rolling back..."
                sh 'helm rollback my-app -n production'
                throw e
            }
        }
    }
}

Health Checks

stage('Health Check') {
    steps {
        script {
            def maxRetries = 10
            def retryCount = 0
            
            while (retryCount < maxRetries) {
                try {
                    sh 'curl -f http://my-app.example.com/health || exit 1'
                    echo "Health check passed!"
                    break
                } catch (Exception e) {
                    retryCount++
                    echo "Health check failed, retry ${retryCount}/${maxRetries}"
                    sleep(10)
                }
            }
            
            if (retryCount >= maxRetries) {
                error "Health check failed after ${maxRetries} retries"
            }
        }
    }
}

Troubleshooting

Helm Command Not Found

// Install Helm in Jenkins agent
stage('Install Helm') {
    steps {
        sh '''
            curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
        '''
    }
}

Kubectl Authentication Issues

// Use explicit kubeconfig path
withKubeConfig([credentialsId: 'kubeconfig']) {
    sh 'export KUBECONFIG=$HOME/.kube/config && kubectl get nodes'
}

Image Pull Errors

// Add registry credentials to Kubernetes
stage('Create Image Pull Secret') {
    steps {
        withCredentials([usernamePassword(credentialsId: 'docker-credentials', 
                                          usernameVariable: 'DOCKER_USER', 
                                          passwordVariable: 'DOCKER_PASS')]) {
            sh """
                kubectl create secret docker-registry regcred \
                    --docker-server=${DOCKER_REGISTRY} \
                    --docker-username=${DOCKER_USER} \
                    --docker-password=${DOCKER_PASS} \
                    --namespace production \
                    --dry-run=client -o yaml | kubectl apply -f -
            """
        }
    }
}

Best Practices

  1. Version your Helm charts - Use semantic versioning
  2. Use separate values files - For different environments
  3. Implement rollback strategy - On deployment failure
  4. Add health checks - Verify deployment success
  5. Use secrets management - Never hardcode credentials
  6. Implement manual approval - For production deployments
  7. Monitor deployments - Set up alerts
  8. Use dry-run mode - Test before deploying
  9. Keep charts in Git - Version control everything
  10. Document your pipeline - For team reference

Useful Commands

# List Helm releases
helm list -n production

# Get release status
helm status my-app -n production

# Get release values
helm get values my-app -n production

# Rollback release
helm rollback my-app -n production

# Uninstall release
helm uninstall my-app -n production

# Test chart
helm template my-app ./charts/my-app

# Lint chart
helm lint ./charts/my-app

Related Articles


Last Updated: October 2026
Author: CloudOpsGuide Team
Difficulty: Advanced
Estimated Reading Time: 14 minutes