Deploy an application with Helm
Components like ingress-nginx, Prometheus, and cert-manager arrive as Helm charts, and so does most of the off-the-shelf software you will want on a cluster. Helm is how you install that class of thing. It takes a packaged application, a chart, and installs it as one named release you can upgrade and roll back as a unit. The chart ships with defaults; a values file is where you bend those defaults to a Syself Autopilot cluster, which is the part a generic Helm tutorial cannot do for you.
Install with values#
$ helm repo add example https://charts.example.com
$ helm install my-app example/some-app \
--namespace team-web --create-namespace \
--version 3.2.1 \
--values values.yaml
The values file overrides the chart's defaults. Two of those overrides matter on almost every chart you install here:
# Bind persistent volumes to a storage class that actually exists on the cluster
persistence:
storageClass: local-nvme # local NVMe; or a Hetzner Cloud volume class
# If the chart creates its own LoadBalancer Service, tell Hetzner where to place it
service:
annotations:
load-balancer.hetzner.cloud/location: fsn1
Both come back below, because getting them wrong is the usual reason a chart that works elsewhere stalls on Syself Autopilot.
Pin versions#
Pin the chart version with --version, and pin the application image tag through values. Those are two separate things: a chart version selects the templates and defaults, the image tag selects the code that actually runs. Leave either unpinned and the next helm install or helm upgrade can pull something newer than you tested, shifting behavior without warning. Pinning both makes a release reproducible, which is what you want when the same values file deploys to more than one cluster.
Upgrade and roll back#
$ helm upgrade my-app example/some-app --namespace team-web --version 3.3.0 --values values.yaml
$ helm history my-app --namespace team-web
$ helm rollback my-app 1 --namespace team-web # back to revision 1 if the upgrade misbehaves
Helm records every release as a numbered revision, so a bad upgrade is one rollback away. That safety net is the real reason to install even a one-manifest app as a release instead of a raw kubectl apply: the history and the reversible upgrade come for free.
Helm on this platform#
Most charts are written to land on a cluster with a single default StorageClass, where a PersistentVolumeClaim that names no class just works. Syself Autopilot hands you one, standard, backed by Hetzner Cloud volumes. It is still worth setting the class per application, because the right storage depends on the workload: local NVMe through local-nvme is fast but pinned to one node, while a Hetzner Cloud volume class is network-attached and follows the pod when a node is replaced. That choice is yours to make, per application: see running a StatefulSet with storage for which fits what.
The practical consequence: a chart whose PVC has no storageClassName set, and no persistence.storageClass value passed, lands on standard. Its volume stays Pending until a pod schedules, because standard binds on first consumer, then binds where that pod runs. Setting persistence.storageClass (or whatever key the chart exposes) is what puts it somewhere else. When pods hang on a fresh install, a kubectl describe pvc in the namespace usually names the reason directly.
The load balancer annotation is the same idea for networking. A chart that provisions its own Service of type LoadBalancer gets a Hetzner load balancer, and load-balancer.hetzner.cloud/location decides which location it lives in. Many charts already expose a service.annotations map for exactly this; pass it there rather than editing the rendered Service after the fact.
For anything you deploy more than once, stop running helm install from a laptop and let Argo CD render the chart from Git: an upgrade then becomes a values change in a pull request.
Pull images from a private registry
Give pods credentials to pull from a private container registry, per namespace or per service account, and read your way out of ImagePullBackOff.
Deploy an application with Kustomize
Adapt plain YAML to each environment without a template language, layering overlays over one base with built-in kubectl Kustomize.