Kubernetes and OpenShift Deployment Patterns: Guided Hands-On Workflow
Render and inspect a pinned Community Build Helm release before any apply, then optionally deploy a bounded local namespace and collect Pod, PVC, Service, readiness, log, and rollback evidence.
Learning objectives
- Pin the released SonarQube chart and current Community Build number rather than accepting moving defaults.
- Create a local values file that makes edition, resources, persistence, security helpers, and exposure choices explicit.
- Run Helm lint/template before apply and inspect the rendered workload, PVC, Service, Secret references, probes, and security contexts.
- Optionally install only into a disposable local namespace after cluster identity, capacity, storage, and permissions are verified.
- Collect first-failure evidence and perform a guarded rollback/uninstall without deleting unrelated namespaces, PVCs, or database state.
1. Lab contract: render is mandatory; cluster apply is optional
The mandatory path needs Helm 3 and local files only. It uses chart
2026.4.1 and Community Build
26.9.0.129388. A real cluster is optional. If you do
have one, it must be local/disposable and you must verify the active
context before mutation.
kubectl config current-context points to a shared,
employer, customer, cloud-production, or unknown cluster; if the
namespace already contains non-lab resources; if a default
StorageClass is unknown; or if allocatable memory cannot safely
accommodate SonarQube.
2. Preflight tools, release artifacts, and cluster identity
helm version
kubectl version --client
helm repo add sonarqube https://SonarSource.github.io/helm-chart-sonarqube
helm repo update
helm show chart sonarqube/sonarqube --version 2026.4.1
helm pull sonarqube/sonarqube --version 2026.4.1 --untar --untardir ./sq-ch05-chart
# Only if a cluster is intentionally available:
kubectl config current-context
kubectl cluster-info
kubectl get nodes
kubectl get storageclass
kubectl get ns sq-ch05-lab --ignore-not-found
Store Chart.yaml, the chart package digest if
available, and helm show chart output in the evidence
packet.
3. Create one explicit render-only values file
Use fake values and keep the mandatory path internal. This file enables a PVC so learners can inspect persistence semantics, disables root helper containers to demonstrate restricted-namespace intent, and does not create public routing.
# values-sq-ch05.yaml
community:
enabled: true
buildNumber: "26.9.0.129388"
monitoringPasscode: "FAKE_LOCAL_MONITORING_ONLY"
initSysctl:
enabled: false
initFs:
enabled: false
persistence:
enabled: true
size: 5Gi
accessMode: ReadWriteOnce
service:
type: ClusterIP
resources:
requests:
cpu: 400m
memory: 2048M
limits:
cpu: 800m
memory: 6144M
ingress:
enabled: false
OpenShift:
enabled: false
Disabling the root helpers means the cluster administrator must already satisfy Elasticsearch/node and storage ownership prerequisites. A successful render does not prove those runtime prerequisites exist.
4. Lint and render before apply
mkdir -p sq-ch05-evidence
helm lint ./sq-ch05-chart/sonarqube -f values-sq-ch05.yaml > sq-ch05-evidence/helm-lint.txt
helm template sq-ch05 sonarqube/sonarqube --version 2026.4.1 --namespace sq-ch05-lab -f values-sq-ch05.yaml > sq-ch05-evidence/rendered-kubernetes.yaml
Rendering is intentionally first because it is deterministic and reviewable. It exposes what the chart intends to create without mutating a cluster.
5. Inspect the rendered object graph
grep -nE '^kind:|name: sq-ch05|securityContext:|runAsNonRoot:|allowPrivilegeEscalation:|PersistentVolumeClaim|storageClassName:|readinessProbe:|livenessProbe:|type: ClusterIP' sq-ch05-evidence/rendered-kubernetes.yaml
Expected categories include a SonarQube workload, Service,
configuration/Secret-related objects, and a PVC because persistence
is enabled. Confirm no Ingress/Route was created and no
init-sysctl/init-fs workload remains. If a
chart release renders differently, record that instead of forcing
the expected shape.
6. Render the OpenShift variant without touching OpenShift
helm template sq-ch05-os sonarqube/sonarqube --version 2026.4.1 --namespace sq-ch05-lab --set community.enabled=true --set community.buildNumber=26.9.0.129388 --set monitoringPasscode=FAKE_LOCAL_MONITORING_ONLY --set OpenShift.enabled=true --set OpenShift.createSCC=false --set persistence.enabled=true > sq-ch05-evidence/rendered-openshift.yaml
Compare the security contexts and helper containers. Do not add arbitrary fixed UIDs/GIDs to “make OpenShift work”; the maintained chart is responsible for its supported OpenShift adaptation.
7. Render a production-shaped external-database contract
Create a values fragment that references a Secret name/key without containing the password itself:
jdbcOverwrite:
enabled: true
jdbcUrl: "jdbc:postgresql://sq-db.example.invalid:5432/sonar"
jdbcUsername: "sonar_lab"
jdbcSecretName: "sq-db-credentials"
jdbcSecretPasswordKey: "password"
The hostname is intentionally invalid and must not be deployed. The point is to prove that the chart receives an external DB endpoint and a Secret reference. Production uses a supported, reachable database with backups and least-privilege credentials.
8. Optional bounded local-cluster deployment
If—and only if—the current context is a disposable local cluster with enough memory, create the isolated namespace and install a test-only H2-backed instance. Keep persistence disabled in this optional execution path to avoid implying the local cluster is production-shaped.
kubectl create namespace sq-ch05-lab
kubectl label namespace sq-ch05-lab pod-security.kubernetes.io/enforce=baseline --overwrite
helm upgrade --install sq-ch05 sonarqube/sonarqube --version 2026.4.1 --namespace sq-ch05-lab --set community.enabled=true --set community.buildNumber=26.9.0.129388 --set monitoringPasscode=FAKE_LOCAL_MONITORING_ONLY --set persistence.enabled=false
9. Observe Pods, events, logs, Service, and readiness
kubectl -n sq-ch05-lab get all
kubectl -n sq-ch05-lab get events --sort-by=.lastTimestamp
kubectl -n sq-ch05-lab get pod -o wide
kubectl -n sq-ch05-lab describe pod -l app=sonarqube
kubectl -n sq-ch05-lab logs -l app=sonarqube --all-containers=true --tail=200
kubectl -n sq-ch05-lab get svc -o wide
helm -n sq-ch05-lab status sq-ch05
helm -n sq-ch05-lab get values sq-ch05 --all
Preserve the first failing event/log before a restart. Readiness means Kubernetes may route traffic; it does not prove database backup, TLS, scanner success, quality-gate behavior, or disaster recovery.
10. Access only through a local port-forward
kubectl -n sq-ch05-lab port-forward service/sq-ch05-sonarqube 9000:9000
Use http://127.0.0.1:9000 from the same machine. Do not
switch the Service to LoadBalancer, create a public
Ingress, or disable TLS verification to make the lab easier.
11. Challenge: diagnose from ownership, not from YAML volume
| Observation | First owner | Evidence |
|---|---|---|
| PVC Pending | StorageClass/provisioner | PVC events + StorageClass |
| Init sysctl denied | Pod Security/node prerequisite | Pod events + namespace policy + chart values |
| Pod OOMKilled | resource sizing/JVM/runtime | container state + limits + logs |
| DB hostname unresolved | cluster DNS/network/DB endpoint | logs + Service/DNS/network policy |
| Service works internally, browser cannot reach it | edge routing/exposure | Service type + Ingress/Route/Gateway state |
12. Guarded rollback and cleanup
For an optional local install, preserve evidence first, then remove the Helm release and only the named lab namespace:
helm -n sq-ch05-lab get manifest sq-ch05 > sq-ch05-evidence/installed-manifest.yaml
helm -n sq-ch05-lab history sq-ch05 > sq-ch05-evidence/helm-history.txt
kubectl -n sq-ch05-lab get all,pvc,secret,configmap -o wide > sq-ch05-evidence/final-inventory.txt
helm uninstall sq-ch05 -n sq-ch05-lab
kubectl get namespace sq-ch05-lab
# Delete only after you verify this namespace is the disposable lab:
kubectl delete namespace sq-ch05-lab
Do not delete cluster-wide StorageClasses, CRDs, ingress controllers, SCCs, nodes, or unrelated namespaces as part of this chapter.
Knowledge check
Why does the mandatory workflow use
helm template before
helm upgrade --install?
Rendering creates reviewable evidence without mutating a cluster and exposes object/security/storage/network intent before execution.
Why is community.buildNumber explicitly
set?
Because chart 2026.4.1 defaults to an older Community Build than the current 26.9 release.
What does a Pending PVC usually tell you?
The first investigation should be the claim, StorageClass, provisioner, capacity, access mode and events—not SonarQube quality configuration.
Why is the optional local deployment labeled test-only?
It may use H2 and local ephemeral infrastructure, which are not the external-database, backup, HA, routing and operational controls expected in production.
What must be preserved before uninstalling a failed release?
Rendered/installed manifests, chart and values identity, Pod events/logs, PVC/Service state, Helm history/status, and the first failure evidence.
Official references and version notes
- SonarQube Community Build — Kubernetes/OpenShift introduction — installation flow and platform boundary.
- Before you start — Kubernetes/OpenShift — resource, database, restricted-namespace, and production prerequisites.
- Customizing the Helm chart — OpenShift, security contexts, persistence, JDBC, ingress and TLS guidance.
- Installing the Helm chart — current Community Build install parameters and OpenShift example.
- Official SonarQube Helm chart repository — maintained chart source, values, changelog, and releases.
- SonarQube chart 2026.4.1 release — pinned released chart artifact used in this chapter.
- SonarQube chart README — edition, compatibility, Pod Security, resources, persistence, JDBC, OpenShift and upgrade guidance.
- SonarQube Data Center Helm chart — commercial Data Center topology and separate chart boundary.
- SonarQube Community Build releases — current Community Build release identity.
- Kubernetes Pod Security Standards — restricted/baseline/privileged namespace security model.
- Kubernetes Persistent Volumes — PVC, StorageClass and access-mode ownership.
- Kubernetes Gateway API — modern external-routing API discussed as a production option.
Version-sensitive statements were rechecked against current
SonarSource, Helm-chart repository, and Kubernetes primary
material on 2026-09-07. Mandatory examples use SonarQube Community
Build 26.9.0.129388 with the latest released
SonarQube Helm chart 2026.4.1. That chart release
originally defaults Community Build to 26.7.0.124771, so examples
deliberately set community.buildNumber=26.9.0.129388.
The released chart documents non-OpenShift Kubernetes support for
1.32–1.35 and OpenShift support for
4.17–4.20. SonarQube Server Developer/Enterprise
and the separate Data Center chart are commercial boundaries and
are not required. No SonarScanner execution, CI provider,
third-party plugin, enterprise identity provider, managed
Kubernetes service, public DNS, or paid infrastructure is required
by the mandatory Chapter 05 path. Re-check the chart release,
supported platform matrix, Community Build number, database
compatibility, and upgrade notes before using these examples
later.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.