In our last post we set up a new .Net Core WebApi application with a SQL Server backend, all running on Linux and Docker. This time, we will deploy our service and database to Amazon Web Services with Kontena.
Configuring Kontena on AWS
The first step is to make sure we have the Kontena CLI tool installed. After that, jump over to the AWS setup guide and follow the instructions. For your Kontena Master, you can use the t2.micro
instance size, but your Kontena Nodes must be at least t2.medium
or larger to support SQL Server's minimum RAM requirements. For this tutorial, we are going to assume you created a 2 node cluster with a Kontena grid named test
.
Docker Registry
In order for Docker to download our service's image file, we need to store it in a Docker registry. Docker offers a public registry called Docker Hub, but that is not really the best place for us to store our private Docker images. Luckily, Kontena offers an easy to set up private image registry. To set this up, we can run the following command from the terminal:
$ kontena registry create
Note that this new registry is not running over HTTPS by default, so you will need to configure Docker to trust the insecure registry registry.test.kontena.local
(Docker for Mac and Docker for Windows let you configure this via the Preferences menu).
VPN
In order for our local Docker to be able to access our new registry, we need to configure VPN access to our AWS grid. Kontena provides this out of the box using Open VPN. To create the VPN and associated config file, run the following command:
$ kontena vpn create
$ kontena vpn config > ~/kontena.ovpn
You can then use the kontena.ovpn
file in any Open VPN software. If you are on macOS we recommend TunnelBlick.
Secrets Management
One thing that we want to avoid is hard coded passwords in our kontena.yml file, specifically the SQL Server user password. Kontena's answer to this is the Kontena Vault. Using Kontena CLI and kontena.yml
we can create a password for our SQL Server instance, and assign it to an environment variable to be consumed by our application. From the terminal, run the following:
$ kontena vault write SQLSERVER_SA_PASSWORD Sup3rs3cr3t
Deploying with Kontena Stacks
Now we are finally ready to deploy our containers to the cloud. We will do this using Kontena Stacks. In order to describe our service and dependent database as a Stack, we need to make a kontena.yml file. In our root directory, create a file called kontena.yml
and edit it as follows:
stack: dotnet-example
version: 0.3.0
services:
internet_lb:
image: kontena/lb:latest
ports:
- 80:80
sqlserver:
image: microsoft/mssql-server-linux
stateful: true
ports:
- 1433:1433
environment:
ACCEPT_EULA: Y
secrets:
- secret: SQLSERVER_SA_PASSWORD
name: SA_PASSWORD
type: env
volumes:
- /var/opt/mssql
api:
image: registry.test.kontena.local/dotnet-example:latest
depends_on:
- sqlserver
build: .
hooks:
pre_build:
- name: dotnet restore
cmd: dotnet restore
- name: dotnet publish
cmd: dotnet publish -c Release -o out
environment:
SQLSERVER_HOST: sqlserver
KONTENA_LB_MODE: http
KONTENA_LB_BALANCE: roundrobin
KONTENA_LB_INTERNAL_PORT: 5000
KONTENA_LB_VIRTUAL_PATH: /
secrets:
- secret: SQLSERVER_SA_PASSWORD
name: SQLSERVER_SA_PASSWORD
type: env
links:
- internet_lb
You will notice there are 3 services here. The first one, internet_lb
, is an instance of the Kontena Load Balancer, based on HAProxy. This allows us to balance incoming HTTP traffic between multiple instances of our service running across multiple nodes.
The second service sqlserver
is our database. Note the stateful: true
line, which tells Kontena this is a stateful service that connects to some sort of hard disk storage. We also set the volumes
section because none are defined in the microsoft/mssql-server-linux
image provided by Microsoft. We also reference the password created earlier via the secrets
section.
The last service is our WebApi service, labelled here as api
. We use the depends_on
section to tell Kontena our service needs the SQL Server service to be running, and we use the environment
and secrets
section to feed the required environment variables to our application to connect to SQL Server and register with the load balancer.
Note the build
and hooks
lines on our kontena.yml
file. Using the stack API we can have Kontena restore and publish our dotnet application, as well as build and push our Docker images all in one command.
Time to build and deploy our application using the Kontena CLI tool:
$ kontena stack build
$ kontena stack install
Next, let's scale up our API service to 3 containers:
$ kontena service scale dotnet-example/api 3
Now let's test out our application. We can use a mix of Kontena CLI commands and some shell scripting to extract our public IP address and test:
$ IP=$(kontena service show dotnet-example/internet_lb | grep 'public ip' | awk '{ print $3 }')
$ curl -i http://$IP/api/products
For a little bit of fun, try modifying your Startup.cs
file to add a bit of middleware that returns the hostname of the API server.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.Use(next =>
{
return async context =>
{
// For testing, don't use this in a real production application!
context.Response.Headers.Add("X-MachineName", Environment.MachineName);
await next(context);
};
});
app.UseMvc();
}
And now let's redeploy our application:
$ kontena stack build
$ kontena stack upgrade dotnet-example kontena.yml
Now you should see the X-MachineName header rotate across all of your host nodes when making API calls.
Wrapping Up
Hopefully by now you see how easy it can be to deploy an Asp.Net Core WebApi service in the cloud. With tools like Docker and Kontena, a modern elastic microservices architecture is within reach.
Accompanying source code for this tutorial can be found at https://github.com/kontena/dotnet-example.
About Kontena
Want to learn about real life use cases of Kontena, case studies, best practices, tips & tricks? Need some help with your project? Want to contribute to a project or help other people? Join Kontena Forum to discuss more about Kontena Platform, chat with other happy developers on our Slack discussion channel or meet people in person at one of our Meetup groups located all around the world. Check Kontena Community for more details.
Image Credits: photography of brown wooden handled stair by Mike Wilson.