DEV Community

Cover image for Deploying NGINX on Minikube Using Helm
Krisha Arya
Krisha Arya

Posted on

Deploying NGINX on Minikube Using Helm

Environment Details

  • OS: Windows 11
  • Container Runtime: Docker Desktop (Linux containers)
  • Kubernetes: Minikube
  • Package Manager: Helm

Objective

  • Install Helm on Windows
  • Start Minikube cluster
  • Create a Helm chart
  • Deploy NGINX using Helm
  • Expose the application using NodePort
  • Verify application internally and externally
  • Understand why some commands fail and alternatives are used

Installing Helm on Windows

Helm is a package manager for Kubernetes, used to deploy applications using reusable charts.

Method 1: Install using Winget

winget install Helm.Helm
Enter fullscreen mode Exit fullscreen mode

📌 Why this method?

  • Simplest and fastest
  • Automatically adds Helm to PATH
  • Recommended for beginners

Method 2: Manual Installation (Alternative)

Download Helm binary:

https://get.helm.sh/helm-v4.1.0-windows-amd64.zip
Enter fullscreen mode Exit fullscreen mode

Extract it and place in:

C:\helm
Enter fullscreen mode Exit fullscreen mode

Add Helm to PATH:

$env:Path += ";C:\helm"
Enter fullscreen mode Exit fullscreen mode

Verify Helm Installation

helm version
Enter fullscreen mode Exit fullscreen mode

✔ Confirms Helm is installed and accessible

Starting Minikube Cluster

Helm works on top of Kubernetes, so Minikube must be running first.

Start Minikube

minikube start --driver=docker
Enter fullscreen mode Exit fullscreen mode

📌 Why Docker driver?

  • Best supported on Windows
  • Lightweight and stable

Possible Errors are:
1) Starting Minikube — Initial Failure
❌ Command
minikube start

❌ Error
PROVIDER_DOCKER_NOT_RUNNING
deadline exceeded running "docker version"

📌 Reason

Minikube is configured to use the Docker driver, but:
Docker Engine was not running.
OR Docker context was incorrect.
Minikube cannot create a Kubernetes cluster without Docker running.

2) Fixing Docker Environment
✅ Step 1: Remove incorrect Docker host variable
Remove-Item Env:DOCKER_HOST

📌 Why?
Sometimes Docker tools inherit a stale DOCKER_HOST variable, which breaks communication with Docker Desktop.

✅ Step 2: Verify variable is removed
echo $Env:DOCKER_HOST

Expected output:
(empty)

✅ Step 3: Switch Docker context
docker context use desktop-linux

📌 Why?
Minikube on Windows requires Linux containers, not Windows containers.

3) Pulling Kubernetes Images (Optional but Used Here)

You manually pulled Kubernetes images:

docker pull registry.k8s.io/kube-apiserver:v1.34.0
docker pull registry.k8s.io/kube-controller-manager:v1.34.0
docker pull registry.k8s.io/kube-scheduler:v1.34.0
docker pull registry.k8s.io/kube-proxy:v1.34.0
docker pull registry.k8s.io/coredns/coredns:v1.12.1
docker pull registry.k8s.io/etcd:3.6.4-0
docker pull registry.k8s.io/pause:3.10.1
docker pull docker.io/kicbase/stable:v0.0.48

📌 Why this was done

Minikube had network trouble reaching registry.k8s.io
Pre-pulling images avoids download failure inside the Minikube container

Check Cluster Status

kubectl get nodes
Enter fullscreen mode Exit fullscreen mode

Expected:

STATUS: Ready
Enter fullscreen mode Exit fullscreen mode

4) Starting Minikube Successfully
✅ Command Used
minikube start --driver=docker --force

📌 Why --force?

Skips some validations
Useful when Docker/network warnings exist
Allows Minikube to fall back to alternative image sources

Creating a Helm Chart

Helm charts provide a template-based way to deploy applications.


Create Chart

helm create my-first-chart
Enter fullscreen mode Exit fullscreen mode

📌 What this does

  • Creates a complete application structure
  • Includes Deployment, Service, and configuration templates

Chart Structure

my-first-chart/
├── charts/
├── templates/
├── Chart.yaml
├── values.yaml
Enter fullscreen mode Exit fullscreen mode

Editing values.yaml

values.yaml contains default configuration values for the chart.

✅ Open file

notepad values.yaml
Enter fullscreen mode Exit fullscreen mode

✅ Replace content with below one.

replicaCount: 1

image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: "latest"

imagePullSecrets: []

nameOverride: ""
fullnameOverride: ""

serviceAccount:
  create: true
  automount: true
  annotations: {}
  name: ""

podAnnotations: {}
podLabels: {}

podSecurityContext: {}
securityContext: {}

service:
  type: NodePort
  port: 80

ingress:
  enabled: false
  className: ""
  annotations: {}
  hosts: []
  tls: []

# THIS BLOCK FIXES YOUR ERROR
httpRoute:
  enabled: false
  annotations: {}
  parentRefs: []
  hostnames: []
  rules: []

resources: {}

livenessProbe:
  httpGet:
    path: /
    port: http

readinessProbe:
  httpGet:
    path: /
    port: http

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

volumes: []
volumeMounts: []

nodeSelector: {}
tolerations: []
affinity: {}
Enter fullscreen mode Exit fullscreen mode

📌 Why NodePort?

  • Easy exposure in Minikube
  • No Ingress needed initially
  • Suitable for learning/testing

Installing the Helm Chart

✅ Install Command

helm install nginx-release .
Enter fullscreen mode Exit fullscreen mode

📌 What happens

  • Helm renders templates
  • Kubernetes objects are created:

    • Deployment
    • Service
    • Pod

Verifying Deployment

🔍 Check Pods

kubectl get pods
Enter fullscreen mode Exit fullscreen mode

Expected:

STATUS: Running
Enter fullscreen mode Exit fullscreen mode

🔍 Check Service

kubectl get svc nginx-release-my-first-chart
Enter fullscreen mode Exit fullscreen mode

Expected:

TYPE: NodePort
PORT: 80:<nodePort>
Enter fullscreen mode Exit fullscreen mode

Getting Node IP & NodePort (Manual Way)

$env:NODEIP = kubectl get nodes -o jsonpath="{.items[0].status.addresses[0].address}"
$env:NODEPORT = kubectl get svc nginx-release-my-first-chart -o jsonpath="{.spec.ports[0].nodePort}"
echo "http://$env:NODEIP`:$env:NODEPORT"
Enter fullscreen mode Exit fullscreen mode

📌 Why this is done

  • NodePort services are accessed via:
  http://<NodeIP>:<NodePort>
Enter fullscreen mode Exit fullscreen mode

Internal Connectivity Test (From Inside Cluster)

Possible errors are:

❌ BusyBox Test (May Fail)

kubectl run test --rm -it --image=busybox -- wget -qO- nginx-release-my-first-chart
Enter fullscreen mode Exit fullscreen mode

❌ Sometimes fails due to:

  • Limited networking tools
  • DNS issues in BusyBox

✅ Correct Alternative (Curl Image)

kubectl run test --rm -it --image=curlimages/curl --restart=Never -- curl http://nginx-release-my-first-chart
Enter fullscreen mode Exit fullscreen mode

✔ Output:

Welcome to nginx!
Enter fullscreen mode Exit fullscreen mode

📌 Why curl image works

  • Built specifically for HTTP testing
  • Reliable DNS + networking

Accessing Service Using Minikube (Recommended Way)

✅ Command

minikube service nginx-release-my-first-chart
Enter fullscreen mode Exit fullscreen mode

📌 What this does

  • Automatically fetches NodePort
  • Creates a tunnel (required for Docker driver on Windows)
  • Opens browser with correct URL

Summary of Errors & Fixes

Error Reason Fix
Docker not running Docker Desktop stopped Restart Docker
BusyBox timeout Image limitations Use curl image
PowerShell -- error Linux syntax used Use single-line command
NodePort not opening Docker driver limitation Use minikube service

Key Learnings (Beginner Friendly)

  • Helm simplifies Kubernetes deployments
  • values.yaml controls app behavior
  • NodePort is easiest exposure method in Minikube
  • Docker driver needs tunnel for service access
  • Not all test images behave the same

Conclusion

You successfully:

  • Installed Helm
  • Created a Helm chart
  • Deployed NGINX using Helm
  • Exposed it via NodePort
  • Verified access internally and externally

Stay tuned for next kubernetes topic ! 😊

Top comments (0)