Overview
This guide walks through deploying Jenkins CI/CD on MicroK8s using Helm charts with MetalLB as the load balancer. This setup provides a production-ready Jenkins environment on bare-metal Kubernetes clusters without requiring cloud provider load balancers.
Architecture Components
| Component | Purpose | Version Info |
|---|---|---|
| MicroK8s | Lightweight Kubernetes distribution | Single-node or multi-node cluster |
| MetalLB | Bare-metal load balancer implementation | Layer 2 or BGP mode |
| Helm | Kubernetes package manager | v3.x recommended |
| Jenkins | CI/CD automation server | Latest LTS via Helm chart |
Prerequisites
Before proceeding, ensure you have:
- MicroK8s installed and running (
microk8s status --wait-ready) - User added to
microk8sgroup for non-root access - Sufficient resources: minimum 2 CPU cores, 4GB RAM recommended
- Network access to the IP range you'll assign to MetalLB
Enable MetalLB
MetalLB is a load-balancer implementation for bare-metal Kubernetes clusters. It provides LoadBalancer-type services that would otherwise only work in cloud environments like AWS, GCP, or Azure.
1microk8s enable metallbDuring enablement, you'll be prompted to specify an IP address range. Choose IPs from your local network that are not used by DHCP to avoid conflicts.
Full installation with modules go here -> MicroK8s install with Helm and OneDev
Understanding MetalLB Modes
MetalLB supports two announcement modes:
Layer 2 Mode (Default for MicroK8s)
- Uses ARP/NDP to announce IPs on the local network
- Simpler setup, no router configuration required
- Single node handles all traffic for a given IP (failover available)
- Best for home labs and small deployments
BGP Mode
- Announces IPs via BGP to network routers
- True load distribution across nodes
- Requires BGP-capable router configuration
- Better for production environments
MetalLB Configuration Resources
After enabling MetalLB, you can customize the IP allocation using Custom Resources:
1# IPAddressPool defines the range of IPs MetalLB can allocate2apiVersion: metallb.io/v1beta13kind: IPAddressPool4metadata:5 name: default-pool6 namespace: metallb-system7spec:8 addresses:9 - 192.168.1.200-192.168.1.220 # Adjust to your network10 autoAssign: true11 avoidBuggyIPs: true # Avoid .0 and .255 addresses1# L2Advertisement enables Layer 2 mode for the pool2apiVersion: metallb.io/v1beta13kind: L2Advertisement4metadata:5 name: default-l26 namespace: metallb-system7spec:8 ipAddressPools:9 - default-poolInstall Helm
Helm is the package manager for Kubernetes, enabling you to define, install, and upgrade complex Kubernetes applications.
1sudo snap install helm --classicVerify Helm Installation
1helm versionConfigure Helm with MicroK8s
If you're using MicroK8s built-in Helm, you can use microk8s helm3 instead. For standalone Helm, ensure kubectl is configured:
1# Export kubeconfig for standalone helm2mkdir -p ~/.kube3microk8s config > ~/.kube/configInstall Jenkins
Add the official Jenkins Helm repository and update the local cache:
1helm repo add jenkins https://charts.jenkins.io2helm repo updateExplore Available Versions
1# List available Jenkins chart versions2helm search repo jenkins/jenkins --versions | head -20Deploy Jenkins
1helm install jenkins jenkins/jenkins --namespace jenkins --create-namespace --set controller.serviceType=LoadBalancerUnderstanding Deployment Parameters
| Parameter | Value | Description |
|---|---|---|
jenkins (1st) | Release name | Helm release identifier |
jenkins/jenkins | Chart reference | Repository/chart name |
--namespace jenkins | Namespace | Kubernetes namespace for isolation |
--create-namespace | Flag | Creates namespace if not exists |
--set controller.serviceType=LoadBalancer | Override | Exposes Jenkins via MetalLB |
Advanced Deployment with Custom Values
For production deployments, create a values.yaml file for customization:
1# jenkins-values.yaml - Production configuration example2controller:3 # Image configuration4 image:5 tag: "lts-jdk17" # Use LTS with JDK 176
7 # Resource allocation8 resources:9 requests:10 cpu: "500m"11 memory: "1Gi"12 limits:13 cpu: "2000m"14 memory: "4Gi"15
16 # Service configuration for MetalLB17 serviceType: LoadBalancer18 servicePort: 808019
20 # Admin configuration21 admin:22 username: admin23 # Password will be auto-generated if not specified24
25 # Install essential plugins26 installPlugins:27 - kubernetes:latest28 - workflow-aggregator:latest29 - git:latest30 - configuration-as-code:latest31 - job-dsl:latest32 - blueocean:latest33
34 # JCasC - Jenkins Configuration as Code35 JCasC:36 defaultConfig: true37 configScripts:38 welcome-message: |39 jenkins:40 systemMessage: "Jenkins configured via Helm on MicroK8s"41
42# Persistence configuration43persistence:44 enabled: true45 size: 10Gi46 storageClass: "microk8s-hostpath" # Use MicroK8s storage47
48# Agent configuration for Kubernetes49agent:50 enabled: true51 image:52 repository: jenkins/inbound-agent53 tag: "latest"54 resources:55 requests:56 cpu: "256m"57 memory: "256Mi"58 limits:59 cpu: "512m"60 memory: "512Mi"Deploy with custom values:
1helm install jenkins jenkins/jenkins \2 --namespace jenkins \3 --create-namespace \4 -f jenkins-values.yamlEnable Required MicroK8s Addons
For full Jenkins functionality, enable these addons:
1# Enable persistent storage for Jenkins data2microk8s enable hostpath-storage3
4# Enable DNS for service discovery5microk8s enable dns6
7# Enable RBAC for security (usually enabled by default)8microk8s enable rbacGet IP
1kubectl get services -n jenkinsExpected Output
1NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE2jenkins LoadBalancer 10.152.183.45 192.168.1.200 8080:32000/TCP 2m3jenkins-agent ClusterIP 10.152.183.89 <none> 50000/TCP 2mThe EXTERNAL-IP is provided by MetalLB and is accessible from your local network.
Verify MetalLB IP Assignment
1# Check MetalLB speaker logs for IP announcement2kubectl logs -n metallb-system -l app=metallb,component=speaker --tail=50Get password
1printf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echoAccess Jenkins
- Open your browser and navigate to:
http://<EXTERNAL-IP>:8080 - Login with:
- Username:
admin - Password: The output from the command above
- Username:
Post-Installation Configuration
Verify Jenkins Pod Health
1# Check pod status2kubectl get pods -n jenkins -w3
4# View Jenkins startup logs5kubectl logs -n jenkins -l app.kubernetes.io/name=jenkins -fConfigure Jenkins Kubernetes Plugin
Jenkins automatically configures the Kubernetes plugin when deployed via Helm. Verify the cloud configuration:
- Navigate to Manage Jenkins → Clouds
- Verify Kubernetes cloud is configured
- Test connection to the cluster
Backup and Recovery
Jenkins data is stored in a PersistentVolume. To backup:
1# Get PVC information2kubectl get pvc -n jenkins3
4# Create a backup job (example using kubectl cp)5kubectl cp jenkins/jenkins-0:/var/jenkins_home ./jenkins-backupTroubleshooting
MetalLB Not Assigning IP
1# Check MetalLB controller status2kubectl get pods -n metallb-system3
4# Verify IPAddressPool configuration5kubectl get ipaddresspools -n metallb-system -o yaml6
7# Check for conflicts in IP range8kubectl describe service jenkins -n jenkinsJenkins Pod Not Starting
1# Check pod events2kubectl describe pod -n jenkins -l app.kubernetes.io/name=jenkins3
4# Check for resource constraints5kubectl top nodes6
7# View init container logs8kubectl logs -n jenkins jenkins-0 -c initHelm Release Issues
1# List Helm releases2helm list -n jenkins3
4# View release history5helm history jenkins -n jenkins6
7# Rollback if needed8helm rollback jenkins <revision> -n jenkinsCleanup
To completely remove Jenkins and associated resources:
1# Uninstall Helm release2helm uninstall jenkins -n jenkins3
4# Delete namespace (removes PVC and all resources)5kubectl delete namespace jenkins6
7# Optional: Disable MetalLB if no longer needed8microk8s disable metallb