How to use Azure Container Registry in Kubernetes
what is Azure Container Registry (ACR)
Azure Container Registry (ACR) is a private registry service for building, storing, and managing container images and related artifacts like as Dockerhub. ACR is used specially by Enterprises which don’t want to have their containers on a public share.
ACR comes in three pricing tiers: Basic, Standard, and Premium. The main difference between them is the amount of included storage and the number of webhooks you can use. Additionally, the premium tier supports geo-replication. This means that your images are still available when a data center goes down.
In this post, I will describe how to create ACR, how to upload images to ACR, and how to pull images from ACR by configuring your Microservice and Azure Kubernetes cluster to run them in your Kubernetes cluster.
Prerequisites
- A GitHub account. Create a free GitHub account, if you don’t already have one.
- An Azure DevOps organization and a project. Create a new organization and/or a new project, if you don’t already have one.
- An Azure account. Sign up for a free Azure account, if you don’t already have one.
Create Azure Container Registry in the Azure Portal
I have described in my post Azure Container Registry (ACR) , how to create and how to push image to ACR. You can create ACR by looking to this post.
Here I have created ACR with name: mehzanContainerRegistry with Resource Group: mehzanRSG, in Region: Sweden Central.
Pushing Image to ACR
You have two alternative to push image to ACR:
- Alternative 1: importing the image from Dockerhub.
- Alternative 2: uploading it from a CI/CD pipeline.
I am going to describe the both alternatives in this post
Alternative 1: Import Image from Dockerhub into ACR
To import the image, use the following Azure CLI commands: (run az login first and then az acr import ..)
az login
az acr import --name mehzancontainerregistry --source docker.io/mehzan07/productmicroservice:latest --image productmicroservice:latest
The first line logs you into your Azure subscription and the second one takes the name of your ACR (name should be lowercase), the source image from Dockerhub, and the image name which will be created in ACR .
In here I have taken the productmicroservice image from my Dockerhub: docker.io/mehzan07. (Your image should be exist in the your Dockerhub, otherwise you can push it from your local).
If importing is succeeded then navigate to your ARC registry in the Azure portal and select Repositories, then you can see productmicroservice (as shown in the following figure). If you double click it shows tag: latest.
Create Azure Kubernetes Service (AKS)
You have to create an Azure Kubernetes Service (AKS), To Create AKS look to my post: Azure Kubernetes Service (AKS)
I have created AKS with name: microservice-aks with Resource group: mehzanRSG in Region: Sweden Central ( in the same Resource group and and same Region for ACR which I have created in this post).
Note: I haven’t create any Services and Progress yet, I shall create this later on.
Pulling Image from Azure Container Register to Kubernetes (aks)
To pull this image from kubernetes we should authorize Kubernetes to pull images from ACR.
Kubernetes is not authorized to pull the image. This is because ACR is a private container registry and you have to give Kubernetes permission to pull the images.
Allowing Kubernetes to pull ACR Images
To allow Kubernetes to pull images from ACR, you first have to create a service principal and give it the acrpull role.
Service principals define who can access the application, and what resources the application can access. A service principal is created in each tenant where the application is used, and references the globally unique application object. The tenant secures the service principal sign-in and access to resources. For more about Service Principal.
Use the following bash script to create the service principal and assign it the acrpull role.
1- Run the following script on Azure CLi command (start from portal):
ACR_NAME=mehzancontainerregistry
SERVICE_PRINCIPAL_NAME=acr-service-principal
ACR_REGISTRY_ID=$(az acr show --name $ACR_NAME --query id --output tsv)
PASSWORD=$(az ad sp create-for-rbac --name $SERVICE_PRINCIPAL_NAME --scopes $ACR_REGISTRY_ID --role acrpull --query "password" --output tsv)
USER_NAME=$(az ad sp list --display-name $SERVICE_PRINCIPAL_NAME --query "[].appId" --output tsv)
echo "Service principal ID: $USER_NAME"
echo "Service principal password: $PASSWORD"
Where the mehzancontainerregisry is the ACR name which we have created in the beginning of this post.
Note: If running of copy of this script is not worked then you should first copy and paste it to notepad and then take from there to run in the Azure CLI.
If it is succeed then output will be like as following:
Service principal ID: f8922aa7-81df-48a5-a8c6-5b158edb6072
Service principal password: oDm8Q~eVBH-15mE25t3EIqyTt0pc87UWmhVURaIM
Save these Service principal ID and Service principal password: and use them in the next step (in the following).
2- Next, create an image pull secret with the following command in the command line:
kubectl create secret docker-registry acr-secret --namespace default --docker-server=mehzancontainerregistry.azurecr.io --docker-username=f8922aa7-81df-48a5-a8c6-5b158edb6072 --docker-password=oDm8Q~eVBH-15mE25t3EIqyTt0pc87UWmhVURaIM
where docker- server value (mehzancontainerregistry.azurecr.io)
is ACR Service and it is created with creating of ACR in the beginning. namespace: as default, docker-username: the Service principal ID value and docker password f Service principal password value from the step 1.
If it succeed the output will be: “secret/acr-secret created “
namespace value can be found from Ks8: dashboard as shown in the following figure:
3- Use the Image Pull Secret in your Microservice (productmicroservice)
After the image pull secret was created, you have to tell your microservice to use it. I have used the values.yaml file (under charts:productmicroservice) for values, as following code:
imagePullSecrets:
- name: acr-secret
I have build image and pushed to my dockerhub before importing of image. The Source code can be found in my Github.
If you used a different name for your secret in the kubectl create secret docker-registry, then you have to use your name instead of acr-secret.
4- Copy the following yaml in somewhere in your local machine and give a file name (like as : acr-secret.yml)
apiVersion: apps/v1
kind: Deployment
metadata:
name: productmicroservice
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: productmicroservice
template:
metadata:
labels:
app: productmicroservice
spec:
containers:
- name: mehzancontainerregistry
image: mehzancontainerregistry.azurecr.io/productmicroservice:latest
imagePullPolicy: IfNotPresent
imagePullSecrets:
- name: acr-secret
And run it in the following kubectl
command as follow:
kubectl apply -f path\filename.yml
I have saved the script in acr-secret.yml in the path C:\Utvecklingprogram\Kubernetes\
And run it as following command line from my local machine
kubectl apply -f C:\Utvecklingprogram\Kubernetes\acr-secret.yml
If it succeed the output shall be: pod/productmicroservice created
where name: productmicroservice is the pod name of productmicroservice in the kubernetes (shall be seen in KS8: dashboard) and containers: name: mehzancontainerregistry
is the ContainerRegistry name we have created in Azure (the name should be lower case). The image: productmicroservice:latest is the image in the Container Registry Service from Azure which we have imported from my Dockerhub.
Test the pulling image from Kubernetes (aks).
Connect to the K8s dashboard (by starting Octant from your local machine) If you have not installed Octant look to the my post: azure-kubernetes-service-aks
Start Octant from your local machine(start menu) and click on the Workloads: Pods, the following shall be displayed:
Look to the Config and Storage: Secret:
As you see the acr-secret is created in your KS8 service.
Look to the Eventes:
If we check the Services on the KS8: dashboard then we see this part is empty, because we have created only a kubernets (microservice-aks) without any “Service and Ingress”. Now we want to have Service and test application (productmicroservice). We can create Service And Ingress as described in my post: Azure Kubernetes Service (AKS) In the section: deploy the first Application.
Now go to the KS8 dashboard : Discovery and Load Balancing: Services then you can see that productmicroservice is created as following image:
Open browser with the external IP : 4.225.208.21, then the Swagger UI is displayed for ProductMicroservice as following:
That is all.
We have created ACR, imported image from dockerhub, created AKS Service and configured, authorized to pull from ACR and tested it with KS8:dashboard.
In the end Cleanup all resources
When you are finished, delete all created resources in your Azure account. AKS creates three additional resource groups. Make sure to delete them too. Delete all resource groups.
Alternative 2: Uploading Image to ACR from Azure DevOps Pipelines
Automated Azure DevOps pipeline is better approach to uploading image to ACR.
The figure above is self descriptive.
First you need to have an Azure DevOps Organization and DevOps project. How to create these, look to my post: How to create a DevOps Organization and DevOps project
Note: You have to created an Azure Container Registry before Setting up a Service Connection to ACR
I have a DevOps Organization: mehzan07 and a project: ProductMicroservice in my DevOps account.
I have also created an ACR In Azure account as I have done in the alternative 1. how to create ACR, look to the my post: Azure Container Registry (ACR).
First we should setup a Service connection to our ACR, in Azure DevOps project.
Setting up a Service Connection to your ACR in DevOps
Before uploading image to ACR, we have to create a Service Connection. In the Azure DevOps project, click on Project settings and then on Service connections as showing i the following:
Press to new Service connection and then search Docker in the Search list of Services and select Docker Registry as following:
Press to Next button, for Registry type: select Azure Container Registry , for Authentication type, select Service Principal, then, you can select your subscription and Azure Container Registry from the list of ACRs (ACR should be exist in the Azure). Provide Service Connection name (you can change the default name) and remember it because you will need it later in your pipeline.
It asks to login to Azure with loading of Registries, you should login to Azure and flow the instruction.
OBS! when you press to Next button then it finds subscription name but can’t find Azure Container registry in the dropdown of Azure container registry (no registry find).
To solve this problem, you can Switch Directory in your DevOps account and Switch back then it can be exist in Container Registry dropdown list, which you have created it in the Azure Portal. and it shall be displayed as follow:
As you see it finds the Subscription, and Azure Container Registry name (mehzanContainerRegistry) and I have give the ConnectionService name: ProductMicroserviceACRConnection
Press to the Save button to create the ProductMicroserviceACRConnection.
What is Azure DevOps Pipeline?
Azure Pipelines is a cloud service that you can use to automatically build and test your code and make it available to other users.
Features of Azure Pipeline.
- Work with any language or platform – Python, Java, PHP, Ruby, C#, and Go
- Deploy to different types of targets at the same time
- Integrate with Azure deployments – Container registries, virtual machines, Azure services, or any on-premises or cloud target (Microsoft Azure, Google Cloud, or AWS)
- Build on Windows, Linux, or macOS machines
- Integrate with GitHub
- Work with open-source projects
Create a new Pipeline
In Azure DevOps, Select Project and press to Pipeline and then press to the Create a new Pipeline: select Github and then Repository, your Repository on Github (for me, mehzan07/ProductMicroservice-DotNET-Core-Master, and in step: Confiture Your Pipeline : select Docker, build and push to Azure Container registry as shown in following figure
When you press to the Docker: Build and push to Azure Container Registry then opens the following:
- Select Azure Subscription : Subscription1 and press Continue
- Select your Container registry from the dropdown menu, (under Container Registry) select mehzanContainerRegistry
- provide an Image Name to your container (I have changed this to productmicroservice)
- Dockerfile path is generated from your Repository on Github (don’t change this).
Press to Validate and configure button then a Pipeline with the following contents created (I have changed the name to Pipelines/BildAndPushImageToACR.yml) and saved it, and the content looks as follow:
I have changed imageRepository to productmicroservice. and content of Pipeline is as follow:
# Docker
# Build and push an image to Azure Container Registry
# https://docs.microsoft.com/azure/devops/pipelines/languages/docker
trigger:
- master
resources:
- repo: self
variables:
# Container registry service connection established during pipeline creation
dockerRegistryServiceConnection: 'd3aa3133-5705-4695-832c-2b0ca10ac77a'
imageRepository: 'productmicroservice'
containerRegistry: 'mehzancontainerregistry.azurecr.io'
dockerfilePath: '$(Build.SourcesDirectory)/ProductMicroservice/ProductMicroservice/Dockerfile'
tag: '$(Build.BuildId)'
# Agent VM image name
vmImageName: 'ubuntu-latest'
stages:
- stage: Build
displayName: Build and push stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- task: Docker@2
displayName: Build and push an image to container registry
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
Press Run button to see the result:
We see that the Build is failed with Error in stage: Build and Push image in the Dockerfile as shown in the following:
ProductMicroservice/ProductMicroservice/
Step 7/28 : COPY ["ProductMicroservice/ProductMicroservice/ProductMicroservice.csproj", "ProductMicroservice/ProductMicroservice/"] Errors COPY failed: file not found in build context or excluded by .dockerignore: stat ProductMicroservice/ProductMicroservice/ProductMicroservice.csproj: file does not exist ##[error]The process '/usr/bin/docker' failed with exit code 1
# Docker
# Build and push an image to Azure Container Registry
# https://docs.microsoft.com/azure/devops/pipelines/languages/docker
trigger:
- master
resources:
- repo: self
variables:
# Container registry service connection established during pipeline creation
dockerRegistryServiceConnection: 'e0d5c2c7-b6b3-484a-a45e-76778128db3e'
imageRepository: 'productmicroservice'
containerRegistry: 'mehzancontainerregistry.azurecr.io'
dockerfilePath: '$(Build.SourcesDirectory)/ProductMicroservice/ProductMicroservice/Dockerfile'
buildContext: DockerTestWebsiteLinux
tag: '$(Build.BuildId)'
# Agent VM image name
vmImageName: 'ubuntu-latest'
stages:
- stage: Build
displayName: Build and push stage
jobs:
- job: Build
displayName: Build
pool:
vmImage: $(vmImageName)
steps:
- task: Docker@2
displayName: Build and push an image to container registry
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
buildContext: $(Build.Repository.LocalPath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
The above YAML is a CI Pipeline with a new pull requests trigger the pipeline to build and publish Docker images to Azure Container Registry. (ACR).
What is $(Build.Repository.LocalPath)?
This environment variable is local path on the agent where your source code files are downloaded, our case $(dockerfilePath)
This variable is agent-scoped, and can be used as an environment variable in a script and as a parameter in a build task, and it is synonyms to the the $(Build.SourcesDirectory). the $(Build.SourcesDirectory) is standard and it should work, but in some reason it is not worked to me. and that is because I have added $(Build.Repository.LocalPath)
in the pipe line. You can even use this variable instead of $(Build.SourcesDirectory). in the line 16 of Pipeline , but I haven’t tested it.
We run again the Pipeline then see that Build is succeed as seen from the following image:
Select to the job: Build and push then you see the build is succeed as follow:
Test the Switch to ACR
Now we look to the Container Registry (mehzanContainerRegistry) in Azure Portal and select the Repository then we see that image: productmicorservice is pushed to the Containery Registry as shown in the bellow:
If you press to the image: productmicroservcie under Repositories then you can see the last version is 58.
Create Azure Kubernetes (aks).
This part is exact the same that I have explained in the Alternative 1 solution and I am not going to repeat it again to this part
Allowing Kubernetes to pull ACR Images
This part is exact the same as Alternative 1 in this post.
Testing on KS8: dashboard
Start Octant from start menu of your local mashine and look to the Events part in as seen in the bellow:
If you look to the Pods on dashboard, you see:
- Pods: productmicroservice-695f96c4f9-862pc
- Secrets: acr-secret
Now we go back to the Azure kubernetes aks and create Services and Progress as we have created before in Alternative 1.. Then back to ks8 dashboard to look to the Services:
Open your browser with IP address: 20.240.154.30, then see that Swagger UI is displayed:
And that is all.
We have build and pushed image from Azure DevOps Pipeline to ACR and Authorized kubernetes to pull from ACR.
In the end Cleanup all resources
When you are finished, delete all created resources in your Azure account by deleting of Resource Groups. AKS creates three additional resource groups. Make sure to delete them too. Delete all resource groups
Conclusion
In this post I have created an Azure Container Registry (ACR) in Azure Portal and uploaded image to ACR with two different alternative ways:
Alternative 1: Imported image from Dockerhub to ACR:
- Imported image from Dockerhub to ACR.
- Created an Azure Kubernetes Service (AKS) and Authorized it to access to pull image from ACR.
- Tested it in KS8 dashboard (Helm octant)
Alternative 2: Uploading Docker image using Azure DevOps Pipelines:
- I have uploaded image by Setting up Azure DevOps project, and setup Service Connection to ACR
- Created Pipeline in DevOps which can took a repository from Github, then build and pushes to ACR.
- Created an Azure Kubernetes Service (AKS) and Authorized it to access to pull image from ACR.
- Tested it in KS8 dashboard (Helm octant)
You can find the source code on my GitHub.
This post is part of “Kubernetes step by step”.