Storing your Helm Charts in Azure Container Registry
One of the big advantages of understanding how the container ecosystem works is that we can figure out when the same standard can be used for several different specifications.
Last year, Helm announced it would support OCI Artifacts, which are nothing more than an open OCI specification for distributing container images and other kinds of data, called artifacts. This specification, like every other OCI specification, is agnostic of providers, tools or clouds, which makes it a fantastic thing to work with.
Container Registries#
A container registry, or a registry, is something everyone who has ever had to deal with containers has had to use. The CR is where we store our container images so we can pull them from anywhere whenever we want.
In essence, an image is basically a set of files following a structure that looks more or less like this:
├── blobs │ └── sha256 │ ├── 1b251d38cfe948dfc0a5745b7af5ca574ecb61e52aed10b19039db3... │ ├── 31fb454efb3c69fafe53672598006790122269a1b3b458607dbe106... │ └── 8ec7c0f2f6860037c19b54c3cfbab48d9b4b21b485a93d87b64690f... ├── index.json └── oci-layoutThe index.json file is the list of every manifest available there, meaning it is the list of every image available in that location. In our case it is a list of all the helm charts stored there.
Each file inside blobs/sha256 is a JSON identifying an artifact, be it an image or a chart. This JSON is compatible with the OCI specification for SHA files. In short, they are a list of configurations describing the blob’s characteristics, its settings, properties, filesystem layers and also the initial commands. For a Helm Chart we have the following file:
{ "schemaVersion": 2, "config": { "mediaType": "application/vnd.cncf.helm.config.v1+json", "digest": "sha256:8ec7c0f2f6860037c19b54c3cfbab48d9b4b21b485a93d87b64690fdb68c2111", "size": 117 }, "layers": [ { "mediaType": "application/tar+gzip", "digest": "sha256:1b251d38cfe948dfc0a5745b7af5ca574ecb61e52aed10b19039db39af6e1617", "size": 2487 } ]}Notice we have a different mediaType: while a regular Docker image has the type application/vnd.oci.image.config.v1+json, here we have the type application/vnd.cncf.helm.config. The same goes for the layers, each layer of an OCI image is of type application/vnd.oci.image.layer.v1.tar+gzip, while here we only have the .tar.gz format.
Storing Charts Locally#
Storing charts in a local registry is pretty simple. Assuming you already have Helm 3 installed, let’s first enable the flag that says we can use OCI artifacts, since support for them is still experimental. For that you only need to export a variable in your shell:
export HELM_EXPERIMENTAL_OCI=1Now, let’s run a Docker registry locally with:
docker un -dp 5000:5000 --name docker-registry registryFrom there we already have an official repository running on our machine and we can push our charts to it. As an example, I’ll use a chart from a repository of mine called Zaqar. After cloning the repository so I have more control, I’ll go into the helm folder and run the command helm chart save zaqar localhost:5000/zaqar/zaqar:2.1.3.
That saves my chart locally, the same way we do with docker pull. Now I can push my saved chart to the repository specified by the name with helm chart push localhost:5000/zaqar/zaqar:2.1.3.
If we want to install the chart we downloaded, we first have to export it from the cache using helm chart export localhost:5000/zaqar/zaqar:2.1.3 -d <destination>, and then run the command helm install <name> ./<destination>.
Hosting charts in Azure Container Registry#
Now that we know what hosting a chart in a local repository looks like, hosting it in Azure CR is almost the same thing. We need access to azure via the Azure CLI, and after logging in we have almost the same set of commands.
I’ll assume you already have the Azure CLI, so let’s create our ACR. First we have to create our resource group with az group create -n helm-reg -l eastus, and then the ACR with the command az acr create -n chartregistry$RANDOM -g helm-reg --sku Basic -o tsv --query loginServer.
One tip is to keep the repository name in a variable:
export ACR=$(az acr create -n chartregistry$RANDOM -g helm-reg --sku Basic -o tsv --query loginServer)Now let’s log into our registry using Azure’s managed keys, but we need to enable administrative control with az acr update -n $ACR --admin-enabled true. Now we can run two commands to fetch the login credentials and save them in our shell:
export ACRUSER=$(az acr credential show -n $ACR --query username -o tsv)export ACRPASS=$(az acr credential show -n $ACR --query 'passwords[0].value' -o tsv)Now we can log into our registry with Helm using helm registry login $ACR --username $ACRUSER --password $ACRPASS, and from here we already have our registry configured. Let’s create another artifact with helm chart save zaqar $ACR/zaqar:2.1.3. Then let’s push it with helm chart push $ACR/zaqar:2.1.3.
Once it is there, we’ll be able to list everything in the repository with an Azure CLI command:
az acr repository show -n $ACR --repository zaqarNotice we get an output that is exactly what we pushed:
{ "changeableAttributes": { "deleteEnabled": true, "listEnabled": true, "readEnabled": true, "writeEnabled": true }, "createdTime": "2021-03-16T20:56:49.6118202Z", "imageName": "zaqar", "lastUpdateTime": "2021-03-16T20:56:49.7812323Z", "manifestCount": 1, "registry": "chartregistry23657.azurecr.io", "tagCount": 1}We can also get more details with the show-manifests command, adding a --detail:
az acr repository show-manifests -n $ACR --repository zaqar --detailThat gives us exactly the OCI artifact definition we saw in the first example:
[ { "changeableAttributes": { "deleteEnabled": true, "listEnabled": true, "quarantineState": "Passed", "readEnabled": true, "writeEnabled": true }, "configMediaType": "application/vnd.cncf.helm.config.v1+json", "createdTime": "2021-03-16T20:56:49.7213057Z", "digest": "sha256:4780713fa23d7144d356c353795b5b84e66ad2b8bbd47c7118b4b85435d50bbc", "imageSize": 1378, "lastUpdateTime": "2021-03-16T20:56:49.7213057Z", "mediaType": "application/vnd.oci.image.manifest.v1+json", "tags": [ "2.1.3" ] }]To install it we can follow the same steps we did with the local registry, after running helm char remove $ACR/zaqar:2.1.3 to remove it locally since we already have it here from our previous exercise:
helm chart pull $ACR/zaqar:2.1.3helm chart export $ACR/zaqar:2.1.3 -d ./destinationhelm install zaqar-acr ./destination
Conclusion#
Using Helm was already easy. One of the big problems we had was that there was no “simple” way to host a chart somewhere when we wanted some kind of private registry. Even though Helm has excellent tools like Chart Museum, they are still not fully standard and, for easy distributed development, it is essential that we have open standards the market can follow as a whole.
Keep in mind this feature is still experimental (at least as I write this article), it should be released soon and then you won’t need the environment variable to control the behavior anymore.
Being experimental does not mean you can’t use it to store your charts, it only means the API may change drastically, with some of its commands even being completely rewritten, but this is a strong sign that the container ecosystem is moving, more and more, towards a single place.
See you!