azure-container-registry-in-kubernetes

 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

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.

azure-container-registry-in-kubernetes-22.png
Importing Image: productmicroservice from Dockerhub to ACR

 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:

azure-container-registry-in-kubernetes-11.png
Namespace: default on ks8: dashboard on top-right dropdown.

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 kubectlcommand 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:

azure-container-registry-in-kubernetes-8
Pod: productmicroservice is pulling from ACR and Running.

Look to the Config and Storage: Secret:

 

azure-container-registry-in-kubernetes-9.png
Config and Storage: Secrets: acr-secret is ok

As you see the acr-secret is created in your KS8 service.

Look to the Eventes:

azure-container-registry-in-kubernetes-10.png
Event shows pod: productmicroservice is created 

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:

azure-container-registry-in-kubernetes-12.png
Service productmicroservice is created and has External IP: 4.225.208.21

Open browser with the external IP : 4.225.208.21, then the Swagger UI is displayed for ProductMicroservice as following:

azure-container-registry-in-kubernetes-13.png
Swagger UI inj the productmicroservice: image pulled from ACR.

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.

azure-container-registry-in-kubernetes-23.png
Azure DevOps Pipeline- Build and push 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:

azure-container-registry-in-kubernetes-1.png
Create a new Service Connection to ACR

Press to new Service connection  and then search Docker in the Search list of Services and select Docker Registry as following:

azure-container-registry-in-kubernetes-2.png
Adding Docker registry connection

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:

azure-container-registry-in-kubernetes-3.png
Service connection to the Azure Container Registry : mehzanContainerRegistry.

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.

azure-container-registry-in-kubernetes-4.png
Service connection : ProductMicroserviceACRConnection. is created

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

azure-container-registry-in-kubernetes-5.png
Configure Pipe line to Docker: Build and push to Azure Container Registry 

When you press to the Docker: Build and push to Azure Container Registry  then opens the following:

azure-container-registry-in-kubernetes-6.png
Docker: Build and push to Azure Container Registry 
  1. Select Azure Subscription : Subscription1 and press Continue
  2. Select your Container registry from the dropdown menu, (under Container Registry) select mehzanContainerRegistry 
  3. provide an Image Name to your container (I have changed this to productmicroservice)
  4. Dockerfile path is generated from your Repository on Github (don’t change this).
azure-container-registry-in-kubernetes-7.png
Configuration for Docker: Build and push an image to Azure Container Registry

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:

azure-container-registry-in-kubernetes-14.png

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:

azure-container-registry-in-kubernetes-15.png
Error Running Pipeline in Dockerfile :COPY [“–/ProductMicroservice.csproj”)
As we see from the above image with executing of Dokerfile:
 Step 6/28 : WORKDIR /src and then trying to copy project file from the path: ProductMicroservice/ProductMicroservice/
The Error is as follow:
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

To solve this problem, I have added  buildContext: $(Buiod.Repository.LocalPath) after line: 36, dockerfile: $(dockerfilePath) in the Pipeline. This is  best way to avoid any hardcoding.

The whole Pipeline yaml file 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: '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:

azure-container-registry-in-kubernetes-20.png
Build and push succeed

Select to the job: Build and push then you see the build is succeed as follow:

azure-container-registry-in-kubernetes-21.png
All steps are succeed to build and push image to the ACR

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:

azure-container-registry-in-kubernetes-16.png
Image productmicroservice is pushed from DevOps CI Pipeline

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:

azure-container-registry-in-kubernetes-17.png
 pulling image “mehzancontainerregistry.azurecr.io/productmicroservice:58

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:

azure-container-registry-in-kubernetes-18.png
Service: productmicroservice is created with External port: 20.240.154.30

Open your browser with IP address: 20.240.154.30, then see that Swagger UI is displayed:

azure-container-registry-in-kubernetes-19.png
Swagger UI from kubernetes microservice-aks, pulling from ACR

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:

  1. Imported image from Dockerhub to ACR.
  2. Created an Azure Kubernetes Service (AKS) and Authorized it to access to pull image from ACR.
  3. Tested it in KS8 dashboard (Helm octant)

Alternative 2: Uploading Docker image using Azure DevOps Pipelines:

  1. I have uploaded image by  Setting up  Azure DevOps project, and setup  Service Connection to ACR
  2. Created Pipeline in DevOps which can took a repository from Github, then build and pushes to ACR.
  3. Created an Azure Kubernetes Service (AKS) and Authorized it to access to pull image from ACR.
  4. 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”.

Back to home page

 

Leave a Reply

Your email address will not be published. Required fields are marked *