morishitaです。
アクトインディではいこレポやいこーよとりっぷなどいくつかのサービスで稼働環境として AWS Elastic Beanstalkを利用しています。
前回は Elastic Beanstalk で極々簡単な Web アプリをデプロイするして公開するまでを紹介しました。
今回は少し発展的な使い方を紹介します。
もっといろいろ設定したい
前回はほとんど何も設定せず、デフォルトのまま Web アプリをデプロイしました。
Elastic Beanstalk には色々と設定できる項目があり、一旦、「環境」を作ると AWS の Web コンソールから設定できるようになります。
次の様な設定項目があります。
お客様にサービスを提供するシステムを本番運用する場合、デフォルトのままではなく少なくとも次の項目は要件に応じて設定したいのではないでしょうか。
- VPC
- オートスケールやインスタンスのストレージの容量
- ALB
- デプロイポリシー
- ログ出力
- データベースとの接続
Web コンソールから設定しても構わないのですが、これらはすべて設定ファイルでも設定できます。
デプロイする Web アプリのディレクトリの直下に .ebextensions ディレクトリを作り、その中の拡張子 *.config のファイルが設定ファイルとして扱われます。
設定ファイルを利用するとソースコードの一部として変更管理できるのでオススメです。
sample-app/ ├── .ebextensions/ │ ├── 01_vpc.config │ ├── 02_asg.config │ ├── 03_alb.config │ └── 04_update.config ├── .elasticbeanstalk/ │ └── config.yml ├── .gitignore └── docker-compose.yml
設定ファイルは1つにまとめる必要はなく、いくつに分けても構いません。
設定できる項目は「すべての環境に対する汎用オプション」に記されています。
具体的な設定例をいくつか見てみましょう。
デプロイするVPC、サブネットを指定する設定例
次の例はインスタンスを配置する VPC とその中のサブネットを指定する例です。
システムごとに専用の VPC を用意し、ネットワークを分離する場合には設定することになると思います。
設定は option_settings
というキーの配下に定義していきます。
option_settings: aws:ec2:vpc: VPCId: 'vpc-XXXXXXXX' AssociatePublicIpAddress: 'false' Subnets: 'subnet-11111111, subnet-22222222' ELBSubnets: 'subnet-XXXXXXXX, subnet-ZZZZZZZZ'
AssociatePublicIpAddress: 'false'
を設定し、Private サブネットにインスタンスを配置するように設定するとインターネットから直接接続できなくなり、よりセキュアにインスタンスを運用できると思います。
オートスケールやインスタンスのストレージの容量の設定例
次の設定はオートスケーリンググループと起動するインスタンスを設定する例です。
オートスケールする条件や起動するインスタンスのストレージなどを指定しています。
option_settings: aws:ec2:instances: EnableSpot: true # スポットインスタンスを利用するか否か InstanceTypes: 't3.small,t2.small' SecurityGroups: 'sg-00000000000000000' SpotFleetOnDemandBase: '2' # 必ずオンデマンドでプロビジョニングする台数 SpotFleetOnDemandAboveBasePercentage: '33' # オンデマンドを利用する割合 aws:autoscaling:asg: Cooldown: 300 # オートスケール処理の最低感覚 MinSize: 2 # 最低サーバ台数 MaxSize: 10 # 最大サーバ台数 aws:autoscaling:launchconfiguration: RootVolumeType: 'gp3' # ストレージボリュームの種類 RootVolumeIOPS: '3000' # ストレージボリュームの IOPS RootVolumeSize: '10' # ストレージ容量(GB) aws:autoscaling:trigger: # オートスケールのトリガー条件 BreachDuration: 5 MeasureName: CPUUtilization Statistic: Average Unit: Percent UpperThreshold: 80 UpperBreachScaleIncrement: 2 LowerThreshold: 60 LowerBreachScaleIncrement: -1
インスタンスに適用するセキュリティグループも上記の設定例では設定しています。
例えば RDS を利用する場合には通信を許可するように設定したセキュリティグループを適用する必要があります。
「環境」に紐づく RDS のデータベースも作成できますが、Web アプリを稼働する「環境」とそれが利用する DB はライフサイクルが同じでなかったりするので、別途作って接続するように設定したほうがいいかなと個人的に思います1。
ALB の設定例
次の例は ALB のサーバ証明書やヘルスチェックについて設定しています。
option_settings: aws:elbv2:listener:443: # HTTPS を受けるリスナー設定 ListenerEnabled: 'true' Protocol: HTTPS SSLCertificateArns: 'arn:aws:acm:ap-northeast-1:999999999999:certificate/00000000-aaaa-xxxx-zzzz-000000000000' SSLPolicy: 'ELBSecurityPolicy-2016-08' aws:elasticbeanstalk:environment:process:default: # ヘルスチェック設定 DeregistrationDelay: '20' HealthCheckInterval: '30' # ヘルスチェック間隔 HealthCheckPath: /healthcheck # ヘルスチェックするパス HealthCheckTimeout: '25' HealthyThresholdCount: '3' UnhealthyThresholdCount: '5' Port: '80' Protocol: HTTP
デプロイポリシーの設定例
デプロイポリシーは「環境」を更新する場合にどの様にサーバに適用していくかです。
ローリングアップデートするのか? 既存サーバを更新するのか? 新しくインスタンスを起動して入れ替えるのか? などを指定します。
次の設定は全サーバ台数の 20% に当たる数のサーバを新たに起動し、新しいイメージや設定を適用し入れ替えながら更新する設定例です。例えば 10 台で運用している場合、2 台追加しては古いものを 2 台づつ減らしながら更新します。
option_settings: aws:elasticbeanstalk:command: BatchSize: 20 BatchSizeType: 'Percentage' DeploymentPolicy: 'RollingWithAdditionalBatch'
Elastic Beanstalk のデプロイポリシーは「設定変更」に詳しく説明されているのでよく読んで運用に即した設定をすると良いと思います。
リソースを追加する
Elastic Beanstalk で構築されるリソースは EC インスタンスと ALB などですが、その他のリソースも同時に作りたい場合もあると思います。
Elastic Beanstalk は裏で CloudFormation スタックが動きます。
.ebextensions の config ファイルの中で CloudFormation テンプレートの断片を書けばそれに従って標準では作られないリソースを同時に作成可能です。
例えば、次の様な設定を追加すると SNS トピックを通知先とする CloudWatch アラームを追加します。
Parameters: AlermSNSTopic: Type: String Description: "AWS SNS Topic to Notify System Alert" Default: "arn:aws:sns:ap-northeast-1:999999999999:system-alert-notifier" Resources: EBALBHealthyHostCountAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: Fn::Join: [ "-", [Ref: AWSEBEnvironmentName, "EB", "ALB", "no", "healthy", "hosts"] ] AlarmDescription: Fn::Join: [ "", [Ref: AWSEBEnvironmentName, ": ALB no healthy backend hosts."] ] Namespace: AWS/ApplicationELB MetricName: HealthyHostCount Dimensions: - Name: LoadBalancer Value: Fn::GetAtt: [ "AWSEBV2LoadBalancer", "LoadBalancerFullName" ] - Name: TargetGroup Value: Fn::GetAtt: [ "AWSEBV2LoadBalancerTargetGroup", "TargetGroupFullName" ] Statistic: Maximum Period: 60 EvaluationPeriods: 3 Threshold: 1 ComparisonOperator: LessThanThreshold AlarmActions: - Ref: AlermSNSTopic InsufficientDataActions: - Ref: AlermSNSTopic
Elastic Beanstalk が作成するリソースを参照する方法は Elastic Beanstalk が環境向けに作成するリソースを変更する に記載されています。詳しくはそちらを参照ください。
ログの設定
Elastic Beanstalk の設定項目にログがありますが、それらは ALB や Docker などから出力されるもので、Web アプリのアプリケーションログの出力に関するものではないです。
Web アプリのログ出力は docker-compose.yml で設定します。awslogs ドライバーを使って Cloudwatch logs 出力するのが最も簡単だと思います。
設定例を次に示します。
services: app: # 〜 中略 〜 logging: driver: awslogs options: awslogs-region: ap-northeast-1 awslogs-group: /aws/elasticbeanstalk/app awslogs-create-group: "true" tag: 'app-{{ with split .ImageName ":" }}{{join . "_"}}{{end}}-{{.ID}}'
この設定例は CloudWatch logs に /aws/elasticbeanstalk/app というロググループを作成しログを出力します。
tag
の値がログストリームの名前になります。デプロイする Docker イメージ名を含んでいるのでデプロイするイメージ毎にストリームが切り替わる設定となります。
こんな感じで設定により結構柔軟に「環境」をカスタマイズできるのがわかるかと思います。
旧 Docker 環境では移行が促されている
以前より Elastic Beanstalk で Docker コンテナを運用している場合、AWS のコンソールで次の警告が表示されているかと思います。
以前はElastic Beanstalk で Docker コンテナを動かす環境は次の 2 種類でした。
- Multi-container Docker running on 64bit Amazon Linux
- Docker running on 64bit Amazon Linux
いずれも Deprecated となっており、これらで作られた環境では先の警告が出ています。
要は、Multi-container Docker running on 64bit Amazon Linux は非推奨になったので Docker running on 64bit Amazon Linux 2 に乗り換えてねってことです。
移行については次のページにまとまっています。
既存の「環境」の種類を変更できないので、新たな「環境」を Docker running on 64bit Amazon Linux 2 で作って入れ替えることになります。
移行の際には Dockerrun.aws.json という独自の JSON 形式で定義していたコンテナ構成を docker-compose.yml に変更する必要があります。
内容的には両フォーマットで大きな違いはないのでほとんどフォーマット変換だけだと思います。
一点、ログ設定だけはログストリームの指定方法が異なるので前述の設定例を参考にしてもらえればと思います。
docker-compose.yml に書き直したら次のコマンドで「環境」を作成します。
$ eb create <作成する環境名> -p docker
既存「アプリケーション」に「環境」を追加する場合、旧環境の種類がデフォルト設定されていると思うので -p docker
オプションで指定します。
ひょっとすると ALB を使いたいのに CLB で「環境」が作られてしまうかもしれません。その場合は --elb-type application
オプションも追加して指定すると良いです。
まだ、EOS の予定は示されてないですが、「非推奨ブランチには、予定されたリタイア日がある場合があります」とあるので放置しておくとそのうちいつまでに移行しなさいって事になると思います。早めに移行したほうが無難でしょう。
EB CLI の注意点
EB CLI を使っていて、いくつか気になる動きがあったので最後に記述します。
利用しているのは EB CLI 3.20.2 (Python 3.10.)です。
eb init
は AWS_PROFILE が効かない
EB CLI は AWS CLI のクレデンシャルを利用します。
複数のプロファイルを使い分けていて、デフォルトプロファイル以外でコマンドを実行したい場合にはそのプロファイルを指定する必要があります。
コマンドを連続して実行する場合にはいちいち --profile
オプションで指定するのは面倒なので AWS CLI では環境変数 AWS_PROFILE
で設定しておくことができます。
EB CLI でも環境変数 AWS_PROFILE
が基本的に使え、eb create
や eb deploy
では AWS_PROFILE
の設定が効きます。
しかし、eb init
では効かないので --profile
オプションで指定する必要があります。バグなのかなと思います。
eb
コマンドはコミットしている状態をデプロイする
docker-compose.yml や .ebextensions に置いた設定ファイルを Git で管理している場合、EB CLI はコミットしている状態をデプロイします。
最初、これに気づかずハマりました。多分、以前はそうじゃなかったと思うのですが…。
eb deploy
コマンドには --staged
オプションがあり、コミットしなくてもステージングしただけの変更をデプロイできるのですが、eb create
コマンドにはこのオプションがないので実行前に予めコミットしておく必要があります。
これが割と不便なので、EB CLI に Git のコミット状態を無視して保存した状態の設定ファイルをそのままデプロイするオプションがあればいいのになと思いました。
ちなみに Git で管理されていない場合には保存されている設定ファイルがそのままデプロイされます。
まとめ
Elastic Beanstalk を .ebextensions の設定ファイルで設定する方法について紹介しました。 各種設定により要件に即した動作に調整できるだけでなく、リソースを追加も可能です。
Elastic Beanstalk の使い所ですが、結局クラスターを構成するすべてのインスタンスで同じコンテナ構成が起動します。
そのため様々な種類のコンテナを動かして、それぞれ稼働コンテナ数を調整したいような複雑なシステムの運用には向かないと思います。
しかし、モノリスな Web アプリを動かすようなシンプルなシステムを運用する環境としては構築が簡単で便利だと思います。
Docker の稼働環境としては今は過渡期で、Docker running on 64bit Amazon Linux 2 に移行が促されています。 それに伴いちょっと癖のある独自形式を学習する必要がなくなり docker-compose.yml になってより使いやすくなったと思います。
Elastic Beanstalk 自体に料金はかかりません。利用する EC2 インスタンスなどの AWS リソースに課金されるだけです。Heroku を検討するのだったら Elastic Beanstalk と比較してみてもいいかなと思います。
参考
- Elastic Beanstalk 環境の設定 (高度)
- Elastic Beanstalk が環境向けに作成するリソースを変更する
- docker-composeのawslogsロギングドライバー設定|ama2|note
- Amazon CloudWatch Logs ロギング・ドライバ — Docker-docs-ja 19.03 ドキュメント
- Customize log driver output | Docker Documentation
最後に
アクトインディではエンジニアを募集しています。
-
「環境」に紐づけて DB を作成しても後で切り離すこともできるようです。ただ、Elastic Beanstalk のコンソールから RDS の DB を作成する画面では Aurora を選択できないようです。↩