Kubernetes
Helm Charts
Docker
Local Docker Image
Container Orchestration

Kubernetes-Helm Charts pointing to a local docker image

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Pointing a Helm chart at a local Docker image only works when the Kubernetes node runtime can actually see that image. Helm does not transfer image layers for you; it only renders manifests, so the real question is whether your cluster can resolve my-app:dev from its own container runtime.

Keep Image Settings Configurable

The chart should treat image name, tag, and pull policy as values rather than hard-coded strings. That gives you one chart that works for local development and registry-backed environments.

yaml
1image:
2  repository: my-app
3  tag: dev
4  pullPolicy: IfNotPresent
yaml
1containers:
2  - name: app
3    image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
4    imagePullPolicy: {{ .Values.image.pullPolicy }}

IfNotPresent is the usual choice for local development because it lets a node reuse an image that has already been loaded instead of forcing a remote pull every time.

Why a Local Tag Often Fails

It is easy to think docker build -t my-app:dev . is enough, because the image exists on your workstation. Kubernetes pods do not use your local Docker cache unless the cluster shares that runtime directly. In most cases, each node has its own image store, so the kubelet still tries to pull the tag remotely unless you preload the image or point to a real registry.

Load the Image Into the Cluster Runtime

The important step is not Helm itself. It is making the image available to the cluster runtime.

For Kind:

bash
docker build -t my-app:dev .
kind load docker-image my-app:dev --name dev-cluster
helm upgrade --install my-app ./chart -f values-dev.yaml

For Minikube:

bash
docker build -t my-app:dev .
minikube image load my-app:dev
helm upgrade --install my-app ./chart -f values-dev.yaml

For k3d:

bash
docker build -t my-app:dev .
k3d image import my-app:dev -c dev-cluster
helm upgrade --install my-app ./chart -f values-dev.yaml

Each of these commands copies the image into the cluster's container runtime. Without that step, pods usually fail with ImagePullBackOff or ErrImagePull.

Prefer a Registry for Shared Environments

Local image tags are useful for personal iteration, but they do not scale well to shared clusters or CI pipelines. For reproducible deployments, push the image to a registry and deploy a stable tag or digest.

yaml
1image:
2  repository: registry.example.com/team/my-app
3  tag: "1.4.2"
4  pullPolicy: IfNotPresent

That gives every node a consistent source of truth and makes rollback behavior much easier to reason about. In production, digests are even better than tags because they are immutable.

Debug the Rendered Manifest and Pod Events

If the pod does not start, verify both the rendered Helm output and the Kubernetes events. You want to know which image string was deployed and what the kubelet tried to pull.

bash
1helm template my-app ./chart -f values-dev.yaml | grep -n "image:"
2kubectl get pods
3kubectl describe pod my-app-12345
4kubectl get events --sort-by=.lastTimestamp

If the rendered manifest is correct but the pod still fails, the issue is usually image availability, pull policy, or registry credentials rather than the chart template itself.

For team workflows, keep local-image settings in a dedicated file such as values-dev.yaml. That makes it obvious when a release is using a personal development tag instead of a registry-backed artifact.

Common Pitfalls

  • Assuming Helm can pull an image directly from your laptop Docker cache into a remote cluster.
  • Using imagePullPolicy: Always with a tag that exists only locally.
  • Reusing mutable tags such as latest, which makes it hard to tell which build actually ran.
  • Forgetting to load a rebuilt image after changing application code.
  • Debugging only the chart template and ignoring pod events, where the actual pull failure is reported.

Summary

  • Helm manages manifests, not container image distribution.
  • Local tags work only when the cluster runtime has the image loaded.
  • Use cluster-specific load commands for Kind, Minikube, and k3d.
  • Prefer registry-backed immutable artifacts for team and CI workflows.
  • Diagnose failures by checking both rendered manifests and pod events.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.