<p>I have a Helm chart that installs different kubernetes resources to deploy my application.
One of those resources is a deployment that has two flavors, one for a client part of the app and one for the server part, so actually they are two deployments. Most of their manifests (yaml files) are exactly the same, the only important difference is that each refers to a different configmap in order to have specific values for some of the configmap properties (particularly the type: client/server and number of replicas). This doesn't seem to be very efficient since I'm duplicating code for the deployments, but it's the way I found to do it.
On the other hand, for the configmaps I made use of Helm's template feature (<code>{{ include }}</code>) so I have a &quot;main&quot; configmap template which has all the common content, and two separate configmaps specifying the differences for each deployment and including the main template.</p>
<p>So far so good, even though there may be some unnecessary code duplication, in which case I wouldn't know how to improve.</p>
<p>The problem is that multiple variants of the above two deployments came into play. For example, I may want to deploy a client-type pod with property X having a certain value, and two server-type pods with property X having a different value. So following my approach, I would have to start creating more deployment yaml files to cover all possible combinations: type=client &amp; X=Y, type=client &amp; X=Z, type=server &amp; X=Y, type=server &amp; X=Z and so on. And the only purpose of this is to be able to specify how many replicas I want for each kind or combination.</p>
<p>Is there any way (using Helm or other Kubernetes related framework) to have a single deployment yaml file and be able to install it multiple times specifying only the properties that vary and the number of replicas for that variation?</p>
<p>For example:</p>
<p>I want:</p>
<ul>
<li>3 replicas that have &quot;type=client&quot; and &quot;X=1&quot;</li>
<li>2 replicas that have &quot;type=server&quot; and &quot;X=1&quot;</li>
<li>4 replicas that have &quot;type=client&quot; and &quot;X=2&quot;</li>
<li>1 replicas that have &quot;type=server&quot; and &quot;X=3&quot;</li>
</ul>
<p>where type and X are properties (data) in some configmap.</p>
<p>Hope it's clear enough, otherwise please let me know, thanks.</p>

Nicolás García
<p>In Helm there are a couple of ways to approach this.  You need to bring the settings up to Helm's configuration layer (they would be in <code>values.yaml</code> or provided via a mechanism like <code>helm install --set</code>); you can't extract them out of the ConfigMap.</p>
<p>One approach is to have your Helm chart install only a single instance of the Deployment and the corresponding ConfigMap.  Have a single <code>templates/deployment.yaml</code> file that includes lines like:</p>
<pre class="lang-yaml prettyprint-override"><code>name: {{ .Release.Name }}-{{ .Chart.Name }}-{{ .Values.type }}-{{ .Values.X }}

replicas: {{ .Values.replicas }}

env:
  - name: TYPE
    value: {{ .Values.type }}
  - name: X
    value: {{ quote .Values.X }}
</code></pre>
<p>Then you can deploy multiple copies of it:</p>
<pre class="lang-sh prettyprint-override"><code>helm install c1 . --set type=client --set X=1 --set replicas=3
helm install s1 . --set type=server --set X=1 --set replicas=2
</code></pre>
<p>You mention that you're generating similar ConfigMaps using templates already, and you can also use that same approach for any YAML structure.  A template takes a single parameter, and one trick that's possible is to pass a list as that parameter.  The other important detail to remember is that the top-level names like <code>.Values</code> are actually field lookups in a special object <code>.</code>, which can get reassigned in several contexts, so you may need to explicitly pass around and reference the top-level object.</p>
<p>Say your template needs the top-level values, and also some extra configuration settings:</p>
<pre class="lang-yaml prettyprint-override"><code>{{- define &quot;a.deployment&quot; -}}
{{- $top := index . 0 -}}
{{- $config := index . 1 -}}
metadata:
  name: {{ include &quot;chart.name&quot; $top }}-{{ $config.type }}-{{ $config.X }}
{{ end -}}
</code></pre>
<p>Note that we unpack the two values from the single list parameter, then pass <code>$top</code> in places where we might expect to pass <code>.</code> as a parameter.</p>
<p>You can have a top-level file per variant of this.  For example, <code>templates/deployment-server-1.yaml</code> might contain:</p>
<pre class="lang-none prettyprint-override"><code>{{- $config := dict &quot;type&quot; &quot;server&quot; &quot;X&quot; &quot;1&quot; -}}
{{- include &quot;a.deployment&quot; (list . $config) -}}
</code></pre>
<p>Here <code>.</code> is the top-level object; we're embedding that and the config dictionary into a single list parameter to match what the template expects.  You could use any templating constructs in the <code>dict</code> call if some of the values were specified in Helm configuration.</p>
<p>Finally, there's not actually a rule that a YAML file contains only a single object.  If your Helm configuration just lists out the variants, you can loop through them and emit them all:</p>
<pre class="lang-none prettyprint-override"><code>{{-/* range will reassign . so save its current value */-}}
{{- $top := . -}}
{{- range .Values.installations -}}
{{-/* Now . is one item from the installations list */-}}
{{-/* This is the YAML start-of-document marker: */-}}
---
{{ include &quot;a.deployment&quot; (list $top .) -}}
{{- end -}}
</code></pre>
<p>You'd just list out all of the variants and settings in the Helm <code>values.yaml</code> (or, again, an externally provided <code>helm install -f more-values.yaml</code> file):</p>
<pre class="lang-yaml prettyprint-override"><code>installations:
  - type: client
    X: 1
    replicas: 3
  - type: server
    X: 1
    replicas: 2
</code></pre>
