Elastic Beanstalk とは
Webアプリケーションをアップロードすると、運用に必要な環境の作成、デプロイ、ロードバランシングまで自動で構築できるPaaSである。
環境は、ウェブサーバー環境、ワーカー環境の2種類が用意されている。(公式サイト - Elastic Beanstalk 概念)
また、複数コンテナを動作させるDocker環境の構築も可能。コンテナの管理はECSらしい。(公式サイト - 複数コンテナの Docker 環境)
使ってみる
Elastic Beanstalk をターミナルから使用するためのツールをインストールする。
# とりあえず brew をアップデート
$ brew update
# ツールをインストール
$ brew install awsebcli
HelloWorldしてみる
Elastic Beanstalk はアプリケーションと環境に分かれている。
アプリケーションには、アプリケーション名、キーペア名、ランタイムバージョン、リージョンを設定する。
環境には、オートスケーリング、ELBの設定をする。
アプリケーション
という枠の中にWebアプリケーションを実行する環境
が複数存在するイメージ。
アプリケーションの作成
$ mkdir HelloWorld
$ cd HelloWorld
# アプリケーションを作成する(profileは適宜変更)
$ eb init --profile eb-demo
eb init
を実行して以下の設定値で作成
- リージョン :us-west-2
- アプリケーション名 :(デフォルト)
- ランタイム :PHP
- PHPバージョン :7.2
- キーペア :eb-demo
設定値が完了すると、HelloWorld
ディレクトリの中に以下のファイル、ディレクトリが作成される。
./
├── .gitignore
└── .elasticbeanstalk
└── config.yml
HelloWorld/.elasticbeanstalk/config.yml
の中身には、アプリケーションの情報(アプリケーション名、キーペア名、ランタイムバージョン、リージョン)が設定されている。
branch-defaults:
default:
environment: null
group_suffix: null
global:
application_name: HelloWorld
branch: null
default_ec2_keyname: aws-eb
default_platform: PHP 7.2
default_region: us-west-2
include_git_submodules: true
instance_profile: null
platform_name: null
platform_version: null
profile: null
repository: null
sc: null
workspace_type: Application
環境の作成
環境を作成する。
コマンド実行後、しばらくすると環境が立ち上がる。
デフォルトでは、オートスケーリンググループ、EC2、ELB、セキュリティグループが作成される。
# ebの作成
# 静的なページを返すだけの設定で作成する
$ echo "Hello World" > index.html
# dev-env という名前で環境を作成する
$ eb create dev-env
ステータスの確認
環境のステータスはeb status
で確認できる。
$ eb status
Environment details for: dev-env
Application name: HelloWorld
Region: us-west-2
Deployed Version: app-200503_044529
Environment ID: e-snihahmjcb
Platform: arn:aws:elasticbeanstalk:us-west-2::platform/PHP 7.2 running on 64bit Amazon Linux 2/3.0.0
Tier: WebServer-Standard-1.0
CNAME: dev-env.eba-ijnmvfx5.us-west-2.elasticbeanstalk.com
Updated: 2020-05-02 19:47:39.052000+00:00
Status: Ready
Health: Green
ヘルスの確認
eb health
で環境のヘルスチェックもできる。
ログの確認
eb logs
で環境ないのログを確認できる。
$ eb logs
============= i-087965f9152f39898 ==============
----------------------------------------
/var/log/eb-engine.log
----------------------------------------
2020/05/02 19:47:24.930642 [INFO] Running command /bin/sh -c systemctl stop php-fpm.service
2020/05/02 19:47:24.935046 [INFO] Executing instruction: FlipApplication
2020/05/02 19:47:24.936947 [INFO] create soft link from /var/app/current/ to /var/www/html
2020/05/02 19:47:24.936981 [INFO] Executing instruction: start X-Ray
2020/05/02 19:47:24.936986 [INFO] X-Ray is not enabled.
2020/05/02 19:47:24.936990 [INFO] Executing instruction: start php-fpm
2020/05/02 19:47:24.936997 [INFO] No plugin in cfn metadata.
2020/05/02 19:47:24.937076 [INFO] Running command /bin/sh -c systemctl show -p PartOf php-fpm.service
2020/05/02 19:47:24.942972 [INFO] Running command /bin/sh -c systemctl daemon-reload
2020/05/02 19:47:25.012288 [INFO] Running command /bin/sh -c systemctl reset-failed
2020/05/02 19:47:25.016430 [INFO] Running command /bin/sh -c systemctl show -p PartOf php-fpm.service
2020/05/02 19:47:25.021426 [INFO] Running command /bin/sh -c systemctl is-active php-fpm.service
2020/05/02 19:47:25.024860 [INFO] Running command /bin/sh -c systemctl start php-fpm.service
2020/05/02 19:47:26.366513 [INFO] Executing instruction: start proxy with new configuration
2020/05/02 19:47:26.366550 [INFO] Running command /bin/sh -c /usr/sbin/nginx -t -c /var/proxy/staging/nginx/nginx.conf
2020/05/02 19:47:26.398655 [ERROR] nginx: the configuration file /var/proxy/staging/nginx/nginx.conf syntax is ok
nginx: configuration file /var/proxy/staging/nginx/nginx.conf test is successful
・
・
・
----------------------------------------
/var/log/nginx/access.log
----------------------------------------
172.31.36.8 - - [02/May/2020:19:50:05 +0000] "GET / HTTP/1.1" 200 12 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36" "180.56.80.253"
172.31.36.8 - - [02/May/2020:19:50:06 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://dev-env.eba-ijnmvfx5.us-west-2.elasticbeanstalk.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36" "180.56.80.253"
----------------------------------------
/var/log/nginx/error.log
----------------------------------------
2020/05/02 19:50:06 [error] 3758#0: *26 open() "/var/www/html/favicon.ico" failed (2: No such file or directory), client: 172.31.36.8, server: , request: "GET /favicon.ico HTTP/1.1", host: "dev-env.eba-ijnmvfx5.us-west-2.elasticbeanstalk.com", referrer: "http://dev-env.eba-ijnmvfx5.us-west-2.elasticbeanstalk.com/"
ファイルを更新してデプロイしてみる
index.html
を内容を書き換えてデプロイしてみる。
eb deploy
で環境にデプロイできる。
ファイルを書き換える
$ echo "Hello World 2" > index.html
# デフォルトだと、1回にすべてのインスタンスに対してデプロイを実行する(All at once)
# All at once だとダウンタイムが発生するので注意
$ eb deploy
ちなみに作成、デプロイ時に使用したソースコードと設定ファイルは、s3に保管される。
バケット名はデフォルトだと、elasticbeanstalk-リージョン名-ランダムな文字列
となる。
環境変数を加えてみる
eb setenv key=name
で環境変数を設定できる。
$ eb setenv ENABLE_COOL_NEW_FEATURE=true
アプリケーションを終了する
eb terminate
で環境を終了できる。(環境に関する全てのサービスを削除する)
# このコマンドで終了できる
# コマンドを実行後、環境名を入力してエンター(今回の例では dev-env)
$ eb terminate
設定ファイルの生成とカスタマイズ
起動しているアプリケーションの、設定ファイルを保存することができる。
$ eb config save dev-env --cfg prod
コマンドを実行すると、HelloWorld/.elasticbeanstalk/saved_configs/prod.cfg.yml
が作成される。
中身は、ELBの設定やオートスケーリングの設定等。
EnvironmentConfigurationMetadata:
Description: Configuration created from the EB CLI using "eb config save".
DateCreated: '1588449138000'
DateModified: '1588449138000'
Platform:
PlatformArn: arn:aws:elasticbeanstalk:us-west-2::platform/PHP 7.2 running on 64bit Amazon Linux 2/3.0.0
OptionSettings:
aws:elasticbeanstalk:command:
BatchSize: '30'
BatchSizeType: Percentage
aws:elb:policies:
ConnectionDrainingEnabled: true
aws:elb:loadbalancer:
CrossZone: true
aws:elasticbeanstalk:environment:
ServiceRole: aws-elasticbeanstalk-service-role
aws:elasticbeanstalk:healthreporting:system:
SystemType: enhanced
aws:autoscaling:launchconfiguration:
IamInstanceProfile: aws-elasticbeanstalk-ec2-role
EC2KeyName: eb-demo
aws:autoscaling:updatepolicy:rollingupdate:
RollingUpdateType: Health
RollingUpdateEnabled: true
EnvironmentTier:
Type: Standard
Name: WebServer
AWSConfigurationTemplateVersion: 1.1.0.0
設定ファイルから環境を起動してみる
eb put
で設定ファイルから環境を起動できる。
# prod はファイル名の.cfgの前の部分
$ eb config put prod
設定ファイルに設定を追加する
HelloWorld/.elasticbeanstalk/saved_configs/prod.cfg.yml
にオートスケーリングの設定を追加する。
# OptionSettingsの下に追加
AWSEBAutoScalingScaleUpPolicy.aws:autoscaling:trigger:
UpperBreachScaleIncrement: '2'
AWSEBCloudwatchAlarmLow.aws:autoscaling:trigger:
LowerThreshold: '20'
MeasureName: CPUUtilization
Unit: Percent
AWSEBCloudwatchAlarmHigh.aws:autoscaling:trigger:
UpperThreshold: '50'
設定を反映して起動してみる。
デプロイが完了するとオートスケーリンググループのスケーリングポリシーが更新される。
$ eb config put prod
$ eb config dev-env --cfg prod
デプロイのタイミングで任意の操作を実行
アプリケーションデプロイのタイミングで、インスタンス上で任意のコマンドを実行する仕組みがある。Beanstalkのアプリケーションバンドル直下に.ebextensions
というディレクトリを作り、その中に拡張子.config
が付いた設定ファイルを配置することで制御できる。
(内部では、cloudformationを実行して各種設定を反映している。、AWSコンソール画面上からも確認できる。)
今回の例では、こんなかんじ。
HelloWorld
├── .ebextensions
├── .elasticbeanstalk
│ ├── config.yml
│ └── saved_configs
│ ├── prod.cfg.yml
│ └── initial-configuration.cfg.yml
├── index.html
└── .gitignore
オートスケーリングの設定を制御してみる
autoscaling.config
という名前で、オートスケーリンググループのconfigを作成する。
設定は以下の通り。
option_settings
にオートスケーリングの設定等追加できる。
# docs 1 https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options.html#configuration-options-precedence
# docs 2 https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/ebextensions-optionsettings.html
option_settings:
# docs 3 https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-autoscalingasg
aws:autoscaling:asg:
# 最小 1台
MinSize: 1
# 最大 10台
MaxSize: 10
# スケーリングのクールダウン 240秒
Cooldown: 240
# docs 4 https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-autoscalinglaunchconfiguration
aws:autoscaling:launchconfiguration:
InstanceType: t2.micro
# ImageId: ...
# SecurityGroups: ...
# InstanceIamProfile: ....
以下のコマンドでデプロイする。
# 初回はこちら
$ eb create prod-env --cfg prod
# すでにアプリケーションが起動中ならこちら
$ eb deploy
DynamoDBの作成と接続情報をデプロイ時に設定してみる
dynamodb.config
という名前で、DB作成から接続情報を設定するconfigを作成する。
設定は以下の通り。
Resources
、Outputs
を使用して他のサービスの作成ができる。(CloudFormationと同じ構文)
Resources
で作成したリソースの情報をoptions_settings
で設定している。
Resources:
DynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
KeySchema:
HashKeyElement:
AttributeName: id
AttributeType: S
# create a table with the least available rd and wr throughput
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
NotificationTopic:
Type: AWS::SNS::Topic
Outputs:
NotificationTopicArn:
Description: Notification topic ARN
Value: { "Ref" : "NotificationTopic" }
option_settings:
aws:elasticbeanstalk:application:environment:
# デプロイ時に設定を環境変数に登録
NOTIFICATION_TOPIC: '`{"Ref" : "NotificationTopic"}`'
DYNAMODB_TABLE: '`{"Ref" : "DynamoDBTable"}`'
AWS_REGION: '`{"Ref" : "AWS::Region"}`'
設定を反映して起動してみる。
$ eb deploy
デプロイ後、サーバー内で以下のコマンドを実行すると環境変数に接続情報が設定されていることが確認できる。
$ /opt/elasticbeanstalk/bin/get-config environment -k NOTIFICATION_TOPIC
$ /opt/elasticbeanstalk/bin/get-config environment -k DYNAMODB_TABLE
$ /opt/elasticbeanstalk/bin/get-config optionsettings
デプロイ時にコマンドを実行してみる
commands.config
という名前で、configを作成する。
commands
とcontainer_commands
の違いとしては、前者はアプリケーションのデプロイ前なのでアプリケーション内のファイルに変更を加えることができない。
後者は、アプリケーションがデプロイされたあとなのでアプリケーション内のファイルに変更を加えることができる。
# docs 1 https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html#linux-commands
commands:
create_hello_world_file:
command: touch hello-world.txt
cwd: /home/ec2-user
# docs 2 https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers-ec2.html#linux-container-commands
container_commands:
modify_index_html:
# アプリケーション内のファイルを触れるので、中身を書き換えてみる
command: 'echo " - modified" >> index.html'
database_migration:
command: 'echo "TODO: database migration"'
# 以下の設定で他のcontainer_commandsよりも優先しての実行ができる
leader_only: true
設定を反映して起動してみる。
$ eb deploy
動作を確認してみる。
$ curl http://prod-env.hogehogefugafuga.us-west-2.elasticbeanstalk.com
Hello World
- modified
デプロイポリシーについて
アップデート方法は以下の5通りある。(公式サイト - Elastic Beanstalk 環境へのアプリケーションのデプロイ)
文章だけだとわかりづらいので図説してみる。
All at once
デフォルト設定ではこの方式をとる。
起動中のアプリケーションに一括でデプロイを行う。
デプロイ完了までの時間が短いが、ダウンタイムが発生する。
デプロイに失敗した場合、自動ロールバックにより古いアプリケーションを再度デプロイする。
ローリング(Rolling)
バッチサイズ分のインスタンスをELBからデタッチして、デプロイを行う。
デプロイが完了後、アタッチする。これを全てのインスタンスが新しいアプリケーションになるまで繰り返す。
注意点としては、デタッチするインスタンス分のリソースが環境から減ることになるので、一時的にインスタンス一台あたりの負荷が上昇する点。
また、古いアプリケーションと新しいアプリケーションが混在する時間が存在する。
デプロイに失敗した場合、初回バッチの場合は、自動ロールバックにより古いアプリケーションを再度デプロイするだけでロールバックが完了するが、
初回バッチ以外で失敗した場合、した図のようにバージョンが混在した状態になってしまうので手動による再デプロイが必要になる。
追加バッチとローリング(Rolling with additional batch)
ローリング
と違い、バッチサイズ分のインスタンスを追加するので、リクエストを受け付けるインスタンスの数は変わらない。
バッチサイズ分のインスタンスを追加して、新しいアプリケーションをデプロイする。デプロイ成功後、ELBから新しいアプリケーションをELBにアタッチして、デプロイしたインスタンス分、古いアプリケーションが起動しているインスタンスをデタッチ、終了する。
注意点としては、ローリング
と同じく古いアプリケーションと新しいアプリケーションが混在する時間が存在する点。
デプロイに失敗した場合、ローリング
の場合と同じく初回バッチの場合は、自動ロールバックにより古いアプリケーションを再度デプロイするだけでロールバックが完了するが、初回バッチ以外で失敗した場合、した図のようにバージョンが混在した状態になってしまうので手動による再デプロイが必要になる。
変更不可(Immutable)
新しいアプリケーションをデプロイするための Auto Scaling Group を作成して、動作の確認が取れたインスタンスから古いアプリケーションと同じ Auto Scaling Group に追加する。全てのインスタンスの追加完了後、デプロイ用に作成した Auto Scaling Group の削除と古いアプリケーションが起動しているインスタンスの終了を行う。
注意点としては、古いアプリケーションと新しいアプリケーションが混在する時間が存在する点。
デプロイに失敗した場合、新しいアプリケーションが起動しているインスタンスの終了とデプロイ用に作成した Auto Scaling Group の削除を行う。
ブルーグリーンデプロイ(Blue/Green)
Route53を用意すれば、ブルーグリーンデプロイもサポートしている。(もはやElastic Beanstalkの機能では無い気がするけど)
トラフィックの重み付け等、設定が可能。(カナリアデプロイが利用できる)
下の図はカナリアデプロイの場合
デプロイに失敗した場合、環境の破棄とトラフィックの重み付けの変更を行うことでロールバックが可能。
解決できなかったこと
東京リージョン(とかオハイオとか)では以下のコマンド実行時にエラーが発生した。AWS何もわからない。
$ eb config put prod
ERROR: NotFoundError - Elastic Beanstalk can't find a platform version that matches "PHP 7.4 running on 64bit Amazon Linux 2".