Helm is a package manager for Kubernetes. You can bundle Kubernetes resources together as charts that define all the necessary resources and dependencies of an application. You can then use the Helm CLI to install all the pods, services, and ingresses for an application in one simple command.

Just like Docker or NuGet, there's a common public repository for Helm charts that the helm CLI uses by default. And just like Docker and NuGet, you can host your own Helm repository for your charts.

In this post, I'll show how you can use an AWS S3 bucket to host a Helm chart repository, how to push custom charts to it, and how to install charts from the chart repository. I won't be going into Helm or Kubernetes in depth, I suggest you check the Helm quick start guide if they're new to you.

If you're not using AWS, and you'd like to store your charts on Azure, Michal Cwienczek has a post on how to create a Helm chart repository using Blob Storage instead.

Installing the prerequisites

Before you start working with Helm properly, youu need to do some setup. The Helm S3 plugin you'll be using later requires that you have the AWS CLI installed and configured on your machine. You'll also need an S3 bucket to use as your repository.

Installing the AWS CLI

I'm using an Ubuntu 16.04 virtual machine for this post, so all the instructions assume you have the same setup.

The suggested approach to install the AWS CLI is to use pip, the Python package index. This obviously requires Python, which you can confirm is installed using:

$ python -V
Python 2.7.12

According to the pip website:

pip is already installed if you are using Python 2 >=2.7.9 or Python 3 >=3.4

However, running which pip returned nothing for me, so I installed it anyway using

$ sudo apt-get install python-pip

Finally, we can install the AWS CLI using:

$ pip install awscli

The last thing to do is to configure your environment to access your AWS account. Add the ~./aws/config and ~./aws/credentials files to your home directory with the appropriate access keys, as described in the docs

Creating the repository S3 bucket

You're going to need an S3 bucket to store your charts. You can create the bucket anyway you like, either using the AWS CLI, or using the AWS Management Console. I used the Management Console to create a bucket called my-helm-charts:

Creating a bucket

Whenever you create a new bucket, it's a good idea to think about who is able to access it, and what they're able to do. You can control this using IAM policies or S3 policies, whatever works for you. Just make sure you've looked into it!

The policy below, for example, grants read and write access to the IAM user andrew.

Once your repository is working correctly, you might want to update this so that only your CI/CD pipeline can push charts to your repository, but that any of your users can list and fetch charts. It may also be wise to remove the delete action completely.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowListObjects",
      "Effect": "Allow",
      "Principal": {
        "AWS": ["arn:aws:iam::111122223333:user/andrew"]
      },
      "Action": [
        "s3:ListBucket"
      ],
      "Resource": "arn:aws:s3:::my-helm-charts"
    },
    {
      "Sid": "AllowObjectsFetchAndCreate",
      "Effect": "Allow",
      "Principal": {
        "AWS": ["arn:aws:iam::111122223333:user/andrew"]
      },
      "Action": [
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::my-helm-charts/*"
    }
  ]
}

Installing the Helm S3 plugin

You're almost set now. If you've haven't already, install Helm using the instructions in the quick start guide.

The final prerequisite is the Helm S3 plugin. This acts as an intermediary between Helm and your S3 bucket. It's not the only way to create a custom repository, but it simplifies a lot of things.

You can install the plugin from the GitHub repo by running:

$ helm plugin install https://github.com/hypnoglow/helm-s3.git
Downloading and installing helm-s3 v0.5.2 ...
Installed plugin: s3

This downloads the latest version of the plugin from GitHub, and registers it with Helm.

Creating your Helm chart repository

You're finally ready to start playing with charts properly!

The first thing to do is to turn the my-helm-charts bucket into a valid chart repository. This requires adding an index.yaml to it. The Helm S3 plugin has a helper method to do that for you, which generates a valid index.yaml and uploads it to your S3 bucket:

$ helm S3 init s3://my-helm-charts/charts
Initialized empty repository at s3://my-helm-charts/charts

If you fetch the contents of the bucket now, you'll find an _index.yaml_file under the /charts key

Initialised project in the repo

Note, the /charts prefix is entirely optional. If you omit the prefix, the Helm chart repository will be in the root of the bucket. I just included it for demonstration purposes here.

The contents of the index.yaml file is very basic at the moment:

apiVersion: v1
entries: {}
generated: 2018-02-10T15:27:15.948188154-08:00

To work with the chart repository by name instead of needing the whole URL, you can add an alias. For example, to create a my-charts alias:

$ helm repo add my-charts s3://my-helm-charts/charts
"my-charts" has been added to your repositories

If you run helm repo list now, you'll see your repo listed (along with the standard stable and local repos:

$ helm repo list
NAME            URL
stable          https://kubernetes-charts.storage.googleapis.com
local           http://127.0.0.1:8879/charts
my-charts       s3://my-helm-charts/charts

You now have a functioning chart repository, but it doesn't have any charts yet! In the next section I'll show how to push charts to, and install charts from, your S3 repository.

Uploading a chart to the repository

Before you can push a chart to the repository, you need to create one. If you already have one, you could use that, or you could copy one of the standard charts from the stable repository. For the sake of completion, I'll create a basic chart, and use that for the rest of the post.

Creating a simple test Helm chart

I used the example from the Helm docs for this test, which creates one of the simplest templates, a ConfigMap, and adds it at the path test-chart/templates/configmap.yaml:

$ helm create test-chart
Creating test-chart
# Remove the initial cruft
$ rm -rf test-chart/templates/*.*
# Create a ConfigMap template at test-chart/templates/configmap.yaml
$ cat >test-chart/templates/configmap.yaml <<EOL
apiVersion: v1
kind: ConfigMap
metadata:
  name: test-chart-configmap
data:
  myvalue: "Hello World"
EOL

You can install this chart into your kubernetes cluster using:

$ helm install ./test-chart
NAME:   zeroed-armadillo
LAST DEPLOYED: Fri Feb  9 17:10:38 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME               DATA  AGE
test-chart-configmap  1     0s

and remove it again completely using the release name presented when you installed it (zeroed-armadillo) :

# --purge removes the release from the "store" completely
$ helm delete --purge zeroed-armadillo
release "zeroed-armadillo" deleted

Now you have a chart to work with it's time to push it to your repository.

Uploading the test chart to the chart repository

To push the test chart to your repository you must first package it. This takes all the files in your ./test-chart repository and bundles them into a single .tgz file:

$ helm package ./test-chart
Successfully packaged chart and saved it to: ~/test-chart-0.1.0.tgz

Once the file is packaged, you can push it to your repository using the S3 plugin, by specifying the packaged file name, and the my-charts alias you specified earlier.

$ helm s3 push ./test-chart-0.1.0.tgz my-charts

Note that without the plugin you would normally have to "manually" sync your local and remote repos, merging the remote repository with your locally added charts. The S3 plugin handles all that for you.

If you check your S3 bucket after pushing the chart, you'll see that the tgz file has been uploaded:

Chart in repository

That's it, you've pushed a chart to an S3 repository!

Searching and installing from the repository

If you do a search for a test chart using helm search you can see your chart listed:

$ helm search test-chart
NAME                    CHART VERSION   APP VERSION     DESCRIPTION
my-charts/test-chart    0.1.0           1.0             A Helm chart for Kubernetes

You can fetch and/or unpack the chart locally using helm fetch my-charts/test-chart or you can jump straight to installing it using:

$ helm install my-charts/test-chart
NAME:   rafting-crab
LAST DEPLOYED: Sat Feb 10 15:53:34 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME               DATA  AGE
mychart-configmap  1     0s

To remove the test chart from the repository, you provide the chart name and version you wish to delete:

$ helm s3 delete test-chart --version 0.1.0 my-charts

That's basically all there is to it! You now have a central repository on S3 for storing your charts. You can fetch, search, and install charts from your repository, just as you would any other.

A warning - make sure you version your charts correctly

Helm charts should be versioned using Semantic versioning, so if you make a change to a chart, you should be sure to bump the version before pushing it to your repository. You should treat the chart name + version as immutable.

Unfortunately, there's currently nothing in the tooling to enforce this, and prevent you overwriting an existing chart with a chart with the same name and version number. There's an open issue to address this in the S3 plugin, but in the mean time, just be careful, and potentially enable versioning of files in S3 to catch any issues. As of version 0.6.0, the plugin will block overwriting a chart if it already exists.

In a similar vein, you may want to disable the ability to delete charts from a repository. I feel like it falls under the same umbrella as immutability of charts in general - you don't want to break downstream charts that have taken a dependency on your chart.

Summary

In this post I showed how to create a Helm chart repository in S3 using the Helm S3 plugin. I showed how to prepare an S3 bucket as a Helm repository, and how to push a chart to it. Finally, I showed how to search and install charts from the S3 repository. .