Declarative approach to deploy Helm chart by Argocd to multiple environments - kubernetes-helm

I’m using Argocd with helm charts. I have two environments: uat, prod.
As far as I understand, proper approach for helm is to have base folder with commons + per env folder.
So I have single branch with 3 folders:
base # for commons: Chart.yaml, templates, etc.
uat # for uat values.yaml
prod # for prod values.yaml
In my helm chart I have following Chart.yaml (stored in base folder):
apiVersion: v1
appVersion: 1.0.11
name: my-nice-app
version: 1.0.11
With every release I increase appVersion and version (version is used as image tag version in charts).
I use declarative approach to deploy helm chart (this is uat application resource, similar is for prod):
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-nice-app
namespace: argocd
spec:
project: default
source:
repoURL: some-url
targetRevision: HEAD
path: base
helm:
version: v3
valueFiles:
- uat/values.yaml
destination:
server: https://kubernetes.default.svc
namespace: uat
syncPolicy:
syncOptions:
- CreateNamespace=false
automated:
selfHeal: true
prune: true
Question:
I do update uat values file.
I do update Chart.yaml with new version.
I would like to deploy uat only (but when I update base prod would also triggers).
Where or how should I store Chart.yaml? Should I change Argocd Application resource? Or only option is to duplicate charts per env?
I prefer also not to store any version related info in Argocd Application resource (so not to change it every time).
It would be nice not to apply kustomized.io.

You should split it into 2 charts (base chart and value chart)
base chart is chart dependency of value chart, like that if you update base chart, value chart won't be affected if you don't update chart dependency.
File Chart.yaml of value-chart will look like this.
apiVersion: v2
name: my-nice-app-prod
description: Chart for production
type: application
version: 0.0.1
appVersion: "1.0.0"
dependencies:
- name: my-nice-app-chart
version: 0.1.9
Link references:
https://helm.sh/docs/helm/helm_dependency/

You should use the variants folder,
The base directory holds configuration which is common to all environments. It is not expected to change often. If you want to do changes to multiple environments at the same time, it is best to use the “variants” folder.
Please go through this doc
https://codefresh.io/blog/how-to-model-your-gitops-environments-and-promote-releases-between-them/

Related

Include configmap with non-managed helm chart

I was wondering if it is possible to include a configmap with its own values.yml file with a helm chart repository that I am not managing locally. This way, I can uninstall the resource with the name of the chart.
Example:
I am using New Relics Helm chart repository and installing the helm charts using their repo name. I want to include a configmap used for infrastructure settings with the same helm deployment without having to use a kubectl apply to add it independently.
I also want to avoid having to manage the repo locally as I am pinning the version and other values separately from the help upgrade install set triggers.
What you could do is use Kustomize. Let me show you with an example that I use for my Prometheus installation.
I'm using the kube-prometheus-stack helm chart, but add some more custom resources like a SecretProviderClass.
kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
helmCharts:
- name: kube-prometheus-stack
repo: https://prometheus-community.github.io/helm-charts
version: 39.11.0
releaseName: prometheus
namespace: prometheus
valuesFile: values.yaml
includeCRDs: true
resources:
- secretproviderclass.yaml
I can then build the Kustomize yaml by running kustomize build . --enable-helm from within the same folder as where my kustomization.yaml file is.
I use this with my gitops setup, but you can use this standalone as well.
My folder structure would look something like this:
.
├── kustomization.yaml
├── secretproviderclass.yaml
└── values.yaml
Using only Helm without any 3rd party tools like kustomize there are two solutions:
Depend on the configurability of the Chart you are using as described by #Akshay in the other answer
Declare the Chart you are looking to add a ConfigMap to as a dependency
You can manage the Chart dependencies in the Chart.yaml file:
# Chart.yaml
dependencies:
- name: nginx
version: "1.2.3"
repository: "https://example.com/charts"
With the dependency in place, you can add your own resource files (e.g., the ConfigMap) to the chart. During Helm install, all dependencies and your custom files will be merged into a single Helm deployment.
my-nginx-chart/:
values.yaml # defines all values including the dependencies
Chart.yaml # declares the dependencies
templates/ # custom resources to be added on top of the dependencies
configmap.yaml # the configmap you want to add
To configure values for a dependency, you need to prefix the parameters in your values.yaml:
my-configmap-value: Hello World
nginx: #<- refers to "nginx" dependency
image: ...

ArgoCD helm chart how to override values yml in declarative helm chart deployment App/controller

I have an yaml which gets deployed by the ArgoCd controller, that deploys a helm chart from artifactory.
For my local development I use a sperate values.yml in the helm chart.
My controller looks like below refer git link
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: <name-to-the-app>
namespace: argocd
spec:
project: default
source:
repoURL: https://harbor.1000kit.org/chartrepo/1000kit/
targetRevision: <version-hardcode-in-repo>
chart: <chart-name-that-is-getting-deployed>
helm:
releaseName: <release-name-hardcoded>
# custom values to override the helm chart one
values: |
<pass-the-custom-values>>
destination:
server: https://kubernetes.default.svc
namespace: <namespace-where-to-be-deployed>
syncPolicy:
automated:
prune: true
selfHeal: true
The helm chart that is getting deployed is containing the values.yaml
I am trying to override the values.yml present in the helm chart in artifcatory, so passing all the values in part of the source -> helm -> values like above.
Question:
In the custom values, I skipped some value but the ArgoCd is fetching those values from the helm chart value.yml and using it. Is this the behavior?
Another observation is that, The helm chart repo values.yaml is being loaded as parmater in the ArgoCD, and the argocd.io application yaml the values are displayed in the UI.
From the documents i see there are parameters, which can be overridden but the values can't be overridden.
spec:
source:
helm:
parameters:
- name: app
value: $ARGOCD_APP_NAME
Is there any option to explicitly tell ArgoCD to ignore the values.yml from the helm chart in artifactory.
I am new to ArgoCd
Looks like,
The helm chart in the artifactory has a key : value combination say
# value present in the helm chart values.yaml
app-details:
name: "demoapp"
version: "1.0"
description: "simple demo app"
In argoCd application manifest
# .....
helm:
releaseName: <release-name-hardcoded>
# custom values to override the helm chart one
values: |
app-details :
name: "demoapp"
version: "1.0"
# if I didn't specify the description here <--------------- *
# ....
* - ArgoCd is setting the default value (from values.yaml) for description key in this case. This description value can be seen in the deployed manifest.
Also the values.yml data are displayed as parameter in the UI.
I had to use a different approach, where I need to make changes in the template charts that uses this description value.

Argocd to override existing base chart values

I was trying to deploy an application with helm on argocd , and this is my case .
I want to deploy vault using helm and
i use hashicorp's vault chart as base chart and overriding the values using sub-chart
And the base chart has conditions on creating services, PVC , etc..
The values are override on the argocd still the service exists even the condition is made false by boolean
Chart.yml
apiVersion: v2
name: keycloak
type: application
version: 1.0.0
dependencies:
- name: keycloak
version: "9.7.3"
repository: "https://charts.bitnami.com/bitnami"
Argocd.yml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: vault
namespace: vault
spec:
project: default
source:
chart: vault
repoURL: https://github.com/myrepo.git
targetRevision: HEAD
destination:
server: "https://kubernetes.default.svc"
namespace: kubeseal
Depends how you are overriding values in your chart and This is more of helm rather than ArgoCD.
Considering the Chart.yaml as below and chart name being infra which also has keycloak as dependency subchart:
apiVersion: v2
name: infra
type: application
version: 1.0.0
dependencies:
- name: keycloak
version: "9.7.3"
repository: "https://charts.bitnami.com/bitnami"
Create a values file in the same directory as your Chart.yaml with following contents
keycloak:
fullnameOverride: keycloak-1
here keycloak: key in the values file sets the values for the subchart of name keycloak
You can have multiple subchart values override like above in one values file.

helm dependencies with different namespaces

Right now, I have to install multiple helm charts in different namespaces for my product to work. I am trying to create a super helm chart in which I am planning to add the helm charts (of my tools, as mentioned above) and install them in one shot. My problem is, as these tools are in different namespaces I am not sure where to specify the namespace key where I want that particular dependency (chart) to be installed. For e.g. if below is the Charts.yaml of my super helm chart
dependencies:
- name: first_chart
version: 1.2.3
repository: https://firstchart.repo
- name: second_chart
version: 1.5.6
repository: https://secondchart.repo
I want my first chart to be installed in namespace foo and the second chart to be installed in namespace bar.
I was looking at using conditions but I believe conditions will only take a boolean as a value.
I stumbled upon this link (https://github.com/helm/helm/issues/2060) which says the we can do it in Helm 3 but mostly on how to keep releases between different namespaces. It does not specifically answer my question.
There is no builtin way to do this with pure Helm, but there is with helmfile.
Your example as helmfile.yaml:
releases:
- name: chart1 # name of the release (helm install <...> first_chart)
chart: repo1/first_chart
version: 1.2.3
namespace: foo
- name: chart2
chart: repo2/second_chart
version: 1.5.6
namespace: bar
# in case you want helmfile to automatically update repos
repositories:
- name: repo1
url: https://firstchart.repo
- name: repo2
url: https://secondchart.repo
Then, run:
helmfile sync => run helm install/upgrade on all releases, or
helmfile apply => same as sync, but do a diff first to only upgrade/install releases that changed
There is way more to helmfile, but this is the gist.
PS: if you struggle with values or want to have something similar to how umbrella Chart values are handled, have a look at helmfile: a simple trick to handle values intuitively
The way I solved this for my clusters with with ArgoCD's App of Apps cluster bootstrapping model. Of course, it requires that ArgoCD is install the cluster. However, for many reasons not relevant to this answer I would highly encourage installing ArgoCD regardless of the easy of bootstrapping capabilities.
Assuming ArgoCD is in place the structure is a single Helm chart containing templates for each of the child charts it will deploy and managed via Argo's Application CRD. You will notice there is a definition as part of the CRD, spec.destination.namespace, which governs where the chart will be deployed.
An example Application template which governs my cert-manager chart deployment to the cert-manager namespace looks like:
{{- if .Values.certManager.enabled }}
# ref: https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#applications
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: cert-manager
# You'll usually want to add your resources to the argocd namespace.
namespace: argocd
# Add a this finalizer ONLY if you want these to cascade delete.
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
# The project the application belongs to.
project: cluster-configs
# Source of the application manifests
source:
repoURL: https://github.com/yourOrg/Helm
targetRevision: {{ .Values.targetRevision }}
path: charts/cert-manager-chart
# helm specific config
helm:
# Helm values files for overriding values in the helm chart
# The path is relative to the spec.source.path directory defined above
valueFiles:
{{- range .Values.certManager.valueFiles }}
- {{ . }}
{{- end }}
# Optional Helm version to template with. If omitted it will fall back to look at the 'apiVersion' in Chart.yaml
# and decide which Helm binary to use automatically. This field can be either 'v2' or 'v3'.
version: v3
# Destination cluster and namespace to deploy the application
destination:
server: https://kubernetes.default.svc
namespace: cert-manager
{{- end }}
With a corresponding values.yaml file for this parent chart which may look something like the following with the path to desired value file(s) in that child chart's directory specified.
targetRevision: v1.11.0
certManager:
enabled: true
valueFiles:
- "values.yaml"
clusterAutoScaler:
valueFiles:
- "envs/dev-account/saas/values.yaml"
clusterResourceLimits:
valueFiles:
- "values.yaml"
externalDns:
valueFiles:
- "envs/dev-account/saas/values.yaml"
ingressNginx:
enabled: true
valueFiles:
- "values.yaml"
Below is a screenshot of one of my app of apps directory to complete the example.

How to choose dependency release name for custom Helm 3 chart

The syntax for adding a dependency to a helm 3 chart looks like this (inside of chart.yaml).
How can you specify a release name if you need multiple instances of a dependency?
apiVersion: v2
name: shared
description: Ingress Controller and Certificate Manager
type: application
version: 0.1.1
appVersion: 0.1.0
dependencies:
- name: cert-manager
version: ~0.13
repository: https://charts.jetstack.io
In the CLI it's just helm upgrade -i RELEASE_NAME CHART_NAME -n NAMESPACE
But inside of Chart.yaml the option to specify a release seems to be missing.
The next question I have is if there's a weird way to do it, how would you write the values for each instance in the values.yaml file?
After 5 more minutes of searching I found that there's an alias field that can be added, like so:
dependencies:
- name: cert-manager
alias: first-one
version: ~0.13
repository: https://charts.jetstack.io
- name: cert-manager
alias: second-one
version: ~0.13
repository: https://charts.jetstack.io
And in the values.yaml file
first-one:
# values go here
second-one:
# values go here
Reference https://helm.sh/docs/topics/charts/#the-chartyaml-file
Using cert-manager is just an example, I can't think of a use-case that would need two instances of that particular chart. I'm hoping to use it for brigade projects