Publishing Helm 3 charts to Azure Container Registry using Azure DevOps - Part 2
In part 1, I covered the what’s happening underneath the covers with the usage of OCI artifacts to publish to Azure Container Registry. As a reminder, we published a dummy file as a generic artifact to the container registry. In this guide, I’ll cover how to push a real Helm 3 chart.
Background
Microsoft recommends that when using Helm 3 charts, that you use the native helm chart
commands so to manage the charts as OCI artifacts.
Microsoft already has good documentation on how to do this using just terminal commands. This guide is more geared towards applying it with Azure DevOps.
Pre-Requisites
- An Azure Container Registry
- Helm Client 3 or later
- Azure CLI version 2.0.71 or later
Disclosure
Helm 3 support for Azure Container Registry is still a preview feature. Even the support from the Helm CLI is still experimental.
The main way
First, define an environment variable of HELM_EXPERIMENTAL_OCI
. Any pipeline variable gets mapped to an environment variable on the agent.
variables:
HELM_EXPERIMENTAL_OCI: 1
ACR.Name: '[Your azure container registry name]'
Azure.ServiceConnection: '[your azure service connection]'
pool:
vmImage: 'ubuntu-latest'
Then ensure you have Helm installed on the agent running the pipeline.
- task: HelmInstaller@1
inputs:
helmVersionToInstall: 'latest'
Next, login to Azure Container Registry using the Azure CLI.
- task: AzureCLI@2
displayName: Login to Azure Container Registry
inputs:
azureSubscription: "$(Azure.ServiceConnection)"
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
az acr login --name $(ACR.Name)
Lastly, save the chart and push it using Bash.
- bash: |
helm chart save ./k8s/realworld-backend/ $(ACR.Name).azurecr.io/charts/realworld-backend:$(Build.BuildNumber)
helm chart push $(ACR.Name).azurecr.io/charts/realworld-backend:$(Build.BuildNumber)
realworld-backend
is the name of my Helm chart. It resides under the k8s/realworld-backend/
subdirectory in my repo. It lives on the same repo as the source code. Replace those two things with your respective helm chart name and the relative location on your repo.
Notice how it’s also pushing the the chart to a charts/realworld-backend
repository on ACR.
Putting it all together
trigger:
- master
pr: none
variables:
HELM_EXPERIMENTAL_OCI: 1
ACR.Name: '[Your azure container registry name]'
Azure.ServiceConnection: '[your azure service connection]'
stages:
- stage: build
displayName: Build and Push
jobs:
- job: job_helm
displayName: Helm Publish
pool:
vmImage: 'ubuntu-latest'
steps:
- task: AzureCLI@2
displayName: Login to Azure Container Registry
inputs:
azureSubscription: "$(Azure.ServiceConnection)"
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
az acr login --name $(ACR.Name)
- task: HelmInstaller@1
inputs:
helmVersionToInstall: 'latest'
- bash: |
helm chart save ./k8s/realworld-backend/ $(ACR.Name).azurecr.io/charts/realworld-backend:latest
helm chart push $(ACR.Name).azurecr.io/charts/realworld-backend:latest
Open Issue
Today, there’s an open issue on GitHub. For myself, I ran into this when publishing the Helm chart from the Azure DevOps Ubuntu and Windows agents. I did not run into this from my workstation using Windows 10. I also ran into this issue from my Linux workstation.
The issue looks like this.
Error: failed to authorize: failed to fetch anonymous token: unexpected status: 401 Unauthorized
I pretty much ruled out it was not an authentication issue by replicating the issue using my user account on my Linux workstation. It worked on my Windows workstation.
Fallback
If you’re running into the same issues as above, you can try the legacy approach. Instead of issuing helm chart
commands, we’ll use the az acr helm
commands.
The pipeline steps are as follows.
steps:
- task: HelmInstaller@1
inputs:
helmVersionToInstall: 'latest'
- bash: |
helm package k8s/realworld-backend/ --app-version $(Build.BuildNumber)
mv *.tgz $(Build.ArtifactStagingDirectory)/
- task: AzureCLI@1
displayName: 'Push helm chart'
inputs:
azureSubscription: $(Azure.ServiceConnection)
scriptLocation: inlineScript
inlineScript: 'az acr helm push -n $(ACR.Name) $(Build.ArtifactStagingDirectory)/*.tgz'
realworld-backend
is the name of my Helm chart. It resides under the k8s/realworld-backend/
subdirectory in my repo. It lives on the same repo as the source code. Replace those two things with your respective helm chart name and the relative location on your repo.
But, this is what happens here.
First, we package the Helm chart using Helm 2 commands. We also override the app version with the build number. It would be useful to know from which build this chart was generated. For the chart version, it would be up to the authors to change it using a SemVer version.
Secondly, we move the packaged helm chart to the staging directory. Then, we push the Helm chart using the Azure CLI ACR Helm commands. Upon pushing to ACR, you’ll have to follow the format [chart name]-[chart version].tgz
.
So, although it looks easy, you might run into some snags because of the preview nature.
Best of luck.