SEANK.H.LIAO

skaffold argocd helm

making different deployment tools coexist

ArgoCD + Helm environment

Say you're doing CI/CD like the cool kids: push to git, some CI pipeline runs and builds your image, some automated push to git happens updating a reference to your deployment, and ArgoCD goes and syncs your application to the new state.

That all sounds fine, and pretty scalable for many deployment environments. But the reality is it's quite a slow development loop when you're working with a single environment. So what can you do?

Oh and your kubernetes manifests are rendered (but no deployed) with Helm, and it's in a top level subdirectory in your repo (repo-root/helm/Chart.yaml).

skaffold options

There are a multitude of options for tools orchestrating the local-to-k8s development flow, but here we're going to focus on skaffold because I like it. (Other options include tilt, telepresence, devspace.)

skaffold v2 (which uses a config version of skaffold/v3...) comes with separate render and deploy phases.

Because we're targeting an environment normally deployed with ArgoCD, our only option for the deploy phase is kubectl. We don't want to leave around helm deployment records that will interfere with ArgoCD operations.

As for the render phase, it's not as easy as just choose helm... ArgoCD adds an extra label to deployed manifests to allow it to track which resources are associated with which ArgoCD Application. We need to keep those so ArgoCD will still be able to cleanup/sync after we're done with local dev. The obvious solution for this is to use kustomize with its built in labels transform.

helm + kustomize postrenderer

Helm has the option for hooking in to a post render tool. What this looks like is a shell script to write the contents of stdin to a file, and calling kustomize with the configured label transform.

 1# skaffold.yaml
 2apiVersion: skaffold/v3
 3kind: Config
 4manifests:
 5  helm:
 6    flags:
 7      global:
 8        - --post-renderer=./render/render.sh
 9    releases:
10      - name: my-app
11        chartPath: ./helm
12        valuesFiles:
13          - helm/values.yaml
14          - helm/values/my-env.yaml
1#!/bin/sh
2# render/render.sh
3
4cp /dev/stdin out.yaml
5
6kustomize build .
7
8rm out.yaml
 1# render/kustomization.yaml
 2apiVersion: kustomize.config.k8s.io/v1beta1
 3kind: Kustomization
 4resources:
 5  - all.yaml
 6labels:
 7  - pairs:
 8      my-argocd-tracking: label
 9    includeSelectors: false
10    includeTemplates: false
kustomize + helm template pre-hook

Another option using the same tools inverts the control and gets rid of the shell script, instead using skaffold hooks to run helm template.

While kustomize has a helmCharts builtin for rendering helm Charts, it's not quite flexible enough, requiring a parent directory holding charts, and only allowing a single values file.

 1# skaffold.yaml
 2apiVersion: skaffold/v3
 3kind: Config
 4manifests:
 5  kustomize:
 6    paths:
 7      - render
 8  hooks:
 9    before:
10      - host:
11          command:
12            - sh
13            - -c
14            - |
15              helm template my-app ./helm -f helm/values.yaml -f helm/values/my-env.yaml > render/all.yaml              
 1# render/kustomization.yaml
 2apiVersion: kustomize.config.k8s.io/v1beta1
 3kind: Kustomization
 4resources:
 5  - all.yaml
 6labels:
 7  - pairs:
 8      my-argocd-tracking: label
 9    includeSelectors: false
10    includeTemplates: false