Microsoft Workloads on AWS

Containerizing Complex Multi-tier Windows Applications using AWS App2Container

Many enterprises want to rapidly containerize and migrate their existing legacy applications to the cloud. That’s why AWS launched AWS App2Container in June 2020, a service that helps customers containerize ASP.NET and Java applications without making any code changes. App2Container allows customers to easily containerize and deploy an existing application to Amazon Elastic Container Service (Amazon ECS), Amazon Elastic Kubernetes Service (Amazon EKS), or AWS App Runner.

Since the launch of AWS App2Container, customers have been asking for the ability to containerize complex multi-tier Windows applications running on Windows Server hosts. In addition to containerizing ASP.NET applications deployed on a single host, beginning with version 1.5 of App2Container, customers can now containerize the following types of applications –

  • Multi-tier Windows applications – Using App2Container, customers can now specify dependencies on applications running on different Windows servers. App2Container deploys these applications on Amazon ECS or Amazon EKS services, and creates network resources for the communication between these applications.
  • Windows services – App2Container can now containerize Windows services and deploy them into AWS container services.
  • Cooperating applications on the same host – App2Container can now containerize multiple applications running on the same host into a single container. This is useful for scenarios where you have to group applications and run them in the same container. Examples include reverse-proxy in front of your application, and instance-local caches.

In this blog, we walk through the process of containerizing a multi-tier application using App2Container and deploying each tier in its own Amazon ECS service.

Sample Multi-Tier Application Architecture

The following diagram illustrates a simplified version of a multi-tier application architecture.

Multi-tier Application Architecture

Figure 1: Multi-tier Application Architecture

Here are details of the multi-tier application architecture.

  • Server A is a Windows Server running Application 1, which is an internet facing ASP.NET IIS website.
  • Server B is a Windows Server running two applications –
    • Application 2 is an internal ASP.NET IIS website.
    • Application 3 is another internal ASP.NET IIS website accessible only on the same server that is, accessible only to Application 2 in this case.
  • Server C is a Windows Server running Application 4, which is a Windows Service.

Target Architecture in AWS

The following diagram showcases the target architecture on AWS when the sample multi-tier application is containerized and deployed to Amazon ECS:

Multi-tier Application Architecture on AWS

Figure 2: Target Architecture in AWS

The following numbers correspond to the numbers in Figure 2.

  1. Application 1 (ASP.NET IIS Website) runs in a container as an Amazon ECS service on an Amazon ECS cluster.
  2. An internet-facing Application Load Balancer sends requests from users to Application 1.
  3. Application 2 (ASP.NET IIS Website) and Application 3 (ASP.NET IIS Website) are running in a single container, and are deployed as an Amazon ECS service on the same Amazon ECS cluster.
  4. An internal Application Load Balancer sends traffic to Application 2. Application 2 communicates with Application 3 inside of the same container.
  5. Application 4 (Windows Service) runs in its own container as an Amazon ECS service on the same Amazon ECS cluster.
  6. An internal Application Load Balancer sends traffic to Application 4.
  7. An Amazon Route 53 private hosted zone is deployed inside the Amazon VPC with DNS entries for Application 2 and Application 4. It enables Application 1 to send requests to Application 2 and Application 4 using an internal domain name.

Containerizing and Deploying to AWS

To containerize and deploy the multi-tier application to the target architecture on AWS using App2Container, we perform the following steps

  1. Containerize Application 2 and Application 3 to run in the same container – Both applications are ASP.NET IIS applications. We specify Application 3 as an additional application in the App2Container configuration for Application 2, so that App2Container generates a Dockerfile and container image that include both Application 2 and Application 3.
  2. Containerize Application 4 – Application 4 is a Windows Service. We use App2Container to containerize this application.
  3. Containerize Application 1 – Application 1 is the main internet facing ASP.NET IIS application. We use App2Container to containerize it.
  4. Run App2Container commands, using the automatic deployment option to deploy the applications to Amazon ECS. By specifying Application 2 and Application 4 as dependencies of Application 1, we use App2Container to deploy Application 1 as an internet-facing Amazon ECS service, along with Application 2 and Application 4 as Amazon ECS services that are privately accessible by Application 1.

Prerequisites

Step 1: Containerize Application 2 and Application 3 in the same container (ASP.NET IIS Applications)

Let’s containerize Application 2 (ASP.NET IIS Application) and specify Application 3 (ASP.NET IIS Application) as an additional application to be included in the same container.

  1. Run the remote inventory command on the worker machine, specifying the IP Address or FQDN of Server B with the –target option.
app2container remote inventory --target ServerB_IP or FQDN --type iis

App2Container added a new command line option –type in version 1.5. It has two valid values at this time for Windows applications –

  • iis – Use this value to generate an inventory of IIS applications on the target server.
  • service – Use this value to generate an inventory of Windows services on the target server.

The –type option is optional. If it is not specified, App2Container returns both IIS applications and Windows services.

The example command returns a list of IIS sites that are eligible for containerization. Please note that App2Container generates a unique ID for each application (e.g. – iis-app2-e54800c3)

  1. Run the remote analyze command from the worker machine, specifying the IP Address or FQDN of Server B with the –target parameter, and the application ID for Application 2.
app2container remote analyze --application-id Application2_ID --target ServerB_IP or FQDN

This command creates a file called analysis.json for Application 2. You can edit fields in the analysis.json file to customize your application container. For more information, see Configuring application containers in the AWS App2Container User Guide.

In version 1.5, App2Container added a new section called additionalApps in analysis.json. Applications listed in the additionalApps section are included in the same container as the primary IIS application being containerized.

There are some considerations for applications listed in the additionalApps section –

  • All applications listed in the additionalApps section should be running on the same Windows Server as the primary IIS application being containerized.
  • Since these applications share the container with the main application, App2Container creates the artifacts necessary to package them into the same container, but does not provision network resources such as Application Load Balancers. Once deployed, only the primary IIS application will be accessible through an Application Load Balancer, but not the applications listed in the additionalApps section.

Let’s add the application ID for Application 3 in the additionalApps section.

{
"a2CTemplateVersion": "1.0",
"createdTime": "2021-04-21-00:43:28",
"containerParameters": {
…
"additionalApps": {
"iis-app3-e54800c3"
},
…
}
  1. To extract all of the necessary artifacts to containerize the application, run the following command.
app2container remote extract --application-id Application2_ID --target ServerB_IP or FQDN
  1. App2Container can now containerize the application directly from the worker machine. Run the following command.
app2container containerize -—input-archive C:\Workspace\remote\ServerB_IP or FQDN\Application2_ID\Application2_ID.zip

When this command runs, App2Container generates three important artifacts –

  • deployment.json – This can be found at <workspace>\Application2_ID.This file contains options for supported deployment destinations. For more information, see Configuring container deployment in the AWS App2Container User Guide.
  • Dockerfile – The Dockerfile generated by App2Container ensures that any applications listed in the additionalApps section of the analysis.json file are included in the same container as the primary IIS application. You can customize the Dockerfile in the following directory <workspace>\Application2_ID\Artifacts\ to suit your needs.
  • Container image – App2Container creates a container image containing the application(s) listed in analysis.json.

Step 2: Containerize Application 4 (Windows Service)

Let’s look at the steps involved in containerizing Application 4, which is a Windows service.

  1. Run the remote inventory command on the worker machine, specifying the IP Address or FQDN of the Server C (server running the Windows service) with the –target
app2container remote inventory --target ServerC_IP or FQDN --type service

We are using the new command line option –type with a value of service. This command displays a list of Windows services that are eligible for containerization. Please note that App2Container generates a Unique ID for each service, for example: service-app4-e719898e4.

By default, App2Container filters out some system services to reduce the number of services listed in the inventory results. If you can’t find your service in the list, you can try the –nofilter option to list all services.

  1. Run the remote analyze command from the worker machine, specifying the IP Address or FQDN of ServerC_IP with the –target option.
app2container remote analyze --application-id Application4_ID --target ServerC_IP or FQDN

This command creates a file called analysis.json for the application or service specified in the –application-id parameter.

{
"a2CTemplateVersion": "1.0",
"createdTime": "2021-04-27-20:08:10",
"containerParameters": {
"_comment": "*** EDITABLE: The below section can be edited according to the application requirements. Please see the Analysis Results section further below for details discovered regarding the application. ***",
"containerBaseImage": " mcr.microsoft.com/dotnet/framework/runtime:4.8-windowsservercore-ltsc2019",
"enableServerConfigurationUpdates": true,
"imageRepositoryName": " service-app4-9dec7519",
"imageTag": "latest",
"additionalExposedPorts": [

],
"appIncludedFiles": [

],
"appExcludedFiles": [

],
"enableLogging": false
},
"analysisInfo": {
"_comment": "*** NON-EDITABLE: Analysis Results ***",
"hostInfo": {
"os": "Microsoft Windows Server 2019 Datacenter",
"osVersion": "10.0.17763",
"osWindowsDirectory": "C:\\Windows",
"arch": "64-bit"
},
"appId": "service-app4-9dec7519",
"appServerIp": "localhost",
"appType": "service",
"appName": "windowsService",
"ports": [
{
"localPort": 87,
"protocol": "http"
}
],
"serviceName": "app4",
"serviceBinary": "app4.exe",
"serviceDir": "C:\\Program Files\\app4\\bin\\Release\\" 
…
}
}

Let’s look into fields in analysis.json that are important in containerizing a Windows service.

  • containerBaseImage is the Windows base image from Microsoft Container Registry. You can change it to other Windows images or your own custom Windows base image. However, the Windows version on the base image must match the Windows version on your Amazon ECS cluster (or Amazon EKS cluster).
  • imageRepositoryName is the name of the Amazon Elastic Container Repository (Amazon ECR) that App2Container creates to store the container image.
  • ports contain a list of ports that App2Container detects as being used by your application. You can change this value based on your knowledge of the application.
  • additionalExposedPorts can be used to expose additional ports on your container.
  • serviceName is the name of the Windows service.
  • serviceBinary is the name of the executable that runs as the Windows service.
  • serviceDir is the absolute path of the directory that the Windows service runs from. App2Container copies this directory into the container image during containerization.
  • appIncludedFiles can be used to specify additional files to be copied into the container.
  • appExcludedFiles can be used to specify that certain files be excluded from the container.
  1. To extract all of the necessary artifacts to containerize Application 4, run the following command.
app2container remote extract --application-id Application4_ID --target ServerC_IP or FQDN
  1. App2Container can now containerize the application. Run the following command.
app2container containerize -—input-archive C:\Workspace\remote\ServerC_IP or FQDN\Application4_ID\Application4_ID.zip

When you run this command, App2Container generates three important artifacts –

  • deployment.json – This can be found at <workspace>\Application4_ID.This file contains options for supported deployment destinations. For more information, see Configuring container deployment in the AWS App2Container User Guide.
  • Dockerfile – As we are containerizing a Windows service in this step, App2Container generates a Dockerfile for a Windows service. You can customize the Dockerfile in the directory <workspace>\Application4_ID\Artifacts\ to suit your specific application requirements.
  • Container image – App2Container creates a container image containing the application listed in analysis.json.

Step 3: Containerize Application 1 (ASP.NET IIS Application)

  1. Since Application 1 directly communicates with Application 2 and Application 4, it will have URLs for Application 2 and Application 4 stored as configuration. The configuration store could be a configuration file (Web.config) or a configuration store (such as AWS Systems Manager Parameter Store). When App2Container containerizes the application group in our example, it will create internal Application Load Balancers for distributing traffic among containers. We should update the configuration of Application 1 to refer to a private endpoint. The domain for this endpoint does not need to exist. As part of deployment, App2Container creates a Route 53 hosted zone and DNS entries to configure this internal domain.

For this example, we use the following values –

  • Application 2
    • Private Root Domain – aws.demo.internal
    • DNS Entry – app2
  • Application 4
    • Private Root Domain – aws.demo.internal
    • DNS Entry – app4

 

Based on the values, we change our Web.config as follows:

Existing config:

<appSettings>
<add key="app2" value="http://serverB/" />
<add key="app4" value="http://serverC/" />
</appSettings>

New config:

<appSettings>
<add key="app2" value="http://app2.aws.demo.internal/" />
<add key="app4" value="http://app4.aws.demo.internal/" />
</appSettings>

The new URL is a combination of the Private Root Domain and the DNS entry prefix. This change should be applied before containerizing the application.

  1. Run the remote inventory command on the worker machine specifying the IP Address or FQDN of Server A with the –target option.
app2container remote inventory --target ServerA_IP or FQDN --type iis

This command displays a list of IIS sites that are eligible for containerization. Please note the application ID for Application 1.

  1. Run the remote analyze command from the worker machine, specifying the IP Address or FQDN of Server A with the –target option, and the Application ID for Application 1.
app2container remote analyze --application-id Application1_ID --target ServerA_IP or FQDN

This command creates a file called analysis.json for Application 2. You can edit fields in the analysis.json file to customize your application container. For more information, see Configuring application containers in the AWS App2Container User Guide.

  1. To extract all necessary artifacts to containerize the application, run the following command.
app2container remote extract --application-id Application1_ID --target ServerA_IP or FQDN
  1. App2Container can now containerize the application. Run the following command.
app2container containerize -—input-archive C:\Workspace\remote\ServerA_IP or FQDN\Application1_ID\Application1_ID.zip

Step 4: Deploy Applications

Let’s examine the deployment.json file created by containerizing Application 1 in Step 3.

{
"a2CTemplateVersion": "1.0",
"applicationId": "iis-app1-e54800c3",
"imageName": "iis-app1-e54800c3",
"exposedPorts": [
{
"localPort": 86,
"protocol": "http"
}
],
"environment": [],
"ecrParameters": {
"ecrRepoTag": "latest"
},
"ecsParameters": {
"createEcsArtifacts": true,
"ecsFamily": "iis-app1-e54800c3",
"cpu": 2,
"memory": 4096,
"dockerSecurityOption": "",
"enableCloudwatchLogging": false,
"publicApp": true,
"stackName": "a2c-iis-app1-e54800c3-ECS",
"resourceTags": [
{}],
"reuseResources": {
"vpcId": "vpc-0ebe8de1c1479f33f",
"reuseExistingA2cStack": {
"cfnStackName": "",
"microserviceUrlPath": ""
},
"sshKeyPairName": "",
"acmCertificateArn": ""
},
"gMSAParameters": {
"domainSecretsArn": "as",
"domainDNSName": "a.com",
"domainNetBIOSName": "ads",
"createGMSA": true,
"gMSAName": "account1"
},
"dependentApps" : [ 
{
"appId":"iis-app2-sf800cde",
"privateRootDomain": "aws.demo.internal",
"dnsRecordName":"app2"
},
{
"appId":"service-app3-9dsge90o",
"privateRootDomain": " aws.demo.internal",
"dnsRecordName":"app3"
}
]
},
"eksParameters": {
"createEksArtifacts": false,
"stackName": "a2c-iis-app1-e54800c3-EKS",
"reuseResources": {
"vpcId": "",
"reuseExistingA2cStack": {
"cfnStackName": ""
},
"sshKeyPairName": ""
},
"gMSAParameters": {
"domainSecretsArn": "",
"domainDNSName": "",
"domainNetBIOSName": "",
"createGMSA": false,
"gMSAName": ""
},
"dependentApps" : []
}
}
  1. In deployment.json, the following Boolean parameters indicate which container management service App2Container should deploy to. There can be exactly one that has a value of true –
    1. createECSArtifacts: true
    2. createEKSArtifacts: false

Since we are deploying to Amazon ECS, createECSArtifacts is set to true and createEKSArtifacts is set to false.

  1. In order to create a public Application Load Balancer for Application 1, set the publicApp parameter inside the ecsParameters section to true.
  2. The ecsParameters and eksParameters sections contain a new sub-section called dependentApps. This section contains details for private applications that Application 1 connects to. Since we are deploying to Amazon ECS, configure the dependentApps array in the ecsParameters section with details for Application 2 and Application 4.
"dependentApps" : [ 
{
"appId":"iis-app2-sf800cde",
"privateRootDomain": "aws.demo.internal",
"dnsRecordName":"app2"
},
{
"appId":"service-app4-9dsge90o",
"privateRootDomain": " aws.demo.internal",
"dnsRecordName":"app4"
}
]
  • appId –Identifies the dependent application to deploy.
  • privateRootDomain – App2Container creates an Amazon Route 53 private hosted zone attached to the VPC listed in deployment.json. It uses this value to create the root domain for the hosted zone.
  • dnsRecordName – This field represents a CNAME record that App2Container creates for each application inside of the Route 53 private hosted zone. The CNAME record points to the private Application Load Balancer that App2Container creates for this application.
  1. Run the app2container generate app-deployment command. It generates the artifacts needed to deploy your containerized application in AWS. This command accesses AWS resources to generate and deploy artifacts to your target environment. If you use the –deploy option, App2Container deploys the artifacts.Ensure that your IAM user has the permissions to deploy these artifacts. See AWS Identity and Access Management in App2Container for more information about setting up IAM users for App2Container.
app2container generate app-deployment --application-id Application1_ID --deploy

When this command runs, App2Container deploys the following resources –

  • For the first application in dependentApps (Application 2), App2Container creates the VPC, Amazon ECS Cluster, Amazon ECS Task Definition, Amazon ECS Service and internal Application Load Balancer. In addition, it creates a Route 53 private hosted zone in the VPC, using the value of privateRootDomain, and adds a CNAME record for the application, using the value of dnsRecordName.
  • Since Application 3 was listed in the additionalApps section in json for Application 2, App2Container containerizes Application 3 to run inside of the same container as Application 2.
  • For each additional application in dependentApps (Application 4), App2Container creates the following resources –
    • A new Amazon ECS Task Definition and Amazon ECS Service. App2Container reuses the Amazon ECS cluster that it created for Application 2, to run the new Amazon ECS service for Application 4.
    • An internal Application Load Balancer inside of the VPC that was previously created.
    • A CNAME record inside of the previously created Route 53 private hosted zone.
  • App2Container deploys the main application (Application 1). It creates a new Amazon ECS Task Definition and Amazon ECS Service, and reuses the Amazon ECS cluster created previously, to run the Amazon ECS service. This time, the Application Load Balancer that it creates is internet-facing, since we set publicApp to true.

 

Conclusion

In this blog, we walked through how to containerize and deploy a multi-tier application to Amazon ECS using AWS App2Container. App2Container accelerates the containerization of both ASP.NET applications and Windows Services. In addition, it generates deployment artifacts and automates deployment for a group of applications.

For a hands-on experience with App2Container, check out the Modernize with AWS App2Container Workshop.


AWS can help you assess how your company can get the most out of cloud. Join the millions of AWS customers that trust us to migrate and modernize their most important applications in the cloud. To learn more on modernizing Windows Server or SQL Server, visit Windows on AWS. Contact us to start your migration journey today.

Neeraj Handa

Neeraj Handa

Neeraj Handa is a Solutions Architect at Amazon Web Services. He is passionate about application architecture, and specializes in helping customers modernize their applications on AWS.