Besides using the goodness of Azure Container Services (ACS). Different Azure services like Azure Container Registry (ACR) and Azure Container Instances (ACI) can be used and connected from independent container orchestrators like kubernetes (k8s). This post will explain how to set up a custom ACR and connect it to an existing k8s cluster to ensure images will be pulled from the private container registry instead of the public docker hub.
Setting up the Azure Container Registry
Although the recent Azure portal is providing a rich user experience, all Azure related stuff in this post will be scripted using the latest Azure CLI 2.0. If you haven’t installed Azure CLI 2.0 yet, you can find detailed instructions here.
First, you need to login in order to get access to all your Azure subscriptions.
Once logged in, you can select any of your subscriptions. You can list all subscriptions using
az account list
Select the suggested subscription by invoking the following script (replace
<SUBSCRIPTION_ID> with the id of your subscription).
az account set --subscription <SUBSCRIPTION_ID>
Creating an Azure Resource Group
Either you can use an existing Azure Resource Group or create a new using:
az group create --location northeurope --name <RESOURCE_GROUP_NAME>
You can list all available locations by using
az account list-locations.
Provisioning an Azure Container Registry
An Azure Container Registry (ACR) can also be created using the new Azure CLI.
az acr create --name <REGISTRY_NAME> --resource-group <RESOURCE_GROUP_NAME> --sku Basic
Once the ACR has been provisioned, you can either enable administrative access (which is okay for testing and described later) or you create a Service Principal (sp) which will provide a
client_id and a
az ad sp create-for-rbac --scopes /subscriptions/<SUBSCRIPTION_ID>/resourcegroups/<RG_NAME>/providers/Microsoft.ContainerRegistry/registries/<REGISTRY_NAME> --role Contributor --name <SERVICE_PRINCIPAL_NAME>
Before executing this script ensure that you replace all tokens being used in the script above. You need to provide the subscription id, the resource group name, the ACR name and a meaningful name for your service principal. You may have noticed the role parameter which is set to
Contributor. ACR supports three different roles:
Owner: (pull, push, and assign roles to other users)
Contributor: (pull and push)
Reader: (pull only access)
Once the service principal has been created, copy the
appId in the response) and the
password in the response). You’ll need those in a few seconds.
To keep things simple, we’ll create a single service principal for now. For real-world scenarios, you may create multiple service principals with different roles. As a developer, you want to push new images to the registry. (So you become a
Contributor). Your container cluster, on the other hand, may only pull images from the registry. So you should create a second service principal with the
Once you made it through the previous steps, it’s time to take care of Docker and Kubernetes. Without any further configuration, both docker and kubernetes will push and pull images from the public docker hub. So let’s change this now and bring in the ACR goodness.
Login from Docker CLI
In order to push images to the newly created ACR instance, you need to login to ACR form the Docker CLI.
docker login <REGISTRY_NAME> -u <CLIENT_ID>
You can also pass the
client_secret directly to the
docker login command, but keep in mind that both
client_secret will be visible in your bash history.
docker login will prompt for the
password) when you execute the command as shown above.
Pushing a Docker image to ACR
Once logged in, you can push any existing docker image to your ACR instance. Before you can push the image to a private registry, you’ve to ensure a proper image name. This can be achieved using the
docker tag command. For demonstration purpose, we’ll use Docker’s hello world image, rename it and push it to ACR.
# pulls hello-world from the public docker hub docker pull hello-world # tag the image in order to be able to push it to a private registry docker tag hello-word <REGISTRY_NAME>/hello-world # push the image docker push <REGISTRY_NAME>/hello-world
Configure Kubernetes to use your ACR
When creating deployments, Replica Sets or Pods, Kubernetes will try to use docker images already stored locally or pull them from the public docker hub. To change this, you need to specify the custom docker registry as part of your Kubernetes object configuration (
Instead of specifying this directly in your configuration, we’ll use the concept of Kubernetes Secrets. You decouple the k8s object from the registry configuration by just referencing the secret by its name. But first, let’s create a new Kubernetes Secret.
kubectl create secret docker-registry <SECRET_NAME> --docker-server <REGISTRY_NAME>.azurecr.io --docker-email <YOUR_MAIL> --docker-username=<SERVICE_PRINCIPAL_ID> --docker-password <YOUR_PASSWORD>
If you want to prevent your
client_secret from being stored in bash history, you can for example use
read -s DOCKER_PASSWORD and provide
$DOCKER_PASSWORD as value for the
Create Pods, Replica Sets, and Deployments using the Secret
No matter which Kubernetes object you’re going to create, you can easily bring Secrets into consideration using the
spec.imagePullSecrets configuration value. As an example see the following
yaml file describing a simple pod which will pull the
hello-world image from the ACR instance to your Kubernetes nodes and uses that image to create the containers.
apiVersion: v1 kind: Pod metadata: name: private-hello-world spec: containers: - name: private-hello-container image: <REGISTRY_NAME>.azurecr.io/hello-world imagePullSecrets: - name: <SECRET_NAME>
You can save the pod configuration to as a local file like
pod-sample.yaml and deploy it using
kubectl by invoking:
kubectl create -f pod-sample.yaml
Once your pod has been provisioned, you can see detailed information about the pod and the docker image, which has been pulled from ACR using
kubectl describe pod <POD_NAME>.
That’s it. You’ve successfully deployed an ACR, configured it with a docker installation and hooked it up in Kubernetes. 🤘 🚀