Amazon Web Services ブログ

AWS App2Container と AWS App Runner の統合によるモダナイゼーションシナリオの拡充

この記事は Expanding modernization scenarios using the AWS App2Container integration with AWS App Runner (記事公開日: 2021 年 6 月 22 日) を翻訳したものです。

多くの企業は、コンテナ技術の専門知識を得るための時間に投資することなく最小限の労力で既存のアプリケーションをコンテナ化して迅速にモダナイゼーションしたいと考えています。そのため、AWS では 2020 年 6 月にコードを変更することなく .NET や Java アプリケーションの コンテナ化を支援するサービス AWS App2Container (A2C) をローンチしました。

A2C は実行中のアプリケーションを分析し、依存関係を含むコンテナイメージ、ネットワーク構成、AWS 上でコンテナを実行するためのデプロイ手順を自動的に生成します。ローンチ以来、Amazon Elastic Container Service (Amazon ECS) および Amazon Elastic Kubernetes Service (Amazon EKS) へのコンテナのデプロイをサポートしており、いずれも AWS Fargate オプションを含んでいます。A2C のバージョン 1.4 からは、Tomcat、Spring Boot、汎用アプリケーションを含むコンテナ化された Java アプリケーションの AWS App Runner へのデプロイをサポートすることを発表します。

AWS App Runner は、フルマネージド型のコンテナアプリケーションサービスで、コンテナやインフラの経験がないお客様でも、数回のクリックでコンテナ化された Web アプリケーションや API の構築、デプロイ、実行を簡単に行うことができます。

この記事では、App Runner と A2C の統合によって実現されるモダナイゼーションのシナリオをご紹介します。オンプレミスで稼働しているアプリケーションの AWS への移行、オンプレミスで稼働している Web アプリケーションの AWS App Runner への移行、そして A2C と App Runner による Spring Boot アプリケーションのデプロイという 3 つのユースケースについて深く掘り下げていきます。

A2C と App Runner の統合

App2Container と App Runner の統合により、開発者は実行中の Linux ベースの Web アプリケーションを分析、コンテナ化、App Runner へのデプロイという簡単な手順を踏むだけで、Web サービスにアクセスするためのセキュアな URL を受け取ることができます。ユーザーは、App Runner が提供する継続的なデプロイメント、自動スケーリング、デプロイされた Web サービスのモニタリングを利用することができます。

App2Container が既存のアプリケーションのコンテナ化を容易にする一方で、App Runner はそのようなアプリケーションを AWS 上で実行するための DevOps 対応のプラットフォームを提供します。

始める前に、App Runner がアプリケーションにとって正しいデプロイメントの選択肢であるかどうかを判断するための重要な考慮事項を示します。

  • アプリケーションは、HTTP/2、HTTP/1.1、および HTTP/1.0 プロトコルを使用して、単一ポートを使用してクライアントにサービスを提供しています。
  • アプリケーションは、リクエストを同期的に処理し、レスポンスが送信された後の非同期的処理は一切行いません。リクエストのコンテキスト外のバックグラウンド処理は、ガベージコレクションやロギングなどのマイナーな基本アクティビティに限定されなければなりません。アプリケーションはステートレスです。つまり、リクエストは互いに独立して、リクエストが処理されているインスタンスからも独立して扱われます。ただし、インスタンスの外部に保存されている状態に依存することが可能です。
  • アプリケーションは、水平方向にスケールすることができ、エフェメラルなインスタンスで動作します。

また、App2Cotainer を使用するアプリケーションのコンテナイメージは、Linux x64 プラットフォームで構築され、イメージサイズは 3 GiB を超えないようにしてください。

アプリケーションのステートレス性や水平方向の拡張性など、これらの要件の多くは、クラウドネイティブなアプリケーション設計の原則に沿ったものです。

既存のアプリケーションのコンテナ化と AWS への移行

このユースケースはお客様がコンテナ化やデプロイメントに関するベストプラクティスを求めている最も人気のある分野の 1 つです。ここでは、オンプレミスで動作している Tomcat アプリケーションをリプラットフォームし、AWS App Runner でデプロイする方法を見てみましょう。

A2C は A2C ユーザーガイドに記載されている指示に従って、ダウンロードおよびインストールすることができます。この記事では、A2C と App Runner との統合の実用的な側面に焦点を当てています。

ここでは Tomcat サーバーとアプリケーションが動作している Linux インスタンスに A2C がインストールされていると仮定します。アプリケーションが適合性チェックに合格すると、A2C はデプロイメントターゲットを AWS App Runner として選択するオプションを提供します。

すべての A2C コマンドは、sudo で実行するか、root で実行する必要があります。

$ app2container inventory 
# the output will applications with identifiers eligible for containerization 
# Assuming the application id discovered was java-tomcat-10b413d7 
$ app2container analyze --application-id java-tomcat-10b413d7 
$ app2container containerize --application-id java-tomcat-10b413d7

現時点では App2Container は生成される JSON ファイル内のエスケープ文字を解釈しません。”containerize” コマンドを実行した際に問題が発生した場合は、analysis.json ファイルにエスケープ文字が含まれていないか確認し、”-DJDBC_CONNECTION_STRING=\”<somevalue>\”” などで削除してください。

App Runner へのデプロイ手順

コンテナ化の手順では、アプリケーションの識別子として指定されたディレクトリに、deployment.json ファイルが作成されます。このファイルには、App Runner を含むサポートされているすべてのデプロイメントターゲットのオプションが含まれています。デプロイメントターゲットとして App Runner を選択するには、createAppRunnerArtifacts 属性が “true” に設定されていて、その他のオプションが “false” に設定されていることを確認します。

"ecsParameters": {
    "createEcsArtifacts": false,
    ...
},
"fireLensParameters": {
    "enableFireLensLogging": false,
    ...
},
"eksParameters": {
    "createEksArtifacts": false,
    ...
},
"appRunnerParameters": {
    "createAppRunnerArtifacts": true,
   ...
}

A2C は新しいバージョンのコンテナ化にも使用される可能性があるため、イメージ名とタグをアプリケーション名とバージョンに変更することを検討してください。

ここではオンプレミスで動作する Tomcat アプリケーションの例として snakes アプリケーションを使用しているため、イメージ名は “snakes-a2c-apprunner” と設定されています。

"imageName": "snakes-a2c-apprunner",
"exposedPorts": [
    {
    "localPort": 8080,
    "protocol": "tcp6"
    }
],
"ecrParameters": {
    "ecrRepoTag": "latest"
},

Note: 公開されるポートは 8080 に設定されていますが、8080 はプレーンな HTTP ポートであるため、SSL 終端の処理については課題があります。App Runner では、HTTPS のセキュアなトラフィックの処理を実装する必要はありません。App Runner は、受信する HTTPS トラフィックをハンドリングし、コンテナにリクエストを渡す前に HTTPS を終端します。

コンテナ化が完了したら docker image list を実行してイメージを確認します。以下のような出力が表示されます。

REPOSITORY           TAG    IMAGE ID     CREATED    SIZE
snakes-a2c-apprunner latest 1ac70afe58b7 2 days ago 1.3GB

この場合、イメージサイズを含むすべてのパラメータと、単一の HTTP ポートの要件が、App Runner のデプロイメント要件を満たしています。

次の手順では、以下の App2Container コマンドを使用してアプリケーションのデプロイメントを生成します。このときアプリケーションの識別子は、お使いのマシンで検出されたものに置き換えてください。

app2container generate app-deployment --application-id java-tomcat-10b413d7

生成されたイメージが App Runner のデプロイメント要件を満たしていない場合、コマンドは失敗します。例えば、イメージのサイズが 3 GB のしきい値を超えている場合、以下のようなエラーメッセージが表示されます。

“App Runner requires container images of 3GB or less. Image sizes can be improved by excluding unnecessary files via "appExcludedFiles" in analysis.json prior to containerization".

AppRunnerDeployment ディレクトリに移動すると生成された apprunner.yml という名前の CloudFormation テンプレートが確認できます。デプロイメントオプションをさらに微調整し、CPU とメモリの要件を確認することができます。この手順は、コンテナのランタイム動作に影響するため重要です。例えば、実行時にメモリの制限を超えた場合、App Runner は直ちにインスタンスを終了します。

以下は生成されたテンプレートの例です (パラメータのみ) 。サービス名をアプリケーション ID ではなく適切なものに変更することを検討してください。

ServiceName:
    Type: String
    Default: "a2c-java-tomcat-10b413d7"
    Description: "The name of the App Runner service that will be deployed"
ContainerImage:
    Type: String
    Default: "<YOUR_ACCOUNT>.dkr.ecr.us-east-1.amazonaws.com/snakes-a2c-apprunner:latest"
    Description: "The ECR container image and tag which should be deployed"
EcrRepoArn:
    Type: String
    Default: "arn:aws:ecr:us-east-1:<YOUR_ACCOUNT>:repository/snakes-a2c-apprunner"
    Description: "The ARN representing the ECR repository. App Runner will be granted read access to this repository."
ContainerPort:
    Type: Number
    Default: 8080
    Description: "The application port which should be exposed"
AutoDeploymentsEnabled:
    Type: String
    Default: "true"
    Description: "true if updates to ECR should automatically update the app runner service, else false"
Cpu:
    Type: Number
    Default: 2048
    Description: "CPU value to use for App Runner service"
Memory:
    Type: Number
    Default: 4096
    Description: "Memory value to use for App Runner service"

ここで考慮すべき重要なオプションとして “AutoDeploymentsEnabled” パラメータがあります。これを true に設定すると、Amazon ECR でイメージが更新されたときに、新しいコンテナを自動的にデプロイすることが可能になります。このオプションは、アプリケーションの継続的デリバリ (CD) を可能にするもので、パイプラインが後続のデプロイメントを簡素化できることを意味します。

最後に CloudFormation CLI でデプロイを実行します。

aws cloudformation deploy --template-file ./apprunner.yml --stack-name my-stack --capabilities CAPABILITY_IAM

生成された CloudFormation テンプレートを変更しなかった場合、A2C の generate-appdeployment --deploy コマンドを使用することもできます。

app2container generate app-deployment --application-id java-tomcat-10b413d7 --deploy

数分後、App Runner コンソールに移動して、サービスが稼働している様子を確認することができます。アプリケーションをデプロイしたリージョンに移動します。上記の App Runner コンソールへのリンクは、us-west-2 を使用していることを前提としています。

List of services in the App Runner console

この時点で、提供された URL をクリックし、アプリケーションが実行されていることを確認することができます。

AWS Elastic Beanstalk から移行するためのオプション

デプロイしたアプリケーションが、もともと AWS Elastic Beanstalk 用に作成されているものであるならば、ほとんどの場合、アプリケーションは AWS App Runner でデプロイするための前提条件を満たしているかもしれません。

この使用例を説明するために AWS Elastic Beanstalk で snakes アプリケーションを実行します。この記事では、データベース部分に関するセクションを省略し、アプリケーションのデプロイメントのみに焦点を当てます。

AWS Elastic Beanstalk でアプリケーションを実行しているノードには App2Container がデプロイされないので、App2Container のリモート機能を使います。ターゲットノードへの SSH 接続が必要です。この例では、SSH キーを作成し、EC2 CLI コマンドでインポートし、SSH キーを使って Elastic Beanstalk 環境を初期化します。また、この SSH キーは App2Container のリモート機能で必要になるので、AWS Secrets Manager にアップロードします。

$ pip install awsebcli
$ ssh-keygen -t rsa -f ~/.ssh/a2crsakey -q -P ""
$ aws ec2 import-key-pair --key-name "A2CKEY" \
--public-key-material fileb://~/.ssh/a2crsakey.pub
$ B64KEY=$(base64 ~/.ssh/a2crsakey)
$ echo -e $'{\n "username": "ec2-user",\n "key": "'$B64KEY'"\n}' >> a2ckey.json
$ aws secretsmanager create-secret --name a2ckey --description "A2C secrets" --secret-string file://a2ckey.json

次にサンプルリポジトリをクローンしてアプリケーションをビルドし、生成された SSH キーで Elastic Beanstalk 環境を初期化します。

$ git clone https://github.com/awslabs/eb-tomcat-snakes.git
$ cd eb-tomcat-snakes
~/eb-tomcat-snakes$ ./build.sh
~/eb-tomcat-snakes$ eb init -k A2CKEY

利用している Elastic Beanstalk 環境が、リモートアクセスを可能にするキーを持たずに初期化されている可能性があります。このような場合は、eb ssh --setup を実行して構成します。ただし、この手順を実行するとアプリケーションを再起動することになります。

.elasticbeanstalk/config.yml に以下の内容を追加します。

deploy:
  artifact: ROOT.war

環境を生成します。

~/eb-tomcat-snakes$ eb create tomcat-snakes --sample --single --timeout 20 -i t2.micro

WAR を新しい環境にデプロイします。

~/eb-tomcat-snakes$ eb deploy --staged

サンプルアプリケーションが起動したので、App2Container がインスタンスにリモートで通信するように設定します。インスタンスの IP または FQDN が必要です。EC2 コンソールで確認することができます。

Instance summary in the EC2 console

この時点で Elastic Beanstalk アプリケーションを EC2 インスタンスにリモートアクセスできるように App2Container を設定しましょう。このコマンドには、キーを含むシークレットの ARN が必要になります。以下のコマンドで調べることができます。

aws secretsmanager list-secrets --query "SecretList[?Name=='a2ckey']"

remote configure コマンドを実行してみましょう。IP または FQDN のどちらかが必要です。

$ app2container remote configure
Server IP address:
Server FQDN (Fully Qualified Domain Name): YOUR_FQDN
Authentication method to be used (key/cert)[default: key]:
Secret ARN for remote connection credentials: arn:aws:secretsmanager:us-east-2:<YOUR_ACCOUNT>:secret:a2ckey-9Y2krE
Continue to configure another server? (y/N)[default: n]: n
? Configure successful, you can view hosts config file at: /root/.app2container-config/remote_hosts.conf

App2Container のコマンドをリモートで実行する場合、構文が若干異なりターゲットとなるリモートホストを IP または FQDN で指定する必要があります。

$ app2container remote inventory --target <YOUR_FQDN>
# Outputs a reference to the inventory file where you can look up YOUR_APP_ID

$ app2container remote analyze --application-id YOUR_APP_ID --target <YOUR_FQDN>
# Outputs a reference to extract command

Elastic Beanstalk はアプリケーションのデプロイにシンボリックリンクを利用しますが、この記事を書いている時点では App2Container では完全には機能しません。この動作はツールで対応していますが、analysis.json ファイルの “appSpecificFiles” 属性を以下のように設定する必要があります。

"appSpecificFiles": ["/var/app/current", "/var/log/tomcat"]

次の手順では、extract コマンドを実行して、コンテナ化のためのアーティファクトをリモートホストから持ってきます。

$ app2container remote extract --target <YOUR_FQDN> --application-id YOUR_APP_ID
# Outputs reference to the containerize command

最後のコマンドでは、前のステップで生成された入力アーカイブを使ってコンテナ化します。

$ app2container containerize --input-archive YOUR_APP_ID-extraction.tar

前述の App Runner のデプロイ手順に従って deployment.json を調整し、createAppRunnerArtifacts 属性を true に設定し、Amazon ECS および EKS のデプロイメントオプションを false に設定しておきます。これで、アプリケーションを App Runner でデプロイする準備が整いました。

app2container generate app-deployment --application-id YOUR_APP_ID --deploy

デフォルトでは “AutoDeploymensEnabled” のオプションが “true” に設定されているので、この時点から明示的にアプリケーションをデプロイする必要はありません。新しいバージョンのコンテナイメージを作成し、Amazon ECR にアップロードして自動デプロイメントを開始します。

Spring Boot アプリケーションのコンテナ化とデプロイ

Spring Boot アプリケーションのように、よりクラウドネイティブな設計のアプリケーションをすでに実行している場合はどうでしょうか。この場合、アプリケーションはすでに単一のデプロイ可能なコンポーネントであり、クラウドネイティブの設計原則に従っていると考えられます。このようなアプリケーションは、App Runner で直接デプロイするための主要なターゲットとなります。しかし、このようなシナリオであっても、A2C は、モダナイゼーションを始めるために使用できるコンテナイメージと CloudFormation テンプレートの例を作成することで、お客様のスタートを支援することができます。前のセクションで説明した、このアプリケーションをコンテナ化するための A2C の inventoryanalyzecontainerize コマンドのシーケンスを実行してみましょう。

Spring Boot アプリケーションが Tomcat HTTP コネクターを実行していても、App2Container はそれを Tomcat アプリケーションとは認識しません。つまり、Tomcat や JBoss 用のイメージ最適化は適用されません。このアプリケーションは、一般的な Java プロセスとして認識されます。その結果、一般的なアプリケーションに対しては防御的なアプローチをとるため、イメージサイズが大きくなってしまいます。

$ docker image list 

REPOSITORY
spring-petclinic latest ca76f806f580 4 weeks ago 12.6GB

標準的な Ubuntu サーバーノードで生成されたイメージサイズが 12.6 GB であることに気づくかもしれません。analyze コマンドを実行した後に生成される analyze.json ファイルに exclude および include 属性を使用して、イメージサイズを最適化する方法があります。例えば:

"appExcludedFiles": [
    "/root/.aws",
    "/usr",
    "/etc",
    "/boot",
    "/dev",
    "/media",
    "/proc",
    "/run",
    "/etc",
    "/var",
    "/home/ubuntu/.m2",
    "/tmp",
    "/bin",
    "/lib",
    "/mnt",
    "/opt",
    "/root",
    "/sbin",
    "/snap"
],

App Runner でのデプロイに適したイメージサイズにするためには、何度か繰り返してみる必要があります。

別の方法としては、containerize コマンドで生成される Dockerfile (app2container/YOUR_APP_ID/Artifacts の下にあります) を、例えば下記の例のように、シンプルなものに変更することができます。

FROM openjdk@sha256:cbba399d3e7ed6c54797a0347aa617e9c25150391acf73518476ba63acfa6dc6
COPY spring-petclinic-2.4.2.jar ./
# Image Entrypoint
CMD java '-jar' 'spring-petclinic-2.4.2.jar'

Dockerfile を調整した後は、--build-only オプションを有効にして containerize コマンドを再実行します。

$ app2container containerize --application-id java-generic-a31d4662 --build-only

これは JVM オプションが欠けているため本番環境に対応したビルドファイルではないかもしれませんが、リーズナブルな出発点であり、1 GB 以下の許容できるイメージサイズになります。

Dockerfile を修正してより軽量なイメージを作成した後、前のセクションで説明した App Runner のデプロイ手順に従ってアプリケーションのデプロイメントを生成することができます。

まとめ

この記事では A2C と App Runner の統合により、3 つのユースケースでモダナイゼーションにアプローチできることを紹介しました。この統合により、開発者はインフラ経験がなくてもコンテナ化された Web アプリケーションや API を迅速にデプロイすることができます。

A2C と App Runner を使い始めるにはサービスドキュメントを参照してください。この記事に関するご意見やご感想や App2Container ツールに関する技術的な質問や機能のリクエストがありましたら、app2container-support@amazon.com までメールでお問い合わせください。

リファレンス

https://aws.amazon.com/jp/blogs/news/modernize-java-and-net-applications-remotely-using-aws-app2container/

https://aws.amazon.com/jp/apprunner/

翻訳はプロフェッショナルサービスの高橋たまが担当しました。原文はこちらです。