Did you know you can publish Helm charts to an Azure Container Registry? It can be useful. Charts can be shared more easily with others or other business units. But also, when using a GitOps workflow, we can reference these Helm charts.

This is a quick guide on how to publish a Helm 3 chart to an Azure Container Registry.

Background

In Helm 2, you needed to install Tiller on your Kubernetes cluster in order to deploy Helm charts. Sure, there were other ways of using it too. With Helm 2, you could upload Helm charts to an Azure Container Registry. These charts could be tagged and versioned.

In Helm 3, there’s no more Tiller. That’s great! Makes things much simpler. We only need the client side tool.

There’s also a new standard for uploading artifacts to a container registry other than containers. The standard is Open Container Initiative (OCI) artifacts. In cloud native applications, applications are usually more involved than just container images. There’s Helm charts, there’s Terraform, maybe ARM, and other file-based artifacts.

If you’re curious about the background, there’s this great blog post from a Microsoft engineer.

Also, this blog post has been inspired by this doc from Microsoft.

Pre-Requisites

  • An Azure Container Registry
  • A service connection to an Azure Subscription
  • A service connection to the container registry

First, you want to install Oras, a CLI tool for managing OCI artifacts.

- bash: |
    set -e
    curl -LO https://github.com/deislabs/oras/releases/download/v0.8.1/oras_0.8.1_linux_amd64.tar.gz
    mkdir -p oras-install/
    tar -zxf oras_0.8.1_*.tar.gz -C oras-install/
    sudo mv oras-install/oras /usr/local/bin/
    sudo rm -rf oras_0.8.1_*.tar.gz oras-install/

The first line set -e forces the Bash script to fail the build in the event of an error.

Once Oras is installed, you want to authenticate against the Azure Container Registry. From the Microsoft guide, it states you have two options. Login through Azure CLI or straight through OCI. I prefer Azure CLI since I already have an Azure service connection.

- task: AzureCLI@2
  displayName: Login to ACR
  inputs:
    azureSubscription: "$(Azure.ServiceConnection)"
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
        az --version
        az acr login --name $(ACR.Name)

Now, that you have Azure CLI installed, you are ready to issue commands to upload your OCI artifacts. I’m going to bash to showcase how to upload a dummy file.

- bash: |
    echo "Here is an artifact!" > artifact.txt

    oras push $(ACR.Name).azurecr.io/samples/artifact:$(Build.BuildNumber) \
      --manifest-config /dev/null:application/vnd.unknown.config.v1+json \
      ./artifact.txt:application/vnd.unknown.layer.v1+txt
  displayName: "Uploading dummy artifact"

This bash script creates a dummy file called artifact.txt. Then it pushes it to a new repository on ACR. Most importantly, we’re able to tag it with the Build.BuildNumber from the current build.

Here’s the end result.

Putting it all together

Here’s what my pipeline looks like.

variables:
  ACR.Name: '[my registry name]'
  ACR.ServiceConnnection: '[my registry service connection]'
  Azure.ServiceConnection: '[my azure service connection]'

stages:
- stage: build
  displayName: Build and Push
  jobs:  
  - job: job_helm
    displayName: Helm Publish
    pool:
      image: 'ubuntu-latest'
    steps:
    - bash: |
        set -e
        curl -LO https://github.com/deislabs/oras/releases/download/v0.8.1/oras_0.8.1_linux_amd64.tar.gz
        mkdir -p oras-install/
        tar -zxf oras_0.8.1_*.tar.gz -C oras-install/
        sudo mv oras-install/oras /usr/local/bin/
        sudo rm -rf oras_0.8.1_*.tar.gz oras-install/
      displayName: "Install Oras"
    - task: AzureCLI@2
      displayName: Login to ACR
      inputs:
        azureSubscription: "$(Azure.ServiceConnection)"
        scriptType: bash
        scriptLocation: inlineScript
        inlineScript: |
            az --version
            az acr login --name $(ACR.Name)
    - bash: |
        echo "Here is an artifact!" > artifact.txt

        oras push $(ACR.Name).azurecr.io/samples/artifact:1.0 \
          --manifest-config /dev/null:application/vnd.unknown.config.v1+json \
          ./artifact.txt:application/vnd.unknown.layer.v1+txt
      displayName: "Uploading dummy artifact"

That’s it! For the next part, I’ll upload a real helm chart.