DotNet Core in kubernetes (Azure Container Registry) 
Tags: dotnet, kubernetes, azure, docker
Published: 2020-02-04 04:51:13

Here in simplest form we are going to run an Asp.Net core application in local Kubernetes.

## Step 1: Creating a container registry

First you need to login to your azure account:
```powershell
az login
```

if you don't know the id of the location you can get it with
```powershell
az account list-locations
```

I am going to use *australiaeast*. So I am going to put it in a variable.

bash:
```bash
location='australiaeast'
```
powershell:
```powershell
$location='australiaeast'
```

The other parameter I am going to need is a name for resource group
bash:
```bash
resource_group_name='ContainerRegistryRG'
```
powershell:
```powershell
$resource_group_name='ContainerRegistryRG'
```

In case you are not using an existing resource group:
```powershell
az group create --location $location --name $resource_group_name
```

Next parameter is a name for the container registry. As it needs to be unique I am adding the seconds from Unix Epoch.

bash:
```bash
crName=TestCR$(date +'%s')
```
powershell:
```powershell
$crName='TestCR' + [int][double]::Parse((get-date -UFormat +%s))
```

Finally, we create the container registry:
```powershell
az acr create -g $resource_group_name -n $crName --sku Basic --admin-enabled -l $location
```

I am going to (manually) store the value of *loginServer* from the json response in *crServerName*.

The next parameters we need are credentials.

```powershell
az acr credential show -g $resource_group_name -n $crName 
```
Take a note of "username" and password value

## Step 2: Creating the docker image

Now we are going to create a dotnet core web application and build a docker image. The complete list is also [here](https://dev.to/mkokabi/simplest-sample-of-dotnetcore-in-docker-1ld7)


```powershell
dotnet new webapp -o KTestDotNetCoreWebApp

cd .\KTestDotNetCoreWebApp\

dotnet publish -c Release -o out

new-item -path "Dockerfile" -ItemType "file" -Value 'FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS runtime
WORKDIR /app 
COPY out ./ 
ENTRYPOINT ["dotnet", "KTestDotNetCoreWebApp.dll"]' 


docker build . -t ktest-dotnetcore-webapp-docker-image
```

We need to tag our docker image with the name of the container registry server. 
```powershell
docker tag ktest-dotnetcore-webapp-docker-image "$crServerName/ktest-dotnetcore-webapp-docker-image"
```

To be able to push to the registry you first need to login. You can login using either of following ways:

```powershell
az acr login --name $crName --username $crName
```
or
```powershell
docker login "$crServerName"
```
both of them will use the username and password you got using *az acr credential show*.

Now we can push our image:
```powershell
docker push "$crServerName/ktest-dotnetcore-webapp-docker-image"
```

## Step 3: using our docker image in Kubernetes

To allow kubernetes pull down our image, we need to define a image pull policy. 
K8s would get the information it needs in a *secret* object. The type of this secret should be *docker-registry*. Here I am going to name it *myregistrykey*. It would be used while defining the container template either for the *pod* or for the *deployment*.

[ref](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod)

```powershell
kubectl create secret docker-registry myregistrykey --docker-server="https://$crServerName" --docker-username="$crName" --docker-password={replace the password} --docker-email=my@email.com
```
- The password is what you get while running the *az acr credential show*
- The email can be anything.

Now we are going to create a deployment object using kubectl run. As *imagePullSecrets* can not be added in the command line of creating the deployment object (or pod object), I would use *--dry-run* option with *-o yaml* to only generate the yaml.

```powershell
kubectl run g5 --image="$crServerName/ktest-dotnetcore-webapp-docker-image:latest" --replicas=2 --port=80 --dry-run -o yaml >g5.yaml
```
Now, we need to add the *imagePullSecrets* at the same level of *containers*.

The final yaml would be like:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    run: g5
  name: g5
spec:
  replicas: 1
  selector:
    matchLabels: 
      run: g5
  template:
    metadata:
      labels:
        run: g5
    spec:
      containers:
      - image: testcr{some numbers}.azurecr.io/ktest-dotnetcore-webapp-docker-image:latest
        name: g5
        ports:
          - containerPort: 80
      imagePullSecrets:
        - name: myregistrykey

```

And now we can create the deployment object using our yaml file.
```powershell
kubectl apply -f g5.yaml
```

The last step is exposing the port 8080 using a *load balancer* service.
```powershell
kubectl expose deployment g2 --type=LoadBalancer --name=glb --port=8080 --target-port=80
```

That's it. You can now browse the application on http://localhost:8080.


---

You might prefer to only create a *pod*. The only difference is add *--restart=Never* in *kubectl run* command and remove the *--replicas*:

```powershell
kubectl run g3 --image="$crServerName/ktest-dotnetcore-webapp-docker-image:latest" --restart=Never --port=80 --dry-run -o yaml >g3.yaml
```

Similarly, edit the yaml file and add under spec add 
``` yaml
      imagePullSecrets:
        - name: myregistrykey
```

and then create the object.
```powershell
kubectl apply -f g3.yaml
```

The exposing step would be the same just saying *pod* instead of *deployment*.

```powershell
kubectl expose pod g3 --type=LoadBalancer --name=glb --port=8080 --target-port=80
```