Top 3 reasons to use Docker (with Kentico Xperience)
Tags: docker, xperience, kentico, dotnet
Published: 2021-01-31 10:03:20

## Introduction
Ever since .NET Core was released I've always wanted to do something with Docker. In my daily work I haven't had the chance yet, since the Kentico CMS we work with relies on .NET Framework and there are no major benefits of running that in Docker.

Luckily, a new version of Kentico, now Kentico Xperience 13, came with .NET Core support! 🎉 In this post I'll show you how to setup Docker with Kentico Xperience 13 and what the benefits of using Docker are.

## What is Docker?
Docker is a platform for developing, deploying and running applications. Docker seperates your application from it's underlying infrastructure so you don't have to configure the hosting environment. That's a huge plus for me, since most developers don't really like to do that anyway. It relies on virtualization technology like Hyper-V, but has many optimizations which make it faster and better than most virtualization technologies out there.

## Docker's architecture
Docker's architecture consists of a few major elements.

![Image of Docker architecture](https://docs.docker.com/engine/images/architecture.svg)

### 📷 Image 
An image is basically an instruction on how to create a container. Most of the times, you will use another image to build your own image. A good example of this is the .NET Core SDK. When creating a Docker image of your .NET Core application, you will reference the SDK image in order to build your application. This way you can even add a SQL Server to your image.

### 📦 Container
A container is an instance of the image that can be run on a Docker host. Containers are isolated from the host system; by default they have their own network and can't be reached externally. They also have their own file storage.

### 📜 Registry 
After an image is created it needs to be pushed to a registry. The registry can be a public registry, like Dockerhub, or a private registry from your company. 

### 🖥️ Host 
The Docker host can pull images from a registry and runs it in a Docker container. A Docker host can be either Windows or Linux, which allows you to run a .NET Core application on Linux. 

We're hosting the major part of our websites in Azure App Services, mostly in the Premium V2 tier. When we compare the prices a of Windows and Linux App Service the differences are huge. A P2V2 App Service costs around €246 a month for Windows and €142 a month for Linux; that's a 57% decrease 😱. See the [App Service pricing](https://azure.microsoft.com/en-us/pricing/details/app-service/linux/) for all prices.

Apart from the reduce in costs, which is of course great for your customers, there's another benefit of Linux applications. Developers like me love it when their application is fast and try to constantly improve the performance. What if I told you that Linux gives you a huge performance boost? Roberto Prevato wrote a [post](https://robertoprevato.github.io/More-about-Linux-vs-Windows-hosted-ASP-NET-Core-applications-in-Azure-App-Service/) about Linux vs Windows performance in Azure App Services. The results? Linux could handle about **twice** the amount of requests per second than Windows with about **half** the response time. I knew Linux was faster than Windows, but this fast? Wow! 🚀

## 🧬 Docker workflow
Alright. We've covered the basics of the Docker architecture, but how does all of this tie together? Let's find out.

1. First, we need to create an image for our application.
2. Then we need to publish this image to a registry.
3. On a Docker host, we need to pull this image from the registry and run it in a container.

That's it! It sounds complicated since there are so many parts involved, but luckily Visual Studio makes it very easy to do on your local machine. 😎

## Kentico Xperience 13 in Docker
Let's get to work 🔨 and get Kentixo Xperience 13 running in Docker!

I'm assuming you have Visual Studio 2019 and SQL Server installed on your machine. So go ahead and do that if you haven't! 🔗

### Installing Kentico
First we need to [download](https://docs.xperience.io/installation/installing-xperience) a trial for Kentico 13 Xperience and [install](https://docs.xperience.io/installation/installing-xperience) it. Make sure to choose .NET Core as development model and install the Dancing Goat 🐐 sample site on step three.

### Run the sample site
So we have everything installed now! Open the Visual Studio solution for the .NET Core site (DancingGoatCore.sln) and run it. If all goes well, you should see the Dancing🕺 Goat sample site:

![Dancing Goat](https://dev-to-uploads.s3.amazonaws.com/i/eptmx5ssrx05uiwn6n3t.png)

### Installing Docker
Now that we have the Dancing Goat website running, we can install [Docker Desktop](https://www.docker.com/products/docker-desktop). This is used as a local image registry and host we can run Docker containers on.

### Creating the image
Okay, we've got Docker running. The next step will be to create a Docker image for the application. Images can be assembled using a Dockerfile, which is a set of commands that Docker uses to build the image.

Luckily, the folks at Microsoft made it very easy for us to create a Docker image from within Visual Studio 🙌. 

Right-click the DancingGoatCore project, click on Add and click on Docker support:

![2021_01_24_1001_49](https://dev-to-uploads.s3.amazonaws.com/i/8zx88rfephb6nq66618j.png)

Choose Windows as operating system (OS) and press OK. A Dockerfile will now be created in the root of the project. This Dockerfile consists of four steps:

#### 1. Base
``` docker
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
WORKDIR /app
EXPOSE 80
```
Sets the runtime for the Docker container. In this case, the .NET Core runtime. It pulls a Docker image from Microsoft to do this. By default, the network of a Docker container is not externally accessible. Since this is a web application, port 80 is exposed and made accessible.

#### 2. Build
``` docker
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /src
COPY ["DancingGoatCore/DancingGoatCore.csproj", "DancingGoatCore/"]
RUN dotnet restore "DancingGoatCore/DancingGoatCore.csproj"
COPY . .
WORKDIR "/src/DancingGoatCore"
RUN dotnet build "DancingGoatCore.csproj" -c Release -o /app/build
```
Builds the application using the .NET Core SDK image. It uses the usual _dotnet build_ command to do this.

#### 3. Publish
``` docker
FROM build AS publish
RUN dotnet publish "DancingGoatCore.csproj" -c Release -o /app/publish
```
Runs the _dotnet publish_ command using the .NET Core SDK.

#### 4. Final
``` docker
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "DancingGoat.dll"]
```
Creates an entrypoint for the image, so Docker knows how to run it.

### Building & running the image
Now it's time to build and run the image in a container 🤩! Docker is a command-line tool, so normally we'd have to invoke two commands: one to build and publish the image, and one to run an image. Visual Studio conveniently helps us with that and added a launch configuration:

![2021_01_25_1916_20](https://dev-to-uploads.s3.amazonaws.com/i/8gyvsnph7jfh3lfs8qb2.png) 

Select it and run the application! 

![2021_01_25_1923_39](https://dev-to-uploads.s3.amazonaws.com/i/fzhfanc5nju3y9nte45b.png)

Uh-oh... a time-out 😅 and even an exception in Visual Studio:
```
CMS.DataEngine.ApplicationInitException: 'A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 0 - No connection could be made because the target machine actively refused it.)'
```
Looks like the application can't reach the database 💾

### Making the database work
Remember when I explained earlier that a Docker container is isolated from the host, even it's network? We did expose port 80 in the Dockerfile for the web server. But.. the container can't reach the SQL Server that is running on your local machine, which causes the exception.

In order to do that, we need to expose the right port on the container which is used by SQL Server, which is 1433. Go back to the Dockerfile and add this line below the _EXPOSE 80_ like:

```Docker
EXPOSE 1433
```

Save the Dockerfile and run the application again. It should work this time, won't it? 🤔

Nope, again a time-out... When I've tried running Kentico Xperience in Docker for the first time, I've really struggled with this and didn't know what caused it. The ports on the Docker image are fine, SQL Server is running, what's wrong?

Turns out that SQL Server blocks all incoming external traffic from port 1433 by default. Time to fix that! 

First, make sure to modify the _CMSConnectionString_ in the _appsettings.json_ file, so the _Data source_ is the local IP adress of your machine, with an explicit port after it: 
```
192.168.xxx.xxx,1433
```

Next, you need to allow communication through port 1433 in Windows Defender. Create an inbound rule to allow TCP traffic through port 1433.

Finally, we need to tweak some SQL Server settings. Press _CTRL+R_ and execute _compmgmt.msc_. In the menu on the left, go to this particular entry:

![2021_01_25_1947_02](https://dev-to-uploads.s3.amazonaws.com/i/h997u4bnozbue7qbz5m5.png)

Right-click on TCP/IP in the middle and set _Enabled_ to _Yes_. In the same window, select the _IP Addresses_ tab and look for the _IPAll_ group and set the TCP port to 1433:

![2021_01_25_1949_38](https://dev-to-uploads.s3.amazonaws.com/i/gnlqrp2lx5a1jhmyqpqi.png)

Press _OK_ and give your machine a quick reboot 🔌.

After your machine has been rebooted, launch the application again and after a short wait you should be greeted with the Dancing Goat website once again 💪🏼

Ever had the problem that a new team-member couldn't get your application running, even if he followed a setup guide? With Docker, a big part of this setup is taken care of by the image. From the used .NET Core SDK, to exposed ports, filesystem configuration and environment variables. All he has to do is install Docker Desktop, check-out the Git repository containing the application and the Docker file and build it. Oh, and maybe configure some SQL Server settings. 😇 But really, that's it! No more struggles with things like .NET Core versions, IIS settings or filesystem permissions 👍

## 💡 Top 3 reasons to use Docker (with Kentico Xperience) 
You've learned what Docker is and how to set it up in a Kentico Xperience 13 website. I hope you're as excited as I am about Kentico Xperience 13 having .NET Core support, since it opens up more possibilities, like using Docker.

Using Docker has many advantages over traditional development, but these are the reasons that have the biggest impact on your team or customer:

✔️ Running Docker containers in a Linux environment in Azure reduces cost by more than **50%** 💰📉
✔️ Linux App Services in Azure are twice as fast and can handle double the requests per second 📈
✔️ New team members are setup much faster 

Thank you for your attention and have fun experimenting with Docker! 📦