Helm Integration

Helm is a package manager for Kubernetes that simplifies application deployment. Integrating Helm with GitOps tools like ArgoCD and Flux allows you to leverage Helm’s templating and packaging capabilities while maintaining GitOps principles.

Helm in GitOps

Helm provides:

  • Templating - Parameterize Kubernetes manifests
  • Packaging - Bundle related resources
  • Versioning - Manage chart versions
  • Dependencies - Handle chart dependencies
graph TB A[Helm Chart] --> B[Git Repository] B --> C[GitOps Controller] C --> D[Helm Release] D --> E[Kubernetes Resources] F[Helm Values] --> B G[Chart Repository] --> C style A fill:#e1f5ff style C fill:#e8f5e9 style D fill:#fff4e1

Helm Chart Management

Chart Repositories

Helm charts can come from:

  • Public repositories - Bitnami, Helm Hub
  • Private repositories - Your own chart registry
  • Git repositories - Charts stored in Git
  • OCI registries - OCI-compatible registries

Chart Versions

Always pin chart versions in production:

# Good - Pinned version
chart:
  spec:
    chart: nginx
    version: '13.2.20'

# Bad - Latest version
chart:
  spec:
    chart: nginx
    version: '*'  # Avoid in production

Chart Dependencies

Manage chart dependencies:

# Chart.yaml
apiVersion: v2
name: web-app
version: 1.0.0
dependencies:
- name: postgresql
  version: 12.1.0
  repository: https://charts.bitnami.com/bitnami

ArgoCD Helm Integration

Basic Helm Application

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: nginx
    targetRevision: 13.2.20
    helm:
      values: |
        service:
          type: LoadBalancer
        replicaCount: 3
  destination:
    server: https://kubernetes.default.svc
    namespace: default

Helm Values Management

Inline Values

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web-app
spec:
  source:
    repoURL: https://charts.example.com
    chart: web-app
    targetRevision: 1.0.0
    helm:
      values: |
        image:
          tag: v1.2.3
        replicaCount: 3
        service:
          type: ClusterIP

Values Files from Git

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web-app
spec:
  source:
    repoURL: https://github.com/org/repo
    targetRevision: main
    path: charts/web-app
    helm:
      valueFiles:
      - values.yaml
      - values-production.yaml

Multiple Value Sources

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web-app
spec:
  source:
    repoURL: https://charts.example.com
    chart: web-app
    targetRevision: 1.0.0
    helm:
      values: |
        image:
          tag: v1.2.3
      valueFiles:
      - values-production.yaml
      parameters:
      - name: replicaCount
        value: "5"

Helm Chart from Git

Store Helm charts in Git:

repo/
├── charts/
│   └── web-app/
│       ├── Chart.yaml
│       ├── values.yaml
│       └── templates/
│           ├── deployment.yaml
│           └── service.yaml
└── apps/
    └── web-app/
        └── application.yaml

Application:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web-app
spec:
  source:
    repoURL: https://github.com/org/repo
    targetRevision: main
    path: charts/web-app
    helm:
      valueFiles:
      - ../../apps/web-app/values-production.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: production

Values Per Environment

Organize values by environment:

repo/
├── charts/
│   └── web-app/
│       ├── Chart.yaml
│       └── templates/
└── apps/
    └── web-app/
        ├── values-dev.yaml
        ├── values-staging.yaml
        └── values-production.yaml

Dev Application:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web-app-dev
spec:
  source:
    repoURL: https://github.com/org/repo
    targetRevision: main
    path: charts/web-app
    helm:
      valueFiles:
      - ../../apps/web-app/values-dev.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: dev

Production Application:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: web-app-prod
spec:
  source:
    repoURL: https://github.com/org/repo
    targetRevision: main
    path: charts/web-app
    helm:
      valueFiles:
      - ../../apps/web-app/values-production.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: production

Helm Repository Management

Add Helm repositories to ArgoCD:

# Add repository
argocd repo add https://charts.bitnami.com/bitnami \
  --type helm \
  --name bitnami

# Or via Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx
spec:
  source:
    repoURL: https://charts.bitnami.com/bitnami
    chart: nginx
    targetRevision: 13.2.20

Flux Helm Integration

HelmRepository CRD

Define Helm chart repositories:

apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
  name: bitnami
  namespace: flux-system
spec:
  interval: 15m0s
  url: https://charts.bitnami.com/bitnami

HelmRelease CRD

Manage Helm releases:

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: nginx
  namespace: flux-system
spec:
  interval: 5m0s
  chart:
    spec:
      chart: nginx
      sourceRef:
        kind: HelmRepository
        name: bitnami
      version: '13.2.20'
  values:
    service:
      type: LoadBalancer
    replicaCount: 3
  targetNamespace: default

Helm Chart from Git

Use charts from Git repositories:

apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
  name: charts
  namespace: flux-system
spec:
  interval: 1m0s
  url: https://github.com/org/charts
  ref:
    branch: main

---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: web-app
  namespace: flux-system
spec:
  interval: 5m0s
  chart:
    spec:
      chart: ./charts/web-app
      sourceRef:
        kind: GitRepository
        name: charts
      version: '*'
  values:
    image:
      tag: v1.2.3
  targetNamespace: production

Values Files in Git

Reference values files from Git:

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: web-app
  namespace: flux-system
spec:
  interval: 5m0s
  chart:
    spec:
      chart: web-app
      sourceRef:
        kind: HelmRepository
        name: my-charts
      version: '1.0.0'
  valuesFrom:
  - kind: ConfigMap
    name: web-app-values
    valuesKey: values.yaml
  - kind: Secret
    name: web-app-secrets
    valuesKey: secrets.yaml

Best Practices

1. Pin Chart Versions

Always pin versions in production:

# Good
chart:
  spec:
    chart: nginx
    version: '13.2.20'

# Bad
chart:
  spec:
    chart: nginx
    version: '*'  # Avoid

2. Separate Values by Environment

charts/web-app/
├── Chart.yaml
└── templates/

apps/web-app/
├── values-dev.yaml
├── values-staging.yaml
└── values-production.yaml

3. Use Value Files, Not Inline Values

For complex configurations:

# Good - Use value files
helm:
  valueFiles:
  - values-production.yaml

# Less ideal - Inline for simple configs
helm:
  values: |
    replicaCount: 3

4. Store Charts in Git

Version control your charts:

repo/
├── charts/
│   └── web-app/
│       ├── Chart.yaml
│       ├── values.yaml
│       └── templates/

5. Test Charts Before Promotion

# Lint chart
helm lint charts/web-app

# Dry run
helm install web-app charts/web-app --dry-run --debug

# Template test
helm template web-app charts/web-app

6. Manage Dependencies

# Chart.yaml
dependencies:
- name: postgresql
  version: 12.1.0
  repository: https://charts.bitnami.com/bitnami

# Update dependencies
helm dependency update charts/web-app

Common Patterns

Pattern 1: Chart + Values in Git

repo/
├── charts/
│   └── web-app/
│       └── ...
└── apps/
    └── web-app/
        └── values.yaml

Pattern 2: External Chart, Values in Git

repo/
└── apps/
    └── web-app/
        └── values.yaml

# Chart from external repository

Pattern 3: Multi-Environment Values

repo/
├── charts/
│   └── web-app/
└── environments/
    ├── dev/
    │   └── values.yaml
    ├── staging/
    │   └── values.yaml
    └── production/
        └── values.yaml

Common Pitfalls

Pitfall 1: Using Latest Version

# Bad
chart:
  spec:
    chart: nginx
    version: '*'  # Can break on updates

Solution: Pin versions

Pitfall 2: Hardcoded Values

# Bad - Hardcoded in chart
image:
  tag: v1.0.0  # In Chart.yaml

Solution: Use values files

Pitfall 3: Not Testing Charts

Problem: Deploying untested charts

Solution: Always test before promotion

Pitfall 4: Mixing Environments

# Bad - Same values for all environments
helm:
  values: |
    replicaCount: 3  # Same for dev and prod

Solution: Separate values per environment

Troubleshooting

Chart Not Found

# Check HelmRepository status (Flux)
kubectl get helmrepository -n flux-system

# Check repository connection
helm repo list
helm repo update

Values Not Applied

# Check rendered values
argocd app get web-app --show-operation

# Check HelmRelease status (Flux)
kubectl describe helmrelease web-app -n flux-system

Chart Update Not Applied

# Force sync
argocd app sync web-app

# Check chart version
kubectl get helmrelease web-app -n flux-system -o yaml

Summary

Helm integration with GitOps:

  • ArgoCD - Use Application with Helm source
  • Flux - Use HelmRepository and HelmRelease CRDs
  • Values Management - Separate values per environment
  • Version Pinning - Always pin versions in production
  • Chart Storage - Store charts in Git for version control
  • Testing - Test charts before promotion

Best practices:

  • Pin chart versions
  • Separate values by environment
  • Store charts in Git
  • Test before deploying
  • Use value files for complex configs

Helm + GitOps provides the benefits of both: Helm’s templating and packaging with GitOps’ declarative, auditable workflows.