Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / containers / docker

Dockerize ASP.NET Boilerplate Projects

4.93/5 (20 votes)
23 Nov 2022CPOL6 min read 72.1K  
Creating a web farm on Docker container using redis, haproxy and abp module zero core template

Introduction

In this article, I will show you how to run ABP module zero core template on Docker, step by step. And then, we will discuss alternative scenarios like web farm using Redis and Haproxy.

As you know, Docker is the most popular software container platform. I won’t go into details of how to install/configure Docker on Windows or what are the advantages of using Docker. You can find related documents here. And there is a Getting Started document as well.

What is ABP Module Zero Core Template?

Module zero core template is a starter project template that is developed using ASP.NET Boilerplate Framework. This a .NET Core project as a Single Page Application with using Angular4. And also, there is a multi-page MVC application as well. But in this article, I will explain Angular4 version.

In module zero core template project, there are two separate projects, one is Angular4 project as web UI and the host project that is used by Angular UI. Let's examine it to better understand the project before running it on Docker.

Getting Started

Creating Template From Site

First, I will download module zero core template from https://www.aspnetboilerplate.com/Templates site.

Image 1

Framework: .NET Core2.0 + Single Page Web Application Angular + Include module zero
Project name: Acme.ProjectName

Before preparing project to run on Docker, let's run the project, first. I am opening the .sln file in folder ProjectName\aspnet-core.

Image 2

Creating Database Using EF Migrations

Before running project, we should create a database using EF migrations on Package Manager Console. First, I am setting Acme.ProjectName.Web.Host as start up project. (Right-click Host project and select Set as Startup Project). And then, open Package Manager Console, select default project to EntityFrameworkCore, run the command below:

update-database

After running this command, database will be created with name ProjectNameDb.

Image 3

Running Host Project

And now, Host project is ready to run. On Visual Studio Ctrl+F5. It opens swagger method index page.

Image 4

All these services are served in application layer of project and used by Angular UI.

Running Angular Project

While host is already running, we can run Angular project that uses APIs. To run Angular project, make sure you have node and npm installed on your machine.

First, run cmd on location ProjectName\angular and run the command "npm install" or just "yarn" to fetch client side packages.

Image 5

Run npm start command in the same directory to start Angular project.

Image 6

Finally, you have to see the line "webpack: Compiled successfully" in the output screen.

Image 7

We started Angular project successfully. Open your browser and navigate to http://localhost:4200/.

Image 8

Use the credentials below to login:

Username admin
Password 123qwe

After you login, you will see the screen below:

Image 9

Check HERE for more details.

To summarize what we did for running Angular project:

  • Run cmd on location ProjectName\angular.
  • Run yarn or npm install command (I used yarn for the above example).
  • Run npm start command.
  • Browse localhost:4200 to see Angular project is running.

Everything is running properly. Ready to run on Docker...

Running Project on Docker

If you have not installed Angular CLI yet, you have to install it. Run the command below to install Angular CLI.

npm install -g @angular/cli

After you ensure Angular CLI is installed, let's see files and folders to configure Docker environment. There is a folder named docker under ProjectName/aspnet-core.

Image 10

In docker/ng folder, there is a docker-compose.yml file and two powershell scripts to run docker compose(up.ps1) and stop(down.ps1) it. And there is one more folder and a powershell script file.

Image 11

This script file to build and publish host and angular project. And also, this script copies the files that is into docker folder to build folder. First, I will run the build-with-ng.ps1 script on location ProjectName/aspnet-core/build.

Image 12

After running script, when you look at the build folder, you will see the outputs folder.

Image 13

Before running up.ps1 command:

  • You have to share the drives. To share it, right click Docker system tray, go to Settings, navigate to shared folders and click all the drives.
  • Database is hosted on the local machine, not on the docker. Website hosted on Docker will be connecting to your local database. And with a trusted connection string, the connection will be unsuccessful. So set your SQL database username & password. To achieve this, modify the file "...\aspnet-core\src\Acme.ProjectName.Web.Host\appsettings.Staging.json". Update Default ConnectionStrings > "Server=10.0.75.1; Database=ProjectNameDb; User=sa; Password=<write your password>;"

Run up.ps1 script to run these two project on docker under location ProjectName/aspnet-core/build/outputs.

Image 14

Angular and host projects are now running. Browse http://localhost:9901/ for Host Project and http://localhost:9902/ for Angular UI.

Image 15

Module Zero Core Tepmlate Web Farm on Docker with Using Redis and Haproxy

Image 16

In a web farm, there is more than one web server, there is a load balancer at the front of these servers and a server to store sharing sessions/caches.

In our example, Angular application will be client, haproxy will be load balancer, host app will be web servers and redis will be shared server.

Create a configuration file for haproxy named haproxy.cfg to location ProjectName\aspnet-core\docker\ng.

haproxy.cfg

(Copy paste code lines makes encoding problem just download the file => Download haproxy.cfg)

global
    maxconn 4096
    
defaults
    mode http
    timeout connect 5s
    timeout client 50s
    timeout server 50s
    
listen http-in
    bind *:8080
    
    server web-1 outputs_abp_host_1:80
    server web-2 outputs_abp_host_2:80
    
    stats enable
    stats uri /haproxy
    stats refresh 1s

Important lines haproxy.cfg are server web-1 and server web-2. I repreduced host applications. This will create two host applications on docker container.

Modified docker-compose.yml.

(Copy paste code lines makes encoding problem just download the file => Download docker-compose.yml)

version: '2'

services:

    abp_redis:
        image: redis
        ports:
            - "6379:6379"

    abp_host:
        image: abp/host
        environment:
            - ASPNETCORE_ENVIRONMENT=Staging
        volumes:
            - "./Host-Logs:/app/App_Data/Logs"

    abp_ng:
        image: abp/ng
        ports:
            - "9902:80"
            
    load_balancer:
        image: haproxy:1.7.1
        volumes:
            - "./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg"
        ports:
            - "9904:8080"

build-with-ng.ps1

Replace the below line:

ASP.NET
(Get-Content $ngConfigPath) -replace "21021", "9901" | Set-Content $ngConfigPath

with this line:

ASP.NET
(Get-Content $ngConfigPath) -replace "21021", "9904" | Set-Content $ngConfigPath

Now Angular UI will connect to haproxy. Haproxy distributes the requests to web servers.

Overwrite up.ps1 with the content below:

Docker
docker rm $(docker ps -aq)
docker-compose up -d abp_redis
sleep 3
docker-compose up -d abp_host
docker-compose up -d abp_ng
sleep 2
docker-compose scale abp_host=2
sleep 2
docker-compose up -d load_balancer

To use redis cache, install Abp.RedisCache library to ProjectName.Web.Core project. And update ProjectNameWebCoreModule.cs like the following:

[DependsOn(...,
     typeof(AbpRedisCacheModule))]
public class ProjectNameWebCoreModule : AbpModule
{

And adding redis cache configuration to PreInitialize method (ProjectNameWebCoreModule.cs).

C#
public override void PreInitialize()
{
    ...

    Configuration.Caching.UseRedis(options =>
    {
        var connectionString = _appConfiguration["Abp:RedisCache:ConnectionString"];
        if (connectionString != null && connectionString != "localhost")
        {
            options.ConnectionString = AsyncHelper.RunSync(() => 
                    Dns.GetHostAddressesAsync(connectionString))[0].ToString();
        }
    })
    
    ...

Add redis configurations appsettings.staging.json.

appsettings.staging.json

JSON
{
  ...,
  "Abp": {
    "RedisCache": {
      "ConnectionString": "outputs_abp_redis_1"
    }
  }
}

outputs_abp_redis_1 is the name of redis container and this name is defining by docker automatically. After this changing, host project will resolve the dns of machine that is deployed on. And now, when I run build-with-ng.ps1 and up.ps1, web farm project will run. And the result:

Image 17

As you can see, all containers are working. When you browse http://localhost:9902, you can see Angular UI is working.

How Will I Know If Haproxy and Redis Work?

There are tools to track haproxy activity (haproxy web interface) and get redis stored data (redis cli).

Haproxy Web Interface

When you browse http://localhost:9904/haproxy, you will see something like the following:

Image 18

When you navigate between on Angular application pages or run any api on host project (http://localhost:9904), you can see that the haproxy is routing the requests to different machines. You can track which machine is running under Session rate>Cur tab that are changing for web-1 and web-2.

Redis cli

To understand if redis is working, you can use redis-cli. Run docker exec -it outputs_abp_redis_1 redis-cli command to run redis-cli interactive mode to connect redis server that is running on docker container. Then to test if redis is running, write ping command and it will return PONG if it works. Now when I write keys * command, I should get the application cache keys.

Image 19

As you can see, redis is working well. Cache keys stored on redis, correctly.

Source Code

You can get the modified source code at this link on Github.

History

  • 22nd February, 2018: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)