Using Common Helm chart for generating multiple microservices in a GitOps Repo with ArgoCD

34 Views Asked by At

I am implementing CI/CD and GitOps repository and currently deciding the approach of how/if separating environment variables to separate (non yaml indented) files.

I am using monorepo, ArgoCD and Helm files stored directly in Git. The common helm chart is a base which can render all my microservices by setting specific values for each of them.

I have the following directory structure:


    .
    ├── apps
    │   ├── .base
    │   │   ├── app1
    │   │   └── app2
    │   ├── .charts
    │   │   └── base-app
    │   │       ├── Chart.yaml
    │   │       ├── templates
    │   │       │   ├── _helpers.tpl
    │   │       │   ├── configmap.yaml
    │   │       │   ├── cronjob.yaml
    │   │       │   ├── deployment.yaml
    │   │       │   └── service.yaml
    │   │       └── values.yaml
    │   ├── dev
    │   │   ├── app1
    │   │   │   │── env.properties
    │   │   │   └── values.yam
    │   │   └── app2
    │   ├── stg
    │   │   ├── app1
    │   │   └── app2
    │   └── pprod
    │   │   ├── app1
    │   │   └── app2
    ├── argocd
    │   ├── appsets
    │       ├── dev-apps.yaml
    │       ├── stg-apps.yaml
    │       └── prod-apps.yaml
    ├── bootstrap.yaml

and my ArgoCd ApplicationSet which is generating apps using git generator


    apiVersion: argoproj.io/v1alpha1
    kind: ApplicationSet
    metadata:
      name: dev-apps
    spec: 
      goTemplate: true
      goTemplateOptions: ["missingkey=error"]

      generators:
       - git:
           repoURL: https://gitlab.com/<hidden>/gitops.git
           revision: HEAD          
           directories:               
           - path: apps/dev/*
                
      template:
        metadata:
          name: '{{.path.basename}}-dev'
        spec:
          project: dev
          source:
            repoURL: https://gitlab.com/<hidden>/gitops.git
            targetRevision: HEAD
            path: test
            helm:
              ignoreMissingValueFiles: true # allow missing value files
              valueFiles:                            
                - '/apps/.base/{{.path.basename}}/values.yaml'  
                - '/{{.path.path}}/values.yaml'               

          destination:
            name: in-cluster
            namespace: dev

          syncPolicy:
            automated:
              prune: true
              allowEmpty: false
              selfHeal: true
            syncOptions:
              - CreateNamespace=true

This way I can pass every values.yaml file to any app.

I would like to improve this and put the environment variables in separate files (e.g. as seen in dev/app1/env.properties). But this way I cannot reference those files via helm template {{ .Files.Get }} and use them to generate ConfigMaps, etc.

I found a solution which is the following:

  • put the common base chart which is now stored in apps/.charts/base-chart directly on the root of the repo
  • pass the relative path (from where the Chart.yaml is) to a variable in Values via Appset Git generator
  • put a filename setting in Values.yaml
  • in the helm template (e.g. ConfigMap) render the contents of the file if the filename variable is set

for example:

...
            helm:
              ignoreMissingValueFiles: true # allow missing value files
              valueFiles:                            
                - '/apps/.base/{{.path.basename}}/values.yaml'  
                - '/{{.path.path}}/values.yaml' 
              parameters:
               - name: "configPath"
                 value: 'apps/{{.path.basename}}'

...

set the config in values.yaml environment.configsFile=env.properties

and then use the path in configPath and filename in configsFile to produce a full path to the file and use it in a configmap template:

{{- if .Values.environment.configsFile }}

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: sample-cfg
  namespace: {{ template "application.namespace" . }}  
data:  
  {{- .Files.Get ( printf "%s/%s" .Values.configPath .Values.environment.configsFile )  | nindent 2 }}
{{- end }} 

And the final structure


    .
    ├── apps
    │   ├── .base
    │   │   ├── app1
    │   │   └── app2
    │   ├── dev
    │   │   ├── app1
    │   │   │   │── env.properties
    │   │   │   └── values.yam
    │   │   └── app2
    │   ├── stg
    │   │   ├── app1
    │   │   └── app2
    │   └── pprod
    │   │   ├── app1
    │   │   └── app2
    ├── argocd
    │   ├── appsets
    │       ├── dev-apps.yaml
    │       ├── stg-apps.yaml
    │       └── prod-apps.yaml
    ├── bootstrap.yaml
    ├── Chart.yaml  
    ├── templates
    │   ├── _helpers.tpl
    │   ├── configmap.yaml
    │   ├── cronjob.yaml
    │   ├── deployment.yaml
    │   └── service.yaml
    └── values.yaml
    

How are you managing this? I would be happy to hear your opinion and get maybe some better ideas.

0

There are 0 best solutions below