Containers

Accelerate modernization of your application using App2Container

Introduction

Many enterprises want to modernize their existing applications and containerize them to minimize disruptions that could stem from clunky, outdated and unscalable legacy systems. These enterprises need tools to simplify the containerization process of existing Java and .NET applications and increase operational efficiency, harmonize CI/CD processes, and increase agility. AWS App2Container (A2C) enables companies to rapidly transform their legacy systems to modern applications onto AWS.

This post highlights the steps involved in decoupling and containerizing your existing applications. AWS App2Container discovers applications running on a server, identifies their dependencies, and generates relevant artifacts for seamless deployment to Amazon ECS and Amazon EKS. It also works with AWS CodeBuild and AWS CodeDeploy to enable a repeatable way to build and deploy containerized applications.

App2Container Illustration

Demonstration

This demonstration contains the following steps:

  1. Install prerequisites: create a Cloud9 environment and IAM accounts, and install Docker and App2Container software.
  2. Install Tomcat, Java and run Java application: install a sample Java/Tomcat application in Cloud9 and test.
  3. Containerize application using app2container: convert application to container using A2C.
  4. Modernize application using app2container: move application to ECS/Fargate using A2C.
  5. Integrate with CICD: create CICD pipeline for Tomcat/Java application using A2C.

💡App2container tool is designed to run with root user account, so throughout the instructions we will be using sudo to run commands with root privileges.

Step 1: Install prerequisites

  • To get started, create a Cloud 9 environment to host Java application, follow the steps listed here to create a workspace using Amazon Linux2 operating system and an IAM role, attach it to the workspace, and update the IAM settings for your workspace. Make sure to have at least 20GB free space in filesystem, which will be used by App2Container to store docker images, Artifacts and other configuration files. If you do not opt to use Cloud9, simply start in your own EC2 or on-premise Linux environment as below.
  • Create IAM user with permissions needed for App2Container tool. Refer to Identity and access management in App2Container permissions page for fine grained permissions. For this demonstration, we will be creating an AdministratorAccess policy and attaching it to an IAM User.
$ aws iam create-user --user-name a2cuser
{
    "User": {
        "UserName": "a2cuser", 
        "Path": "/", 
        "CreateDate": "2020-10-11T00:17:14Z", 
        "UserId": "AIDA2CILTSA6OKPTNQKUA", 
        "Arn": "arn:aws:iam::<account id>:user/a2cuser"
    }
}
$ aws iam attach-user-policy --user-name a2cuser --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
  • Create IAM access keys for the user created above, and add the secret access key and access key ID to ~/.aws/credentials file in home directory of user where application is running and being moved to ECS/Fargate. The values of the secret access key and ID are hidden in below command set for security purpose.
    Update ~/.aws/config in home directory to include AWS region where to migrate the application.
$ aws iam create-access-key --user-name a2cuser
{
    "AccessKey": {
        "UserName": "a2cuser", 
        "Status": "Active", 
        "CreateDate": "2020-10-11T00:20:08Z", 
        "SecretAccessKey": "  ", 
        "AccessKeyId": "  "
    }
}

$ sudo bash
# mkdir ~/.aws
# cat ~/.aws/credentials
[default]
aws_access_key_id = 
aws_secret_access_key =

# cat ~/.aws/config 
[default]
region = us-east-1
$ curl -o AWSApp2Container-installer-linux.tar.gz https://app2container-release-us-east-1.s3.us-east-1.amazonaws.com/latest/linux/AWSApp2Container-installer-linux.tar.gz
$ sudo tar xvf AWSApp2Container-installer-linux.tar.gz
$ sudo ./install.sh
  • The App2Container tool requires Docker Engine to be installed on application server where it’s being containerized. Follow the commands below to install Docker Engine, and start and enable service.

Note: You can skip below instructions if you are using Cloud9. Docker Engine is installed by default in a Cloud9 environment.

$ sudo yum install docker -y
$ sudo systemctl start docker
$ sudo systemctl enable docker
  • An S3 bucket is required to store artifacts and AWS CloudFormation templates generated by App2Container. Create S3 an bucket as below. Amazon S3 bucket names must be unique globally. If you get the “Bucket name already exists” or “BucketAlreadyExists” error, then you must use a different bucket name to create the bucket.

As shown below, we are appending the output of ‘date +%s` command to s3 bucket name to create unique bucket name.

$ aws s3 mb s3://app2-container-`date +%s`
make_bucket: app2container-java-1604428748

$ aws s3 ls |grep  app2-container-java
2020-10-11 00:25:17 app2-container-java-1604428748

Step 2: Install Tomcat and Java, and run the Java application

  • Install Apache Tomcat server. At the time of writing this blog, the latest stable version 9.0.39 was picked to test and installed.
$ cd /home/ec2-user
$ wget https://mirror.olnevhost.net/pub/apache/tomcat/tomcat-9/v9.0.39/bin/apache-tomcat-9.0.39.tar.gz
$ tar -zvxf apache-tomcat-9.0.39.tar.gz 
  • Clone eb-tomcat-snakes repo from github/aws-samples and build WAR file to use with Tomcat server. Run build script to compile application and copy WAR file to webapps folder in install directory of Tomcat.
$ cd /home/ec2-user
$ git clone https://github.com/aws-samples/eb-tomcat-snakes.git
Cloning into 'eb-tomcat-snakes'...
remote: Enumerating objects: 304, done.
remote: Total 304 (delta 0), reused 0 (delta 0), pack-reused 304
Receiving objects: 100% (304/304), 7.04 MiB | 31.75 MiB/s, done.
Resolving deltas: 100% (165/165), done.

$ cd eb-tomcat-snakes
$ ./build.sh
$ ls -l ROOT.war 
-rw-rw-r-- 1 ec2-user ec2-user 6407735 Oct 28 01:58 ROOT.war

$ cd /home/ec2-user
$ rm -rf apache-tomcat-9.0.39/webapps/ROOT
$ cp eb-tomcat-snakes/ROOT.war apache-tomcat-9.0.39/webapps/
  • Start Tomcat server and test the eb-tomcat-snakes application from browser. Default install runs on port 8080. You can access the application from URL as http://{host IP or DNS NAME}:8080
$ cd /home/ec2-user
$ apache-tomcat-9.0.39/bin/startup.sh 
Using CATALINA_BASE:   /home/ec2-user/apache-tomcat-9.0.39
Using CATALINA_HOME:   /home/ec2-user/apache-tomcat-9.0.39
Using CATALINA_TMPDIR: /home/ec2-user/apache-tomcat-9.0.39/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /home/ec2-user/apache-tomcat-9.0.39/bin/bootstrap.jar:/home/ec2-user/apache-tomcat-9.0.39/bin/tomcat-juli.jar
Using CATALINA_OPTS:   
Tomcat started.

$ curl http://localhost:8080
  • Test the application by opening “preview running application” from Cloud9 environment. This application also include option to store details in database, but we are skipping the database section for this blog. Databases will addressed in next post if users are interested in database migration part. You might notice ‘Connection Failed’ message in some parts of application due to missing a database. You can safely ignore during this test.

Step 3: Containerize application using App2Container

Now that we have sample working application with tomcat and Java, let’s now use App2Container to containerize application.

  • First, you can begin by running a one-time initialization on the installed server for the App2Container CLI with the init command. Make sure to enter the S3 bucket name created in Step 1.6; this is to store application artifacts.
$ sudo app2container init
Workspace directory path for artifacts[default: /root/app2container]: 
AWS Profile (configured using 'aws configure --profile')[default: default]: 
Optional S3 bucket for application artifacts: app2-container-java-1604428748
Report usage metrics to AWS? (Y/N)[default: y]: 
Require images to be signed using Docker Content Trust (DCT)? (Y/N)[default: n]: 
Configuration saved
  • Next, you can run inventory command to view Java applications running on the host. Each application is identified with a unique application ID. Note the application ID listed below command output, and replace it subsequent steps where application ID is used.
$ sudo app2container inventory
{
        "*java-tomcat-43b44018*": {
                "processId": 18408,
                "cmdline": "/usr/bin/java ... -Dcatalina.home=/home/ec2-user/apache-tomcat-9.0.39 -Djava.io.tmpdir=/home/ec2-user/apache-tomcat-9.0.39/temp org.apache.catalina.startup.Bootstrap start ",
                "applicationType": "java-tomcat",
                "webApp": "ROOT"
        }
}
  • The analyze command generates a report for the application running on the host. Review analysis.json and edit according to the application requirements, You can update container parameters and analysis info as required. For the demonstration, we will use default settings created by analyze command.
$ sudo app2container analyze --application-id java-tomcat-43b44018
✔ Created artifacts folder /root/app2container/java-tomcat-43b44018
✔ Generated analysis data in /root/app2container/java-tomcat-43b44018/analysis.json
👍 Analysis successful for application java-tomcat-43b44018

💡 Next Steps:
1. View the application analysis file at /root/app2container/java-tomcat-43b44018/analysis.json.
2. Edit the application analysis file as needed.
3. Start the containerization process using this command: app2container containerize –application-id java-tomcat-43b44018

  • Next, we will generate Docker images out of the running application using containerize command.
$ sudo app2container containerize --application-id java-tomcat-43b44018
✔ AWS prerequisite check succeeded
✔ Docker prerequisite check succeeded
✔ Extracted container artifacts for application
✔ Entry file generated
✔ Dockerfile generated under /root/app2container/java-tomcat-43b44018/Artifacts
✔ Generated dockerfile.update under /root/app2container/java-tomcat-43b44018/Artifacts
✔ Generated deployment file at /root/app2container/java-tomcat-43b44018/deployment.json
👍 Containerization successful. Generated docker image java-tomcat-43b44018

You’re all set to test and deploy your container image.
💡 Next Steps:
1. View the container image with “docker images” and test the application.
2. When you’re ready to deploy to AWS, please edit the deployment file as needed at /root/app2container/java-tomcat-43b44018/deployment.json.
3. Generate deployment artifacts using “app2container generate app-deployment –application-id java-tomcat-43b44018”

  • Verify that the Docker image was created successfully using ‘docker images’ command.
$ sudo docker images |grep java-tomcat-43b44018
java-tomcat-43b44018                                                 latest   
  • In-addition to creating Docker images, App2Container also creates artifacts required to modernize applications with AWS container with Amazon ECS and Amazon EKS. For this demonstration we will be using Amazon ECS and AWS Fargate. You can also review the container platform settings in deployment.json file. See the snippet below for the ECS/Fargate configuration. Make sure createEcsArtifacts is set to True and deployTarget to ‘FARGATE’.
 "ecsParameters": {
              "createEcsArtifacts": true,
              "ecsFamily": "java-tomcat-43b44018",
              "cpu": 2,
              "memory": 4096,
              "dockerSecurityOption": "",
              "publicApp": true,
              "stackName": "a2c-java-tomcat-43b44018-ECS",
              "reuseResources": {
                     "vpcId": "",
                     "cfnStackName": "",
                     "sshKeyPairName": ""
              },
              "gMSAParameters": {
                     "domainSecretsArn": "",
                     "domainDNSName": "",
                     "domainNetBIOSName": "",
                     "createGMSA": false,
                     "gMSAName": ""
              },
              "deployTarget": "FARGATE"
  • A container Dockerfile file is created in the artifacts directory. You can choose to customize application if required.
$ sudo ls -l /root/app2container/java-tomcat-43b44018/Artifacts
total 111980
-rw-r--r-- 1 root root 114647040 Oct 28 03:14 ContainerFiles.tar
-rw-r--r-- 1 root root      3394 Oct 28 03:14 Dockerfile
-rw-r--r-- 1 root root       182 Oct 28 03:14 Dockerfile.update
-rwxr-xr-x 1 root root       715 Oct 28 03:14 entryfile
-rw-r--r-- 1 root root       347 Oct 28 03:14 excludedFiles
-rw-r--r-- 1 root root       813 Oct 28 03:14 includeFiles
  • Now that application is fully containerized, we can stop the application running on Cloud9 and start it from “docker image.” This validates the Docker image and tests the application running out of container.
$ cd /home/ec2-user/
$ apache-tomcat-9.0.39/bin/shutdown.sh 
$ sudo docker images |grep java-tomcat
java-tomcat-ed0da29b   latest              292f519cc00b        14 minutes ago      1.23GB

$ sudo docker run -d -p 8080:8080 java-tomcat-ed0da29b
$ sudo docker ps 
CONTAINER ID        IMAGE                  COMMAND                  CREATED              STATUS              PORTS                              NAMES
bc59967273b7        java-tomcat-ed0da29b   "/bin/sh -c /entryfi…"   About a minute ago   Up About a minute   8005/tcp, 0.0.0.0:8080->8080/tcp   quizzical_goldberg
$ curl http://localhost:8080
$ sudo docker stop bc59967273b7

We are using the curl command to test the application running on the container. You can also “preview running application” from the Cloud9 environment if needed to test from browser.

Step 4: Modernize application using App2Container

  • Next, we will use generate app-deployment command with ‘—deploy’, which creates an Amazon ECR registry to store docker image, uploads CloudFormation templates to S3, and deploys the templates. The CloudFormation stack will create an ECS cluster on Fargate and deploys the task to the ECS cluster. You can login to console and track status in CloudFormation service for ‘—deploy’ used in this step.
$ sudo app2container generate app-deployment --application-id java-tomcat-43b44018 --deploy
✔ AWS prerequisite check succeeded
✔ Docker prerequisite check succeeded
✔ Created ECR Repository
✔ Registered ECS Task Definition with ECS
✔ Uploaded CloudFormation resources to S3 Bucket: app2container-java
✔ Generated CloudFormation Master template at: /root/app2container/java-tomcat-43b44018/EcsDeployment/ecs-master.yml
✔ Initiated CloudFormation stack creation. This may take a few minutes. To track progress, open the AWS CloudFormation console.
👍 ECS deployment successful for application java-tomcat-43b44018

💡 The URL to your Load Balancer Endpoint is:
<DNS Name>.<region>.elb.amazonaws.com

💡 Successfully created ECS stack a2c-java-tomcat-43b44018-ECS. Check the AWS CloudFormation Console for additional details.

  • Finally, the Java application hosted in ECS/Fargate. A Load Balancer Endpoint is deployed for the task and URL is listed in section above. You can test from curl utility or from web browser as below. DNS Name and region are masked for security reasons. Replace them with correct values from previous section output.
$ curl http://*<DNS Name>**.<region>*.elb.amazonaws.com/

Login to the AWS Management Console and browse through your ECS service to check resource created and running tasks details.

Step 5: Integrate with CI/CD

Finally, we will now integrate Tomcat/Java application hosted on Amazon ECS using the Fargate launch type with AWS CI/CD services.

  • The command app2container generate pipeline with ‘-deploy’ creates a CodeCommit repository to store application artifacts, and generates CloudFormation templates to create CodePipeline components, and uploads to an S3 bucket. The CloudFormation stack will create CodePipeline components with CodeStart based on application deployment settings and artifacts. You can login to the console and track the status in CloudFormation service for ‘—deploy’ used in this step.
$ sudo app2container generate pipeline --application-id java-tomcat-43b44018 --deploy
✔ Generated buildspec file(s)
✔ Generated CloudFormation templates
✔ Committed files to CodeCommit repository
✔ Initiated CloudFormation stack creation. This may take a few minutes. To track progress, open the AWS CloudFormation console.
✔ Deployed pipeline through CloudFormation
👍 Pipeline deployment successful for application java-tomcat-43b44018

💡 Successfully created AWS CodePipeline stack 'a2c-java-tomcat-43b44018-ecs-pipeline-stack' for application. Check the AWS CloudFormation Console for additional details.

  • Browse through AWS CodeCommit, AWS CodeBuild, and AWS CodePipeline in the console to explore more about artifacts and configurations created for a modernized application. You should now see the pipeline as below for your application. If you need to test the pipeline, clone the CodeCommit repository ‘a2c-java-tomcat-43b44018-ecs’ created for the application and update the Dockerfile as required. Commit changes will trigger pipeline and ECS/Fargate tasks will be refreshed automatically with no manual intervention.

Conclusion

You’ve successfully ported a Tomcat/Java application running on a standalone host to ECS/Fargate using App2Container. AWS App2Container is offered free. You only pay for the actual usage of AWS services like EC2, ECS, EKS, and S3 based on their usage. For more details, please refer to App2Container FAQs and App2Container documentation.

If you have any comments or feedback about this blog, please post them in the comments section below. Have technical questions or feature requests related to App2Container tool? Email us at: app2container-support@amazon.com

Mridula Grandhi

Mridula Grandhi

Mridula Grandhi is a Principal Technical Account Manager for AWS. Mridula is also a Containers enthusiast and works with AWS customers to design, deploy, and manage their AWS workloads/architectures. You can reach her on Twitter via @gmridula1 (DMs are open).

Suresh Pathakamuri

Suresh Pathakamuri

Suresh is a Senior Technical Account Manager with Amazon Web Services Enterprise Support. He works with AWS enterprise customers providing technical guidance and assistance for Infrastructure, Containers, Modernization, and DevOps to help them make the best use of AWS services. Outside of work, he enjoys spending time with family and friends.