Back to Blog

Kubernetes Helm: Chart Authoring, Values Files, Umbrella Charts, and ArgoCD GitOps

Master Helm in 2026 — authoring production-grade Helm charts, values.yaml structure, chart templates, umbrella charts for multi-service deployment, Helm hooks,

Viprasol Tech Team
June 30, 2026
13 min read

Kubernetes Helm: Chart Authoring, Values Files, Umbrella Charts, and ArgoCD GitOps

Helm is the package manager for Kubernetes — it templates Kubernetes manifests, manages versioned releases, and handles upgrades and rollbacks. Combined with ArgoCD's GitOps model, you get a deployment system where the desired state lives in Git and the cluster continuously reconciles to match it.


Helm Chart Structure

charts/api/
├── Chart.yaml          # Chart metadata and dependencies
├── values.yaml         # Default configuration values
├── values-staging.yaml # Environment-specific overrides
├── values-prod.yaml
├── templates/
│   ├── _helpers.tpl    # Template helpers (named templates)
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── hpa.yaml        # Horizontal Pod Autoscaler
│   ├── configmap.yaml
│   ├── serviceaccount.yaml
│   └── NOTES.txt       # Post-install notes
└── .helmignore
# Chart.yaml
apiVersion: v2
name: api
description: Viprasol API service
type: application
version: 1.0.0         # Chart version (bump on chart changes)
appVersion: "2.4.1"    # App version (from image tag)
dependencies:
  - name: postgresql
    version: "13.x.x"
    repository: https://charts.bitnami.com/bitnami
    condition: postgresql.enabled  # Disabled in prod (using RDS)

values.yaml — Complete Example

# values.yaml — production-grade defaults
replicaCount: 2

image:
  repository: 123456789.dkr.ecr.us-east-1.amazonaws.com/api
  pullPolicy: IfNotPresent
  tag: ""  # Overridden by CI with git SHA

imagePullSecrets:
  - name: ecr-pull-secret

nameOverride: ""
fullnameOverride: ""

serviceAccount:
  create: true
  annotations:
    eks.amazonaws.com/role-arn: ""  # IRSA role override per env

podAnnotations:
  prometheus.io/scrape: "true"
  prometheus.io/port: "3001"
  prometheus.io/path: "/metrics"

podSecurityContext:
  fsGroup: 1000
  runAsNonRoot: true

securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  runAsUser: 1000
  capabilities:
    drop: [ALL]

service:
  type: ClusterIP
  port: 80
  targetPort: 3001

ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
  hosts:
    - host: api.yourproduct.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: api-tls
      hosts: [api.yourproduct.com]

resources:
  requests:
    memory: "256Mi"
    cpu: "100m"
  limits:
    memory: "512Mi"
    cpu: "500m"

autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70
  targetMemoryUtilizationPercentage: 80

env:
  NODE_ENV: production
  PORT: "3001"

envFrom:
  - secretRef:
      name: api-secrets  # Created by external-secrets-operator or manually

livenessProbe:
  httpGet:
    path: /health/live
    port: 3001
  initialDelaySeconds: 10
  periodSeconds: 30
  failureThreshold: 3

readinessProbe:
  httpGet:
    path: /health/ready
    port: 3001
  initialDelaySeconds: 5
  periodSeconds: 10
  failureThreshold: 3

# Zero-downtime deployments
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 0
    maxSurge: 1

# Disruption budget: at least 1 pod always available
podDisruptionBudget:
  enabled: true
  minAvailable: 1

topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: DoNotSchedule

☁️ Is Your Cloud Costing Too Much?

Most teams overspend 30–40% on cloud — wrong instance types, no reserved pricing, bloated storage. We audit, right-size, and automate your infrastructure.

  • AWS, GCP, Azure certified engineers
  • Infrastructure as Code (Terraform, CDK)
  • Docker, Kubernetes, GitHub Actions CI/CD
  • Typical audit recovers $500–$3,000/month in savings

Templates: Deployment

# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "api.fullname" . }}
  labels:
    {{- include "api.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  strategy:
    {{- toYaml .Values.strategy | nindent 4 }}
  selector:
    matchLabels:
      {{- include "api.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      annotations:
        # Force rolling update when configmap changes
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        {{- with .Values.podAnnotations }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
      labels:
        {{- include "api.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "api.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.service.targetPort }}
              protocol: TCP
          env:
            {{- range $key, $value := .Values.env }}
            - name: {{ $key }}
              value: {{ $value | quote }}
            {{- end }}
          {{- with .Values.envFrom }}
          envFrom:
            {{- toYaml . | nindent 12 }}
          {{- end }}
          livenessProbe:
            {{- toYaml .Values.livenessProbe | nindent 12 }}
          readinessProbe:
            {{- toYaml .Values.readinessProbe | nindent 12 }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}

Umbrella Charts for Multi-Service Deployment

An umbrella chart bundles multiple services into a single deployable unit:

# charts/platform/Chart.yaml
apiVersion: v2
name: platform
description: Full Viprasol platform
type: application
version: 1.0.0
dependencies:
  - name: api
    version: "1.x.x"
    repository: "file://../api"  # Local chart
  - name: worker
    version: "1.x.x"
    repository: "file://../worker"
  - name: frontend
    version: "1.x.x"
    repository: "file://../frontend"
# charts/platform/values.yaml
# Override sub-chart values using chart name as prefix
api:
  replicaCount: 3
  image:
    tag: "abc123"  # All services get same release tag
  env:
    DATABASE_URL: postgresql://...

worker:
  replicaCount: 2
  image:
    tag: "abc123"
  env:
    QUEUE_CONCURRENCY: "10"

frontend:
  replicaCount: 2
  image:
    tag: "abc123"
# Update dependencies and deploy umbrella chart
helm dependency update charts/platform/
helm upgrade --install platform charts/platform/ \
  -f charts/platform/values.yaml \
  -f charts/platform/values-prod.yaml \
  --set api.image.tag="${GIT_SHA}" \
  --set worker.image.tag="${GIT_SHA}" \
  --set frontend.image.tag="${GIT_SHA}" \
  --namespace production \
  --atomic \            # Roll back if any resource fails
  --timeout 5m

⚙️ DevOps Done Right — Zero Downtime, Full Automation

Ship faster without breaking things. We build CI/CD pipelines, monitoring stacks, and auto-scaling infrastructure that your team can actually maintain.

  • Staging + production environments with feature flags
  • Automated security scanning in the pipeline
  • Uptime monitoring + alerting + runbook automation
  • On-call support handover docs included

ArgoCD GitOps

ArgoCD watches a Git repository and synchronizes the cluster state to match:

# argocd/applications/platform.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: platform-production
  namespace: argocd
spec:
  project: production
  source:
    repoURL: https://github.com/yourorg/infra.git
    targetRevision: main
    path: charts/platform
    helm:
      valueFiles:
        - values.yaml
        - values-prod.yaml
      # Override image tags dynamically (Argo CD Image Updater updates this)
      parameters:
        - name: api.image.tag
          value: "abc123"

  destination:
    server: https://kubernetes.default.svc
    namespace: production

  syncPolicy:
    automated:
      prune: true       # Delete resources removed from Git
      selfHeal: true    # Auto-fix manual cluster changes
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground
    retry:
      limit: 3
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Image updater workflow (auto-deploy on new image push):

# ArgoCD Image Updater: watches ECR and updates values automatically
metadata:
  annotations:
    argocd-image-updater.argoproj.io/image-list: api=123456789.dkr.ecr.us-east-1.amazonaws.com/api
    argocd-image-updater.argoproj.io/api.update-strategy: newest-build
    argocd-image-updater.argoproj.io/write-back-method: git
    argocd-image-updater.argoproj.io/git-branch: main

With this setup: CI builds and pushes an image → Image Updater detects it → updates the Git values file → ArgoCD detects the Git change → deploys to cluster. Full GitOps with audit trail.


Helm Hooks

Hooks run at specific points in the release lifecycle:

# templates/migrations-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "api.fullname" . }}-migrations
  annotations:
    "helm.sh/hook": pre-upgrade,pre-install   # Run before deployment
    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
    "helm.sh/hook-weight": "-5"               # Run before other pre-hooks
spec:
  template:
    spec:
      containers:
        - name: migrations
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          command: ["pnpm", "db:migrate"]
          envFrom:
            - secretRef:
                name: api-secrets
      restartPolicy: Never
  backoffLimit: 3

Working With Viprasol

We build Helm chart libraries and ArgoCD GitOps pipelines — chart design, umbrella chart architecture, Image Updater automation, Helm testing with helm unittest, and migration from kubectl to GitOps.

Talk to our team about Kubernetes platform engineering and GitOps.


See Also

Share this article:

About the Author

V

Viprasol Tech Team

Custom Software Development Specialists

The Viprasol Tech team specialises in algorithmic trading software, AI agent systems, and SaaS development. With 100+ projects delivered across MT4/MT5 EAs, fintech platforms, and production AI systems, the team brings deep technical experience to every engagement. Based in India, serving clients globally.

MT4/MT5 EA DevelopmentAI Agent SystemsSaaS DevelopmentAlgorithmic Trading

Need DevOps & Cloud Expertise?

Scale your infrastructure with confidence. AWS, GCP, Azure certified team.

Free consultation • No commitment • Response within 24 hours

Viprasol · Big Data & Analytics

Making sense of your data at scale?

Viprasol builds end-to-end big data analytics solutions — ETL pipelines, data warehouses on Snowflake or BigQuery, and self-service BI dashboards. One reliable source of truth for your entire organisation.