Containers

Modernize your .NET application using AWS App2Container and AWS Toolkit for .NET

Overview

As businesses increasingly embrace cloud computing, many organizations are seeking to migrate their existing .NET applications from on-premises data centers to AWS. However, the transition of these workloads can often be complex and time-consuming. To simplify this process, AWS App2Container(A2C) is a robust command-line tool that assists users in lifting and shifting their on-premises or virtual machine (VM)-based applications into containerized environments managed by Amazon Elastic Container Service (Amazon ECS) or Amazon Elastic Kubernetes Service (Amazon EKS). With A2C, organizations can efficiently package their .NET applications into containers, facilitating a seamless transition to the cloud. This not only simplifies the migration process but also enables businesses to use the numerous benefits of containerization, such as enhanced scalability, portability, and resource utilization. By using A2C, companies can make sure their applications are well-optimized for the cloud environment, thus driving greater efficiency and performance.

Complementing this, AWS Toolkit for .NET Refactoring is a Visual Studio extension that reduces the time and effort necessary for developers to refactor legacy .NET applications to cloud-based alternatives on AWS. Toolkit for .NET Refactoring assesses the application source code and recommends modernization pathways, such as porting to .NET Core.

Why replatform?

Application modernization needs developer involvement, and developers access application’s source code, update API calls, replace outdated packages, and rebuild the application. Once the new application build is ready, the application packages are deployed by operators to the selected orchestration system. The refactoring process updates the application code for use in modern development, test, and deployment systems, which needs more resources and takes longer to complete. However, the replatforming process helps operators modernize their infrastructure, without the developer’s involvement in the process. Using A2C operators can take application’s binaries and deploy the application to cloud-native container orchestration such as Amazon EKS, Amazon ECS, or AWS App Runner. The replatforming does not access the application source code or ask developers to update API calls. When using A2C on a worker node, it performs the following tasks categorized into two main stages:

  • Remote Discovery and Analysis:
    • Establishes secure communication to the source server from the worker node through Windows Remote Management (WinRM).
    • Remotely analyzes the source server, collecting analysis files within the worker node.
    • Creates dedicated folders for each remote Source Server on the Worker node.
    • Generates an inventory list for the application server, identifying eligible ASP.NET (Windows) applications for containerization.
    • Analyzes the run-time dependencies of supported applications, considering cooperating processes and network port dependencies.
  • Remote Extraction and Containerization:
    • Extracts application artifacts from the source server to the worker node for containerization.
    • On the worker node, generates a container image.

Getting started with application replatforming

In this section, we perform the following steps to replatform of a .NET application installed on a source node.

An S3 bucket is required to store A2C-generated artifacts. Refer to the S3 bucket creation guide.

To deploy the .Net application in your own AWS account, you can use this CloudFormation template using the AWS CloudFormation console. Remember the stack name you are using here, as this is used in a later section.

This template provisions the following components on the source node:

  • Source node running Windows Server 2012
  1. Source node comes with Internet Information Services (IIS) already installed, which is used to manage website content
  2. AWS Command Line Interface (AWS CLI) version 2, pre-installed
  3. PowerShell 5.0

And on the worker node:

  • Worker node running Windows Server 2019
  • AWS CLI pre-installed
  • Container runtime
  • Retrieve credentials for source and worker node

You can find login details in the CloudFormation output. Make sure you’re signed in to the right AWS Region to see the CloudFormation Stack. Follow these steps to get access to the username:

  • Sign-in to the Console and go to CloudFormation.
  • Look for stack that you created in the previous section_._
  1. Select the stack name and go to the Outputs tab.
  • The username and password are available under the Value header.
  • Reset worker and source nodes password for RDP access
  1. Select the EC2 instance labelled source node and select Connect.
  2. In the Session Manager tab, choose Connect.
  3. A new browser window opens, showing the source node PowerShell terminal.
  4. Run the following PowerShell command to reset the source node password: ([adsi]”WinNT://$env:computername/”).SetPassword(‘)
  5. Verify the command for accuracy, then press Enter. Make sure there are no errors.

Note: Follow the same steps with worker node to gain RDP access.

  1. Choose Other type of secrets.
  2. Navigate to the Key/Value tab.
  3. Add two key/value pairs as follows:
  • Pair 1:
    • Key: username
    • Value: a2cstudent
  • Pair 2:
    • Key: password
    • Value: <use password set in step 5>
  • Provide a secret name and description, then copy the Secret ARN for later use.
  • Verify the application on source node

The application installed in the source node is an IIS website. To check if that website is up and running, run the following command:

get-weburl -url http://localhost:80

It should give a 200 response, otherwise open it on a web browser to check if the website is hosted on the EC2 instance.

  • Enable WinRM on source node

_ _ To connect to your Windows Source Server from a Windows Server 2019 worker node, you must enable the WinRM protocol on your Source Web Server. Make sure your application server meets the specified requirements listed for Windows in the Supported Applications list.

  • Connect to your source node Server using RDP.
  • Open the PowerShell console as Administrator.
  • Navigate to the C:\SetupFiles\WinRM folder.
  • Run the “ls” command to make sure that the WinRMSetup.ps1 and New-SelfSignedCertificateEx.ps1 files are in the same location.
  • Execute the “.\WinRMSetup.ps1” command.
  • Verify that the expected output as displayed:

IgnoreError

Ignore error saying MSFT_NetFirewallRule not found.

  • Install A2C in worker node
  • Use Remote Desktop Service to RDP into the worker node.
  • Open PowerShell in Administrator mode.
  • Navigate to the C:\a2cInstaller\a2cInstaller\
  • Run the .\install.ps1 command.

  • Accept the End User License Agreement (EULA).
  • Type ‘app2container’ in the prompt and select enter to see Getting Started.
  • Run the command ‘app2container init’ and configure the settings as follows:

As the part of CloudFormation template, we have used the AWS Identity and Access Management (IAM) profile ‘A2CRole’ with access to Amazon S3, Amazon Elastic Container Registry (Amazon ECR), and Amazon ECS.

  • Workspace directory path: C:\a2cworkspace.
  • AWS Profile: Use the instance profile pre-configured.
  • AWS Region: Use the Region where the lab is provisioned. It should be the default AWS Region listed here.
  • S3 bucket: Use the bucket name created in the section Creating S3 bucket.
  • Report usage metric: Enter ‘N’ for the lab.
  • Automatically upload logs and A2C generated artifacts on crashes and internal errors: Enter ‘N’ for the lab.
  • Require images to be signed using Docker Content Trust: Enter ‘N’ for the lab.
  • All application artifacts are created under c:\a2cworkspace. Make sure that the folder permission are secure, and select Enter and make sure the necessary permissions are secured.
  • When you go to C drive you should notice a new folder is created with the name a2cworkspace.
  • Execute ‘app2container remote configure‘ command to configure the remote source server.
  • Extract the IP of the worker node from Ipconfig command and use it in “Server IP address”.
  1. Leave the ‘Server FQDN (Fully Qualified Domain Name)’ blank and select Enter.
  • When prompted for Secret ARN, copy and paste the value from Secrets Manager and select Enter as shown in the following:

  • Containerize the application with discovery and analyze

In this step, we containerize the deployed .Net application. We use the worker node for our A2C processes. By using the WinRM process, we collect, analyze, and extract the application. When you execute the remote commands from your worker node, it connects to the source node and runs the necessary commands on it.

Discovery Phase:

  • Use A2C to create an application inventory by discovering and running .NET applications on the server.

app2container remote inventory —target

  • Locate the inventory in the designated workspace directory (such as ‘C:\a2cworkshop\remote’), containing an “inventory.json” file with the .NET application details.

  • Note the application ID from the JSON output of the inventory file. Otherwise, run the following command to fetch the application ID:

jq -r ‘keys[] | select(test(“^iis-dnn-*”))’ C:\a2cworkshop\remote\inventory.json

Analysis Phase:

  • Execute the “app2container remote analyze” command, replacing with the application ID and with the source server’s private IP address.

app2container remote analyze —application-id —target

  • Review the analysis report generated, which includes editable parameters for container settings and non-editable sections providing application-level analysis information.
  • Examine the “analysis.json” file within the application’s folder to understand the analysis results, and proceed with the containerization process accordingly.

Extract and containerize

The next phase entails extracting application artifacts from the source node and then containerizing them on the worker node using A2C.

Extraction Phase:

  • Choose to run the steps on the worker node for standardized scaling activities and enhanced security.
  • Execute the “app2container remote extract” command on the worker node to retrieve .Net application artifacts from the source server.
app2container remote extract --target <private-IP of your source server> --application-id <app-id>
  • Replace and with the appropriate values.
  • The extraction process takes a few minutes, and upon completion, a zip file containing the application artifacts is created.
  • Following extraction, the application-related artifacts are available on the worker node, eliminating the need for communication with the source application server.

Containerization Phase:

  • Containerize the web application on the worker node using the “app2container containerize” command.

app2container containerize —input-archive C:\a2cworkspace\remote<YourPrivateIPAddress><application-id><application-id>.zip

  • Specify the location of the input zip file generated in the previous step with the —input-archive parameter.
  • The process takes a few minutes, as the worker node downloads the Windows 2019 base image for the container.
  • After completion, verify the creation of container images by running ‘docker images’ on the worker node.
  • When you run the “app2container containerize” command, it automatically creates a deployment.json file inside the application folder.

You have two options for deployment to your target container management environment (Amazon ECR with Amazon ECS, or Amazon EKS). By default, A2C generates deployment files for Amazon ECS. If you want to change it to Amazon EKS, then edit the ‘deployment.json’ file and set ‘eksParameter’ to ‘true’ and ‘ecsParameter’ to ‘false’.

Follow this URL for deployment to Amazon ECS.

And follow this URL for deployment to Amazon EKS.

Why refactor?

We have seen the ease and benefits for replatforming an application. Now let’s look at refactoring the application. In the refactoring scenario we take the application that is running, in this case it is a .NET framework 4.8 application, on a VM.

To containerize the application, we decide to modernize the framework used to create the application. The modernization in this case means we have access, familiarity, and permission to modify the application code. In the following demonstration, we take the application to the .NET 6 framework, and along the modernization process we are required to modify API calls, application routines used, and parameters used in the old source code. Once the code modifications are completed, we push our code to our code repository to rebuild the application with the new code base. Since .NET 6 supports containerization directly from IDE such as Visual Studio, we can containerize the application once the code is checked. This approach requires application code familiarity and adherence to the organization programing policy. Developers are asked to be involved the modernization of a legacy application. If your organization decides to refactor, then you need to consider the following aspects of the process:

  • Availability of application code
  • Programmers’ availability and familiarity with the application’s code
  • Applications’ life cycle and deprecation schedule
  • Post refactoring testing and validation

This part of the post shows refactoring of the C# application. AWS Toolkit for.NET Refactoring guides and helps resolve discrepancies in the old code base that needs to be addressed. AWS Toolkit for .NET Refactoring can also help you deploy the modified application to an ECS cluster for testing and validation. AWS modernization tools can help developers and operators streamline their applications transformation.

Adding AWS Toolkit for .NET Refactoring to your IDE AWS Toolkit for .NET Refactoring is an extension to your IDE, and in our case an extension to Visual Studio 2022, as shown in the following image.

Once the extension is installed and configured to refactor the code to your preferred version, you can start your assessment of the application code. In the following sections we are refactoring code from .NET Framework 4.8 to .NET 6.

Starting application code assessment We start the assessment from the extension dashboard. AWS Toolkit for .NET Refactoring assessment scans the application code, and provides the following overview.

The dashboard show that the application has several incompatibilities between the code versions, which mean that the application developer needs to replace some of the outdated packages, modify API calls, and change the code to interface with new packages. Let’s start making those changes in the application.

Change application code First there are some packages that can be replaced and updated by AWS Toolkit for .NET Refactoring. The command and error shell in the IDE shows which packages can be replaced and the location in the code from which the updated package is called.

We use the porting capabilities of AWS Toolkit for .NET Refactoring to automatically port any portable packages that we can. In our example here, AWS Toolkit for .NET Refactoring ports 10 packages out of the 17 that we require porting. The porting is a non-reversal action in the application code. Once the porting is completed, the application code is modified without the ability to revert back. Make sure you check the latest version of your code to your code version system prior to starting the porting.

Now that our application code has been ported to .NET 6, we need to start resolving the build errors that arise from incompatibilities in the code with the usage of .NET 6.

We reload the modified application code to our IDE.

**Rebuilding the application ** We execute the build command in the IDE, and review the error messages in the IDE console. The errors in the build process need developer intervention to include the right packages and modify the necessary API calls to resolve the changes in syntax and/or input or output values.

In the application code we have to add inclusion to new packages that now incorporate calls to services and functions included in the new framework code. Developers have to follow line-by-line in the error console and resolve the error code. In this example, the developer changed the calls to error message reporting, added new versions of database call APIs, changed namespaces used by the application, and more. The code changes require familiarity with the code, as changes in our part of the application created new errors in other parts of the application due changes made to a function that is used across the code base, as shown in the following image.

After the right changes are made in the application code, we obtained an error free code base, as shown in the following image:

We rerun the application build again. The result in the IDE console shows a list of compiler errors that require the attention of the developer. The developer modifies the code to add the needed context in the right part of the application, as shown in the following image.

Once the application compiler issues are resolved, the application is built successfully. We are ready to deploy the application, as shown in the following image.

From the IDE we can publish the application to different packaging formats. In the preceding example we create a portable version of the application. The portable version can run on different operating system technologies such as Windows and Linux. Developers and operators have the option to build the solution to specific operating system technology. We can also publish the application to a container image, which is our main target, as shown in the following image.

Operators need to provide credentials to the supported registry in order to upload the application binaries. Once the application is uploaded to containers registry used, operators can start the application deployment to their preferred containers orchestration system.

Final testing Once the refactoring process is completed, the code base is updated to the new version. Unless specified prior to the refactoring process, the AWS Toolkit for .NET Refactoring replaces the old code with the newer version. Operators who need access to the original code should fork the original code version for reference. To final test the application, deploy the modernized container to Amazon EKS or Amazon ECS, and make sure the application functionality is similar to the original version. To further develop features and capabilities, the application developer can continue adding code and functionality, using the modernized application source code.

Cleaning up

After you are finished, the following resources need to be deleted:

  • the application resources deployed into the ECS cluster, then the ECS cluster itself
  • the CI pipeline that created the container images and captures/stores the checkpoint (this includes the ECR repository that stores the container images)
  • the remote host used for replatforming the application with A2C
  • the S3 bucket or folder created to store the intermediate artifacts, CloudFormation templates, and ECS tasks or EKS pods

Conclusion

We reviewed two different methods to modernize a legacy application. In the first section we replatformed the application, and the replatforming involved the application operator and did not change the application code. In the second section, we refactored the application that needed the help from both the application developer and operator. The benefit of replatforming is the ease and speed of moving the application to a cloud native environment. Refactoring, contrary to replatforming, delivers the ability to modernize the application development environment along with the application operating environment, while requiring involvement from both operators and developers. To start your workloads’ modernization journey, we recommend you use AWS modernization tools for assessing, mobilizing, and operating applications. AWS provides tools to assess (Migration Hub Strategy Recommendation), mobilize (A2C, Porting Assist, Microservice Extractor), and operate (A2C) legacy applications in a modernized environment.