Windows Containers on ECS – Part 2

BLOG ARTICLE

Time to go from theory to practice; following on from Part 1 Windows Containers on ECS, in this post I’ll demonstrate how to implement a Windows container workload.

Example Windows Workload in ECS

There are plenty of examples out there of running IIS or even SQL Server in containers — Microsoft provides base images for them, but a better example of a real-world business application running in a container might have a number of specific needs:

  • it probably has a GUI, even though we won’t be able to interact with it;
  • it probably uses some kind of remote storage (for example, an SQL Server database)
  • it almost certainly uses the registry
Setting the scene: our fake application

Without going to the extent of actually creating such an application from scratch, let’s consider an example application for pretend company FooCorp.

FooCorp have an inventory management system called “Invento” that was written in-house. It’s been running on-premises on its own physical server for years now. It uses SQL Server for its back-end database, which runs on the same box, and to which it authenticates using SQL Server authentication, instead of Windows authentication (i.e. it uses a username/password). These credentials are stored in the registry. Thankfully, some time ago, the system was adapted to have a web services REST interface as well as the GUI, so that it could be used by remote offices without having to RDP over low-bandwidth links.

A diagram of the current architecture might look like this:

diagram of current architecture

FooCorp have decided that they need to modernise their infrastructure and migrate to cloud, in order to reduce their on-premises costs and reduce some of the frequent downtime the application experiences due to old hardware, and reboots for patching and maintenance.

The ECS Redesign

To provide the highest availability for the application, FooCorp have chosen to move the SQL Server database to RDS, running in a Multi-AZ configuration.

The Invento application will be containerised, and will run on an ECS platform with worker nodes in an AutoScaling Group (ASG) that spans multiple availability zones. Because only one instance of the application can run at any time, there’s no point in having multiple worker nodes running constantly so to control costs, the ASG will be set to a desired capacity of 1 node.

Because the application has to process RESTful API queries, a load balancer is placed in front of the worker nodes so that a consistent endpoint can be used by the remote offices.

The overall architecture looks like this:

Containerising the Application

In order to containerise the application, the following things need to be done:

  • create a wrapper script which takes environment variables and sets the SQL Server username and password in the registry of the container, and then starts the Invento application
  • build a windows container image with the Invento application binaries in it, runtime dependencies for the application, and the wrapper script
  • publish the container images to the Elastic Container Registry (ECR) in FooCorp’s AWS account
  • create an ECS Task Definition which sets:
    • the container image to run
    • the ports to expose from the container
    • the amount of CPU and memory required for the container
    • the runtime environment, including the database username and password filled in automatically from Secrets Manager
  • create an ECS Service which sets the number of replicas of the Task Definition to run (which will be 1)

An example Dockerfile for this pretend application could look like this:

FROM mcr.microsoft.com/windows/servercore:1809

ADD scripts/install-chocolatey.ps1 scripts/start.ps1 c:/

ARG NUGET_PROVIDER_MIN_VERSION=2.8.5.201
# Install the AWS tools for powershell, used by the wrapper
RUN Install-PackageProvider -Name NuGet -MinimumVersion $env:NUGET_PROVIDER_MIN_VERSION -Force
RUN Install-Module -Name PowerShellGet -Force -SkipPublisherCheck
RUN Install-Module -Name PackageManagement -Force -SkipPublisherCheck
RUN Install-Module -Name AWS.Tools.Installer -Force -SkipPublisherCheck
RUN Install-AWSToolsModule AWS.Tools.SecretsManager -CleanUp -Force

# Add external dependencies
RUN c:/install-chocolatey.ps1
RUN choco install msoledbsql vcredist2015 dotnet4.5.2 7zip sql2008r2.nativeclient -y
ARG INVENTO_VERSION=3.14.5

# Add the application installer and unpack it
ADD invento-${INVENTO_VERSION}.exe c:/
RUN 7z x invento-${INVENTO_VERSION}.exe

# Set the container to start the wrapper script
ENTRYPOINT ["powershell", "-Command", "$ErrorActionPreference = 'Stop';
$ProgressPreference = 'SilentlyContinue';", “/start.ps1”]

There are a few things to remember about this approach:

  • rebuilding the container to update to a new version of the application is as simple as providing a new version; only the layers after the version change need to be rebuilt, so the windows base image, the various powershell modules, and the chocolatey packages do not need to be re-downloaded
  • the installer is only extracted (or run) once — when the container is being built. The installer does not need to run every time the container starts up
  • the wrapper script (start.ps1) needs to take care of all the application initialisation steps, including setting any registry keys appropriately
  • when the wrapper script runs, it needs to wait for the application process to exit; the lifecycle of the container is tied to the lifecycle of the wrapper script.
Deploying the Infrastructure

The infrastructure deployment is possible via a number of methods, but our preferred and recommended way is to use CloudFormation which allows for repeatable, controlled infrastructure-as-code deployments of almost all AWS services.

CloudFormation can define and deploy the RDS instances, the AutoScaling Groups, and all the required network configurations as well as setting up automated backups for RDS, defining the secrets rotation policies, and setting up the configurations to have logs and metrics shipped from the running application container into CloudWatch.

Conclusion

Windows Containers are a mature and robust technology that can be used successfully to increase compute resource utilisation safely and rapidly while controlling licensing costs. Amazon Elastic Container Service (ECS) is the most straightforward container orchestration framework available today, and it has full support for Windows-based container workloads.

If your organisation is interested in exploring more about containerised Windows applications, please contact Cevo today to discuss your needs.