Subcharts and Global Values

    Before we dive into the code, there are a few important details to learn about subcharts.

    1. A subchart is considered “stand-alone”, which means a subchart can never explicitly depend on its parent chart.
    2. For that reason, a subchart cannot access the values of its parent.
    3. A parent chart can override values for subcharts.
    4. Helm has a concept of global values that can be accessed by all charts.

    As we walk through the examples in this section, many of these concepts will become clearer.

    For these exercises, we’ll start with the chart we created at the beginning of this guide, and we’ll add a new chart inside of it.

    Notice that just as before, we deleted all of the base templates so that we can start from scratch. In this guide, we are focused on how templates work, not on managing dependencies. But the Charts Guide has more information on how subcharts work.

    Adding Values and a Template to the Subchart

    Next, let’s create a simple template and values file for our mysubchart chart. There should already be a values.yaml in mychart/charts/mysubchart. We’ll set it up like this:

    1. dessert: cake

    Next, we’ll create a new ConfigMap template in mychart/charts/mysubchart/templates/configmap.yaml:

    1. apiVersion: v1
    2. kind: ConfigMap
    3. metadata:
    4. name: {{ .Release.Name }}-cfgmap2
    5. data:
    6. dessert: {{ .Values.dessert }}

    Because every subchart is a stand-alone chart, we can test mysubchart on its own:

    1. $ helm install --dry-run --debug mychart/charts/mysubchart
    2. SERVER: "localhost:44134"
    3. CHART PATH: /Users/mattbutcher/Code/Go/src/k8s.io/helm/_scratch/mychart/charts/mysubchart
    4. NAME: newbie-elk
    5. TARGET NAMESPACE: default
    6. CHART: mysubchart 0.1.0
    7. MANIFEST:
    8. ---
    9. apiVersion: v1
    10. kind: ConfigMap
    11. metadata:
    12. name: newbie-elk-cfgmap2
    13. data:
    14. dessert: cake

    Our original chart, mychart is now the parent chart of mysubchart. This relationship is based entirely on the fact that mysubchart is within mychart/charts.

    Note the last two lines. Any directives inside of the section will be sent to the mysubchart chart. So if we run helm install --dry-run --debug mychart, one of the things we will see is the mysubchart ConfigMap:

    1. # Source: mychart/charts/mysubchart/templates/configmap.yaml
    2. apiVersion: v1
    3. kind: ConfigMap
    4. metadata:
    5. name: unhinged-bee-cfgmap2
    6. data:
    7. dessert: ice cream

    The value at the top level has now overridden the value of the subchart.

    There’s an important detail to notice here. We didn’t change the template of mychart/charts/mysubchart/templates/configmap.yaml to point to .Values.mysubchart.dessert. From that template’s perspective, the value is still located at .Values.dessert. As the template engine passes values along, it sets the scope. So for the mysubchart templates, only values specifically for mysubchart will be available in .Values.

    Sometimes, though, you do want certain values to be available to all of the templates. This is accomplished using global chart values.

    Global Chart Values

    Global values are values that can be accessed from any chart or subchart by exactly the same name. Globals require explicit declaration. You can’t use an existing non-global as if it were a global.

    The Values data type has a reserved section called Values.global where global values can be set. Let’s set one in our mychart/values.yaml file.

    1. favorite:
    2. drink: coffee
    3. food: pizza
    4. pizzaToppings:
    5. - mushrooms
    6. - cheese
    7. - peppers
    8. - onions
    9. mysubchart:
    10. dessert: ice cream
    11. salad: caesar

    Because of the way globals work, both mychart/templates/configmap.yaml and mychart/charts/mysubchart/templates/configmap.yaml should be able to access that value as {{ .Values.global.salad}}.

    :

    1. apiVersion: v1
    2. kind: ConfigMap
    3. metadata:
    4. name: {{ .Release.Name }}-configmap
    5. data:
    6. salad: {{ .Values.global.salad }}

    Now if we run a dry run install, we’ll see the same value in both outputs:

    1. # Source: mychart/templates/configmap.yaml
    2. apiVersion: v1
    3. kind: ConfigMap
    4. metadata:
    5. name: silly-snake-configmap
    6. data:
    7. salad: caesar
    8. ---
    9. # Source: mychart/charts/mysubchart/templates/configmap.yaml
    10. apiVersion: v1
    11. kind: ConfigMap
    12. metadata:
    13. name: silly-snake-cfgmap2
    14. data:
    15. dessert: ice cream
    16. salad: caesar

    Globals are useful for passing information like this, though it does take some planning to make sure the right templates are configured to use globals.

    Parent charts and subcharts can share templates. Any defined block in any chart is available to other charts.

    For example, we can define a simple template like this:

    1. {{- define "labels" }}from: mychart{{ end }}

    Recall how the labels on templates are globally shared. Thus, the labels chart can be included from any other chart.

    While chart developers have a choice between include and template, one advantage of using include is that include can dynamically reference templates:

      The above will dereference $mytemplate. The template function, in contrast, will only accept a string literal.

      Avoid Using Blocks

      The Go template language provides a block keyword that allows developers to provide a default implementation which is overridden later. In Helm charts, blocks are not the best tool for overriding because if multiple implementations of the same block are provided, the one selected is unpredictable.