Helm with Jenkins

A comprehensive guide to Helm with Jenkins covering Jenkins pipelines, chart automation, deployment strategies, and best practices for automated Helm workflows.

Jenkins Pipelines Automation
Why Jenkins for Helm?

Jenkins remains one of the most widely used CI/CD tools in enterprises. When combined with Helm, it provides a powerful platform for automating Kubernetes deployments. Jenkins offers several advantages for Helm workflows:

  • Mature Ecosystem: Thousands of plugins for integration
  • Flexibility: Supports any workflow pattern
  • Distributed Builds: Scale across multiple agents
  • Pipeline as Code: Declarative and scripted pipelines
  • Kubernetes Integration: Native support for Kubernetes agents
  • Enterprise Features: RBAC, audit logs, and security
Key Concept: Jenkins pipelines can automate the entire Helm chart lifecycle: linting, testing, packaging, signing, and deploying—all triggered by Git events or schedules.
Jenkins Pipeline Basics for Helm
// Jenkinsfile - Basic Helm Pipeline pipeline { agent any environment { HELM_VERSION = 'v3.14.0' CHART_DIR = 'charts/my-app' RELEASE_NAME = 'my-app' NAMESPACE = 'default' } stages { stage('Checkout') { steps { checkout scm } } stage('Install Helm') { steps { sh ''' curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh --version ${HELM_VERSION} helm version ''' } } stage('Lint') { steps { sh 'helm lint ${CHART_DIR}' } } stage('Template') { steps { sh 'helm template ${RELEASE_NAME} ${CHART_DIR} --debug' } } stage('Package') { steps { sh 'helm package ${CHART_DIR} --destination dist' } } stage('Deploy') { steps { sh 'helm upgrade --install ${RELEASE_NAME} ${CHART_DIR} --namespace ${NAMESPACE} --wait --timeout 5m' } } stage('Test') { steps { sh 'helm test ${RELEASE_NAME} --timeout 5m' } } } post { success { echo 'Deployment successful!' } failure { echo 'Deployment failed!' } always { cleanWs() } } }

Declarative Pipeline

Simpler, more structured syntax. Recommended for most Helm workflows.

Scripted Pipeline

More flexible, Groovy-based syntax. For complex workflows.

Kubernetes Agents

Dynamic agents that run in Kubernetes pods. Efficient resource usage.

Artifacts

Store packaged charts as Jenkins artifacts for distribution.
Kubernetes Agents for Helm

Jenkins Kubernetes plugin allows dynamic agent provisioning in Kubernetes. This is ideal for Helm workflows as it provides isolated, ephemeral environments for each build.

// Jenkinsfile - Kubernetes Agent pipeline { agent { kubernetes { yaml ''' apiVersion: v1 kind: Pod spec: containers: - name: helm image: alpine/helm:3.14.0 command: - cat tty: true - name: kubectl image: bitnami/kubectl:1.28 command: - cat tty: true - name: docker image: docker:24.0 command: - cat tty: true volumeMounts: - name: docker-sock mountPath: /var/run/docker.sock volumes: - name: docker-sock hostPath: path: /var/run/docker.sock ''' } } stages { stage('Lint') { steps { container('helm') { sh 'helm lint charts/my-app' } } } stage('Package') { steps { container('helm') { sh 'helm package charts/my-app --destination dist' } } } stage('Build Image') { steps { container('docker') { sh ''' docker build -t myregistry/my-app:${BUILD_NUMBER} . docker push myregistry/my-app:${BUILD_NUMBER} ''' } } } stage('Deploy') { steps { container('kubectl') { sh ''' helm upgrade --install my-app charts/my-app \ --namespace default \ --set image.tag=${BUILD_NUMBER} \ --wait --timeout 5m ''' } } } stage('Test') { steps { container('helm') { sh 'helm test my-app --timeout 5m' } } } } }
Kubernetes Agent Benefits:
  • Isolated environments for each build
  • Automatic scaling of build capacity
  • No permanent agents to maintain
  • Efficient resource utilization
  • Consistent tool versions across builds
Multi-Environment Deployment
// Jenkinsfile - Multi-Environment Deployment pipeline { agent { kubernetes { yaml ''' apiVersion: v1 kind: Pod spec: containers: - name: helm image: alpine/helm:3.14.0 command: ['cat'] tty: true - name: kubectl image: bitnami/kubectl:1.28 command: ['cat'] tty: true ''' } } parameters { choice(name: 'ENVIRONMENT', choices: ['dev', 'staging', 'production'], description: 'Target environment') string(name: 'RELEASE_VERSION', defaultValue: '1.0.0', description: 'Chart version') booleanParam(name: 'DRY_RUN', defaultValue: false, description: 'Dry run only') } environment { CHART_DIR = 'charts/my-app' RELEASE_NAME = 'my-app' VALUES_FILE = "values-${params.ENVIRONMENT}.yaml" } stages { stage('Validate') { steps { container('helm') { sh ''' echo "Validating chart for ${ENVIRONMENT}" helm lint ${CHART_DIR} -f ${CHART_DIR}/${VALUES_FILE} ''' } } } stage('Template') { steps { container('helm') { sh ''' echo "Rendering templates for ${ENVIRONMENT}" helm template ${RELEASE_NAME} ${CHART_DIR} \ -f ${CHART_DIR}/${VALUES_FILE} \ --set image.tag=${RELEASE_VERSION} \ > rendered-${ENVIRONMENT}.yaml ''' } } } stage('Approve') { when { expression { params.ENVIRONMENT == 'production' } } steps { timeout(time: 1, unit: 'HOURS') { input message: "Deploy to ${params.ENVIRONMENT}?", ok: 'Deploy', submitter: 'admin,release-manager' } } } stage('Deploy') { when { expression { !params.DRY_RUN } } steps { container('kubectl') { sh ''' helm upgrade --install ${RELEASE_NAME} ${CHART_DIR} \ --namespace ${ENVIRONMENT} \ --create-namespace \ -f ${CHART_DIR}/${VALUES_FILE} \ --set image.tag=${RELEASE_VERSION} \ --wait --timeout 10m \ --atomic ''' } } } stage('Verify') { when { expression { !params.DRY_RUN } } steps { container('kubectl') { sh ''' echo "Verifying deployment in ${ENVIRONMENT}" kubectl get pods -n ${ENVIRONMENT} -l app=my-app kubectl get svc -n ${ENVIRONMENT} -l app=my-app kubectl rollout status deployment/my-app -n ${ENVIRONMENT} ''' } } } stage('Test') { when { expression { !params.DRY_RUN } } steps { container('helm') { sh 'helm test ${RELEASE_NAME} -n ${ENVIRONMENT} --timeout 5m' } } } } post { success { slackSend( channel: '#deployments', color: 'good', message: "✅ Deployment successful: ${RELEASE_NAME} to ${ENVIRONMENT} (${RELEASE_VERSION})" ) } failure { slackSend( channel: '#deployments', color: 'danger', message: "❌ Deployment failed: ${RELEASE_NAME} to ${ENVIRONMENT} (${RELEASE_VERSION})" ) } } }
Multi-Environment Best Practices:
  • Use environment-specific values files
  • Require approval for production deployments
  • Use --atomic for automatic rollback
  • Verify deployments after installation
  • Run helm tests for each environment
  • Send notifications on success/failure
Advanced Pipeline Features

Chart Signing in Jenkins

// Jenkinsfile - Chart Signing pipeline { agent any environment { GPG_KEY_ID = credentials('gpg-key-id') GPG_PASSPHRASE = credentials('gpg-passphrase') } stages { stage('Import GPG Key') { steps { withCredentials([file(credentialsId: 'gpg-private-key', variable: 'GPG_KEY')]) { sh ''' gpg --batch --import $GPG_KEY ''' } } } stage('Package and Sign') { steps { sh ''' helm package charts/my-app \ --sign \ --key "${GPG_KEY_ID}" \ --keyring ~/.gnupg/secring.gpg \ --destination dist ''' } } stage('Verify Signature') { steps { sh ''' for chart in dist/*.tgz; do helm verify "$chart" done ''' } } stage('Publish') { steps { sh ''' helm push dist/*.tgz oci://myregistry.azurecr.io/helm ''' } } } }

Unit Testing in Jenkins

// Jenkinsfile - Unit Testing pipeline { agent any stages { stage('Install Plugins') { steps { sh 'helm plugin install https://github.com/helm-unittest/helm-unittest' } } stage('Unit Test') { steps { sh 'helm unittest charts/my-app --debug' } post { always { junit 'test-results/*.xml' } } } stage('Validate with Kubeconform') { steps { sh ''' wget https://github.com/yannh/kubeconform/releases/latest/download/kubeconform-linux-amd64.tar.gz tar xf kubeconform-linux-amd64.tar.gz helm template test charts/my-app | ./kubeconform -strict ''' } } } }

Security Scanning in Jenkins

// Jenkinsfile - Security Scanning pipeline { agent any stages { stage('Scan Charts') { steps { sh ''' # Install Trivy wget https://github.com/aquasecurity/trivy/releases/latest/download/trivy_0.48.0_Linux-64bit.tar.gz tar xf trivy_0.48.0_Linux-64bit.tar.gz # Scan chart ./trivy config charts/my-app ''' } } stage('Check Secrets') { steps { sh ''' # Install gitleaks wget https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks_8.18.0_linux_x64.tar.gz tar xf gitleaks_8.18.0_linux_x64.tar.gz # Scan for secrets ./gitleaks detect --source charts/my-app --verbose ''' } } } }
Jenkins + Helm Best Practices

Pipeline as Code

Store Jenkinsfile in your Git repository alongside charts.

Use Kubernetes Agents

Run builds in ephemeral Kubernetes pods for isolation.

Secure Credentials

Use Jenkins Credentials for registry tokens and GPG keys.

Lint Before Deploy

Always lint and validate charts before deployment.

Atomic Deployments

Use --atomic for automatic rollback on failure.

Notifications

Send build and deployment notifications to Slack/Teams.

Archive Artifacts

Store packaged charts and test results as artifacts.

Security Scans

Scan charts for vulnerabilities and secrets in CI.
// Best practices summary // 1. Pipeline as Code // Store Jenkinsfile in Git: // - charts/my-app/Jenkinsfile // - Jenkinsfile in repository root // 2. Use Kubernetes Agents agent { kubernetes { yaml '''...''' } } // 3. Secure Credentials withCredentials([ string(credentialsId: 'registry-token', variable: 'TOKEN'), file(credentialsId: 'gpg-key', variable: 'GPG_KEY') ]) { // Use credentials } // 4. Lint Before Deploy sh 'helm lint charts/my-app' // 5. Atomic Deployments sh ''' helm upgrade --install my-app charts/my-app \ --atomic \ --wait \ --timeout 10m ''' // 6. Notifications post { success { slackSend(channel: '#deployments', color: 'good', message: 'Deployment successful') } failure { slackSend(channel: '#deployments', color: 'danger', message: 'Deployment failed') } } // 7. Archive Artifacts archiveArtifacts artifacts: 'dist/*.tgz', fingerprint: true // 8. Security Scans sh 'trivy config charts/my-app' sh 'gitleaks detect --source charts/my-app'
Frequently Asked Questions
How do I install Helm in Jenkins?
Use the official install script in a pipeline step: curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash. Or use a Docker image with Helm pre-installed.
How do I use Kubernetes agents with Helm?
Use the Jenkins Kubernetes plugin. Define a pod template with Helm and kubectl containers. The agent runs in a pod, providing isolation and scalability.
How do I handle secrets in Jenkins for Helm?
Use Jenkins Credentials to store registry tokens, GPG keys, and Kubernetes configs. Use withCredentials to securely inject them into pipeline steps.
How do I implement multi-environment deployment with Jenkins?
Use parameters to select the environment, environment-specific values files, and input steps for production approval. Deploy to each environment sequentially with verification.
How do I sign Helm charts in Jenkins?
Import your GPG private key from Jenkins Credentials, then use helm package --sign. Store the key and passphrase as credentials.
How do I run helm test in Jenkins?
After deployment, run helm test <release> --timeout 5m. Check the exit code and fail the pipeline if tests fail.
How do I rollback with Jenkins?
Use helm rollback <release> <revision> in a pipeline step. Or use --atomic during upgrade for automatic rollback on failure.
What are the best practices for Jenkins + Helm?
Store Jenkinsfile in Git, use Kubernetes agents, secure credentials, lint before deploy, use atomic deployments, send notifications, archive artifacts, and scan for security issues.
Previous: Helm with GitHub Actions Next: Debugging Helm Charts

Jenkins provides a powerful, flexible platform for automating Helm chart workflows. Implement these pipelines and best practices to ensure reliable, secure, and efficient Helm deployments.