Azure development environment in Docker

As a Windows user I find it difficult to work with Kubernetes in Powershell. So I have build a Docker image to move my execution to Linux, while the coding remains in Windows’ IDE.

The image described in this post has Azure Cli, kubelet and helm installed.

A Service Principal is used to authenticate from the container. Here is a post that explains how this is done.

Build the image

The Dockerfile looks like this:

FROM ubuntu:latest

RUN apt update && \
    apt upgrade -y && \
    apt install curl libicu-dev -y

# azure cli
RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash && \
    az upgrade --yes

# kubectl
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" && \
    install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

# helm
RUN curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

RUN cat >/login.sh <<EOL
#!/bin/bash
az login --service-principal -u \$AZURE_SERVICE_PRINCIPAL_ID -p \$AZURE_KEY_PATH --tenant \$AZURE_TENANT
EOL

# remove \r and make it executable
RUN sed -i 's/\r$//g' login.sh && \
    chmod 711 login.sh

Installing kubectl and helm is needed only for work with Kubernetes and AKS. Even though the base image is light – 70MB – the image rounds up to 1GB, thanks to 700MB that Azure Cli brings to the table.

The login.sh script that is created is used to login to Azure from the container.

Now the image can be build from the folder where Dockerfile is saved:

docker build . --tag=markokole/azure-dev-env

Create the container and execute it

Environment file envs holds values for variables AZURE_SERVICE_PRINCIPAL_ID, AZURE_TENANT and AZURE_KEY_PATH.

Value for AZURE_KEY_PATH has to be equal to the path where the key is mapped to in the container.

AZURE_SERVICE_PRINCIPAL_ID=
AZURE_TENANT=
AZURE_KEY_PATH=/.azure/key

Run the container:

 docker run -itd --rm --name azure-local `
                      --env-file envs `                      
                      -v C:\marko\git\azure\bicep:/local-git `
                      -v C:\marko\keys\developerCli.pem:/.azure/key:ro `
                      markokole/azure-dev-env

Two volumes are mapped into the container:

  • work folder to allow writing scripts in IDEs in Windows and executing them from container.
  • Key and certificate (in one file) are mapped to a file in the container in order to be able to login to Azure.

The container is entered with the following command:

docker exec -it azure-local /bin/bash

And once in the container, the login script can be executed.

./login.sh

The output, if login is successful, is a JSON object as described in the post about logging to Azure services with service principal.

Make image available on docker hub

Login to docker and push the image if anyone is interested in using it.

docker image push markokole/azure-dev-env

Service Principal for development purposes from CLI

Create Service Principle

The object of this post is to create a service principal that is used to build services in Azure from CLI. To be able to do this, we log in using az login and use user with role Owner. This is one time and just ot create a Service Principal that is going to be used in the future.

Below code creates a service principal developerCli with built-in role Contributor on a level (scope) of subscription. A new certificate is created for this service principal.

az ad sp create-for-rbac --name developerCli `
                         --role Contributor `
                         --scopes /subscriptions/00000000-0000-0000-0000-000000000000 `
                         --create-cert

The scope is quite wide and not best practice. This can be fine tuned by adding more scopes as a space delimited list to the –scope.

The output is similar to this one:

{
  "appId": "10000000-0000-0000-0000-000000000000",
  "displayName": "developerCli",
  "fileWithCertAndPrivateKey": "C:\\Users\\marko\\tmpupgm31k_.pem",
  "password": null,
  "tenant": "20000000-0000-0000-0000-000000000000"
}

In Azure Console, the new Service Principal can be found under service Microsoft Entra ID -> drop down menu Manage -> App registrations ->All applications.

It makes sense to rename PEM file that was generated. For simplicity I will rename it to match the name of the Service Principal. Perhaps also a good idea to move the file. If you do so, move it before you start your work with this Service Principal because this file is being read at every az command.

Test Service Principle

Now the Service Principal can be tested:

az login --service-principal `
         -u 10000000-0000-0000-0000-000000000000 `
         -p C:\marko\keys\developerCli.pem `
         --tenant 20000000-0000-0000-0000-000000000000

Value for tenant can either be tenant id from the output when Service Principal was created or publisher domain – value with suffix .onmicrosoft.com.

If all goes well a JSON object is returned:

[
  {
    "cloudName": "AzureCloud",
    "homeTenantId": "20000000-0000-0000-0000-000000000000",
    "id": "30000000-0000-0000-0000-000000000000",
    "isDefault": true,
    "managedByTenants": [],
    "name": "Test",
    "state": "Enabled",
    "tenantId": "20000000-0000-0000-0000-000000000000",
    "user": {
      "name": "10000000-0000-0000-0000-000000000000",
      "type": "servicePrincipal"
    }
  }
]

Value Test is the subscription this Service Principal is created in.