App2Containerでtomcat環境をコンテナ化してみた

2020.09.02

中山です

この記事はApp2Containerをとりあえず触ってみた、チュートリアル的な記事となります。

App2Containerとは

App2Containerは、ASP.NETおよびJavaアプリケーションをコンテナ化するツールです。

AWS App2Container の発表 - アプリケーションをコンテナ化して AWS クラウドに移行する

これによって、既存のアプリケーションをAWSのコンテナプラットフォームサービスであるECSもしくはEKSに簡単にデプロイできるようになります。

やってみた

公式のチュートリアルに沿って試していきたいと思います。今回は、tomcat上で動作するアプリケーションの移行をやってみます。

Containerizing a Java application on Linux

動作要件

動作要件は以下の通りです。 移行元の環境を用意する際にこれらが満たされていることを確認します。

  • 移行元にAWS CLIがインストールされていること
  • 移行元にdockerがインストールされていること
  • 移行元でJavaアプリケーションが動作していること
  • Root権限
  • 移行元にtarがインストールされていること
  • 移行元に20GBの空き容量があること

作業の流れ

作業の流れは以下の通りです。

  • 移行元環境の作成
  • 前提条件の確認
  • インストール
  • 初期化
  • 移行元環境の分析
  • コンテナ化
  • デプロイ
  • 動作確認

移行元環境の作成

まず、移行元となる環境を用意します。

今回はElastic Beanstalkを利用します。 プラットフォームとしては"Java 7 with Tomcat 7 version 3.3.9"を利用します。 また、アプリケーションとしてはサンプルアプリを利用します。

なお、動作要件を満たすためにEBSボリュームの拡張とSSHでログインするためKeyPairの設定を行いました。

前提条件の確認

環境ができたらSSHでログインします。

まずは前提条件の確認です。

AWS CLI

こちらはインストール済みでした。

$ aws  --version
aws-cli/1.18.13 Python/2.7.18 Linux/4.14.186-110.268.amzn1.x86_64 botocore/1.15.13

Docker

こちらはインストールされていないのでインストールします。

sudo yum install docker -y

また、サービスを開始しておく必要があります。

sudo service docker start

tar

こちらもインストール済みです。

$ tar --version
tar (GNU tar) 1.26
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by John Gilmore and Jay Fenlason.

インストール

次にツール本体をインストールします。

まずはダウンロードします。

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

初期化

インストールが完了したら初期化を実行します。

$ sudo app2container init

ウィザードでアーティファクトの出力先などを設定します。 この時点ではすべてデフォルトとします。 なお、アーティファクトの出力先としてのS3バケット名を後で設定することになります。

Workspace directory path for artifacts[default: /root/app2container]:
AWS Profile (configured using 'aws configure --profile')[default: default]:
Optional S3 bucket for application artifacts:
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

移行元環境の分析

次に、移行対象となるアプリケーションの分析を行います。

まず、アプリケーションの一覧を出力します。

sudo app2container inventory
{
                "java-tomcat-36177892": {
                                "processId": 3509,
                                "cmdline": "/usr/lib/jvm/jre/bin/java ... -Djava.util.logging.config.file=/usr/share/tomcat7/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager org.apache.catalina.startup.Bootstrap start ",
                                "applicationType": "java-tomcat",
                                "webApp": ""
                }
}

次に、移行対象となるアプリケーションの分析を行います。 この際、一覧に出力されたアプリケーションID("java-tomcat-"で始まる部分)を指定します。

sudo app2container analyze --application-id java-tomcat-36177892
? Created artifacts folder /root/app2container/java-tomcat-36177892
? Generated analysis data in /root/app2container/java-tomcat-36177892/analysis.json
? Analysis successful for application java-tomcat-36177892

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

分析が完了するとJSON形式で詳細な構成が出力されます。 具体的には以下のような感じになります。

sudo cat /root/app2container/java-tomcat-36177892/analysis.json
{
       "a2CTemplateVersion": "1.0",
       "createdTime": "2020-09-01 13:49:511",
       "containerParameters": {
              "_comment1": "*** EDITABLE: The below section can be edited according to the application requirements. Please see the analysisInfo section below for details discovered regarding the application. ***",
              "imageRepository": "java-tomcat-36177892",
              "imageTag": "latest",
              "containerBaseImage": "amazonlinux:2018.03",
              "appExcludedFiles": [],
              "appSpecificFiles": [],
              "applicationMode": true,
              "logLocations": [],
              "enableDynamicLogging": false,
              "dependencies": []
       },
       "analysisInfo": {
              "_comment2": "*** NON-EDITABLE: Analysis Results ***",
              "processId": 3509,
              "appId": "java-tomcat-36177892",
              "userId": "91",
              "groupId": "91",
              "cmdline": [
                     "/usr/lib/jvm/jre/bin/java",
                     "-DJDBC_CONNECTION_STRING=",
                     "-Xms256m",
                     "-Xmx256m",
                     "-XX:MaxPermSize=64m",
                     "-classpath",
                     ":/usr/share/tomcat7/bin/bootstrap.jar:/usr/share/tomcat7/bin/tomcat-juli.jar:/usr/share/java/commons-daemon.jar",
                     "-Dcatalina.base=/usr/share/tomcat7",
                     "-Dcatalina.home=/usr/share/tomcat7",
                     "-Djava.awt.headless=true",
                     "-Djava.endorsed.dirs=",
                     "-Djava.io.tmpdir=/var/cache/tomcat7/temp",
                     "-Djava.util.logging.config.file=/usr/share/tomcat7/conf/logging.properties",
                     "-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager",
                     "org.apache.catalina.startup.Bootstrap",
                     "start"
              ],
              "webApp": "",
              "osData": {
                     "ANSI_COLOR": "0;33",
                     "CPE_NAME": "cpe:/o:amazon:linux:2018.03:ga",
                     "HOME_URL": "http://aws.amazon.com/amazon-linux-ami/",
                     "ID": "amzn",
                     "ID_LIKE": "rhel fedora",
                     "NAME": "Amazon Linux AMI",
                     "PRETTY_NAME": "Amazon Linux AMI 2018.03",
                     "VERSION": "2018.03",
                     "VERSION_ID": "2018.03"
              },
              "osName": "amzn",
              "ports": [
                     {
                            "localPort": 8080,
                            "protocol": "tcp6"
                     },
                     {
                            "localPort": 8005,
                            "protocol": "tcp6"
                     }
              ],
              "Properties": {
                     "JDBC_CONNECTION_STRING": "",
                     "catalina.base": "/usr/share/tomcat7",
                     "catalina.home": "/usr/share/tomcat7",
                     "classpath": ":/usr/share/tomcat7/bin/bootstrap.jar:/usr/share/tomcat7/bin/tomcat-juli.jar:/usr/share/java/commons-daemon.jar",
                     "java.awt.headless": "true",
                     "java.endorsed.dirs": "",
                     "java.io.tmpdir": "/var/cache/tomcat7/temp",
                     "java.util.logging.config.file": "/usr/share/tomcat7/conf/logging.properties",
                     "java.util.logging.manager": "org.apache.juli.ClassLoaderLogManager",
                     "jdkVersion": "1.7.0_261"
              },
              "applicationType": "java-tomcat",
              "AdvancedAppInfo": {
                     "Directories": {
                            "base": "/usr/share/tomcat7",
                            "bin": "/usr/share/tomcat7/bin",
                            "conf": "/usr/share/tomcat7/conf",
                            "endorsed": "",
                            "home": "/usr/share/tomcat7",
                            "lib": "/usr/share/tomcat7/lib",
                            "logConfig": "/usr/share/tomcat7/conf/logging.properties",
                            "logs": "/usr/share/tomcat7/logs",
                            "tempDir": "/var/cache/tomcat7/temp",
                            "webapps": "/usr/share/tomcat7/webapps",
                            "work": "/usr/share/tomcat7/work"
                     },
                     "jdkVersion": "1.7.0_261"
              },
              "env": {
                     "AWS_AUTO_SCALING_HOME": "/opt/aws/apitools/as",
                     "AWS_CLOUDWATCH_HOME": "/opt/aws/apitools/mon",
                     "AWS_ELB_HOME": "/opt/aws/apitools/elb",
                     "AWS_PATH": "/opt/aws",
                     "CATALINA_BASE": "/usr/share/tomcat7",
                     "CATALINA_HOME": "/usr/share/tomcat7",
                     "CATALINA_PID": "/var/run/tomcat7.pid",
                     "CATALINA_TMPDIR": "/var/cache/tomcat7/temp",
                     "EC2_AMITOOL_HOME": "/opt/aws/amitools/ec2",
                     "EC2_HOME": "/opt/aws/apitools/ec2",
                     "HISTCONTROL": "ignoredups",
                     "HISTSIZE": "1000",
                     "HOME": "/usr/share/tomcat7",
                     "HOSTNAME": "ip-172-31-19-69",
                     "JASPER_HOME": "/usr/share/tomcat7",
                     "JAVA_HOME": "/usr/lib/jvm/jre",
                     "JAVA_OPTS": " -DJDBC_CONNECTION_STRING=\"\" -Xms256m -Xmx256m -XX:MaxPermSize=64m",
                     "KILL_SLEEP_WAIT": "5",
                     "LANG": "en_US.UTF-8",
                     "LESSOPEN": "||/usr/bin/lesspipe.sh %s",
                     "LESS_TERMCAP_mb": "\u001b[01;31m",
                     "LESS_TERMCAP_md": "\u001b[01;38;5;208m",
                     "LESS_TERMCAP_me": "\u001b[0m",
                     "LESS_TERMCAP_se": "\u001b[0m",
                     "LESS_TERMCAP_ue": "\u001b[0m",
                     "LESS_TERMCAP_us": "\u001b[04;38;5;111m",
                     "LOGNAME": "tomcat",
                     "MAIL": "/var/spool/mail/tomcat",
                     "PATH": "/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin",
                     "PWD": "/usr/share/tomcat7",
                     "SECURITY_MANAGER": "false",
                     "SHELL": "/bin/sh",
                     "SHLVL": "2",
                     "SHUTDOWN_VERBOSE": "false",
                     "SHUTDOWN_WAIT": "30",
                     "TERM": "linux",
                     "TOMCAT_CFG": "/etc/tomcat7/tomcat7.conf",
                     "TOMCAT_NAME": "tomcat7",
                     "TOMCAT_USER": "tomcat",
                     "USER": "tomcat",
                     "_": "/usr/lib/jvm/jre/bin/java"
              },
              "cwd": "/usr/share/tomcat7",
              "procUID": {
                     "euid": "91",
                     "suid": "91",
                     "fsuid": "91",
                     "ruid": "91"
              },
              "procGID": {
                     "egid": "91",
                     "sgid": "91",
                     "fsgid": "91",
                     "rgid": "91"
              },
              "userNames": {
                     "91": "tomcat"
              },
              "groupNames": {
                     "91": "tomcat"
              },
              "fileDescriptors": [
                     "/var/log/tomcat7/catalina.out",
                     "/var/log/tomcat7/host-manager.2020-09-01.log",
                     "/usr/share/java/tomcat7/tomcat-i18n-de.jar",
                     "/usr/share/java/tomcat7/jasper.jar",
                     "/usr/share/java/tomcat7/catalina-ant.jar",
                     "/usr/share/java/apache-commons-pool-1.5.6.jar",
                     "/usr/share/java/tomcat7-servlet-3.0-api.jar",
                     "/usr/share/java/tomcat7/tomcat-util.jar",
                     "/usr/share/java/tomcat7/websocket-api.jar",
                     "/usr/share/java/tomcat7/tomcat-i18n-ko.jar",
                     "/usr/share/java/tomcat7/tomcat-i18n-ja.jar",
                     "/var/log/tomcat7/catalina.out",
                     "/usr/share/java/tomcat7/tomcat-i18n-zh-CN.jar",
                     "/usr/share/java/tomcat7/tomcat-i18n-fr.jar",
                     "/usr/share/java/tomcat7/tomcat-juli.jar",
                     "/usr/share/java/tomcat7/tomcat-api.jar",
                     "/usr/share/java/ecj.jar",
                     "/usr/share/java/tomcat7/tomcat-dbcp.jar",
                     "/usr/share/java/tomcat7/tomcat-jdbc.jar",
                     "/usr/share/java/tomcat7/catalina-tribes.jar",
                     "/usr/share/java/tomcat7/annotations-api.jar",
                     "/usr/share/java/tomcat7/catalina.jar",
                     "/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.261.x86_64/jre/lib/rt.jar",
                     "/usr/share/java/apache-commons-dbcp.jar",
                     "/usr/share/java/tomcat7-jsp-2.2-api.jar",
                     "/usr/share/java/tomcat7/tomcat-i18n-es.jar",
                     "/usr/share/java/tomcat7/tomcat-coyote.jar",
                     "/usr/share/java/tomcat7-el-2.2-api.jar",
                     "/usr/share/java/tomcat7/jasper-el.jar",
                     "/usr/share/java/tomcat7/tomcat7-websocket.jar",
                     "/usr/share/java/tomcat7/tomcat-i18n-ru.jar",
                     "/usr/share/java/tomcat7/catalina-ha.jar",
                     "/usr/share/java/apache-commons-collections.jar",
                     "/usr/share/tomcat7/bin/bootstrap.jar",
                     "/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.261.x86_64/jre/lib/ext/localedata.jar",
                     "/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.261.x86_64/jre/lib/resources.jar",
                     "/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.261.x86_64/jre/lib/jsse.jar",
                     "/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.261.x86_64/jre/lib/jce.jar",
                     "/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.261.x86_64/jre/lib/ext/sunpkcs11.jar",
                     "/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.261.x86_64/jre/lib/ext/sunjce_provider.jar",
                     "/usr/share/tomcat7/bin/tomcat-juli.jar",
                     "/var/log/tomcat7/localhost_access_log.txt",
                     "/usr/share/java/apache-commons-daemon.jar",
                     "/var/log/tomcat7/catalina.2020-09-01.log",
                     "/var/log/tomcat7/localhost.2020-09-01.log",
                     "/var/log/tomcat7/manager.2020-09-01.log"
              ],
              "dependencies": {}
       }
}

すごい!(小並)

この後のコンテナ化にあたっては設定ファイルをこのまま使います。 実際に利用する際には適宜調整しましょう。 このファイルの仕様については以下のドキュメントで確認できます。

Configuring application containers

コンテナ化

分析が完了したらコンテナ化を実行します。

が、今回の手順だとここでエラーが発生します。

sudo app2container containerize --application-id java-tomcat-36177892
Error retrieving credentials for profile
Failed Containerizing application java-tomcat-36177892

??  Invalid AWS profile provided. Double check your ~/.aws/credentials and ~/.aws/config files to ensure your profile configuration is correct.

どうやら、"root"のホームディレクトリにAWS CLIのためのプロファイルを指定する必要があるようです。 また、インスタンスメタデータから認証情報を取得することもできないようです。 2020年9月1日時点では仕様なのか不具合なのかよくわかっておりませんが、一旦アクセスキーを設定します。 このユーザーに必要な権限については以下のドキュメントをご確認ください。

Identity and access management in App2Container

rootに切り替えます。

sudo su -

アクセスキー・アクセスシークレットキーとリージョンを設定します。

aws configure

ec2-userに戻ります。

exit

ということで再度実行します。 すると、今度は別のエラーが・・・

? AWS prerequisite check succeeded
? Docker prerequisite check succeeded
Failed Containerizing application java-tomcat-36177892

??  Error parsing json. Examine the edited json file and ensure it is a valid json.

JSONファイルが不正とのことなので、lintツールで検証してみます。 ツールのインストール手順は割愛。

sudo cat /root/app2container/java-tomcat-36177892/analysis.json | jsonlint
Error: Parse error on line 109:
...ONNECTION_STRING=\\"\\" -Xms256m -Xmx256
-----------------------^
Expecting 'EOF', '}', ':', ',', ']', got 'undefined'
    at Object.parseError (/home/ec2-user/.nodebrew/node/v14.9.0/lib/node_modules/jsonlint/lib/jsonlint.js:55:11)
    at Object.parse (/home/ec2-user/.nodebrew/node/v14.9.0/lib/node_modules/jsonlint/lib/jsonlint.js:132:22)
    at parse (/home/ec2-user/.nodebrew/node/v14.9.0/lib/node_modules/jsonlint/lib/cli.js:82:14)
    at Socket.<anonymous> (/home/ec2-user/.nodebrew/node/v14.9.0/lib/node_modules/jsonlint/lib/cli.js:149:41)
    at Socket.emit (events.js:326:22)
    at endReadableNT (_stream_readable.js:1244:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)

よく見てみると、analyzeサブコマンド実行後に出力されたファイルから少し書き換わっていました(謎)。。。 ということで修正します。

修正前がこちらで、

"JAVA_OPTS": " -DJDBC_CONNECTION_STRING=\\"\\" -Xms256m -Xmx256m -XX:MaxPermSize=64m",

修正後がこちらです。(暫定)

"JAVA_OPTS": " -DJDBC_CONNECTION_STRING= -Xms256m -Xmx256m -XX:MaxPermSize=64m",

で、再実行します。 三度目の正直で成功しました。

? AWS prerequisite check succeeded
? Docker prerequisite check succeeded
? Extracted container artifacts for application
? Entry file generated
? Dockerfile generated under /root/app2container/java-tomcat-36177892/Artifacts
? Generated dockerfile.update under /root/app2container/java-tomcat-36177892/Artifacts
? Generated deployment file at /root/app2container/java-tomcat-36177892/deployment.json
? Containerization successful. Generated docker image java-tomcat-36177892

? 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-36177892/deployment.json.
3. Generate deployment artifacts using "app2container generate app-deployment --application-id java-tomcat-36177892"

これでコンテナ化の作業は完了です。

まずは生成されたアーティファクトを確認します。

sudo ls -alR /root/app2container/java-tomcat-36177892/
/root/app2container/java-tomcat-36177892/:
total 28
drw-r--r-- 3 root root  4096 Sep  1 14:20 .
drw-r--r-- 4 root root  4096 Sep  1 13:49 ..
-rw-r--r-- 1 root root 10681 Sep  1 14:19 analysis.json
drw-r--r-- 2 root root  4096 Sep  1 14:19 Artifacts
-rw-r--r-- 1 root root  1588 Sep  1 14:20 deployment.json

/root/app2container/java-tomcat-36177892/Artifacts:
total 79808
drw-r--r-- 2 root root     4096 Sep  1 14:19 .
drw-r--r-- 3 root root     4096 Sep  1 14:20 ..
-rw-r--r-- 1 root root 81694720 Sep  1 14:19 ContainerFiles.tar
-rw-r--r-- 1 root root     2223 Sep  1 14:19 Dockerfile
-rw-r--r-- 1 root root      182 Sep  1 14:19 Dockerfile.update
-rwxr-xr-x 1 root root      597 Sep  1 14:19 entryfile
-rw-r--r-- 1 root root      347 Sep  1 14:19 excludedFiles
-rw-r--r-- 1 root root      966 Sep  1 14:19 includeFiles

Dockerfileを確認してみます。

sudo cat /root/app2container/java-tomcat-36177892/Artifacts/Dockerfile
FROM amazonlinux:2018.03
MAINTAINER AWS
WORKDIR /
# Copying Entryfile
COPY entryfile /entryfile
# Pre install packages
RUN yum -y install tar && yum -y install gzip && yum -y install shadow-utils.x86_64
# Adding and unpacking Tar file
COPY ContainerFiles.tar /
RUN tar xvfP /ContainerFiles.tar --directory / --skip-old-files --same-owner --ignore-failed-read && rm -rf /ContainerFiles.tar
# Follow the below example to update files# COPY ["generic_config_file", "/root/app2container/java-tomcat-36177892/Artifacts/generic_config_file"]# Adding advanced app mode installs
RUN yum install -y java-1.7.0-openjdk-devel
# Environment Variables
ENV EC2_HOME /opt/aws/apitools/ec2
ENV HISTCONTROL ignoredups
ENV JAVA_HOME /usr/lib/jvm/jre
ENV TERM linux
ENV CATALINA_BASE /usr/share/tomcat7
ENV PATH /usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin
ENV PWD /usr/share/tomcat7
ENV SHELL /bin/sh
ENV SHUTDOWN_VERBOSE false
ENV USER tomcat
ENV AWS_ELB_HOME /opt/aws/apitools/elb
ENV MAIL /var/spool/mail/tomcat
ENV SHLVL 2
ENV SHUTDOWN_WAIT 30
ENV CATALINA_PID /var/run/tomcat7.pid
ENV LESS_TERMCAP_mb \u001b[01;31m
ENV LESS_TERMCAP_me \u001b[0m
ENV LESS_TERMCAP_ue \u001b[0m
ENV LESS_TERMCAP_us \u001b[04;38;5;111m
ENV TOMCAT_CFG /etc/tomcat7/tomcat7.conf
ENV KILL_SLEEP_WAIT 5
ENV JAVA_OPTS  -DJDBC_CONNECTION_STRING= -Xms256m -Xmx256m -XX:MaxPermSize=64m
ENV LESS_TERMCAP_se \u001b[0m
ENV TOMCAT_USER tomcat
ENV HOME /usr/share/tomcat7
ENV AWS_CLOUDWATCH_HOME /opt/aws/apitools/mon
ENV HISTSIZE 1000
ENV LESSOPEN ||/usr/bin/lesspipe.sh %s
ENV TOMCAT_NAME tomcat7
ENV _ /usr/lib/jvm/jre/bin/java
ENV AWS_AUTO_SCALING_HOME /opt/aws/apitools/as
ENV CATALINA_TMPDIR /var/cache/tomcat7/temp
ENV HOSTNAME ip-172-31-19-69
ENV LESS_TERMCAP_md \u001b[01;38;5;208m
ENV CATALINA_HOME /usr/share/tomcat7
ENV EC2_AMITOOL_HOME /opt/aws/amitools/ec2
ENV JASPER_HOME /usr/share/tomcat7
ENV LANG en_US.UTF-8
ENV LOGNAME tomcat
ENV SECURITY_MANAGER false
ENV AWS_PATH /opt/aws
# Exposing ports
EXPOSE 8080
EXPOSE 8005
# User and user group
RUN groupadd -f -r -g 91 tomcat
RUN id -u tomcat > /dev/null 2>&1 || useradd -r -g 91 -u 91 tomcat
USER tomcat:tomcat
WORKDIR /usr/share/tomcat7
# Image Entrypoint
CMD /entryfile

"deployment.json"の内容も確認します。

sudo cat /root/app2container/java-tomcat-36177892/deployment.json
{
       "a2CTemplateVersion": "1.0",
       "applicationId": "java-tomcat-36177892",
       "imageName": "java-tomcat-36177892",
       "exposedPorts": [
              {
                     "localPort": 8080,
                     "protocol": "tcp6"
              },
              {
                     "localPort": 8005,
                     "protocol": "tcp6"
              }
       ],
       "environment": [],
       "ecrParameters": {
              "ecrRepoTag": "latest"
       },
       "ecsParameters": {
              "createEcsArtifacts": true,
              "ecsFamily": "java-tomcat-36177892",
              "cpu": 2,
              "memory": 4096,
              "dockerSecurityOption": "",
              "enableCloudwatchLogging": false,
              "publicApp": true,
              "stackName": "a2c-java-tomcat-36177892-ECS",
              "reuseResources": {
                     "vpcId": "",
                     "cfnStackName": "",
                     "sshKeyPairName": ""
              },
              "gMSAParameters": {
                     "domainSecretsArn": "",
                     "domainDNSName": "",
                     "domainNetBIOSName": "",
                     "createGMSA": false,
                     "gMSAName": ""
              }
       },
       "eksParameters": {
              "createEksArtifacts": false,
              "stackName": "a2c-java-tomcat-36177892-EKS",
              "reuseResources": {
                     "vpcId": "",
                     "cfnStackName": "",
                     "sshKeyPairName": ""
              }
       }
}

この部分は必要に応じて設定を変更しましょう。 仕様は以下のドキュメントで確認できます。

Configuring container deployment

デプロイ

最後にデプロイします。 が、ここでもつまずきました。 どうやらApp2Containerでデプロイまで行う場合には初期化の際にS3バケットを指定しておく必要があるようです。

sudo app2container generate app-deployment --deploy --application-id java-tomcat-36177892
??  You must configure an S3 Bucket using init

ということで、このタイミングで以下の作業を再度実行します。

  • S3バケットの作成
  • init(S3バケットを指定)

再度デプロイを実行したところ、無事デプロイが開始されました。 デプロイの完了には少々時間がかかるので、待ちましょう。

? AWS prerequisite check succeeded
? Docker prerequisite check succeeded
? Created ECR Repository
? Registered ECS Task Definition with ECS
? Uploaded CloudFormation resources to S3 Bucket: XXXXXXXXXXXX-app2container
? Generated CloudFormation Master template at: /root/app2container/java-tomcat-36177892/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-36177892

? The URL to your Load Balancer Endpoint is:
a2c-j-Publi-153T5R0NSN1U7-140373333.ap-northeast-1.elb.amazonaws.com

? Successfully created ECS stack a2c-java-tomcat-36177892-ECS. Check the AWS CloudFormation Console for additional details.

ちなみに、このデプロイの際にinitで指定したS3バケットにCloudFormationテンプレートが作成されます。

aws s3 ls s3://XXXXXXXXXXXX-app2container --recursive
2020-09-01 23:38:50      12258 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-cluster.yml
2020-09-01 23:38:50       2327 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-dns.yml
2020-09-01 23:38:50      16521 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-gmsa-automation-doc.yml
2020-09-01 23:38:50       2545 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-gmsa-execute.yml
2020-09-01 23:38:50       7216 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-gmsa-iam-roles.yml
2020-09-01 23:38:50       6112 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-gmsa-lambda-functions.yml
2020-09-01 23:38:50       3713 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-gmsa.yml
2020-09-01 23:38:50      16909 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-lb-webapp.yml
2020-09-01 23:38:50      19955 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-master.yml
2020-09-01 23:38:50      10882 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-private-app.yml
2020-09-01 23:38:50       9586 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-public-load-balancer.yml
2020-09-01 23:38:50       3377 a2c-java-tomcat-36177892/ecs/subtemplates/ecs-vpc.yml

また、移行元の環境でもECSのタスク定義が生成されたりECRにコンテナイメージがアップロードされていたり、(良くも悪くも)裏でいい感じにやってくれます。

sudo ls -alR /root/app2container/java-tomcat-36177892/
/root/app2container/java-tomcat-36177892/:
total 40
drw-r--r-- 4 root root  4096 Sep  1 14:46 .
drw-r--r-- 4 root root  4096 Sep  1 13:49 ..
-rw-r--r-- 1 root root 10681 Sep  1 14:19 analysis.json
drw-r--r-- 2 root root  4096 Sep  1 14:36 Artifacts
-rw-r--r-- 1 root root  1588 Sep  1 14:37 deployment.json
drwxr-xr-x 2 root root  4096 Sep  1 14:38 EcsDeployment
-rw-r--r-- 1 root root   580 Sep  1 14:46 pipeline.json
-rw-r--r-- 1 root root  2154 Sep  1 14:38 taskDef.json

/root/app2container/java-tomcat-36177892/Artifacts:
total 79808
drw-r--r-- 2 root root     4096 Sep  1 14:36 .
drw-r--r-- 4 root root     4096 Sep  1 14:46 ..
-rw-r--r-- 1 root root 81694720 Sep  1 14:36 ContainerFiles.tar
-rw-r--r-- 1 root root     2223 Sep  1 14:36 Dockerfile
-rw-r--r-- 1 root root      182 Sep  1 14:36 Dockerfile.update
-rwxr-xr-x 1 root root      597 Sep  1 14:36 entryfile
-rw-r--r-- 1 root root      347 Sep  1 14:36 excludedFiles
-rw-r--r-- 1 root root      966 Sep  1 14:36 includeFiles

/root/app2container/java-tomcat-36177892/EcsDeployment:
total 36
drwxr-xr-x 2 root root  4096 Sep  1 14:38 .
drw-r--r-- 4 root root  4096 Sep  1 14:46 ..
describe-repositories
{
    "repositories": [
        {
            "repositoryUri": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/java-tomcat-36177892",
            "imageScanningConfiguration": {
                "scanOnPush": false
            },
            "registryId": "XXXXXXXXXXXX",
            "imageTagMutability": "MUTABLE",
            "repositoryArn": "arn:aws:ecr:ap-northeast-1:XXXXXXXXXXXX:repository/java-tomcat-36177892",
            "repositoryName": "java-tomcat-36177892",
            "createdAt": 1598971090.0
        }
    ]
}

動作確認

出力されたURLにアクセスしてみます。 問題無さそうですね。

$ curl a2c-j-Publi-153T5R0NSN1U7-140373333.ap-northeast-1.elb.amazonaws.com
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <!--
    Copyright 2010-2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.

    Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at

        http://aws.Amazon/apache2.0/

    or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
  -->
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Welcome</title>
  <style>
  body {
    color: #ffffff;
    background-color: #c7c7c7;
    font-family: Arial, sans-serif;
    font-size:14px;
    -moz-transition-property: text-shadow;
    -moz-transition-duration: 4s;
    -webkit-transition-property: text-shadow;
    -webkit-transition-duration: 4s;
    text-shadow: none;
  }
  body.blurry {
    -moz-transition-property: text-shadow;
    -moz-transition-duration: 4s;
    -webkit-transition-property: text-shadow;
    -webkit-transition-duration: 4s;
    text-shadow: #fff 0px 0px 25px;
  }
  a {
    color: #0188cc;
  }
  .textColumn, .linksColumn {
    padding: 2em;
  }
  .textColumn {
    position: absolute;
    top: 0px;
    right: 50%;
    bottom: 0px;
    left: 0px;

    text-align: right;
    padding-top: 11em;
    background-color: #0188cc;
    background-image: -moz-radial-gradient(left top, circle, #6ac9f9 0%, #0188cc 60%);
    background-image: -webkit-gradient(radial, 0 0, 1, 0 0, 500, from(#6ac9f9), to(#0188cc));
  }
  .textColumn p {
    width: 75%;
    float:right;
  }
  .linksColumn {
    position: absolute;
    top:0px;
    right: 0px;
    bottom: 0px;
    left: 50%;

    background-color: #c7c7c7;
  }

  h1 {
    font-size: 500%;
    font-weight: normal;
    margin-bottom: 0em;
  }
  h2 {
    font-size: 200%;
    font-weight: normal;
    margin-bottom: 0em;
  }
  ul {
    padding-left: 1em;
    margin: 0px;
  }
  li {
    margin: 1em 0em;
  }

  </style>
</head>
<body id="sample">
  <div class="textColumn">
    <h1>Congratulations</h1>
    <p>Your first AWS Elastic Beanstalk Application is now running on your own dedicated environment in the AWS Cloud</p>
  </div>

  <div class="linksColumn">
    <h2>What's Next?</h2>
    <ul>
      <li><a href="http://aws.amazon.com/elasticbeanstalk/ug/">Learn how to build, deploy and manage your own applications using AWS Elastic Beanstalk</a></li>
      <li><a href="http://aws.amazon.com/elasticbeanstalk/concepts/">AWS Elastic Beanstalk concepts</a></li>
      <li><a href="http://aws.amazon.com/elasticbeanstalk/deployment/">Learn how to create new application versions</a></li>
      <li><a href="http://aws.amazon.com/elasticbeanstalk/environments/">Learn how to manage your application environments</a></li>
    </ul>
    <h2>Download the AWS Reference Application</h2>
    <ul>
      <li><a href="http://aws.amazon.com/elasticbeanstalk/referenceapp/">Explore a fully-featured reference application using the AWS SDK for Java</a></li>
    </ul>
    <h2>AWS Toolkit for Eclipse</h2>
    <ul>
      <li><a href="http://aws.amazon.com/elasticbeanstalk/eclipse/">Developers may build and deploy AWS Elastic Beanstalk applications directly from Eclipse</a></li>
      <li><a href="http://aws.amazon.com/elasticbeanstalk/eclipsesc/">Get started with Eclipse and AWS Elastic Beanstalk by watching this video</a></li>
      <li><a href="http://aws.amazon.com/elasticbeanstalk/docs/">View all AWS Elastic Beanstalk documentation</a></li>
    </ul>
  </div>
</script>
</body>
</html>

まとめ

ということで、移行元のアプリケーションのことをよく理解していなくても移行することができました。

この「理解してなくても移行できた」というのは素晴らしいことでもあると同時に危うさも感じます。 もし、この記事を読んでいただいた皆さんが移行先の環境を運用する立場だとします。 よく理解しないままデプロイできたからといってリリースされ運用することを求められたら怖くないですか?私は怖いです。

App2Containerを利用する場合でも生成されたアーティファクトをよく確認し、適切な状態になっているかをよく確認するべきでしょう。 理解することは、大事です。

現場からは以上です。

参考情報

認証情報の設定でめっちゃハマったのですが、こちらの記事に非常に助けられました。圧倒的感謝!

AWS App2Container で既存アプリケーションをコンテナ化しよう