Contents

The output or file structure below illustrates the expected result.

payment-service/ ← chart name ├── Chart.yaml ← chart metadata (name, version, appVersion) ├── values.yaml ← default values ├── values-staging.yaml ← staging overrides ├── values-production.yaml ← production overrides └── templates/ ├── _helpers.tpl ← reusable named templates ├── deployment.yaml ├── service.yaml ├── ingress.yaml ├── configmap.yaml ├── hpa.yaml ├── serviceaccount.yaml └── NOTES.txt ← printed after install # Create scaffold with helm create helm create payment-service

The YAML below shows the complete configuration for this feature. Adjust the values to match your environment.

# Chart.yaml apiVersion: v2 name: payment-service description: Spring Boot payment microservice type: application version: 0.1.0 # chart version — increment on chart changes appVersion: "1.0.0" # application version — the Docker image tag maintainers: - name: platform-team email: platform@example.com dependencies: # Optional — pull in a PostgreSQL sub-chart for local dev - name: postgresql version: "14.x.x" repository: "https://charts.bitnami.com/bitnami" condition: postgresql.enabled # only install if enabled in values

The YAML below shows the complete configuration for this feature. Adjust the values to match your environment.

# values.yaml replicaCount: 2 image: repository: myorg/payment-service tag: "" # defaults to Chart.appVersion if empty pullPolicy: IfNotPresent service: type: ClusterIP port: 80 targetPort: 8080 ingress: enabled: false className: nginx host: payment.example.com tls: true resources: requests: cpu: 250m memory: 512Mi limits: cpu: 1000m memory: 1Gi autoscaling: enabled: false minReplicas: 2 maxReplicas: 10 targetCPUUtilizationPercentage: 70 springProfiles: "production" config: logLevel: INFO maxRetryAttempts: 3 postgresql: enabled: false # disable by default — use external DB in production podAnnotations: {} nodeSelector: {} tolerations: [] affinity: {}

The YAML below shows the complete configuration for this feature. Adjust the values to match your environment.

{{/* templates/deployment.yaml */}} apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "payment-service.fullname" . }} namespace: {{ .Release.Namespace }} labels: {{- include "payment-service.labels" . | nindent 4 }} spec: {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: {{- include "payment-service.selectorLabels" . | nindent 6 }} template: metadata: labels: {{- include "payment-service.selectorLabels" . | nindent 8 }} annotations: # Force pod restart when ConfigMap changes (checksum annotation) checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} spec: containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - containerPort: 8080 env: - name: SPRING_PROFILES_ACTIVE value: {{ .Values.springProfiles | quote }} - name: JAVA_TOOL_OPTIONS value: "-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0" envFrom: - configMapRef: name: {{ include "payment-service.fullname" . }}-config resources: {{- toYaml .Values.resources | nindent 12 }} readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 20 periodSeconds: 10 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 30 periodSeconds: 15 {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }}

The YAML below shows the complete configuration for this feature. Adjust the values to match your environment.

{{/* templates/_helpers.tpl */}} {{/* Full name: release-name + chart-name, capped at 63 chars */}} {{- define "payment-service.fullname" -}} {{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Common labels */}} {{- define "payment-service.labels" -}} helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} {{ include "payment-service.selectorLabels" . }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} {{/* Selector labels */}} {{- define "payment-service.selectorLabels" -}} app.kubernetes.io/name: {{ .Chart.Name }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }}

The YAML below shows the complete configuration for this feature. Adjust the values to match your environment.

# values-production.yaml — overrides on top of values.yaml defaults replicaCount: 5 image: tag: "1.2.3" # pin exact version in production ingress: enabled: true host: api.example.com autoscaling: enabled: true minReplicas: 3 maxReplicas: 20 resources: requests: cpu: 500m memory: 1Gi limits: cpu: 2000m memory: 2Gi config: logLevel: WARN

The commands below build and run the application. Make sure Docker is running locally before executing the image build steps.

# Lint — validate templates before deploying helm lint payment-service/ -f values-production.yaml # Dry-run — render templates without applying helm install payment-service ./payment-service \ --namespace payments \ --values values-production.yaml \ --dry-run --debug # Install helm install payment-service ./payment-service \ --namespace payments --create-namespace \ --values values-production.yaml # Upgrade — deploy new image version helm upgrade payment-service ./payment-service \ --namespace payments \ --values values-production.yaml \ --set image.tag=1.3.0 \ --atomic # auto-rollback if upgrade fails --wait # wait for pods to be ready # View release history helm history payment-service -n payments # Rollback to previous revision helm rollback payment-service -n payments # Rollback to specific revision helm rollback payment-service 2 -n payments # Uninstall helm uninstall payment-service -n payments

Hooks let you run jobs at specific points in the release lifecycle — e.g., run a database migration before the deployment is upgraded.

# templates/db-migrate-job.yaml apiVersion: batch/v1 kind: Job metadata: name: {{ include "payment-service.fullname" . }}-db-migrate annotations: "helm.sh/hook": pre-upgrade,pre-install # run before the upgrade/install "helm.sh/hook-weight": "-5" # lower runs first "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded spec: template: spec: restartPolicy: Never containers: - name: migrate image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" command: ["java", "-jar", "app.jar", "--spring.batch.job.enabled=true"] env: - name: SPRING_PROFILES_ACTIVE value: "migrate"

Helmfile declaratively manages multiple Helm releases — useful for deploying a full microservices stack with one command.

# helmfile.yaml repositories: - name: bitnami url: https://charts.bitnami.com/bitnami releases: - name: payment-service namespace: payments chart: ./charts/payment-service values: - ./values/payment-service/values-{{ .Environment.Name }}.yaml - name: order-service namespace: orders chart: ./charts/order-service values: - ./values/order-service/values-{{ .Environment.Name }}.yaml - name: kafka namespace: kafka chart: bitnami/kafka version: "26.x.x" values: - ./values/kafka/values-{{ .Environment.Name }}.yaml environments: staging: values: - env: staging production: values: - env: production # Deploy all services to staging helmfile -e staging apply # Diff before applying to production helmfile -e production diff # Apply to production helmfile -e production apply