Helm Flow Control with Conditional Control Structures

Helm uses templates to generate Kubernetes manifests from chart content. To customize the templates, you can use Helm's built-in functions and operators or create your own. One of Helm’s most powerful features is flow control during a template's generation using control structures.

In this blog, you’ll see how to use conditional blocks (if/else) for flow control in Helm.

To learn more about template customization, read this blog: What are Template Function and Pipeline in Helm?

What are Conditional Control Structures?

Helm's conditional flow control is a feature that allows for the execution of certain code blocks only if certain conditions are met. This is an important concept, as it allows for the creation of more complex and flexible templates. By using conditional flow control, developers can create code that is capable of responding to changing conditions and adapting to new situations.

It makes use of the if/else condition blocks to determine the text that should be generated. Below is an example that uses this control structure.

Of course, an if/else conditional block does not have to be this complex (with so many else and else ifs).

In practice, a simple conditional flow control block can look something like this:

This block can be interpreted like this: if there is no autoscaling.enabled value that the user defined in his values.yaml file (or it is defined as false ), then print out a replicas: line in the manifest sent out to Kubernetes. If there is an autoscaling.enabled value defined as true , then just skip printing the replicas: .

In an if statement, we can use either a simple value or an entire pipeline. For instance, we can extract a value from somewhere, pass it through a pipeline of functions, transform the data in some ways, and then evaluate if the end result is true or false . But how does it decide if it is true or false ?

If the evaluated pipeline returns a boolean value like true or false , it’s easy to understand how that is interpreted. Otherwise, if it’s a number, 0 is interpreted as false. If it's a non-zero number, it is interpreted as true. If it’s a string, an empty one is false, while if it contains even a single letter, it is true . The same can be said for other kinds of objects, like arrays and so on: if they’re empty, this is equivalent to being false; if they’re non-empty, the condition is evaluated as true .

Conditional Flow Control Example

Let’s use this in our deployments.yaml file. Our final content should look like this:

So all we did was basically wrap around our pre-existing line replicas: {{ .Values.replicaCount }} between the newly added lines {{ if not .Values.autoscaling.enabled }} and {{ end }} . We’ll also need to edit our values.yaml file and define this new autoscaling value that our if statement will verify.

Scroll to the end and add these lines:

Make sure the text is properly indented (there should be two empty spaces before the enabled: false line). Also, change replicaCount to 3 . The final content should look like this:

So, with autoscaling disabled (set to false), we expect our if statement to print out a replicas line in the generated manifest.

And we see that indeed it does (also notice the weird empty lines added before and after the replicas line; we’ll see how to fix that too):

But this is the same as what happened before. Let’s see if our if statement does its job when autoscaling is enabled.

Let’s see the generated manifest this time by running helm template ./nginx

generated Kubernetes manifest

We can see no more replicas line.

Controlling Whitespace/Newlines Output

We noticed how our conditional block generates some rather weird output (empty lines) around the replicas line. Remember that our if and end statement is wrapped around that line.

So, when seeing the new empty lines added in the generated manifest, we can imagine that those have something to do with that if and end line above and below the replicas line.

The templating language we use in our template files has a simple method to deal with this. We just need to add a - sign next to the curly brackets.

This will remove whitespace/newlines to the left :

This will remove whitespace/newlines to the right :

Let’s edit our deployment template file again and add the “ - ” signs to their proper places, at the beginning of the if statement and the end statement. The final content will look like this:

Let’s see how our generated manifest changes using helm template ./nginx

To learn more Helm concepts, check out KodeKloud's Helm for Beginners course:

helm conditional assignment

Conditional flow control is particularly useful in applications that need to handle a wide range of user inputs or environmental factors. Overall, it is an essential tool for any Helm user looking to create powerful, dynamic templates.

helm conditional assignment

Empower Yourself with KodeKloud!

Over One Million students have taken KodeKloud DevOps Courses!

Supercharge your DevOps Journey with us. Our 65+ expertly crafted courses cover all aspects of DevOps, ensuring you gain a solid understanding of the most sought-after skills in the industry. Our highly experienced, dedicated, and hard-working trainers go to great lengths to ensure that DevOps is made simple to understand.

More on Helm:

  • Helm Plugins
  • Helm Chart Dependencies
  • Helper Files and Named Templates
  • 7 Helm Best Practices with Examples
  • Understanding and Building Helm Chart Tests
  • Uploading a Helm Chart

Mumshad Mannambeth

Mumshad Mannambeth

Devops blog.

Subscribe for Exclusive Offers, Deals, and Latest Updates from KodeKloud!

Congratulations! You’ve subscribed to our newsletter and exclusive offers from KodeKloud! Stay tuned for inbox updates!

Helm Template If/Else

  • 3.1 nil pointer evaluating interface
  • 4.1 Testing the Existence of Two Configuration Elements in the Same Expression
  • 4.2 Testing the Non-Existence of a Configuration Element
  • 4.3 Negation
  • 4.4 Testing Equality and Inequality of Values
  • 5 Interesting Links
  • https://helm.sh/docs/chart_template_guide/control_structures/#if-else
  • Helm Templates

if / else can be used to create conditional blocks.

The if control structures evaluate pipelines, not just values. A value is a special case of a pipeline:

A pipeline evaluates to false if the result of the pipeline, or the value, is:

  • a boolean false
  • a numeric zero. ⚠️. Also see Notable Values .
  • an empty string
  • a nil (empty or null)
  • an empty collection (map, slice, tuple, dict, array).

In any other case, the condition is evaluated to true.

nil pointer evaluating interface

While nil (empty or missing) values are evaluated to false, this only applies to the leaf of the YAML path. All intermediate path elements leading to the leaf must exist, and must NOT be empty, otherwise the template rendering engine will error out with a message similar to:

The above failure was generated by the expression:

where the input values.yaml is:

If the root key appearance is missing altogether, the failure is identical.

The error was caused by the fact that there is no collection (map) under appearance , or there is no appearance at all, so the attempt to locate the color in a non-existed map errored out. To fix it, one approach is to check the non-nilness of all intermediate YAML path elements:

Using an and function is not an option, because unlike an AND operator in most languages, shortcutting is not used when evaluating function's arguments, so:

will trigger:

Another approach is to make the collection not empty, by adding at least one element (even if the element is empty):

Expressions

if expressions are built with functions: eq , ne , lt , gt , and , or , so the function name is provided first, followed by the arguments. Functions can be grouped with ( ).

Testing the Existence of Two Configuration Elements in the Same Expression

Testing the non-existence of a configuration element.

The following conditional evaluates to true and the embedded content is rendered if the configuration element does NOT exist:

Testing Equality and Inequality of Values

Interesting links.

  • https://stackoverflow.com/questions/49789867/can-we-use-or-operator-in-helm-yaml-files

Navigation menu

You are viewing info for Helm 3 - check the version FAQs or see to Helm 2 for prior versions.

Viewing Helm 3 release. For Helm 2 go here .

Flow Control

Control structures (called “actions” in template parlance) provide you, the template author, with the ability to control the flow of a template’s generation. Helm’s template language provides the following control structures:

  • if / else for creating conditional blocks
  • with to specify a scope
  • range , which provides a “for each”-style loop

In addition to these, it provides a few actions for declaring and using named template segments:

  • define declares a new named template inside of your template
  • template imports a named template
  • block declares a special kind of fillable template area

In this section, we’ll talk about if , with , and range . The others are covered in the “Named Templates” section later in this guide.

The first control structure we’ll look at is for conditionally including blocks of text in a template. This is the if / else block.

The basic structure for a conditional looks like this:

Notice that we’re now talking about pipelines instead of values. The reason for this is to make it clear that control structures can execute an entire pipeline, not just evaluate a value.

A pipeline is evaluated as false if the value is:

  • a boolean false
  • a numeric zero
  • an empty string
  • a nil (empty or null)
  • an empty collection ( map , slice , tuple , dict , array )

Under all other conditions, the condition is true.

Let’s add a simple conditional to our ConfigMap. We’ll add another setting if the drink is set to coffee:

Since we commented out drink: coffee in our last example, the output should not include a mug: true flag. But if we add that line back into our values.yaml file, the output should look like this:

Controlling Whitespace

While we’re looking at conditionals, we should take a quick look at the way whitespace is controlled in templates. Let’s take the previous example and format it to be a little easier to read:

Initially, this looks good. But if we run it through the template engine, we’ll get an unfortunate result:

What happened? We generated incorrect YAML because of the whitespacing above.

mug is incorrectly indented. Let’s simply out-dent that one line, and re-run:

When we sent that, we’ll get YAML that is valid, but still looks a little funny:

Notice that we received a few empty lines in our YAML. Why? When the template engine runs, it removes the contents inside of {{ and }} , but it leaves the remaining whitespace exactly as is.

YAML ascribes meaning to whitespace, so managing the whitespace becomes pretty important. Fortunately, Helm templates have a few tools to help.

First, the curly brace syntax of template declarations can be modified with special characters to tell the template engine to chomp whitespace. {{- (with the dash and space added) indicates that whitespace should be chomped left, while -}} means whitespace to the right should be consumed. Be careful! Newlines are whitespace!

Make sure there is a space between the - and the rest of your directive. {{- 3 }} means “trim left whitespace and print 3” while {{-3 }} means “print -3”.

Using this syntax, we can modify our template to get rid of those new lines:

Just for the sake of making this point clear, let’s adjust the above, and substitute an * for each whitespace that will be deleted following this rule. an * at the end of the line indicates a newline character that would be removed

Keeping that in mind, we can run our template through Helm and see the result:

Be careful with the chomping modifiers. It is easy to accidentally do things like this:

That will produce food: "PIZZA"mug:true because it consumed newlines on both sides.

For the details on whitespace control in templates, see the Official Go template documentation

Finally, sometimes it’s easier to tell the template system how to indent for you instead of trying to master the spacing of template directives. For that reason, you may sometimes find it useful to use the indent function ( {{ indent 2 "mug:true" }} ).

Modifying scope using with

The next control structure to look at is the with action. This controls variable scoping. Recall that . is a reference to the current scope . So .Values tells the template to find the Values object in the current scope.

The syntax for with is similar to a simple if statement:

Scopes can be changed. with can allow you to set the current scope ( . ) to a particular object. For example, we’ve been working with .Values.favorites . Let’s rewrite our ConfigMap to alter the . scope to point to .Values.favorites :

(Note that we removed the if conditional from the previous exercise)

Notice that now we can reference .drink and .food without qualifying them. That is because the with statement sets . to point to .Values.favorite . The . is reset to its previous scope after {{ end }} .

But here’s a note of caution! Inside of the restricted scope, you will not be able to access the other objects from the parent scope. This, for example, will fail:

It will produce an error because Release.Name is not inside of the restricted scope for . . However, if we swap the last two lines, all will work as expected because the scope is reset after {{ end }} .

After looking at range , we will take a look at template variables, which offer one solution to the scoping issue above.

Looping with the range action

Many programming languages have support for looping using for loops, foreach loops, or similar functional mechanisms. In Helm’s template language, the way to iterate through a collection is to use the range operator.

To start, let’s add a list of pizza toppings to our values.yaml file:

Now we have a list (called a slice in templates) of pizzaToppings . We can modify our template to print this list into our ConfigMap:

Let’s take a closer look at the toppings: list. The range function will “range over” (iterate through) the pizzaToppings list. But now something interesting happens. Just like with sets the scope of . , so does a range operator. Each time through the loop, . is set to the current pizza topping. That is, the first time, . is set to mushrooms . The second iteration it is set to cheese , and so on.

We can send the value of . directly down a pipeline, so when we do {{ . | title | quote }} , it sends . to title (title case function) and then to quote . If we run this template, the output will be:

Now, in this example we’ve done something tricky. The toppings: |- line is declaring a multi-line string. So our list of toppings is actually not a YAML list. It’s a big string. Why would we do this? Because the data in ConfigMaps data is composed of key/value pairs, where both the key and the value are simple strings. To understand why this is the case, take a look at the Kubernetes ConfigMap docs . For us, though, this detail doesn’t matter much.

The |- marker in YAML takes a multi-line string. This can be a useful technique for embedding big blocks of data inside of your manifests, as exemplified here.

Sometimes it’s useful to be able to quickly make a list inside of your template, and then iterate over that list. Helm templates have a function to make this easy: tuple . In computer science, a tuple is a list-like collection of fixed size, but with arbitrary data types. This roughly conveys the way a tuple is used.

The above will produce this:

In addition to lists and tuples, range can be used to iterate over collections that have a key and a value (like a map or dict ). We’ll see how to do that in the next section when we introduce template variables.

We are a Cloud Native Computing Foundation incubating project.

© Helm Authors 2020 | Documentation distributed under CC-BY-4.0

© 2020 The Linux Foundation. All rights reserved. The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page.

HatchJS.com

Cracking the Shell of Mystery

Helm If Value Exists: A Guide to Checking for a Key in a ConfigMap

Avatar

Helm if value exists

Helm is a package manager for Kubernetes. It allows you to install, upgrade, and manage Kubernetes applications. The `helm if value exists` command is a useful way to check if a value exists in a Helm chart before installing or upgrading it. This can help you avoid errors and ensure that your applications are installed correctly.

In this article, we will discuss the `helm if value exists` command in detail. We will cover the syntax of the command, how to use it, and some examples of how it can be used. We will also discuss some of the limitations of the command and how to work around them.

By the end of this article, you will have a good understanding of the `helm if value exists` command and how you can use it to manage your Kubernetes applications.

Helm is a package manager for Kubernetes. It allows you to install, upgrade, and manage Kubernetes applications. Helm charts are packages that contain all the necessary files to deploy an application on Kubernetes.

The `if value exists` condition can be used to check if a value exists in a Kubernetes secret or config map. This can be useful for conditional deployments, where you only want to install an application if a specific value is set.

For example, you could use the `if value exists` condition to install a database only if a database password is set.

What is Helm if value exists?

The `if value exists` condition is a Helm parameter that can be used to check if a value exists in a Kubernetes secret or config map. The condition takes a single argument, which is the name of the key to check.

If the value exists, the `if value exists` condition will evaluate to `true`. If the value does not exist, the `if value exists` condition will evaluate to `false`.

How to use Helm if value exists?

To use the `if value exists` condition, you can use the following syntax:

helm install my-chart –set key=value –if-exists=true

In this example, we are using the `if value exists` condition to install the `my-chart` chart with the specified value for the `key` key. If the `key` key does not exist in the Kubernetes secret or config map, the chart will not be installed.

You can also use the `if value exists` condition with the `values` flag. For example, the following command will install the `my-chart` chart with the specified values, but only if the `key` key exists in the Kubernetes secret or config map:

helm install my-chart –values values.yaml –if-exists=true

Here are some examples of how you can use the `if value exists` condition:

  • Install a database only if a database password is set:

helm install my-chart –set database.password=password –if-exists=true

  • Install a service only if a service port is set:

helm install my-chart –set service.port=8080 –if-exists=true

  • Install a deployment only if a deployment replicas is set:

helm install my-chart –set deployment.replicas=3 –if-exists=true

The `if value exists` condition is a powerful tool that can be used to conditionally deploy Kubernetes applications. It can be used to ensure that applications are only deployed if the necessary resources are available, or to avoid deploying applications if there are potential problems.

By using the `if value exists` condition, you can ensure that your Kubernetes deployments are more reliable and secure.

The `if value exists` condition in Helm allows you to conditionally install or upgrade a chart based on the existence of a particular value. This can be useful for ensuring that a chart is only installed or upgraded when certain conditions are met.

To use the `if value exists` condition, you must specify the `values` parameter to the `helm install` or `helm upgrade` command. The `values` parameter is a map of key-value pairs, and you can use the `if value exists` condition to check for the existence of a particular key.

For example, the following command will install the `my-chart` chart only if the `version` key is set in the `values` parameter:

helm install my-chart –set version=1.0.0

If the `version` key is not set in the `values` parameter, the `my-chart` chart will not be installed.

You can also use the `if value exists` condition to upgrade a chart to a specific version. For example, the following command will upgrade the `my-chart` chart to version 1.0.0 if the `version` key is set in the `values` parameter:

helm upgrade my-chart –set version=1.0.0

If the `version` key is not set in the `values` parameter, the `my-chart` chart will not be upgraded.

The `if value exists` condition can be used to conditionally install or upgrade charts based on a variety of factors, such as the version of the chart, the environment in which the chart is being installed, or the values that are set for the chart. This can be a powerful tool for ensuring that charts are only installed or upgraded when the desired conditions are met.

Examples of using Helm if value exists

Here are some examples of using the `if value exists` condition:

  • To install a chart with a specific version, you can use the following command:

This command will only install the `my-chart` chart if the `version` key is set to `1.0.0` in the `values` parameter.

  • To upgrade a chart to a specific version, you can use the following command:

This command will only upgrade the `my-chart` chart if the `version` key is set to `1.0.0` in the `values` parameter.

  • To install a chart in a specific namespace, you can use the following command:

helm install my-chart –namespace my-namespace

This command will only install the `my-chart` chart in the `my-namespace` namespace.

  • To install a chart with a specific set of values, you can use the following command:

helm install my-chart –values values.yaml

This command will only install the `my-chart` chart with the values that are specified in the `values.yaml` file.

  • To upgrade a chart to a specific set of values, you can use the following command:

helm upgrade my-chart –values values.yaml

This command will only upgrade the `my-chart` chart to the values that are specified in the `values.yaml` file.

The `if value exists` condition can be used to conditionally install or upgrade charts based on a variety of factors. This can be a powerful tool for ensuring that charts are only installed or upgraded when the desired conditions are met.

The `if value exists` condition in Helm is a powerful tool that can be used to conditionally install or upgrade charts based on a variety of factors. This can be a useful way to ensure that charts are only installed or upgraded when the desired conditions are met.

Here are some additional resources that you may find helpful:

  • [Helm documentation on the `if value exists` condition](https://helm.sh/docs/chart/templating/if-value-exists)
  • [Helm cookbook on using the `if value exists` condition](https://helm.sh/docs/topics/charts/cookbook/conditional-installation)

A: Helm if value exists is a Helm chart condition that checks if a specific value exists in a Kubernetes Secret, ConfigMap, or environment variable. If the value exists, the chart will be deployed. If the value does not exist, the chart will not be deployed.

Q: How do I use helm if value exists?

A: To use helm if value exists, you can use the following syntax:

This will install the `my-chart` chart if the value `key` exists in the specified Secret, ConfigMap, or environment variable.

Q: What are the limitations of helm if value exists?

A: There are a few limitations to helm if value exists. First, it can only check for the existence of a single value. Second, it cannot check for the value of a complex object, such as a map or list. Third, it cannot check for the existence of a value in a specific field of a complex object.

Q: What are some best practices for using helm if value exists?

A: Here are a few best practices for using helm if value exists:

  • Use helm if value exists to conditionally deploy charts that are only needed in certain environments. For example, you could use helm if value exists to deploy a chart that contains Kubernetes resources that are only needed in a production environment.
  • Use helm if value exists to avoid deploying charts that contain resources that you do not need. For example, you could use helm if value exists to prevent a chart from deploying a service that is already running in your cluster.
  • Use helm if value exists to make your charts more flexible and easier to maintain. For example, you could use helm if value exists to allow you to deploy the same chart in different environments with different configurations.

Q: Where can I learn more about helm if value exists?

A: You can learn more about helm if value exists by reading the following resources:

  • [The Helm documentation on conditions](https://helm.sh/docs/chart/values/conditions)
  • [The Helm documentation on secrets](https://helm.sh/docs/secrets/)
  • [The Helm documentation on configmaps](https://helm.sh/docs/configmaps/)

We hope that this blog post has been helpful in understanding the Helm if value exists condition. If you have any questions or feedback, please feel free to reach out to us.

Author Profile

Marcus Greenwood

Latest entries

  • December 26, 2023 Error Fixing User: Anonymous is not authorized to perform: execute-api:invoke on resource: How to fix this error
  • December 26, 2023 How To Guides Valid Intents Must Be Provided for the Client: Why It’s Important and How to Do It
  • December 26, 2023 Error Fixing How to Fix the The Root Filesystem Requires a Manual fsck Error
  • December 26, 2023 Troubleshooting How to Fix the `sed unterminated s` Command

Similar Posts

Sas to usb converter: the ultimate guide to choosing the right one.

SAS to USB Converter: The Ultimate Guide SAS (Serial Attached SCSI) is a high-speed data interface used in enterprise storage systems. USB (Universal Serial Bus) is a more common interface used for connecting peripheral devices to computers. SAS to USB converters allow you to connect SAS devices to a computer via a USB port. This…

Python Type Hints with Default Values: A Guide for Better Code

Python Type Hints with Default Values: A Guide for Beginners Python is a powerful and versatile programming language that is used by developers of all skill levels. One of the features that makes Python so popular is its type hinting system, which allows you to specify the types of data that a function or variable…

What Does LEGO Mean in Latin?

Have you ever wondered what the word LEGO means? Its a common question, and the answer may surprise you. LEGO is actually a Latin phrase that means I put together. This is a fitting name for the company, which has been creating building blocks for children since 1949. LEGO bricks are designed to be compatible…

Can Pex B Be Expanded?

Can PEX B Be Expanded? PEX B is a type of cross-linked polyethylene (PEX) pipe that is used for plumbing applications. It is a versatile material that is resistant to corrosion, chemicals, and temperature extremes. PEX B is also easy to install and can be expanded to fit a variety of applications. In this article,…

How Much Weight Can a 2×10 Support Horizontally?

How Much Weight Can a 2×10 Support Horizontally? When it comes to building a structure, one of the most important factors to consider is the weight that the materials will be able to support. This is especially true for horizontal beams, which are used to support the weight of the roof or floor above them….

ORA-12170: TNS: connect timeout occurred

Oracle Error ORA-12170: TNS:Connect Timeout Occurred Have you ever tried to connect to an Oracle database and received the error message “ORA-12170: TNS:Connect Timeout Occurred”? This error occurs when a client cannot connect to an Oracle database within the specified timeout period. There are a number of reasons why this error might occur, but the…

Helm Logo Documentation

The chart template developer’s guide.

This guide provides an introduction to Helm’s chart templates, with emphasis on the template language.

Templates generate manifest files, which are YAML-formatted resource descriptions that Kubernetes can understand. We’ll look at how templates are structured, how they can be used, how to write Go templates, and how to debug your work.

This guide focuses on the following concepts:

  • The Helm template language
  • Using values
  • Techniques for working with templates

This guide is oriented toward learning the ins and outs of the Helm template language. Other guides provide introductory material, examples, and best practices.

Getting Started with a Chart Template

In this section of the guide, we’ll create a chart and then add a first template. The chart we created here will be used throughout the rest of the guide.

To get going, let’s take a brief look at a Helm chart.

As described in the Charts Guide , Helm charts are structured like this:

The templates/ directory is for template files. When Tiller evaluates a chart, it will send all of the files in the templates/ directory through the template rendering engine. Tiller then collects the results of those templates and sends them on to Kubernetes.

The values.yaml file is also important to templates. This file contains the default values for a chart. These values may be overridden by users during helm install or helm upgrade .

The Chart.yaml file contains a description of the chart. You can access it from within a template. The charts/ directory may contain other charts (which we call subcharts ). Later in this guide we will see how those work when it comes to template rendering.

A Starter Chart

For this guide, we’ll create a simple chart called mychart , and then we’ll create some templates inside of the chart.

From here on, we’ll be working in the mychart directory.

A Quick Glimpse of mychart/templates/

If you take a look at the mychart/templates/ directory, you’ll notice a few files already there.

  • NOTES.txt : The “help text” for your chart. This will be displayed to your users when they run helm install .
  • deployment.yaml : A basic manifest for creating a Kubernetes deployment
  • service.yaml : A basic manifest for creating a service endpoint for your deployment
  • _helpers.tpl : A place to put template helpers that you can re-use throughout the chart

And what we’re going to do is… remove them all! That way we can work through our tutorial from scratch. We’ll actually create our own NOTES.txt and _helpers.tpl as we go.

When you’re writing production grade charts, having basic versions of these charts can be really useful. So in your day-to-day chart authoring, you probably won’t want to remove them.

A First Template

The first template we are going to create will be a ConfigMap . In Kubernetes, a ConfigMap is simply a container for storing configuration data. Other things, like pods, can access the data in a ConfigMap.

Because ConfigMaps are basic resources, they make a great starting point for us.

Let’s begin by creating a file called mychart/templates/configmap.yaml :

TIP: Template names do not follow a rigid naming pattern. However, we recommend using the suffix .yaml for YAML files and .tpl for helpers.

The YAML file above is a bare-bones ConfigMap, having the minimal necessary fields. In virtue of the fact that this file is in the templates/ directory, it will be sent through the template engine.

It is just fine to put a plain YAML file like this in the templates/ directory. When Tiller reads this template, it will simply send it to Kubernetes as-is.

With this simple template, we now have an installable chart. And we can install it like this:

In the output above, we can see that our ConfigMap was created. Using Helm, we can retrieve the release and see the actual template that was loaded.

The helm get manifest command takes a release name ( full-coral ) and prints out all of the Kubernetes resources that were uploaded to the server. Each file begins with --- to indicate the start of a YAML document, and then is followed by an automatically generated comment line that tells us what template file generated this YAML document.

From there on, we can see that the YAML data is exactly what we put in our configmap.yaml file.

Now we can delete our release: helm delete full-coral .

Adding a Simple Template Call

Hard-coding the name: into a resource is usually considered to be bad practice. Names should be unique to a release. So we might want to generate a name field by inserting the release name.

TIP: The name: field is limited to 63 characters because of limitations to the DNS system. For that reason, release names are limited to 53 characters. Kubernetes 1.3 and earlier limited to only 24 characters (thus 14 character names).

Let’s alter configmap.yaml accordingly.

The big change comes in the value of the name: field, which is now {{ .Release.Name }}-configmap .

A template directive is enclosed in {{ and }} blocks.

The template directive {{ .Release.Name }} injects the release name into the template. The values that are passed into a template can be thought of as namespaced objects , where a dot ( . ) separates each namespaced element.

The leading dot before Release indicates that we start with the top-most namespace for this scope (we’ll talk about scope in a bit). So we could read .Release.Name as “start at the top namespace, find the Release object, then look inside of it for an object called Name ”.

The Release object is one of the built-in objects for Helm, and we’ll cover it in more depth later. But for now, it is sufficient to say that this will display the release name that Tiller assigns to our release.

Now when we install our resource, we’ll immediately see the result of using this template directive:

Note that in the RESOURCES section, the name we see there is clunky-serval-configmap instead of mychart-configmap .

You can run helm get manifest clunky-serval to see the entire generated YAML.

At this point, we’ve seen templates at their most basic: YAML files that have template directives embedded in {{ and }} . In the next part, we’ll take a deeper look into templates. But before moving on, there’s one quick trick that can make building templates faster: When you want to test the template rendering, but not actually install anything, you can use helm install ./mychart --debug --dry-run . This will send the chart to the Tiller server, which will render the templates. But instead of installing the chart, it will return the rendered template to you so you can see the output:

Using --dry-run will make it easier to test your code, but it won’t ensure that Kubernetes itself will accept the templates you generate. It’s best not to assume that your chart will install just because --dry-run works.

In the next few sections, we’ll take the basic chart we defined here and explore the Helm template language in detail. And we’ll get started with built-in objects.

Built-in Objects

Objects are passed into a template from the template engine. And your code can pass objects around (we’ll see examples when we look at the with and range statements). There are even a few ways to create new objects within your templates, like with the list function we’ll see later.

Objects can be simple, and have just one value. Or they can contain other objects or functions. For example. the Release object contains several objects (like Release.Name ) and the Files object has a few functions.

In the previous section, we use {{.Release.Name}} to insert the name of a release into a template. Release is one of the top-level objects that you can access in your templates.

  • Release.Name : The release name
  • Release.Time : The time of the release
  • Release.Namespace : The namespace to be released into (if the manifest doesn’t override)
  • Release.Service : The name of the releasing service (always Tiller ).
  • Release.Revision : The revision number of this release. It begins at 1 and is incremented for each helm upgrade .
  • Release.IsUpgrade : This is set to true if the current operation is an upgrade or rollback.
  • Release.IsInstall : This is set to true if the current operation is an install.
  • Values : Values passed into the template from the values.yaml file and from user-supplied files. By default, Values is empty.
  • The available fields are listed in the Charts Guide
  • Files.Get is a function for getting a file by name ( .Files.Get config.ini )
  • Files.GetBytes is a function for getting the contents of a file as an array of bytes instead of as a string. This is useful for things like images.
  • Capabilities.APIVersions is a set of versions.
  • Capabilities.APIVersions.Has $version indicates whether a version (e.g., batch/v1 ) or resource (e.g., apps/v1/Deployment ) is available on the cluster. Note, resources were not available before Helm v2.15.
  • Capabilities.KubeVersion provides a way to look up the Kubernetes version. It has the following values: Major , Minor , GitVersion , GitCommit , GitTreeState , BuildDate , GoVersion , Compiler , and Platform .
  • Capabilities.TillerVersion provides a way to look up the Tiller version. It has the following values: SemVer , GitCommit , and GitTreeState .
  • Name : A namespaced filepath to the current template (e.g. mychart/templates/mytemplate.yaml )
  • BasePath : The namespaced path to the templates directory of the current chart (e.g. mychart/templates ).

The values are available to any top-level template. As we will see later, this does not necessarily mean that they will be available everywhere .

The built-in values always begin with a capital letter. This is in keeping with Go’s naming convention. When you create your own names, you are free to use a convention that suits your team. Some teams, like the Helm Charts team, choose to use only initial lower case letters in order to distinguish local names from those built-in. In this guide, we follow that convention.

Values Files

In the previous section we looked at the built-in objects that Helm templates offer. One of these built-in objects is Values . This object provides access to values passed into the chart. Its contents come from four sources:

  • The values.yaml file in the chart
  • If this is a subchart, the values.yaml file of a parent chart
  • A values file is passed into helm install or helm upgrade with the -f flag ( helm install -f myvals.yaml ./mychart )
  • Individual parameters passed with --set (such as helm install --set foo=bar ./mychart )

The list above is in order of specificity: values.yaml is the default, which can be overridden by a parent chart’s values.yaml , which can in turn be overridden by a user-supplied values file, which can in turn be overridden by --set parameters.

Values files are plain YAML files. Let’s edit mychart/values.yaml and then edit our ConfigMap template.

Removing the defaults in values.yaml , we’ll set just one parameter:

Now we can use this inside of a template:

Notice on the last line we access favoriteDrink as an attribute of Values : {{ .Values.favoriteDrink }} .

Let’s see how this renders.

Because favoriteDrink is set in the default values.yaml file to coffee , that’s the value displayed in the template. We can easily override that by adding a --set flag in our call to helm install :

Since --set has a higher precedence than the default values.yaml file, our template generates drink: slurm .

Values files can contain more structured content, too. For example, we could create a favorite section in our values.yaml file, and then add several keys there:

Now we would have to modify the template slightly:

While structuring data this way is possible, the recommendation is that you keep your values trees shallow, favoring flatness. When we look at assigning values to subcharts, we’ll see how values are named using a tree structure.

Deleting a default key

If you need to delete a key from the default values, you may override the value of the key to be null , in which case Helm will remove the key from the overridden values merge.

For example, the stable Drupal chart allows configuring the liveness probe, in case you configure a custom image. Here are the default values:

If you try to override the livenessProbe handler to exec instead of httpGet using --set livenessProbe.exec.command=[cat,docroot/CHANGELOG.txt] , Helm will coalesce the default and overridden keys together, resulting in the following YAML:

However, Kubernetes would then fail because you can not declare more than one livenessProbe handler. To overcome this, you may instruct Helm to delete the livenessProbe.httpGet by setting it to null:

At this point, we’ve seen several built-in objects, and used them to inject information into a template. Now we will take a look at another aspect of the template engine: functions and pipelines.

Template Functions and Pipelines

So far, we’ve seen how to place information into a template. But that information is placed into the template unmodified. Sometimes we want to transform the supplied data in a way that makes it more usable to us.

Let’s start with a best practice: When injecting strings from the .Values object into the template, we ought to quote these strings. We can do that by calling the quote function in the template directive:

Template functions follow the syntax functionName arg1 arg2... . In the snippet above, quote .Values.favorite.drink calls the quote function and passes it a single argument.

Helm has over 60 available functions. Some of them are defined by the Go template language itself. Most of the others are part of the Sprig template library . We’ll see many of them as we progress through the examples.

While we talk about the “Helm template language” as if it is Helm-specific, it is actually a combination of the Go template language, some extra functions, and a variety of wrappers to expose certain objects to the templates. Many resources on Go templates may be helpful as you learn about templating.

One of the powerful features of the template language is its concept of pipelines . Drawing on a concept from UNIX, pipelines are a tool for chaining together a series of template commands to compactly express a series of transformations. In other words, pipelines are an efficient way of getting several things done in sequence. Let’s rewrite the above example using a pipeline.

In this example, instead of calling quote ARGUMENT , we inverted the order. We “sent” the argument to the function using a pipeline ( | ): .Values.favorite.drink | quote . Using pipelines, we can chain several functions together:

Inverting the order is a common practice in templates. You will see .val | quote more often than quote .val . Either practice is fine.

When evaluated, that template will produce this:

Note that our original pizza has now been transformed to "PIZZA" .

When pipelining arguments like this, the result of the first evaluation ( .Values.favorite.drink ) is sent as the last argument to the function . We can modify the drink example above to illustrate with a function that takes two arguments: repeat COUNT STRING :

The repeat function will echo the given string the given number of times, so we will get this for output:

Using the default function

One function frequently used in templates is the default function: default DEFAULT_VALUE GIVEN_VALUE . This function allows you to specify a default value inside of the template, in case the value is omitted. Let’s use it to modify the drink example above:

If we run this as normal, we’ll get our coffee :

Now, we will remove the favorite drink setting from values.yaml :

Now re-running helm install --dry-run --debug ./mychart will produce this YAML:

In an actual chart, all static default values should live in the values.yaml, and should not be repeated using the default command (otherwise they would be redundant). However, the default command is perfect for computed values, which can not be declared inside values.yaml. For example:

In some places, an if conditional guard may be better suited than default . We’ll see those in the next section.

Template functions and pipelines are a powerful way to transform information and then insert it into your YAML. But sometimes it’s necessary to add some template logic that is a little more sophisticated than just inserting a string. In the next section we will look at the control structures provided by the template language.

Operators are functions

Operators are implemented as functions that return a boolean value. To use eq , ne , lt , gt , and , or , not etcetera place the operator at the front of the statement followed by its parameters just as you would a function. To chain multiple operations together, separate individual functions by surrounding them with parentheses.

Now we can turn from functions and pipelines to flow control with conditions, loops, and scope modifiers.

Flow Control

Control structures (called “actions” in template parlance) provide you, the template author, with the ability to control the flow of a template’s generation. Helm’s template language provides the following control structures:

  • if / else for creating conditional blocks
  • with to specify a scope
  • range , which provides a “for each”-style loop

In addition to these, it provides a few actions for declaring and using named template segments:

  • define declares a new named template inside of your template
  • template imports a named template
  • block declares a special kind of fillable template area

In this section, we’ll talk about if , with , and range . The others are covered in the “Named Templates” section later in this guide.

The first control structure we’ll look at is for conditionally including blocks of text in a template. This is the if / else block.

The basic structure for a conditional looks like this:

Notice that we’re now talking about pipelines instead of values. The reason for this is to make it clear that control structures can execute an entire pipeline, not just evaluate a value.

A pipeline is evaluated as false if the value is:

  • a boolean false
  • a numeric zero
  • an empty string
  • a nil (empty or null)
  • an empty collection ( map , slice , tuple , dict , array )

In any other case, the condition is evaluated to true and the pipeline is executed.

Let’s add a simple conditional to our ConfigMap. We’ll add another setting if the drink is set to coffee:

Note that .Values.favorite.drink must be defined or else it will throw an error when comparing it to “coffee”. Since we commented out drink: coffee in our last example, the output should not include a mug: true flag. But if we add that line back into our values.yaml file, the output should look like this:

Controlling Whitespace

While we’re looking at conditionals, we should take a quick look at the way whitespace is controlled in templates. Let’s take the previous example and format it to be a little easier to read:

Initially, this looks good. But if we run it through the template engine, we’ll get an unfortunate result:

What happened? We generated incorrect YAML because of the whitespacing above.

mug is incorrectly indented. Let’s simply out-dent that one line, and re-run:

When we sent that, we’ll get YAML that is valid, but still looks a little funny:

Notice that we received a few empty lines in our YAML. Why? When the template engine runs, it removes the contents inside of {{ and }} , but it leaves the remaining whitespace exactly as is.

YAML ascribes meaning to whitespace, so managing the whitespace becomes pretty important. Fortunately, Helm templates have a few tools to help.

First, the curly brace syntax of template declarations can be modified with special characters to tell the template engine to chomp whitespace. {{- (with the dash and space added) indicates that whitespace should be chomped left, while -}} means whitespace to the right should be consumed. Be careful! Newlines are whitespace!

Make sure there is a space between the - and the rest of your directive. {{- 3 }} means “trim left whitespace and print 3” while {{-3}} means “print -3”.

Using this syntax, we can modify our template to get rid of those new lines:

Just for the sake of making this point clear, let’s adjust the above, and substitute an * for each whitespace that will be deleted following this rule. an * at the end of the line indicates a newline character that would be removed

Keeping that in mind, we can run our template through Helm and see the result:

Be careful with the chomping modifiers. It is easy to accidentally do things like this:

That will produce food: "PIZZA"mug:true because it consumed newlines on both sides.

For the details on whitespace control in templates, see the Official Go template documentation

Finally, sometimes it’s easier to tell the template system how to indent for you instead of trying to master the spacing of template directives. For that reason, you may sometimes find it useful to use the indent function ( {{indent 2 "mug:true"}} ).

Modifying scope using with

The next control structure to look at is the with action. This controls variable scoping. Recall that . is a reference to the current scope . So .Values tells the template to find the Values object in the current scope.

The syntax for with is similar to a simple if statement:

Scopes can be changed. with can allow you to set the current scope ( . ) to a particular object. For example, we’ve been working with .Values.favorites . Let’s rewrite our ConfigMap to alter the . scope to point to .Values.favorites :

(Note that we removed the if conditional from the previous exercise)

Notice that now we can reference .drink and .food without qualifying them. That is because the with statement sets . to point to .Values.favorite . The . is reset to its previous scope after {{ end }} .

But here’s a note of caution! Inside of the restricted scope, you will not be able to access the other objects from the parent scope. This, for example, will fail:

It will produce an error because Release.Name is not inside of the restricted scope for . . However, if we swap the last two lines, all will work as expected because the scope is reset after {{end}} .

After looking at range , we will take a look at template variables, which offers one solution to the scoping issue above.

Looping with the range action

Many programming languages have support for looping using for loops, foreach loops, or similar functional mechanisms. In Helm’s template language, the way to iterate through a collection is to use the range operator.

To start, let’s add a list of pizza toppings to our values.yaml file:

Now we have a list (called a slice in templates) of pizzaToppings . We can modify our template to print this list into our ConfigMap:

Let’s take a closer look at the toppings: list. The range function will “range over” (iterate through) the pizzaToppings list. But now something interesting happens. Just like with sets the scope of . , so does a range operator. Each time through the loop, . is set to the current pizza topping. That is, the first time, . is set to mushrooms . The second iteration it is set to cheese , and so on.

We can send the value of . directly down a pipeline, so when we do {{ . | title | quote }} , it sends . to title (title case function) and then to quote . If we run this template, the output will be:

Now, in this example we’ve done something tricky. The toppings: |- line is declaring a multi-line string. So our list of toppings is actually not a YAML list. It’s a big string. Why would we do this? Because the data in ConfigMaps data is composed of key/value pairs, where both the key and the value are simple strings. To understand why this is the case, take a look at the Kubernetes ConfigMap docs . For us, though, this detail doesn’t matter much.

The |- marker in YAML takes a multi-line string. This can be a useful technique for embedding big blocks of data inside of your manifests, as exemplified here.

Sometimes it’s useful to be able to quickly make a list inside of your template, and then iterate over that list. Helm templates have a function that’s called just that: list .

The above will produce this:

In addition to lists, range can be used to iterate over collections that have a key and a value (like a map or dict ). We’ll see how to do that in the next section when we introduce template variables.

With functions, pipelines, objects, and control structures under our belts, we can turn to one of the more basic ideas in many programming languages: variables. In templates, they are less frequently used. But we will see how to use them to simplify code, and to make better use of with and range .

In an earlier example, we saw that this code will fail:

Release.Name is not inside of the scope that’s restricted in the with block. One way to work around scoping issues is to assign objects to variables that can be accessed without respect to the present scope.

In Helm templates, a variable is a named reference to another object. It follows the form $name . Variables are assigned with a special assignment operator: := . We can rewrite the above to use a variable for Release.Name .

Notice that before we start the with block, we assign $relname := .Release.Name . Now inside of the with block, the $relname variable still points to the release name.

Running that will produce this:

Variables are particularly useful in range loops. They can be used on list-like objects to capture both the index and the value:

Note that range comes first, then the variables, then the assignment operator, then the list. This will assign the integer index (starting from zero) to $index and the value to $topping . Running it will produce:

For data structures that have both a key and a value, we can use range to get both. For example, we can loop through .Values.favorite like this:

Now on the first iteration, $key will be drink and $val will be coffee , and on the second, $key will be food and $val will be pizza . Running the above will generate this:

Variables are normally not “global”. They are scoped to the block in which they are declared. Earlier, we assigned $relname in the top level of the template. That variable will be in scope for the entire template. But in our last example, $key and $val will only be in scope inside of the {{range...}}{{end}} block.

However, there is one variable that is always global - $ - this variable will always point to the root context. This can be very useful when you are looping in a range and need to know the chart’s release name.

An example illustrating this:

So far we have looked at just one template declared in just one file. But one of the powerful features of the Helm template language is its ability to declare multiple templates and use them together. We’ll turn to that in the next section.

Named Templates

It is time to move beyond one template, and begin to create others. In this section, we will see how to define named templates in one file, and then use them elsewhere. A named template (sometimes called a partial or a subtemplate ) is simply a template defined inside of a file, and given a name. We’ll see two ways to create them, and a few different ways to use them.

In the “Flow Control” section we introduced three actions for declaring and managing templates: define , template , and block . In this section, we’ll cover those three actions, and also introduce a special-purpose include function that works similarly to the template action.

An important detail to keep in mind when naming templates: template names are global . If you declare two templates with the same name, whichever one is loaded last will be the one used. Because templates in subcharts are compiled together with top-level templates, you should be careful to name your templates with chart-specific names .

One popular naming convention is to prefix each defined template with the name of the chart: {{ define "mychart.labels" }} . By using the specific chart name as a prefix we can avoid any conflicts that may arise due to two different charts that implement templates of the same name.

Partials and _ files

So far, we’ve used one file, and that one file has contained a single template. But Helm’s template language allows you to create named embedded templates, that can be accessed by name elsewhere.

Before we get to the nuts-and-bolts of writing those templates, there is file naming convention that deserves mention:

  • Most files in templates/ are treated as if they contain Kubernetes manifests
  • The NOTES.txt is one exception
  • But files whose name begins with an underscore ( _ ) are assumed to not have a manifest inside. These files are not rendered to Kubernetes object definitions, but are available everywhere within other chart templates for use.

These files are used to store partials and helpers. In fact, when we first created mychart , we saw a file called _helpers.tpl . That file is the default location for template partials.

Declaring and using templates with define and template

The define action allows us to create a named template inside of a template file. Its syntax goes like this:

For example, we can define a template to encapsulate a Kubernetes block of labels:

Now we can embed this template inside of our existing ConfigMap, and then include it with the template action:

When the template engine reads this file, it will store away the reference to mychart.labels until template "mychart.labels" is called. Then it will render that template inline. So the result will look like this:

Conventionally, Helm charts put these templates inside of a partials file, usually _helpers.tpl . Let’s move this function there:

By convention, define functions should have a simple documentation block ( {{/* ... */}} ) describing what they do.

Even though this definition is in _helpers.tpl , it can still be accessed in configmap.yaml :

As mentioned above, template names are global . As a result of this, if two templates are declared with the same name the last occurrence will be the one that is used. Since templates in subcharts are compiled together with top-level templates, it is best to name your templates with chart specific names . A popular naming convention is to prefix each defined template with the name of the chart: {{ define "mychart.labels" }} .

Setting the scope of a template

In the template we defined above, we did not use any objects. We just used functions. Let’s modify our defined template to include the chart name and chart version:

If we render this, the result will not be what we expect:

What happened to the name and version? They weren’t in the scope for our defined template. When a named template (created with define ) is rendered, it will receive the scope passed in by the template call. In our example, we included the template like this:

No scope was passed in, so within the template we cannot access anything in . . This is easy enough to fix, though. We simply pass a scope to the template:

Note that we pass . at the end of the template call. We could just as easily pass .Values or .Values.favorite or whatever scope we want. But what we want is the top-level scope.

Now when we execute this template with helm install --dry-run --debug ./mychart , we get this:

Now {{ .Chart.Name }} resolves to mychart , and {{ .Chart.Version }} resolves to 0.1.0 .

The include function

Say we’ve defined a simple template that looks like this:

Now say I want to insert this both into the labels: section of my template, and also the data: section:

The output will not be what we expect:

Note that the indentation on app_version is wrong in both places. Why? Because the template that is substituted in has the text aligned to the right. Because template is an action, and not a function, there is no way to pass the output of a template call to other functions; the data is simply inserted inline.

To work around this case, Helm provides an alternative to template that will import the contents of a template into the present pipeline where it can be passed along to other functions in the pipeline.

Here’s the example above, corrected to use nindent to indent the mychart_app template correctly:

Now the produced YAML is correctly indented for each section:

It is considered preferable to use include over template in Helm templates simply so that the output formatting can be handled better for YAML documents.

Sometimes we want to import content, but not as templates. That is, we want to import files verbatim. We can achieve this by accessing files through the .Files object described in the next section.

Accessing Files Inside Templates

In the previous section we looked at several ways to create and access named templates. This makes it easy to import one template from within another template. But sometimes it is desirable to import a file that is not a template and inject its contents without sending the contents through the template renderer.

Helm provides access to files through the .Files object. Before we get going with the template examples, though, there are a few things to note about how this works:

  • It is okay to add extra files to your Helm chart. These files will be bundled and sent to Tiller. Be careful, though. Charts must be smaller than 1M because of the storage limitations of Kubernetes objects.
  • Files in templates/ cannot be accessed.
  • Files excluded using .helmignore cannot be accessed.
  • Charts do not preserve UNIX mode information, so file-level permissions will have no impact on the availability of a file when it comes to the .Files object.

Basic example

Path helpers, glob patterns, configmap and secrets utility functions.

With those caveats behind, let’s write a template that reads three files into our ConfigMap. To get started, we will add three files to the chart, putting all three directly inside of the mychart/ directory.

config1.toml :

config2.toml :

config3.toml :

Each of these is a simple TOML file (think old-school Windows INI files). We know the names of these files, so we can use a range function to loop through them and inject their contents into our ConfigMap.

This config map uses several of the techniques discussed in previous sections. For example, we create a $files variable to hold a reference to the .Files object. We also use the list function to create a list of files that we loop through. Then we print each file name ( {{.}}: |- ) followed by the contents of the file {{ $files.Get . }} .

Running this template will produce a single ConfigMap with the contents of all three files:

When working with files, it can be very useful to perform some standard operations on the file paths themselves. To help with this, Helm imports many of the functions from Go’s path package for your use. They are all accessible with the same names as in the Go package, but with a lowercase first letter. For example, Base becomes base , etc.

The imported functions are:

As your chart grows, you may find you have a greater need to organize your files more, and so we provide a Files.Glob(pattern string) method to assist in extracting certain files with all the flexibility of glob patterns .

.Glob returns a Files type, so you may call any of the Files methods on the returned object.

For example, imagine the directory structure:

You have multiple options with Globs:

(Not present in version 2.0.2 or prior)

It is very common to want to place file content into both configmaps and secrets, for mounting into your pods at run time. To help with this, we provide a couple utility methods on the Files type.

For further organization, it is especially useful to use these methods in conjunction with the Glob method.

Given the directory structure from the Glob example above:

You can import a file and have the template base-64 encode it to ensure successful transmission:

The above will take the same config1.toml file we used before and encode it:

Sometimes it is desirable to access each line of a file in your template. We provide a convenient Lines method for this.

Currently, there is no way to pass files external to the chart during helm install . So if you are asking users to supply data, it must be loaded using helm install -f or helm install --set .

This discussion wraps up our dive into the tools and techniques for writing Helm templates. In the next section we will see how you can use one special file, templates/NOTES.txt , to send post-installation instructions to the users of your chart.

Creating a NOTES.txt File

In this section we are going to look at Helm’s tool for providing instructions to your chart users. At the end of a helm install or helm upgrade , Helm can print out a block of helpful information for users. This information is highly customizable using templates.

To add installation notes to your chart, simply create a templates/NOTES.txt file. This file is plain text, but it is processed like as a template, and has all the normal template functions and objects available.

Let’s create a simple NOTES.txt file:

Now if we run helm install ./mychart we will see this message at the bottom:

Using NOTES.txt this way is a great way to give your users detailed information about how to use their newly installed chart. Creating a NOTES.txt file is strongly recommended, though it is not required.

Subcharts and Global Values

To this point we have been working only with one chart. But charts can have dependencies, called subcharts , that also have their own values and templates. In this section we will create a subchart and see the different ways we can access values from within templates.

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

  • A subchart is considered “stand-alone”, which means a subchart can never explicitly depend on its parent chart.
  • For that reason, a subchart cannot access the values of its parent.
  • A parent chart can override values for subcharts.
  • 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.

Creating a Subchart

For these exercises, we’ll start with the mychart/ 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:

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

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

Overriding Values of a Child Chart

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 .

Because mychart is a parent, we can specify configuration in mychart and have that configuration pushed into mysubchart . For example, we can modify mychart/values.yaml like this:

Note the last two lines. Any directives inside of the mysubchart 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:

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.

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

mychart/templates/configmap.yaml :

mychart/charts/mysubchart/templates/configmap.yaml :

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

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.

Sharing Templates with Subcharts

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:

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.

The suggestion is to instead use include .

The .helmignore file

The .helmignore file is used to specify files you don’t want to include in your helm chart.

If this file exists, the helm package command will ignore all the files that match the pattern specified in the .helmignore file while packaging your application.

This can help in avoiding unnecessary or sensitive files or directories from being added in your helm chart.

The .helmignore file supports Unix shell glob matching, relative path matching, and negation (prefixed with !). Only one pattern per line is considered.

Here is an example .helmignore file:

We’d love your help making this document better. To add, correct, or remove information, file an issue or send us a pull request.

Debugging Templates

Debugging templates can be tricky simply because the templates are rendered on the Tiller server, not the Helm client. And then the rendered templates are sent to the Kubernetes API server, which may reject the YAML files for reasons other than formatting.

There are a few commands that can help you debug.

  • helm lint is your go-to tool for verifying that your chart follows best practices
  • helm install --dry-run --debug : We’ve seen this trick already. It’s a great way to have the server render your templates, then return the resulting manifest file.
  • helm get manifest : This is a good way to see what templates are installed on the server.

When your YAML is failing to parse, but you want to see what is generated, one easy way to retrieve the YAML is to comment out the problem section in the template, and then re-run helm install --dry-run --debug :

The above will be rendered and returned with the comments intact:

This provides a quick way of viewing the generated content without YAML parse errors blocking.

Wrapping Up

This guide is intended to give you, the chart developer, a strong understanding of how to use Helm’s template language. The guide focuses on the technical aspects of template development.

But there are many things this guide has not covered when it comes to the practical day-to-day development of charts. Here are some useful pointers to other documentation that will help you as you create new charts:

  • The Helm Charts project is an indispensable source of charts. That project is also sets the standard for best practices in chart development.
  • The Kubernetes Documentation provides detailed examples of the various resource kinds that you can use, from ConfigMaps and Secrets to DaemonSets and Deployments.
  • The Helm Charts Guide explains the workflow of using charts.
  • The Helm Chart Hooks Guide explains how to create lifecycle hooks.
  • The Helm Charts Tips and Tricks article provides some useful tips for writing charts.
  • The Sprig documentation documents more than sixty of the template functions.
  • The Go template docs explain the template syntax in detail.
  • The Schelm tool is a nice helper utility for debugging charts.

Sometimes it’s easier to ask a few questions and get answers from experienced developers. The best place to do this is in the Kubernetes Slack Helm channels:

  • #helm-users

Finally, if you find errors or omissions in this document, want to suggest some new content, or would like to contribute, visit The Helm Project .

YAML Techniques

Most of this guide has been focused on writing the template language. Here, we’ll look at the YAML format. YAML has some useful features that we, as template authors, can use to make our templates less error prone and easier to read.

Scalars and Collections

According to the YAML spec , there are two types of collections, and many scalar types.

The two types of collections are maps and sequences:

Scalar values are individual values (as opposed to collections)

Scalar Types in YAML

In Helm’s dialect of YAML, the scalar data type of a value is determined by a complex set of rules, including the Kubernetes schema for resource definitions. But when inferring types, the following rules tend to hold true.

If an integer or float is an unquoted bare word, it is typically treated as a numeric type:

But if they are quoted, they are treated as strings:

The same is true of booleans:

The word for an empty value is null (not nil ).

Note that port: "80" is valid YAML, and will pass through both the template engine and the YAML parser, but will fail if Kubernetes expects port to be an integer.

In some cases, you can force a particular type inference using YAML node tags:

In the above, !!str tells the parser that age is a string, even if it looks like an int. And port is treated as an int, even though it is quoted.

Strings in YAML

Much of the data that we place in YAML documents are strings. YAML has more than one way to represent a string. This section explains the ways and demonstrates how to use some of them.

There are three “inline” ways of declaring a string:

All inline styles must be on one line.

  • Bare words are unquoted, and are not escaped. For this reason, you have to be careful what characters you use.
  • Double-quoted strings can have specific characters escaped with \ . For example "\"Hello\", she said" . You can escape line breaks with \n .
  • Single-quoted strings are “literal” strings, and do not use the \ to escape characters. The only escape sequence is '' , which is decoded as a single ' .

In addition to the one-line strings, you can declare multi-line strings:

The above will treat the value of coffee as a single string equivalent to Latte\nCappuccino\nEspresso\n .

Note that the first line after the | must be correctly indented. So we could break the example above by doing this:

Because Latte is incorrectly indented, we’d get an error like this:

In templates, it is sometimes safer to put a fake “first line” of content in a multi-line document just for protection from the above error:

Note that whatever that first line is, it will be preserved in the output of the string. So if you are, for example, using this technique to inject a file’s contents into a ConfigMap, the comment should be of the type expected by whatever is reading that entry.

Controlling Spaces in Multi-line Strings

In the example above, we used | to indicate a multi-line string. But notice that the content of our string was followed with a trailing \n . If we want the YAML processor to strip off the trailing newline, we can add a - after the | :

Now the coffee value will be: Latte\nCappuccino\nEspresso (with no trailing \n ).

Other times, we might want all trailing whitespace to be preserved. We can do this with the |+ notation:

Now the value of coffee will be Latte\nCappuccino\nEspresso\n\n\n .

Indentation inside of a text block is preserved, and results in the preservation of line breaks, too:

In the above case, coffee will be Latte\n 12 oz\n 16 oz\nCappuccino\nEspresso .

Indenting and Templates

When writing templates, you may find yourself wanting to inject the contents of a file into the template. As we saw in previous chapters, there are two ways of doing this:

  • Use {{ .Files.Get "FILENAME" }} to get the contents of a file in the chart.
  • Use {{ include "TEMPLATE" . }} to render a template and then place its contents into the chart.

When inserting files into YAML, it’s good to understand the multi-line rules above. Often times, the easiest way to insert a static file is to do something like this:

Note how we do the indentation above: indent 2 tells the template engine to indent every line in “myfile.txt” with two spaces. Note that we do not indent that template line. That’s because if we did, the file content of the first line would be indented twice.

Folded Multi-line Strings

Sometimes you want to represent a string in your YAML with multiple lines, but want it to be treated as one long line when it is interpreted. This is called “folding”. To declare a folded block, use > instead of | :

The value of coffee above will be Latte Cappuccino Espresso\n . Note that all but the last line feed will be converted to spaces. You can combine the whitespace controls with the folded text marker, so >- will replace or trim all newlines.

Note that in the folded syntax, indenting text will cause lines to be preserved.

The above will produce Latte\n 12 oz\n 16 oz\nCappuccino Espresso . Note that both the spacing and the newlines are still there.

Embedding Multiple Documents in One File

It is possible to place more than one YAML documents into a single file. This is done by prefixing a new document with --- and ending the document with ...

In many cases, either the --- or the ... may be omitted.

Some files in Helm cannot contain more than one doc. If, for example, more than one document is provided inside of a values.yaml file, only the first will be used.

Template files, however, may have more than one document. When this happens, the file (and all of its documents) is treated as one object during template rendering. But then the resulting YAML is split into multiple documents before it is fed to Kubernetes.

We recommend only using multiple documents per file when it is absolutely necessary. Having multiple documents in a file can be difficult to debug.

YAML is a Superset of JSON

Because YAML is a superset of JSON, any valid JSON document should be valid YAML.

The above is another way of representing this:

And the two can be mixed (with care):

All three of these should parse into the same internal representation.

While this means that files such as values.yaml may contain JSON data, Helm does not treat the file extension .json as a valid suffix.

YAML Anchors

The YAML spec provides a way to store a reference to a value, and later refer to that value by reference. YAML refers to this as “anchoring”:

In the above, &favoriteCoffee sets a reference to Cappuccino . Later, that reference is used as *favoriteCoffee . So coffees becomes Latte, Cappuccino, Espresso .

While there are a few cases where anchors are useful, there is one aspect of them that can cause subtle bugs: The first time the YAML is consumed, the reference is expanded and then discarded.

So if we were to decode and then re-encode the example above, the resulting YAML would be:

Because Helm and Kubernetes often read, modify, and then rewrite YAML files, the anchors will be lost.

Appendix: Go Data Types and Templates

The Helm template language is implemented in the strongly typed Go programming language. For that reason, variables in templates are typed . For the most part, variables will be exposed as one of the following types:

  • string: A string of text
  • bool: a true or false
  • int: An integer value (there are also 8, 16, 32, and 64 bit signed and unsigned variants of this)
  • float64: a 64-bit floating point value (there are also 8, 16, and 32 bit varieties of this)
  • a byte slice ( []byte ), often used to hold (potentially) binary data
  • struct: an object with properties and methods
  • a slice (indexed list) of one of the previous types
  • a string-keyed map ( map[string]interface{} ) where the value is one of the previous types

There are many other types in Go, and sometimes you will have to convert between them in your templates. The easiest way to debug an object’s type is to pass it through printf "%t" in a template, which will print the type. Also see the typeOf and kindOf functions.

We are a Cloud Native Computing Foundation incubating project.

  • Documentation
  • Building Operators

Helm Operator Tutorial

NOTE: If your project was created with an operator-sdk version prior to v1.0.0 please migrate , or consult the legacy docs .

Prerequisites

  • Go through the installation guide .
  • Make sure your user is authorized with cluster-admin permissions.
  • example.com is used as the registry Docker Hub namespace in these examples. Replace it with another value if using a different registry or namespace.
  • Authentication and certificates if the registry is private or uses a custom CA.

We will create a sample project to let you know how it works and this sample will:

  • Create an Nginx Deployment if it doesn’t exist
  • Ensure that the Deployment size is the same as specified by the Nginx CR spec

Create a new project

Use the CLI to create a new Helm-based nginx-operator project:

This creates the nginx-operator project specifically for watching the Nginx resource with APIVersion demo.example.com/v1alpha1 and Kind Nginx .

For Helm-based projects, operator-sdk init also generates the RBAC rules in config/rbac/role.yaml based on the resources that would be deployed by the chart’s default manifest. Be sure to double check that the rules generated in config/rbac/role.yaml meet the operator’s permission requirements.

To learn more about the project directory structure, see the project layout doc.

Use an existing chart

Instead of creating your project with a boilerplate Helm chart, you can also use --helm-chart , --helm-chart-repo , and --helm-chart-version to use an existing chart, either from your local filesystem or a remote chart repository.

If --helm-chart is specified, the --group , --version , and --kind flags become optional. If left unset, the default will be:

If --helm-chart is a local chart archive (e.g example-chart-1.2.0.tgz ) or directory, it will be validated and unpacked or copied into the project.

Otherwise, the SDK will attempt to fetch the specified helm chart from a remote repository.

If a custom repository URL is not specified by --helm-chart-repo , the following chart reference formats are supported:

<repoName>/<chartName> : Fetch the helm chart named chartName from the helm chart repository named repoName , as specified in the $HELM_HOME/repositories/repositories.yaml file. Use helm repo add to configure this file.

<url> : Fetch the helm chart archive at the specified URL.

If a custom repository URL is specified by --helm-chart-repo , the only supported format for --helm-chart is:

  • <chartName> : Fetch the helm chart named chartName in the helm chart repository specified by the --helm-chart-repo URL.

If --helm-chart-version is not set, the SDK will fetch the latest available version of the helm chart. Otherwise, it will fetch the specified version. The option --helm-chart-version is not used when --helm-chart itself refers to a specific version, for example when it is a local path or a URL.

Note: For more details and examples run operator-sdk init --plugins helm --help .

Customize the operator logic

For this example the nginx-operator will execute the following reconciliation logic for each Nginx Custom Resource (CR):

  • Create an nginx Deployment if it doesn’t exist
  • Create an nginx Service if it doesn’t exist
  • Create an nginx Ingress if it is enabled and doesn’t exist
  • Ensure that the Deployment, Service, and optional Ingress match the desired configuration (e.g. replica count, image, service type, etc) as specified by the Nginx CR

Watch the Nginx CR

By default, the nginx-operator watches Nginx resource events as shown in watches.yaml and executes Helm releases using the specified chart:

Reviewing the Nginx Helm Chart

When a Helm operator project is created, the SDK creates an example Helm chart that contains a set of templates for a simple Nginx release.

For this example, we have templates for deployment, service, and ingress resources, along with a NOTES.txt template, which Helm chart developers use to convey helpful information about a release.

If you aren’t already familiar with Helm Charts, take a moment to review the Helm Chart developer documentation .

Understanding the Nginx CR spec

Helm uses a concept called values to provide customizations to a Helm chart’s defaults, which are defined in the Helm chart’s values.yaml file.

Overriding these defaults is as simple as setting the desired values in the CR spec. Let’s use the number of replicas as an example.

First, inspecting helm-charts/nginx/values.yaml , we see that the chart has a value called replicaCount and it is set to 1 by default. If we want to have 2 nginx instances in our deployment, we would need to make sure our CR spec contained replicaCount: 2 .

Update config/samples/demo_v1alpha1_nginx.yaml to look like the following:

Similarly, we see that the default service port is set to 80 , but we would like to use 8080 , so we’ll again update config/samples/demo_v1alpha1_nginx.yaml by adding the service port override:

As you may have noticed, the Helm operator simply applies the entire spec as if it was the contents of a values file, just like helm install -f ./overrides.yaml works.

Configure the operator’s image registry

All that remains is to build and push the operator image to the desired image registry. Your Makefile composes image tags either from values written at project initialization or from the CLI. In particular, IMAGE_TAG_BASE lets you define a common image registry, namespace, and partial name for all your image tags. Update this to another registry and/or namespace if the current value is incorrect. Afterwards you can update the IMG variable definition like so:

Once done, you do not have to set IMG or any other image variable in the CLI. The following command will build and push an operator image tagged as example.com/nginx-operator:v0.0.1 to Docker Hub:

Run the operator

There are three ways to run the operator:

  • As a Go program outside a cluster
  • As a Deployment inside a Kubernetes cluster
  • Managed by the Operator Lifecycle Manager (OLM) in bundle format

1. Run locally outside the cluster

Execute the following command, which installs your CRDs and runs the manager locally:

2. Run as a Deployment inside the cluster

By default, a new namespace is created with the name <project-name>-system , ex. nginx-operator-system , and will be used for the deployment.

Run the following to deploy the operator. This will also install the RBAC manifests from config/rbac .

Verify that the nginx-operator is up and running:

3. Deploy your Operator with OLM

First, install OLM :

Bundle your operator, then build and push the bundle image. The bundle target generates a [bundle][doc-bundle] in the bundle directory containing manifests and metadata defining your operator. bundle-build and bundle-push build and push a bundle image defined by bundle.Dockerfile .

Finally, run your bundle. If your bundle image is hosted in a registry that is private and/or has a custom CA, these configuration steps must be completed.

Check out the docs for a deep dive into the operator-sdk 's OLM integration.

Create a Nginx CR

Create the nginx CR that we modified earlier:

Ensure that the nginx-operator creates the deployment for the CR:

Check the pods to confirm 2 replicas were created:

Check that the service port is set to 8080 :

Update the replicaCount and remove the port

Change the spec.replicaCount field from 2 to 3, remove the spec.service field:

And apply the change:

Confirm that the operator changes the deployment size:

Check that the service port is set to the default ( 80 ):

Troubleshooting

Use the following command to check the operator logs.

Use the following command to check the CR status and events.

Clean up the resources:

Note: Make sure the above custom resource has been deleted before proceeding to run make undeploy , as helm-operator’s controller adds finalizers to the custom resources. Otherwise your cluster may have dangling custom resource objects that cannot be deleted.

Next, check out the following:

  • Operator packaging and distribution with OLM .
  • The advanced features doc for more use cases and under-the-hood details.

IMAGES

  1. [Solved] Helm Conditional Templates

    helm conditional assignment

  2. Helm Flow Control with Conditional Control Structures

    helm conditional assignment

  3. Commands

    helm conditional assignment

  4. #path2DevOps

    helm conditional assignment

  5. Helm Commands Cheat Sheet {Free Downloadable PDF}

    helm conditional assignment

  6. Conditional statement in helm template towardslearning.in

    helm conditional assignment

VIDEO

  1. Helm Interview Questions

  2. Felwinter's Helm Strand Warlock Is A Blast

  3. Conditional and selected signal assignment statements

  4. Conditional assignment in #javascript or #servicenow using && and || operators #servicenowdeveloper

  5. Samurai4321

  6. Top 40 Javascript One Liners

COMMENTS

  1. Is it possible to define variables use if/else condition in helm chart

    Helm also includes (almost all of) a support template library called Sprig which includes a ternary function, which acts sort of like an inline "if" statement. For your example you could write ... Helm If / else with conditional value if exists. 0. Kubernetes Helm Chart Template if-condition. 1.

  2. Helm

    Note that we removed the if conditional from the previous exercise because it is now unnecessary - the block after with only executes if the value of PIPELINE is not empty.. Notice that now we can reference .drink and .food without qualifying them. That is because the with statement sets . to point to .Values.favorite.The . is reset to its previous scope after {{ end }}.

  3. Helm

    Variables are assigned with a special assignment operator: :=. ... But one of the powerful features of the Helm template language is its ability to declare multiple templates and use them together. We'll turn to that in the next section. Prev. ← Flow Control. Next.

  4. Helm Flow Control with Conditional Control Structures

    Helm's conditional flow control is a feature that allows for the execution of certain code blocks only if certain conditions are met. This is an important concept, as it allows for the creation of more complex and flexible templates. By using conditional flow control, developers can create code that is capable of responding to changing ...

  5. Helm

    The above will first check to see if .name is empty. If it is not, it will return that value. If it is empty, coalesce will evaluate .parent.name for emptiness. Finally, if both .name and .parent.name are empty, it will return Matt.. ternary. The ternary function takes two values, and a test value. If the test value is true, the first value will be returned.

  6. Dynamically render a value with a Helm conditional statement

    The Helm templating language supports conditional statements. In this video, learn how to use Helm conditionals to render a dynamic value.

  7. Learn HELM If Else looping

    Helm's template language provides the following control structures:if/else for creating conditional blockswith to specify a scoperange, which provides a "for...

  8. Helm Template If/Else

    Overview. if / else can be used to create conditional blocks. The if control structures evaluate pipelines, not just values. A value is a special case of a pipeline: A pipeline evaluates to false if the result of the pipeline, or the value, is: a numeric zero. ⚠️. Also see Notable Values.

  9. Helm

    Flow Control. Control structures (called "actions" in template parlance) provide you, the template author, with the ability to control the flow of a template's generation. Helm's template language provides the following control structures: if / else for creating conditional blocks. with to specify a scope.

  10. HELM

    Control flow provides us with the ability to control the template generation process. HELM's template language provides the following process controls: if/else conditional block. with specified range. range loop block. Among other things, it provides some operations for declaring and using named template sections:

  11. go

    This template outputs the port number when called; its single parameter should be the standard top-level Helm object. - name: KAFKA_PORT value: {{ include "kafka.port" . | quote }} Or, if in a specific context, you happen to need it as a variable, you can include it there (using the Helm include extension to capture the called template's output ...

  12. Helm If Value Exists: A Guide to Checking for a Key in a ConfigMap

    The `if value exists` condition is a Helm parameter that can be used to check if a value exists in a Kubernetes secret or config map. The condition takes a single argument, which is the name of the key to check. If the value exists, the `if value exists` condition will evaluate to `true`. If the value does not exist, the `if value exists ...

  13. Helm

    In helm templates, variables are less frequently used. But we will see how to use them to simplify code and make better use of with and range. In the Helm — Flow Control article, we have already ...

  14. Helm

    helm lint is your go-to tool for verifying that your chart follows best practices; helm install --dry-run --debug: We've seen this trick already. It's a great way to have the server render your templates, then return the resulting manifest file. helm get manifest: This is a good way to see what templates are installed on the server.

  15. Helm Operator Tutorial

    Create a new project. Use the CLI to create a new Helm-based nginx-operator project: mkdir nginx-operator. cd nginx-operator. operator-sdk init --plugins helm --domain example.com --group demo --version v1alpha1 --kind Nginx. This creates the nginx-operator project specifically for watching the Nginx resource with APIVersion demo.example.com ...

  16. helm chaining multiple conditions

    Conditional helm hook. 26. If clause in helm chart. 0. How to conditionally render helm templates based on existence of nested values. 0. How to use if/else loop in Helm. 0. if condition with AND operator and greater than condition in helm. 0. Helm condition check on two values and return useful message. 3.

  17. Variables in values.yml

    #kubernetes #Helmcharts #helm #devops=====In the video i'll be demonstrating about Variablise Helm Charts using values.yml https...

  18. How can I conditionally set a variable in a Go template based on an

    Future solution (Available with Helm 2.10) I came across the same question in the context of Helm templates which are go templates with some additional features pre-installed such as Sprig. 28 March 2018, in this pr a Terenary operator was added to Sprig, and in time Helm will have them as well solving the issue both you and I have. terenary

  19. Helm

    Appendix: Go Data Types and Templates. The Helm template language is implemented in the strongly typed Go programming language. For that reason, variables in templates are typed. For the most part, variables will be exposed as one of the following types: There are many other types in Go, and sometimes you will have to convert between them in ...

  20. kubernetes helm

    Helm Conditional Templates. 0. How to neatly define an if conditional operation for a list of values in Helm template? 13. ... Seeking a Polynomial Time Algorithm for Balanced Weight Assignment to Nodes in a Tree PTIJ: Guide to being a super hero if you are Jewish What does a voltage or current source actually output? ...

  21. Helm

    In Helm's dialect of YAML, the scalar data type of a value is determined by a complex set of rules, including the Kubernetes schema for resource definitions. But when inferring types, the following rules tend to hold true. If an integer or float is an unquoted bare word, it is typically treated as a numeric type: count: 1 size: 2.34.