Modernizing with AWS

Containerizing legacy ASP.NET applications using AWS App2Container (A2C)

Every day, companies are running legacy applications on top of highly scalable container architectures such as Amazon Elastic Container Service (ECS) and Amazon Elastic Kubernetes Services (Amazon EKS). This is because legacy applications, many of them Windows-based, can be difficult for companies to manage and often need a heavy infrastructure lift to maintain. Because many legacy applications are no longer receiving software updates and run on operating systems that have reached an end-of-support lifecycle, customers are looking for new way to re-platform and manage legacy application lifecycles.

Amazon Web Services launched AWS App2Container, a service that helps customers containerize legacy applications without making any code changes.  This helps customers run legacy Microsoft applications the same way they run new applications on Amazon ECS and Amazon EKS. AWS App2Container is a client-server application that analyzes, extracts, containerizes, and deploys ASP.NET and JAVA applications on Amazon ECS or Amazon EKS—all in just few steps. On top of that, AWS offers production support for Kubernetes on Windows and fully supports Windows worker nodes, making your modernization journey seamless.

In this tutorial, we containerize an ASP.NET application called DNN Platform, which is an open-source .NET content management system built on ASP.NET and SQL Server. For this tutorial, the DNN Platform database layer has been migrated to Amazon Relational Database Service (Amazon RDS).

Prerequisites

For this tutorial, you should have:

Tutorial

The tutorial contains the following steps:

  1. Create an IAM User and Policy to be used with AWS App2Container.
  2. Install AWS App2Container in the application server
  3. Inventory and analyze the application
  4. Extract and upload the application to Amazon S3
  5. (Optional) Install AWS App2Container in the worker machine
  6. Containerize the application
  7. Generate the application artifacts to containerize the application.
  8. Launch the application on Amazon Elastic Kubernetes Services (Amazon EKS)

Step 1: Create an IAM User and Policy to be used with AWS App2Container

1. Create an IAM user in the AWS Command Line Interface by executing the following command:

New-IAMUser -Path "/ps-created-users/" -UserName "app2container"

2. Create a JSON file containing the IAM Policy that matches either Amazon EKS or Amazon ECS, using the examples on the official documentation.

3. Create the IAM Policy based on the JSON file generated on the step 2. Save the ARN value output to be used in the next step.

New-IAMPolicy -PolicyName "app2container" -policyDocument (Get-Content -Raw app2Container.json)

4. Attach the IAM policy just created in step 3 to your newly created IAM user by executing the following command:

Register-IAMUserPolicy -UserName app2container -PolicyArn arn:aws:iam::YOURACCOUNTID:policy/app2container

Step 2: Install AWS App2Container in the application server

1. Download AWS App2Container and unzip the content on the application server running the application you want to containerize.

2. Execute the install.ps1 in an elevated PowerShell session to install AWS App2Container.

3. Configure the AWS App2Container tool using your newly created IAM User and Policy with the following command:

app2container init

App2Container initiation

Now, AWS App2Container is configured and ready to be used in the application server.

Step 3: Inventory and analyze the application

1. Execute the following command to check if the target application can be containerized by AWS App2Container:

app2container inventory

All the IIS Sites capable of being containerized by the tool is displayed. It is important to note that AWS App2Container generated an UID (e.g.: iis-dnn-c5654c20) per application. The UID is used by all the next steps and has an essential role in distinguishing each application.

2. Using the UID generated, analyze the application by executing the following command:

app2container analyze --application-id APP-UID

The App2Container analyze command generates an analysis file called analysis.json in the workspace directory that we selected in the application server. The report provides the analysis as well as options to update containerization parameters.

Understanding the analysis file is a crucial step of the entire containerization process. Let’s dive in.

{
  "createdTime": "2020-05-04-17:36:36",
  "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/aspnet:4.7.2-windowsservercore-ltsc2019*",
    "enableServerConfigurationUpdates": true,
    "imageRepositoryName": "*iis-dnn-c5654c20*",
    "imageTag": "*latest*",
    "includedWebApps": [
      
    ],
    "additionalExposedPorts": [
      
    ],
    "appIncludedFiles": [
      
    ],
    "enableLogging": false
  • The “containerBaseImage” is the Windows base image selected in the Microsoft Container Registry (MCRthat matches your application framework (on the ASP.NET demo environment). You have the option of changing it and using your custom Windows base image. It is important to note that the Windows base image must match the same Windows Version on the Amazon ECS and Amazon EKS cluster. 
  • The “imageRepositoryName” is the name of the Amazon ECR (Elastic Container Repository) that is created to store the container image generated by AWS App2Container. You can change it for an existing repository or change the name if you want.
  • The “imageTag” is the TAG created in the container image.
  • The “includeWebApplications” option can be modified if you want to include additional IIS Sites that may be part of your web application.
  • The “additionalExposedPorts” is an option if you want to publish additional ports instead of port 80 to your container.
  • The “appIncludeFiles” is an option to include any files which are not part of the IIS Site, but it is a requirement to have, such as a DLL file.

This analysis file outputs the Windows Server Version, IIS and Application Pool configuration, Bindings, File Paths, and features installed on the Windows Server beyond the IIS, and the report.txt file path. The report.txt contains the file name and line number in where you may change the database Connections Strings.

Step 4: Extract and upload the application to Amazon S3

1. Execute the following “extract” command to generate an application archive for the analyzed application with the S3 bucket is the one specified in step 2.3. This contains all the necessary files to build the container image. I used the –output s3 to upload the artifacts to an S3 bucket, which I use in the AWS App2Container worker machine.

app2container extract --application-id APP-UID --output s3

Step 5: (Optional) Install AWS App2Container in the worker machine

1. Using the same steps as you followed in installing App2Container in the application server, install App2Container in the worker machine.

Having an AWS App2Container worker machine means that you don’t need to install all the Docker components in your application server to build the Docker image, upload it to Amazon ECR, and generates Amazon ECS/Amazon EKS artifacts. An excellent choice is to use an Amazon EC2 instance based on the Amazon ECS-optimized Windows 2019 Full AMI, which  already includes Docker. If you prefer, you can also deploy the worker machine in an on-premises virtual environment.

Step 6: Containerize the application

Creating the Dockerfile from the scratch isn’t an easy task. You need to write Dockerfiles using multi-stage steps to minimize the number of layers and entry points. AWS App2Container simplifies the container image build process for you by generating a completed Dockerfile.

1. On the AWS App2Container worker machine, execute the following command:

app2Container containerize --input-archive s3://YOURBUCKETNAME/ARCHIVE-KEY/FILE.ZIP

Containerize Input Archive

2. Access the workspace directory to see the following directory/files structure:

3. Select the Artifacts directory, which is the context directory that App2Container uses to build the container image.

Note: Directory “DNN” is the IIS Site name that contains all the web application files.

  • Dockerfile is the Dockerfile generated by AWS App2Container based on the current IIS configuration, it can be edited as you need.
  • Entrypoint.ps1 is the entry point that is going to be used to output the IIS Logs to the docker console.
  • You can use WebDeploy.msi to restore the full IIS configurations from the current production environment to use it in the Windows Container image.
  • WIN-KU.zip is the IIS backup generated by AWS App2Container and is used with the WebDeploy in case of an IIS Configuration restore into the windows container image.

Now, let’s examine the Dockerfile file generated by AWS App2Container.

# escape= `
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.7.2-windowsservercore-ltsc2019
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

RUN Remove-Website 'Default Web Site';

# Set up Website: dnn
RUN New-Item -Path 'C:\inetpub\dnn' -Type Directory -Force;
RUN if(-NOT (Get-IISAppPool dnn)) {New-WebAppPool -Name dnn }
RUN New-Website -Name 'dnn' -PhysicalPath 'C:\inetpub\dnn' -Port 80 -ApplicationPool 'dnn' -Force;
COPY ["dnn", "C:\\inetpub\\dnn"]
RUN $path='C:\inetpub\dnn'; `
    $acl = Get-Acl $path; `
    $newOwner = [System.Security.Principal.NTAccount]('BUILTIN\IIS_IUSRS'); `
    $acl.SetOwner($newOwner); `
    dir -r $path | Set-Acl -aclobject  $acl

EXPOSE 80

# Windows Authentication was not detected. Please Uncomment the below RUN commands if you want to use Windows Authentication."
# AppPool's Identity is set as Network Service to enable Windows Authentication using GMSA.
# RUN Install-WindowsFeature -Name Web-Windows-Auth -IncludeAllSubFeature
# RUN Import-Module WebAdministration; Set-ItemProperty IIS:\AppPools\dnn -name processModel.identityType -value 2
# RUN Import-Module WebAdministration; Set-WebConfigurationProperty -Filter '/system.webServer/security/authentication/anonymousAuthentication' -Name Enabled -Value False -PSPath 'IIS:\' -Location 'dnn'
# RUN Import-Module WebAdministration; Set-WebConfigurationProperty -Filter '/system.webServer/security/authentication/windowsAuthentication' -Name Enabled -Value True -PSPath 'IIS:\' -Location 'dnn'

# Included files:

# Export additional ports 

# Set up log volumes if needed, for example: 
# VOLUME C:\inetpub\logs
# VOLUME C:\yourApp\App_Data\Logs

# The following Windows features are installed on your host, but not in the container.
# You can uncomment the ones you want to have them installed while building docker image.
# RUN Install-WindowsFeature -Name File-Services -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name FS-FileServer -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name Web-Windows-Auth -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name Web-Mgmt-Tools -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name Web-Mgmt-Console -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name NET-Framework-Features -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name NET-Framework-Core -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name InkAndHandwritingServices -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name Server-Media-Foundation -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name FS-SMB1 -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name User-Interfaces-Infra -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name Server-Gui-Mgmt-Infra -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name Desktop-Experience -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name Server-Gui-Shell -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name PowerShell-V2 -IncludeAllSubFeature
# RUN Install-WindowsFeature -Name PowerShell-ISE -IncludeAllSubFeature

# Uncomment the following section will restore your server configuration in your container.
# COPY 'WIN-KUCUV3Q9KNF_WebServer_20200616150934.zip'  'C:\temp\WIN-KUCUV3Q9KNF_WebServer_20200616150934.zip'
# COPY 'WebDeploy_amd64_en-US.msi'  'C:\temp\WebDeploy_amd64_en-US.msi'
# RUN Start-Process 'C:\temp\WebDeploy_amd64_en-US.msi' '/qn' -PassThru | Wait-Process
# RUN Add-PSSnapin 'WDeploySnapin3.0' ; Restore-WDServer -Package 'C:\temp\WIN-KUCUV3Q9KNF_WebServer_20200616150934.zip'

You can see that App2Container selects the base image from the ASP.NET application in the analysis.json file. However, you can edit the base image as needed, while doing this, make sure that the new image matches Container Host OS version.

Using Windows Authentication on a Windows Container requires the use of gMSA and Authentication changes on IIS. AWS App2Container prepares the container image to support Windows Authentication by adding the following configurations in the Dockerfile:

  • Changing the IIS Application Pool account to use Network Service account.
  • Installing the IIS Feature for Windows Authentication.
  • Changing the IIS Authentication to disable Anonymous authentication and enables Windows Authentication.

App2Container also provides two PowerShell scripts as outputs to the “app2container containerize” command, along with an instruction file. The first PowerShell script DomainJoinAddToSecGroup.ps1 joins the container host and adds it to an Active Directory Security Group. The second script CreateCredSpecFile.ps1 creates the gMSA, grants access to the AD security group to retrieve gMSA password, and generates the Docker credspec file.

Step 7:  Generate the application artifacts to containerize the application

1. To generate the applications artifacts to be used with Amazon ECS or Amazon EKS, execute the following command:

app2container generate app-deployment --application-id APP-UI

By default AWS App2Container generates the artifacts to be used on Amazon ECS, but you can change it to generate artifacts to be used on Amazon EKS.

Open the deployment.json file generated by app2container, there are two parameters:

  • createECSArtifacts: true
  • createEKSArtifacts: false

Modifying the createEKSArtifacts to True, and createEcsArtifcats to false, then app2container generates the Amazon EKS artifacts.

{
       "a2CTemplateVersion": "1.0",
       "applicationId": "iis-dnn-c5654c20",
       "imageName": "iis-dnn-c5654c20",
       "exposedPorts": [
              {
                     "localPort": 80,
                     "protocol": "http"
              }
       ],
       "environment": [],
       "ecrParameters": {
              "ecrRepoTag": "latest"
       },
       "ecsParameters": {
              "createEcsArtifacts": false,
              "ecsFamily": "iis-dnn-c5654c20",
              "cpu": 2,
              "memory": 4096,
              "dockerSecurityOption": "",
              "enableCloudwatchLogging": false,
              "publicApp": true,
              "stackName": "a2c-iis-dnn-c5654c20-ECS",
              "reuseResources": {
                     "vpcId": "",
                     "cfnStackName": "",
                     "sshKeyPairName": ""
              },
              "gMSAParameters": {
                     "domainSecretsArn": "",
                     "domainDNSName": "",
                     "domainNetBIOSName": "",
                     "createGMSA": false,
                     "gMSAName": ""
              }
       },
       "eksParameters": {
              "createEksArtifacts": true,
              "stackName": "a2c-iis-dnn-c5654c20-EKS",
              "reuseResources": {
                     "vpcId": "",
                     "cfnStackName": "",
                     "sshKeyPairName": ""
              }
       }
}

2. Now, in the parent folder, you should be able to see the following files:

  • EksDeployment Directory contains a CloudFormation template to deploy the EKS Cluster and Windows Worker Nodes.
  • The eks_deployment.yaml is the manifest file that you can use to deploy the Windows Pod on Amazon Elastic Kubernetes Services (Amazon EKS).
  • eks_service.yaml is the manifest file that you can use to deploy the Kubernetes Service on Amazon Elastic Kubernetes (Amazon EKS). Finally,
  • pipeline.json is the manifest file that you can use to deploy the CI/CD pipeline to be used along with the Amazon ECS or Amazon EKS cluster.

Step 8: Launch the application on Amazon Kubernetes Service (Amazon EKS)

1. Using kubectl, execute the following command:

kubectl apply -f eks_service.yaml

kubectl apply -f eks_deployment.yaml

2. Confirm if the pod is ready and running. The status should say “1/1” under READY and “running” under STATUS.

kubectl get pod

Kubectl pods running console

3. Via web browser, access the Elastic Load Balancer (ELB) created by the Amazon EKS cluster. This redirects to the Pod where you can access your application.
ASP.NET app screenshot

Conclusion

Containerization allows you to unify the infrastructure needed to operate your legacy applications, helping you save on both infrastructure and management costs. Specifically, App2Container helps you containerize these applications and standardize them across a single set of tooling for monitoring, operations, and software delivery.

For additional information on how to monitor Amazon EKS Windows Pods, you can read this blog post. To learn more about data persistence on Windows Containers running on Amazon EKS, check out this blog post or this blog post for Amazon ECS.

To learn more on migrating Windows Server or SQL Server, visit Windows on AWS. For more information on how AWS can help you modernize your legacy Windows applications, check our our Modernization page. Contact us to start your modernization journey today.

Marcio Morales

Marcio Morales

Sr. Microsoft Specialist SA