# How to Deploy a Helm Chart on a Kubernetes Cluster

Source: https://docs.quake.ai/docs/kubernetes/how-to/deploy-helm-chart
Markdown: https://docs.quake.ai/docs/kubernetes/how-to/deploy-helm-chart.md

---

# How to deploy a Helm chart on a Kubernetes cluster

Install the Helm CLI, point it at a Quake AI Kubernetes cluster (OpenStack Magnum), and deploy a chart with a values file. This guide covers adding a chart repository, running `helm upgrade --install`, supplying image-pull credentials for private registries, exposing a release through a Kubernetes Service of type `LoadBalancer`, and rolling back a release.


**Helm and chart sources are yours to own.** Helm runs against any standard Kubernetes cluster. A Quake AI Kubernetes cluster runs upstream Kubernetes, so Helm works against it the same way it works anywhere. Quake AI does not run a managed Helm service or an application catalog. You choose the chart repositories you trust, you own the `values.yaml` you supply, and you operate the releases you install. This page uses charts from a public repository as a concrete example; substitute any chart you control.


<PrerequisiteBlock methods={["cli"]}>

- A Quake AI Kubernetes cluster in `CREATE_COMPLETE` status. See [How to create a Kubernetes cluster](/docs/kubernetes/how-to/create-cluster).
- `kubectl` installed on your workstation. The [cluster creation guide](/docs/kubernetes/how-to/create-cluster) covers retrieving a kubeconfig.
- The `openstack` CLI authenticated with a password-scoped session. `openstack coe cluster config` reads the cluster's kubeconfig through Magnum. See the [Kubernetes FAQ](/docs/kubernetes/faq) for the password-scope requirement.
- Network access from your workstation to the cluster's Kubernetes API endpoint.

</PrerequisiteBlock>

## Install the Helm CLI

Helm is a single client-side binary. It stores release state as Secrets inside the cluster, so no server-side component (no Tiller) runs on the cluster. Helm 3 and Helm 4 share the same command set used in this guide.

Install Helm with the official script:

```bash
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
```

On macOS, install Helm with Homebrew instead:

```bash
brew install helm
```

Confirm the version:

```bash
helm version
```

Expected output names a current Helm release (for example `v3.15.x` or `v4.x`):

```text
version.BuildInfo{Version:"v4.2.2", GitTreeState:"clean", GoVersion:"go1.24.0"}
```

## Connect Helm to your cluster

Helm reads the same kubeconfig as `kubectl`. Retrieve the cluster's kubeconfig from Magnum, then confirm both tools target the cluster.

Retrieve and load the kubeconfig:

```bash
openstack coe cluster config production-k8s --dir "$HOME/.kube/production-k8s"
export KUBECONFIG="$HOME/.kube/production-k8s/config"
```

`openstack coe cluster config` with `--dir` writes the cluster's `config` file to the directory you name. Without `--dir` the command writes `config` into the current working directory, which fails when that directory already holds a `config` entry (for example a Helm chart's `config/` folder). Set `KUBECONFIG` to the written file so both `kubectl` and `helm` read it.

Confirm `kubectl` reaches the cluster:

```bash
kubectl get nodes
```

Confirm Helm resolves the same context:

```bash
helm list --all-namespaces
```

An empty release table confirms Helm connects to a cluster with no Helm-managed releases yet.

## Add a chart repository

A chart repository is an index of packaged charts served over HTTP. Add the repository that hosts the chart you want, then refresh the local index.

```bash
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
```

Search the repository for a chart and inspect its configurable values:

```bash
helm search repo bitnami/nginx
helm show values bitnami/nginx > default-values.yaml
```

`helm show values` writes the chart's full default values to `default-values.yaml`. Use it as the reference for the keys you override in your own values file.



Since 28.08.2025, Bitnami limits the free public chart catalog. Installing `bitnami/nginx` may print a subscription or rolling-tag warning. The walk in this guide still completes with the free images; substitute any chart repository you control if your policy forbids vendor warnings.



## Install a chart with a values file

Keep your overrides in a version-controlled values file rather than passing every setting on the command line. Create `values.yaml` with the settings your deployment needs:

```yaml
replicaCount: 2
service:
  type: ClusterIP
resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 250m
    memory: 256Mi
```

Install the chart with `helm upgrade --install`. This command installs the release if it does not exist and upgrades it in place if it does, so the same command works for the first deploy and every later change:

```bash
helm upgrade --install web bitnami/nginx \
  --namespace web \
  --create-namespace \
  --values values.yaml
```

| Flag | Description |
|---|---|
| `web` | The release name. Helm tracks all resources it creates under this name. |
| `bitnami/nginx` | The chart reference in `repository/chart` form. |
| `--namespace` | The target namespace for the release. |
| `--create-namespace` | Creates the namespace if it does not already exist. |
| `--values` | Path to your values file. Repeat the flag to layer multiple files; later files win. |

Confirm the release and its pods:

```bash
helm status web --namespace web
kubectl get pods --namespace web
```

To preview the manifests a release would apply without changing the cluster, add `--dry-run` to the `helm upgrade --install` command.

## Pull images from a private registry

If your chart references images in a private registry, create an image-pull secret in the release namespace and reference it from your values file. Without it, pods fail to start with `ImagePullBackOff`.

Create the secret:

```bash
kubectl create secret docker-registry regcred \
  --namespace web \
  --docker-server=registry.example.com \
  --docker-username=YOUR_REGISTRY_USER \
  --docker-password=YOUR_REGISTRY_TOKEN
```

Reference the secret from your values file. Most charts expose an image-pull-secrets key; some read a global key:

```yaml
global:
  imagePullSecrets:
    - regcred
```

Charts vary in where they expose this key. Check the output of `helm show values` for the exact path before you set it. Re-run the `helm upgrade --install` command to apply the change.

## Expose a release with a load balancer

A chart that serves traffic outside the cluster can expose it through a Kubernetes Service of type `LoadBalancer`. The cluster assigns a public address to the Service and routes traffic to the release pods.

Set the Service type in your values file:

```yaml
service:
  type: LoadBalancer
```

Apply the change and watch for the assigned address:

```bash
helm upgrade --install web bitnami/nginx \
  --namespace web \
  --values values.yaml
kubectl get svc web-nginx --namespace web --watch
```

When provisioning completes, the `EXTERNAL-IP` column shows the load balancer address. On a healthy cluster, the address usually appears within a few minutes. Wait up to 10 minutes before you treat a pending address as a failure.

### When EXTERNAL-IP stays pending

The cluster provisions the public Service endpoint asynchronously. If `EXTERNAL-IP` is still empty after about 10 minutes, inspect the Service and its events:

```bash
kubectl describe svc web-nginx --namespace web
kubectl get events --namespace web --field-selector involvedObject.name=web-nginx
openstack quota show --floatingip
```

Healthy provisioning emits `EnsuringLoadBalancer` and `EnsuredLoadBalancer` events on the Service. Repeated error events point to cluster networking, cloud-controller-manager, or floating IP quota problems rather than Helm. Capture the command output above before you file a platform ticket if provisioning never completes.


**Floating IP count.** Each Service of type `LoadBalancer` that requests a public address consumes one floating IP. Confirm your project's floating IP budget with `openstack quota show` before exposing multiple Services. To keep public-address use low, expose a single ingress Service and route internal traffic to it with `ClusterIP` Services.



**Terminate TLS inside the cluster.** A `LoadBalancer` Service forwards TCP or UDP traffic to the cluster. Use an in-cluster ingress controller such as ingress-nginx or Traefik for HTTPS termination, hostname routing, and path routing. Use cert-manager with an ACME issuer to request and renew certificates.


## Roll back a release

Helm records a numbered revision on every install and upgrade. When an upgrade misbehaves, roll back to a known-good revision.

List the revision history:

```bash
helm history web --namespace web
```

Roll back to a specific revision:

```bash
helm rollback web 1 --namespace web
```

`helm rollback` creates a new revision that restores the resource state of the target revision, so the rollback is itself recorded in the history and is reversible. Confirm the result:

```bash
helm status web --namespace web
```

To remove a release and the resources it created:

```bash
helm uninstall web --namespace web
```

`helm uninstall` deletes the release's Kubernetes objects, including any `LoadBalancer` Service, which releases the associated floating IP back to your project.

## Next steps

- [How to deploy to a Quake AI Kubernetes cluster from CI](/docs/kubernetes/how-to/deploy-from-ci): automate `helm upgrade` or `kubectl apply` from GitHub Actions or GitLab CI
- [How to use a container registry with Quake AI](/docs/kubernetes/how-to/use-container-registry): image pull secrets for private charts
- [How to create a Kubernetes cluster](/docs/kubernetes/how-to/create-cluster): provision the cluster this guide deploys to
- [How to create a cluster template](/docs/kubernetes/how-to/create-cluster-template): control boot volumes, node addressing, and the control-plane endpoint
- [How to manage a Kubernetes cluster](/docs/kubernetes/how-to/manage-cluster): scale workers, retrieve the kubeconfig, and delete clusters
- [Kubernetes FAQ](/docs/kubernetes/faq): control plane ownership, quotas, and CLI authentication
- [Kubernetes CLI reference](/reference/kubernetes/cli): the `openstack coe cluster` command set
