.NET Core is a subset of the .NET framework, but unlike .NET, it is cross platform. This means that .NET Core applications can be run on any operating system - Linux, Windows, or macOS

Bitnami Stacksmith is a tool that automates packaging and optimizes your application for deployment in clouds as well as in containers. It can be used in new application development (as I demonstrate here) as well as with legacy applications, to ease re-platforming the application from a data center to the cloud.

This is the first post of a set of two blog posts in which we are covering the whole process to prepare, package, migrate, and deploy a .NET Core application to the cloud using Stacksmith.

This post, focuses on preparing a .NET Core application to run in the cloud or a Kubernetes cluster, using Linux as the operating system. In a follow-on post, I use Stacksmith to build the deployable artifacts that can be used to launch the application.

If you already have your application prepared, then skip this blog post and go directly to the second part: Packaging a NET Core Application using Stacksmith to deploy it.

What is Stacksmith and how does it work?

Stacksmith allows applications to be packaged for multiple environments. In this article, I focus on Microsoft Azure and Kubernetes. Packaging a .NET Core application for AWS follows the exact same process, the only difference being how the solution is launched inside each of the clouds.

Stacksmith also simplifies maintaining the application after it is deployed. Stacksmith continuously monitors trusted package and code repositories and alerts you when patches and security updates become available. It provides simple (click "update") and automated (supports continuous updating) ways to maintain your applications, ensuring they stay up-to-date and secure. In this article, I focus on the packaging piece of Stacksmith functionality.

Stacksmith provides a set of "stack templates" designed to package specific application types. Each template is optimized for each available cloud as well as for containers. Stacksmith also includes a generic template that provides more flexibility if needed.

For this example I use the ".NET Core application with DB (MySQL)" stack template. The templates are designed to use cloud-native resources best suited for the chosen stack template. In my example, it uses a fully-managed database provided by the cloud vendors - Azure Database for MySQL for the Azure cloud.

The following image shows the Stacksmith workflow:

Stacksmith workflow

Preparing the .NET Core application for migration

Stacksmith enables migrating almost any .NET Core application. By default, Stacksmith ensures that the assets it creates (images and deployment templates) include the .NET Core runtime and that everything is configured to run the application on the chosen platform.

In order to package the sample .NET Core application, I require the following artifacts:

  • Compiled version of the application - the output of building and performing the publishing step for the application.
  • Boot script that is run whenever a virtual machine (VM) or container is started. The script performs additional application configuration.

Note that Stacksmith also supports additional scripts, such as a build script that can be run at build time to install additional dependencies, such as additional system packages, specific agents and/or monitoring tools. However, if the application does not have any external dependencies, a build script is not needed.

For the purpose of this article I use a Sample .NET Core TO-DO application that uses a MySQL database for persisting its data. The source code for the application can be obtained here.

In the following sections, I explain how to prepare the compiled version of the application and what the boot script for this specific application does. I also provide a detailed description of what each file is and how it can be created for any application. Pre-built files for the sample TO-DO application can also be downloaded from the following links:

Compiling application from source code

In order to compile the application from source code:

  1. Clone the stacksmith-examples repository.
  2. Go to the dotnet-core-with-mysql/todo/app subfolder.

The application can be built in redistributable format either from Visual Studio or directly from command line. The output is a folder containing the compiled version of the application along with all its dependencies.

Compiling the application from Visual Studio

To build the application in Visual Studio, open the AspNetCoreTodo.csproj project file and perform the following:

  1. Navigate to the "Build" menu and choose the "Configuration Manager" option.
  2. Ensure that in the "Configuration" section, the "Release" option is selected.
  3. Go to the "Build" menu and choose "Publish AspNetCoreTodo".
  4. Choose "Folder" as the publishing method.
  5. Click "Publish".

The output is stored in the folder that was chosen in step 4, which defaults to bin/Release/PublishOutput.

Compiling the application from the command line

To build the application from the command line, ensure that you have .NET Core SDK installed. Next, run the dotnet publish command:

C> dotnet publish -c Release

The above command works on all operating systems (such as macOS, Linux, and Windows).

The output is stored in the bin/Release/netcoreapp2.0/publish folder.

Application configuration

The next artifact to prepare is the boot script. This is code that is run before the .NET Core application is started. It can be used to perform setup tasks that can only be done at run time.

The sample TO-DO application that I am packaging requires this script to perform the following two things:

  1. Configure the application so that it knows how to connect to the MySQL database.
  2. Ensure the MySQL database has been properly initialized.

1. Configuring the application to connect to the MySQL database

The application stores how to connect to the database in the appsettings.json file.

The following is a sample configuration:

{
"ConnectionStrings": {
"DefaultConnection": "Server=127.0.0.1;Database=todolist;Uid=root;Pwd=root;"
},
...
}

The format of the connection string is standard for the MySQL connector for .NET and is documented in more detail in MySQL Connector/NET documentation.

Setting the value can be done by using the sed command:

sed -i \
  "s!\(DefaultConnection.*\)\"Server=.*\"!\\1\"Server=${DATABASE_HOST}\\;Database=${DATABASE_NAME}\\;Uid=${DATABASE_USER};Pwd=${DATABASE_PASSWORD}\\;\"!" \
  "${appdir}/appsettings.json"

The command replaces the entire value of DefaultConnection inside the file, taking connectivity details from the database connectivity environment variables and applying them to the DefaultConnection setting. The environment variables are DATABASE_USER, DATABASE_PASSWORD, DATABASE_HOST and DATABASE_NAME accordingly.

2. Initializing the MySQL database

The TO-DO application I have chosen does not deal with database schema setup on its own.

First, I will check that the script can connect to the database using a simple SQL query: SELECT 1+1. Next I will verify whether the database was already initialized. This can be checked by testing if the Items table exists - it is a table in which the application stores the list of items. If the table does not exist, I will import the schema.

Here’s how this can be implemented:

# ensure database can be reached
mysql --ssl "-u${DATABASE_USER}" "-p${DATABASE_PASSWORD}" "-h${DATABASE_HOST}" "${DATABASE_NAME}" -e "SELECT 1+1;"

# check if the Items database table exists by invoking a query counting all items
if ! mysql --ssl "-u${DATABASE_USER}" "-p${DATABASE_PASSWORD}" "-h${DATABASE_HOST}" "${DATABASE_NAME}" -e "SELECT COUNT(*) FROM Items;" ; then
     # if the database did not exist, import the SQL file with schema
  mysql --ssl "-u${DATABASE_USER}" "-p${DATABASE_PASSWORD}" "-h${DATABASE_HOST}" "${DATABASE_NAME}" -B <"${appdir}/mysql-schema.sql"
fi

The command uses the same database connectivity environment variables.

For reference, here’s the complete boot script source code:

#!/bin/bash

readonly appdir="/opt/app"

set -euo pipefail

# configure the connection for .NET Core application
sed -i \
  "s!\(DefaultConnection.*\)\"Server=.*\"!\\1\"Server=${DATABASE_HOST}\\;Database=${DATABASE_NAME}\\;Uid=${DATABASE_USER};Pwd=${DATABASE_PASSWORD}\\;\"!" \
  "${appdir}/appsettings.json"

# ensure database can be reached
mysql --ssl "-u${DATABASE_USER}" "-p${DATABASE_PASSWORD}" "-h${DATABASE_HOST}" "${DATABASE_NAME}" -e "SELECT 1+1;"

if ! mysql --ssl "-u${DATABASE_USER}" "-p${DATABASE_PASSWORD}" "-h${DATABASE_HOST}" "${DATABASE_NAME}" -e "SELECT COUNT(*) FROM Items;" ; then
mysql --ssl "-u${DATABASE_USER}" "-p${DATABASE_PASSWORD}" "-h${DATABASE_HOST}" "${DATABASE_NAME}" -B <"${appdir}/mysql-schema.sql"
fi

The script can also be seen in the stacksmith-examples repository.

In the second part of this post, I will show you how to use Stacksmith to package the compiled version of the application along with the boot script so it can be deployed in Azure cloud as well as in Kubernetes: