Creating an Ansible Role From a Helm Chart

A walkthrough example of turning an example helm chart into an Ansible role, which can then be used to create an Anslble Operator.

This guide will walk you through taking a helm chart, and creating an Ansible operator using memcached as an example. You can find an example helm chart and converted ansible operator at and see what the changes look like.

A lot of the conversion can be handled with a useful conversion utility, available here: After installing the converter and adding it to your $PATH run

$ helmExport export <role> --helm-chart=<location of chart> --workspace=<output location> --generatreFilters=true --emitKeysSnakeCase=true

This will mostly give you an Ansible role that works the same as you Helm chart with the templates in /<your role>/templates/ . However, there are a few things that will need to be modified. Helm template syntax is a bit different at time from Jinja2 that Ansible uses. Some common things to watch out for are:

  • The "toYaml" filter in Helm is "to_yaml" in jinja2.

  • "toJSON" likewise needs to be changed to "to_json"

  • The "b64enc" filter needs to be changed to "b64encode"

  • Any varibles generated by your _helpers.tpl file are not available. You can either define them in the role's defaut/main.yml, hardcode them, or remove them from the templates.

  • Values that come from the Chart directly instead of the Values.yaml file (ex. .Chart.Name) are also not available

Check your templates for these syntax errors and go ahead and fix them.

If you create new variables, remember to add them to the roles/<your role>/defaults/main.yml file (this is what replaces the Values.yaml file, and works exactly the same).

In Helm, there's a lot of labels that will be consistent throughout things your operator will create. You can choose to keep some around and remove some entirely as redundant. For example, in the sample operator, we've removed the release and heritage labels/label selectors, and changed the app and chart labels to use a new values in the defaults/main.yml file.

Helm templates tend to leave room for users to add their own annotations. Ansible considers this a security risk. While technically optional, you should find these open-ended annotations in your templates and remove them. Here's a sample of what they look like in a template:

  name: {{ template "memcached.fullname" . }}
    app: {{ template "memcached.fullname" . }}
    chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
    release: "{{ .Release.Name }}"
    heritage: "{{ .Release.Service }}"
{{ toYaml .Values.serviceAnnotations | indent 4 }}

In the above example, we'd take out lines 8 and 9 (line 8 would stay in if we had some annotations we wanted). The same bit of yaml in an Ansible role would look like this:

  name: {{ name }} #The "name" variable was added to defaults/main.yml
    app: {{ name }}
    chart: "{{ name }}-{{ version }}" #The "version" variable was also added to defaults/main.yml
    #The annotations field was removed entirely, since we don't have any for this object.

After making these changes, it is highly recommended to test the ansible role. It's impossible to account for all the filters with different syntax between Helm and Ansible, so you'll want to verify the role will run before moving on with your operator. To test the role, create a playbook.yml in the operator's root directory that looks like this:

- hosts: localhost
  - <your role>

To run the playbook, run

$ ansible-playbook playbook.yml

while logged in to your testing cluster. If everything comes back fine, you're all set. Otherwise, you'll need to look at the error message to see what bit of syntax is causing the problem, and change it in your templates. To test each template one at a time, go to the roles/<your role>/tasks/main.yml and comment out the templates you aren't testing yet.

Last updated