Create your FREE Codefresh account and start making pipelines fast. Create Account

How to Run and Apply a Codefresh Helmfile: a Step-by-Step Guide

13 min read

Editors note: We did a webinar on this very topic. Scroll to the bottom of this post or click here to view the webinar.

If you’re looking to deploy your services to Kubernetes, Helm works great. However, once you start deploying to multiple environments, developing code as a team, or automating in a CI/CD pipeline, you start to run into limitations with Helm.

Codefresh Pipelines using Helmfile has the power and flexibility to address these issues and many others. It’s also one of the best ways to organize your Helm code and values.

The nice thing is that Helmfile just manages Helm, and it works with Helm 2 & 3.. You are not locked in – you can still run plain old Helm with some powerful Go/Sprig Templating exposed.

Utilizing Helmfiles is more streamlined, which allows teams to develop Helm Charts together using clean and reusable Codefresh Pipelines.

In this tutorial, we’re going to walk through a deploy starting from a completely clean GKE install. For our example project, I’ll be using a monolithic git repository, however, Helmfile works great with a repository per Helm Chart as well.

Getting Started

Before you can complete the steps to run and apply a Codefresh Helmfile, you will need the following:

  • GKE Cluster (I used 1.15.11-gke.11)
  • IAM
  • Kubectl, Helm, Helmfile

It’s worth noting that some basic knowledge of K8s and Helm is a prerequisite.  If you aren’t familiar with them already, there’s a lot of great resources out there already.  Including some Codefresh Webinars.  Windows is going to run into some issues around the plugins if using Powershell / windows native shells..  I’d recommend using Windows Subsystem Linux (WSL), which should get you past any Windows issues.  If you encounter problems, post below in the comments.

What is Helmfile?

Helm is great in that (1) it gives us the power of dependency management, i.e. our Chart can depend on other Charts and (2) allows templating of yaml files.  Helmfile allows us to have dependencies between separate Helm installs.  This way we can install multiple helm charts with 1 command, but Helmfile is actually using Helm to install multiple Charts.  

Helmfile also allows us to template values.yaml.  In standard Helm Charts this isn’t allowed.  Helm wants the yaml file to be declarative.  Declarative languages work great for ensuring that a system is going to get to the final state we want without worrying about imperative coding type issues.  But maintaining a bunch of static values.yaml files is messy and not DRY.  Which is why often with Declarative Languages you end up using imperative programming in front of the declarative tool/language.

Helmfile allows you to manage any number of Helm charts. Here’s an example of some of the things Helmfile can help you accomplish:

  • Setup Helm repos
  • Automate commands to run before/after Helm via Hooks
  • Preview changes before deployment, similar to Terraform Plan
  • Install dependencies as a separate Helm deploy with one command
  • Manage the order of your Helm chart dependencies
  • Golang/Sprig Templating values.yaml, and helm parameters
  • Manage secrets as part of a Helm deploy
  • Run a script or acquire data from another source
  • Use of Environment Variables in Templating

Most importantly, Helmfile prevents vendor lock-in and allows for Golang Templating free from restrictions.

Step 1 – Create the GKE Cluster

First, I logged into my Google account for cloud.

For creating your GKE cluster, use the following directions (below) as an example. If you want more detail regarding this step, you can follow or looking at Google Cloud’s Quickstart page here.

Example Application:

In order to demonstrate a real-world example, we will be deploying a simple Hello World Application to Kubernetes.  The Hello World application is simply an Nginx site.  However, we want Hello World exposed via Traefik Ingress to the public internet,  Along with installing an Ingress we also want to create 1 namespace for Hello World and 1 for Traefik.  We will deploy our application to multiple environments with the option to configure DNS & SSL.

In Part 1, we will cover deploying Hello World, but we won’t get to Ingress, DNS, SSL, or Multiple Environment Support in Part 1.  Later parts of the blog will continue to build until we have a more complete real-world example deploying Hello World to a completely new Kubernetes cluster. 

Step 2: Set Up Helm Repos

As of Helm 2, no Chart Repositories come pre-configured.  Helm Chart Repositories are expected to be set up before running Helm, but Helm doesn’t give you a way to manage them.  It becomes something that either is in Documentation or may be automated with a custom script.  With Helmfile you can declaratively set up your Helm Repos.  Helmfile will run commands to manage those Repositories before trying to install the Helm Chart.

In this step, we will set up the “stable” Helm Repository, which contains the Traefik chart we are going to use for Ingress.  Then with the “stable” repository being setup, we can successfully install the Traefik Chart.

As you can see when you currently attempting to install “mytraefik” the repository is missing

Helmfile allows setting up of all different types of Helm Repositories including public and private with credentials, using GitHub as a Chart Repository, etc.  Here we will just set up the public stable chart repository.

Then apply Helmfile.

Now that Helmfile has installed the proper charts, it’s time to run Helm Hooks.

Step 3: Run Helm Hooks

Another issue that is common to come across is wanting to run a command before or after Helmfile.  For example, maybe you want to run Terraform before Helmfile, or in this example, we will create a missing namespace before running Helm.  Helmfile Hooks can be trigger by the following Events:

  • Prepare: events are triggered after each release in your Helmfile is loaded from YAML, before execution.
  • Presync: events are triggered before each release is applied to the remote cluster. This is the ideal event to execute any commands that may mutate the cluster state as it will not be run for read-only operations like lint, diff, or template.
  • Postsync: events are triggered after each release is applied to the remote cluster. This is the ideal event to execute any commands that may mutate the cluster state as it will not be run for read-only operations like lint, diff, or template.
  • Cleanup: events are triggered after each release is processed.

You can find more details on GitHub about Helm Hooks this aren’t to be confused with Helm Chart Hooks which are similar but actually part of a Helm chart and limited to working with K8s resources.  Helm chart hooks don’t allow you to do things like run Terraform or a custom script you’ve created so using Helmfile Hooks and Helm Chart Hooks are complementary and do not overlap

Alright, let’s use the “Prepare” event to execute a script that will create a namespace if it’s missing.  This was a feature of Helm 2, but has been removed from Helm 3.

First, use Helm to create a Helm Chart for  “helloworld” service.

You’ll notice that the Namespace doesn’t exist, and as a result, the command failed.  So our next step is to use a hook and Helmfile to make sure the namespace is created before we proceed with the install.

At this point, you should have the following setup below:

Finally, we can apply Helmfile.

Near the top, we can see our logs confirming that we successfully created a namespace. Additionally, we were able to install our helm chart into the newly-formed namespace.

Helmfile Diff

Helm is great for applying changes and knowing that things will eventually be consistent.  One issue though is that it’s a Black Box.  Like Terraform Plan it would be great to see the difference and what changes a Helm chart install will have on the system.  Luckily Helmfile leverages the Helm Diff plugin to make this happen.  If you’ve been following along, you’ve been seeing REDACTED sections, this contained the Diff output.  In order to use it on the command line simply run “helmfile diff”, a diff is also run when “helmfile apply” is run, but unlike a Terraform apply it will not ask you if you want to proceed or not, it simply proceeds with the apply.  So be careful when running “helmfile apply”.  Because we want to ensure that helmfile diff is always run and looked at before running helmfile apply, and we want others to be able to run deploys and get insight into other deploys, let’s also set up a Codefresh Pipeline now.  First, we need to get our K8s cluster and Helmfile setup to run in Codefresh.

***Note: currently there is an open issue regarding a 3 way Diff that’s supported in Helm 3.  Unfortunately, the Helm Diff plugin has not been updated to support a 3 way Diff.  This means if manual changes have been made to your cluster, the diff will not see those changes. 

Step 4: Configure Codefresh to See GKE Cluster

We need to add our GKE cluster we previously set up into Codefresh. This allows us to create a pipeline that will deploy to the GKE cluster that we integrated into Codefresh.

To begin, click “Kubernetes” on the left panel. Then click “ADD CLUSTER” in the upper right.

Add a cluster to “Custom Providers.”

If you need more assistance during this part of the process, check out the Codefresh tutorial here to add your cluster.

Unless you want to manually update your codefresh.yaml, make sure to name your cluster “codefresh-helmfile-demo”.  This is because Codefresh automatically sets up kube context for you by injecting a kube config file.  Your kube context is based on your cluster name.

Click “TEST CONNECTION,” and if successful, click “SAVE.”

Step 5: Create a Codefresh Pipeline

Now that we have our Kubernetes cluster setup and integrated with Codefresh, and we have a working Helmfile to deploy Hello World, let’s build a Codefresh CI/CD pipeline.  Our Pipeline will: 

  1. Clone Git Repository
  2. Run Helmfile Diff to show what a deploy of Hello World will change
  3. Pause for User Confirmation before deploying
  4. Run Helmfile Apply to deploy Hellow World

When we are done we will have a Pipeline like:

Next step is to Create a New Codefresh Pipeline

To access your pipeline from Git Repo, update the Helmfile with (in this case) “./code-01/codefresh.yml”. See below.

See below for a copy of the codefresh.yaml.

The next step is to add a few variables. Your build will determine the number of variables you’ll need.  We will cover details of Docker image bradenwright/cfstep-helmfile in later parts of the blog.  For purposes of this step, the cfstep-helmfile which Codefresh has available would work as well.  Since changes aren’t relevant to this post, I’ll cover in detail later.


Now you will be able to run your build. Simply click “Run” using the following defaults:

Within Codefresh, you should see that the pipeline stops to wait for approval. Meanwhile, the output from the Dry Run step will show what’s going to change if/when the Pipeline is “APPROVED” and deployed.

In this example, you can see the Deployment for Myapp is going to change if approved.

Everything looks great! 

Congratulations! You’ve successfully run and applied your Codefresh Helmfile.

We also recorded a webinar on this very topic. Watch it now:


Braden Wright

Braden Wright

Braden is a Staff Cloud Architect at Rootlevel Technology, a Codefresh partner.

4 responses to “How to Run and Apply a Codefresh Helmfile: a Step-by-Step Guide

  1. Mourad Djedour says:

    Hello Braden,
    Thank a lot for this very helpful post. I’m trying ti setup a similar ci-cd pipeline with codefresh.
    I see tyhat you use a freestyle stage to deploy into k8s. Si i d have 2 questions with your setup:
    1- how can i execute a command like :
    helmfile -f custom_helmfile.yaml –environment env sync
    2- how can ‘ a pass arguments in each deploy like the container tag

    Thank you

    1. Kostis Kapelonis says:


      In the freestyle step you can put any argument that you can pass in your terminal. So if you use a specific helmfile parameter you can simply append it in your command line inside the freestyle step.

      1. Mourad Djedour says:

        Thnak you Kostis !
        I tyed this without success
        – python3 / -f ./api.yaml –state-values-set api.container.imageTag=”${{image_name}}-${{CF_SHORT_REVISION}}”

        i got this error, it seems that it doent reconize the provided helmfile
        Executing command: python3 / -f ./api.yaml –state-values-set api.container.imageTag=”${{image_name}}-${{CF_SHORT_REVISION}}”no state file found. It must be named helmfile.d/*.{yaml,yml}, helmfile.yaml, or charts.yaml, or otherwise specified with the –file flag

        1. Kostis Kapelonis says:


          Try to place another command such as “pwd” before your python 3 command so that you verify you are in the correct directory.

          Also all Codefresh variables have capital names. I don’t think image_name will work there.

          But I would suggest you simply open a support ticket with us (from the top right menu in the Codefresh UI) so that our support team can take a look.
          Be sure to provide the URL of the build that has the issue.

Leave a Reply

* All fields are required. Your email address will not be published.

See how Codefresh helps you
deploy more and fail less!