How to choose dependency release name for custom Helm 3 chart - kubernetes

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

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: ...

Declarative approach to deploy Helm chart by Argocd to multiple environments

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/

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.

Helm: Conditional deployment of a dependent chart, only install if it has not been installed before

While installing a helm chart a condition for the dependency works well as the following Chart.yaml file. But it doesn't allow to apply the condition based on the existing Kubernetes resource.
# Chart.yaml
apiVersion: v1
name: my-chart
version: 0.3.1
appVersion: 0.4.5
description: A helm chart with dependency
dependencies:
- name: metrics-server
version: 2.5.0
repository: https://artifacts.myserver.com/v1/helm
condition: metrics-server.enabled
I did a local install of the chart (my-chart) in a namespace(default), then I try to install the same chart in another namespace(pb) I get the following error which says the resource already exists. This resource, "system:metrics-server-aggregated-reader", has been installed cluster wide as previous dependency (metrics-server). Following is the step to reproduce.
user#hostname$helm install my-chart -n default --set metrics-server.enabled=true ./my-chart
NAME: my-chart
LAST DEPLOYED: Wed Nov 25 16:22:52 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
My Cluster
user#hostname$helm install my-chart -n pb --set metrics-server.enabled=true ./my-chart
Error: rendered manifests contain a resource that already exists. Unable to continue with install: ClusterRole "system:metrics-server-aggregated-reader" in namespace "" exists and cannot be imported into the current release: invalid ownership metadata; annotation validation error: key "meta.helm.sh/release-namespace" must equal "pb": current value is "default"
There is a way to modify the template inside the metrics-server chart to conditionally generate the manifest files as described in Helm Conditional Templates. In order to do this I have to modify and maintain the metrics-server chart in internal artifact which will restrict me using the most recent charts.
I am looking for an approach to query the existing Kubernetes resource, "system:metrics-server-aggregated-reader", and only install the dependency chart if such resource do not exists.

How to set a different namespace for child helm charts?

When you install a chart with a child chart that doesn't specify a namespace, Helm will use the one specified on command line via --namespace. Is it possible to override this flag for a specific child chart?
For example if I have chart A which depends on chart B and I specify --namespace foo, I want to be able to customize the resources of chart B to be installed into some other namespace bar instead of foo.
Update 2:
Helm 3 added support for multi namespaces https://github.com/helm/helm/issues/2060
Update 1:
If a resource template specifies a metadata.namespace, then it will be installed in that namespace. For example, if I have a pod with metadata.namespace: x and I run helm install mychart --namespace y, that pod will be installed in x. I guess you could use regular helm templates with the namespace to parameterize it.
Original answer:
We do not plan on fully supporting multi-namespaced releases until Helm 3.0
https://github.com/kubernetes/helm/issues/2060#issuecomment-306847365
As a workaround, you install for each namespace individually using --skip-dependencies or with dependency conditions
If you already have different charts then you can use helmfile to achieve this.
Step 1:
create the following folder.
my-awesome-infrastructure/
helm
helmfile
helmfile.yaml
Where helm and helmfile are the binary executables.
Step 2: install the helm diff plugin which is needed used helmfile.
helm plugin install https://github.com/databus23/helm-diff
Step 3: declare your charts in the helmfile.yaml.
helmBinary: ./helm
repositories:
- name: ingress-nginx
url: https://kubernetes.github.io/ingress-nginx
- name: bitnami
url: https://charts.bitnami.com/bitnami
releases:
- name: nginx-ingress
namespace: nginx-ingress
createNamespace: true
chart: ingress-nginx/ingress-nginx
version: ~4.1.0
- name: jupyterhub
namespace: jupyterhub
createNamespace: true
chart: bitnami/jupyterhub
version: ~1.1.12
- name: metrics-server
namespace: metrics-server
createNamespace: true
chart: bitnami/metrics-server
version: ~5.11.9
Step 4: run helmfile to deploy all charts.
./helmfile apply
In the above example, you are deploying three separate charts to three separate namespaces.
Under the covers, helmfile will run helm install separately and create separate releases.