Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Secure Helm Release Management on AKS

Hello. Your chart now renders two Deployments, two Services, and an optional Ingress, while referring to a database Secret by name and key rather than containing its value. So far, you have only rendered the chart locally. This lesson takes it through a controlled AKS release: validate it, install it without disturbing the manually managed application, inspect an upgrade, and roll back to a known-good revision.

Allow about 50–60 minutes if your AKS lab is already running. You can complete the local validation without Azure resources; do not start or prolong an AKS lab solely to follow along if its cost would exceed your remaining budget.


A release needs a safe landing place

Helm installs a chart as a release. Its name, namespace, chart, and values together determine the resources Helm manages and the revisions it can later restore. In this lesson, ui-lab is the example release name and app-lab is the example namespace; substitute your existing namespace if different.

The chart generates names such as ui-lab-backend and ui-lab-frontend. Those should be distinct from your manually managed Deployments and Services. Keep Ingress disabled for this first installation: a second Ingress claiming the same host and paths could interfere with your existing application. Port-forwarding will let you test the new Services without publishing another endpoint.

Before making a release, read the relevant Helm commands in their original context:

Using Helm | Helm

Read the official Helm guide to distinguish a chart from an installed release and to see how a values file affects installation.

In “'helm install': Installing a Package,” start where the guide introduces the two install arguments. Read installation and releases. Then continue from “Helm does not wait until all of the resources are running before it exits” through the helm status example to see why a returned install command is not, by itself, an application test. In “Customizing the Chart Before Installing,” read values overrides, stopping after the explanation of -f and --set precedence. Focus on using these mechanisms for non-secret settings only.

For the connected part of this lab, confirm these prerequisites rather than assuming that rendering proved them:

  • Your short-lived AKS cluster is reachable with kubectl, and the intended namespace exists.
  • Both versioned images exist in your private registry, and AKS can pull them.
  • The namespace contains the Secret name and key referenced by the backend chart. A Secret in another namespace will not satisfy that reference.
  • Your PostgreSQL lab is reachable from the backend, and any required schema preparation is complete. Avoid running incompatible schema changes against a database also used by the manually managed application.
  • The cluster has room for an additional frontend and backend Pod. If that would require another paid node, defer the installation or plan the cutover before proceeding.

Prepare a non-secret, uncommitted-or-reviewed-as-appropriate lab override at charts/frontend-lab/values-release.yaml:

frontend:
  image:
    repository: replace-me.azurecr.io/frontend
    tag: "replace-with-a-pushed-version"

backend:
  image:
    repository: replace-me.azurecr.io/backend
    tag: "replace-with-a-pushed-version"
  config:
    logLevel: INFO
  databaseSecret:
    name: app-db
    key: database-url

ingress:
  enabled: false

Replace the repositories, tags, and Secret reference with your actual lab settings. Do not put a password, connection string, token, or certificate content in this file. Check that your backend’s environment-variable name and probe paths still match the chart you adapted last lesson.


Validate before touching the cluster

Validation has layers. helm lint checks the chart; helm template shows what its templates produce; a connected dry run can catch some cluster-side problems. None of them establishes that a container will pull successfully, become ready, or serve a working REST or WebSocket request.

Debugging Templates | Helm

Read Helm’s debugging guide for the distinct jobs of linting, local rendering, connected dry runs, and inspecting an installed manifest.

In “Debugging Templates,” read the opening explanation and the command list. Stop after the helm get manifest bullet; the later material on debugging lookup is not needed for this chart. Notice which checks work locally and which involve the cluster.

Cost of local validation: The following commands create no Azure resources and incur no new Azure charge. Any AKS cluster, database, registry, or networking resources you have left running continue to accrue their existing charges.

From the repository root:

helm lint ./charts/frontend-lab \
  -f ./charts/frontend-lab/values-release.yaml

helm template ui-lab ./charts/frontend-lab \
  --namespace app-lab \
  -f ./charts/frontend-lab/values-release.yaml

Expect four rendered objects: two Deployments and two Services. There should be no Ingress. Check the exact image tags, backend probe paths, LOG_LEVEL, and the secretKeyRef. In particular, verify that the output contains a Secret name and key, not a credential value. Do not save rendered output containing secrets if you later adapt the chart to render any.

If AKS is already running, inspect the target before installing:

kubectl config current-context
kubectl -n app-lab get deployments,services,ingresses
kubectl -n app-lab describe secret app-db
helm list -n app-lab --all

describe secret shows metadata and keys without printing their values; confirm that the required key exists. Check that ui-lab is not already a release and that the chart-generated resource names are not already in use. If the chart was installed previously, stop and inspect its history instead of attempting a fresh install—particularly because your previous lesson changed a Deployment selector that cannot be updated as an ordinary Kubernetes Deployment upgrade.

For a connected check, use a server dry run if your Helm CLI supports it:

helm install ui-lab ./charts/frontend-lab \
  --namespace app-lab \
  -f ./charts/frontend-lab/values-release.yaml \
  --dry-run=server --debug

Review the output before sharing or storing it: a Helm dry run can print rendered manifests and values. This chart should contain only a Secret reference, but that safety depends on what you actually put in its files. A successful dry run still cannot establish Secret contents, registry authorization, database connectivity, or probe success.

Cost of connected validation: This does not install the release. It uses your already-running AKS cluster, whose nodes and associated resources continue to be billed while it is up; it should not require another node, public IP, or load balancer. If you must provision or restart the cluster for this step, first revisit your lab estimate and budget alerts.


Install and inspect the first revision

Once the prerequisites and rendered manifests are correct, install with a bounded wait:

helm install ui-lab ./charts/frontend-lab \
  --namespace app-lab \
  -f ./charts/frontend-lab/values-release.yaml \
  --wait --timeout 5m

--wait makes Helm wait for its Kubernetes readiness conditions, subject to the timeout. It is useful, but it is not an end-to-end test. A successful install should create revision 1. Inspect both Helm’s account of the release and Kubernetes’ account of its workloads:

helm status ui-lab -n app-lab
helm history ui-lab -n app-lab
helm get values ui-lab -n app-lab
helm get manifest ui-lab -n app-lab

kubectl -n app-lab get deployments ui-lab-backend ui-lab-frontend
kubectl -n app-lab get services ui-lab-backend ui-lab-frontend
kubectl -n app-lab get pods -l app.kubernetes.io/instance=ui-lab

helm get values shows the release overrides; helm get manifest shows the Kubernetes objects Helm stored for the release. Inspect that output privately before copying it anywhere. Helm release history is not a secret store: even if your chart renders a Kubernetes Secret, putting its literal value in chart values or templates can retain that value in release data. Here, the manifest should contain only secretKeyRef.name and secretKeyRef.key.

Test the new Services without adding an Ingress. In one terminal, run:

kubectl -n app-lab port-forward svc/ui-lab-backend 18000:80

In a second terminal, check the endpoints your application actually implements:

curl -f http://127.0.0.1:18000/health/live
curl -f http://127.0.0.1:18000/health/ready

Stop that port-forward, then check the frontend separately:

kubectl -n app-lab port-forward svc/ui-lab-frontend 18080:80
curl -f http://127.0.0.1:18080/

Stop the second port-forward when finished. These checks establish that the new Pods and Services respond locally; they do not test your disabled Ingress or a browser WebSocket connection. Continue using the existing Ingress until you deliberately plan its cutover. If installation times out, inspect release status and Pod conditions before deciding whether to retry or roll back; do not assume Helm has removed the attempted resources.

Cost of installation and inspection: The release adds two Pods to your existing AKS cluster but, with ingress.enabled: false and ClusterIP Services, does not request a new public load balancer. It may increase node, registry-transfer, database, or logging usage. If the Pods trigger an additional node, that can be a substantial new charge relative to a roughly $50 monthly lab budget. The existing AKS nodes, database, registry storage, and any existing public IP or Ingress infrastructure remain billable throughout the test.


Upgrade one observable setting, then roll it back

A revision is a recorded release state, not necessarily a new application image. For a controlled first upgrade, keep the proven image tags and change only the backend’s non-secret log level. That makes the effect easy to inspect without building or pulling another image.

Using Helm | Helm

Return to the official Helm guide for its upgrade and rollback examples, the meaning of release revisions, and the difference between rollback and uninstall.

In “'helm upgrade' and 'helm rollback': Upgrading a Release, and Recovering on Failure,” begin with the upgrade command near the start of the subsection, then read values and history through the explanation of revision numbers. In “Helpful Options for Install/Upgrade/Rollback,” read the --wait bullet, from readiness conditions to the end of that bullet. Finally, in “'helm uninstall': Uninstalling a Release,” read uninstall behavior. The examples use a different application; focus on the release commands rather than its settings.

Apply the same reviewed override file on upgrade and reset to the chart defaults before applying it. Supply --set only for this non-secret log level:

helm upgrade ui-lab ./charts/frontend-lab \
  --namespace app-lab \
  --reset-values \
  -f ./charts/frontend-lab/values-release.yaml \
  --set backend.config.logLevel=DEBUG \
  --wait --timeout 5m

If successful, this creates revision 2. Inspect what Helm recorded and what Kubernetes now runs:

helm history ui-lab -n app-lab
helm get values ui-lab -n app-lab
kubectl -n app-lab rollout status deployment/ui-lab-backend --timeout=180s
kubectl -n app-lab get deployment ui-lab-backend -o yaml

In the Deployment, look for LOG_LEVEL set to DEBUG while DATABASE_URL still uses valueFrom.secretKeyRef. Do not infer that a ready Pod proves the application’s behavior: repeat the relevant port-forward health checks if the upgrade could affect them. For future image upgrades, use a versioned, already-pushed image tag and verify the application before deciding to retain the revision.

Now practice a deliberate rollback to revision 1:

helm rollback ui-lab 1 \
  --namespace app-lab \
  --wait --timeout 5m

helm history ui-lab -n app-lab
helm get values ui-lab -n app-lab
kubectl -n app-lab rollout status deployment/ui-lab-backend --timeout=180s

Confirm that LOG_LEVEL is back to INFO and the baseline images remain in place. A rollback to revision 1 normally creates a new revision 3; it does not erase revision 2 or move the revision counter backward. In a real incident, run helm history first and choose the last verified good revision rather than blindly using 1. Helm can restore recorded Kubernetes configuration; it cannot undo database writes or an incompatible schema migration.

Cost of upgrade and rollback: These operations use the existing cluster and normally create no new Azure service. A rolling Deployment may temporarily run old and new Pods together; insufficient node capacity could trigger another node or cause the rollout to stall. Keep the lab window short and check the cluster’s actual capacity before upgrading.


Close the lab without confusing rollback and cleanup

Rollback keeps the release installed. When you are finished with this separate test release, remove it:

helm uninstall ui-lab -n app-lab
kubectl -n app-lab get deployments,services

Check that the ui-lab workloads and Services are gone and that the manually managed application remains. Uninstalling normally removes the release record too, so do not uninstall as your first response to an upgrade you intend to roll back. Helm did not create your pre-existing database Secret, PostgreSQL instance, AKS cluster, registry, or manually managed Ingress; uninstalling the chart will not remove those.

Cost of cleanup: helm uninstall has no separate Azure fee and stops the two release workloads. It does not stop billing for the AKS cluster and nodes, database, registry storage, public IP, or other lab resources. Follow your earlier Terraform and Azure cleanup plan, verify what it will destroy, and confirm that paid resources are actually gone when the lab is over.


What to retain

You have used four different kinds of evidence: linting and rendering for chart structure, a connected dry run for pre-install checks, Helm history and manifests for release state, and Pod plus HTTP checks for running behavior. The database credential stayed outside chart values, rendered templates, command-line overrides, and release history; only its Kubernetes Secret reference traveled with the release.

This completes the Helm portion of your AKS workflow. Next, the course moves to GitHub Actions, where you will build and push versioned images using OIDC authentication before automating deployments and verification.

Can't find a good explanation? Sign up and we'll make it for you

Sign up