ElasticBeanstalk Custom Platformとは?
今までのElasticBeanstalkでは事前定義済みの環境にアプリケーションをデプロイすることで環境を構築していたが、2017/02/22のリリースでCustom Platformを定義することが可能になった。
これまでもベースAMIをもとにカスタマイズした環境を利用することは可能だったが、AMIの管理(ビルドやバージョン管理、それらを利用したデプロイなど)は自力で行う必要があった。
今回リリースされたCustom PlatformはPackerを利用したAMIのビルドやバージョン管理、デプロイをマネージドサービスとして提供している。
なので、ためしにElixir/Phoenixを起動するCustom Platformを構築してみた。(してみた
というレベルに見合わない時間がかかったけど)
副産物としてerlangのAmazon Linux用のrpmができた。sonodar/erlang-rpm
作成したCustom PlatformのテンプレートやプロビジョニングソースはGithubにあげておきました。
ソースの解説は一番最後に書いてあります。まずはCustom Platformを動かすところから。
Phoenixアプリケーションのビルド方針
- Exrm(Elixirのビルドライブラリ)を利用したコンパイル済みバイナリのデプロイではなく、ソースをデプロイしてElasticBeanstalk(以降、EB)環境上でソースのビルドを行うものとする。
- DBおよびecto(Elixirのスキーママイグレーションライブラリ)は使わない構成とする
- ecto使う事自体は簡単なのでIssueを追加しておいた
- brunch(Phoenixのアセットコンパイル用npmパッケージ)も使わない構成とする
Custom Platformのビルド
awsebcliのインストール
$ brew install awsebcli
テンプレートソースのclone
$ git clone https://github.com/sonodar/elasticbeanstalk-phoenix-platform.git
$ cd elasticbeanstalk-phoenix-platform
ElasticBeanstalk Custom Platformのビルド
以下のコマンドでローカルディレクトリに.elasticbeanstalk/config.yml
ファイルが作成される。
$ ebp init -r ap-northeast-1
Enter Platform Name
(default is "elasticbeanstalk-phoenix-platform"):
この時点ではまだプラットフォームの作成は行われていない。
プラットフォームの作成は以下のコマンドで行う。
初回実行時にPacker実行用のElasticBeanstalk環境(Custom Platform Builder
)も自動的に作成される。
$ ebp create
INFO: createPlatform is starting.
INFO: Initiated platform version creation for 'elasticbeanstalk-phoenix-platform/1.0.0'.
INFO: Creating Packer builder environment 'eb-custom-platform-builder-packer'.
INFO: Starting Packer building task.
INFO: Creating CloudWatch log group '/aws/elasticbeanstalk/platform/elasticbeanstalk-phoenix-platform'.
# ... 中略 ...
INFO: 'packer build' finished.
INFO: Successfully built AMI(s): 'ami-93a5fef4' for 'arn:aws:elasticbeanstalk:ap-northeast-1:xxxxxxxxxxxx:platform/elasticbeanstalk-phoenix-platform/1.0.0'
INFO: Creating CloudWatch log group '/aws/elasticbeanstalk/platform/elasticbeanstalk-phoenix-platform'.
INFO: Successfully built AMI(s): 'ami-93a5fef4' for 'arn:aws:elasticbeanstalk:ap-northeast-1:xxxxxxxxxxxx:platform/elasticbeanstalk-phoenix-platform/1.0.0'
INFO: Packer built AMIs: ami-93a5fef4.
INFO: Successfully created platform version 'elasticbeanstalk-phoenix-platform/1.0.0'.
作成された環境の確認。Status
がReady
となっていればプラットフォームの作成が成功している。
$ ebp list
arn:aws:elasticbeanstalk:ap-northeast-1:xxxxxxxxxxxx:platform/elasticbeanstalk-phoenix-platform/1.0.0 Status: Ready
今回用のサンプルPhoenixプロジェクトの作成
Macの場合はおもむろに以下のコマンドを打つ。
brew install elixir
mix local.hex
mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez
mix phoenix.new eb_phoenix --no-brunch --no-ecto
cd eb_phoenix
依存ライブラリをインストールするかどうか聞かれるのでy
応答
Fetch and install dependencies? [Yn] y
動作確認。以下のコマンドを実行して http://localhost:4000 にアクセス。
mix phoenix.server # 停止は Ctrl+C を2回
サンプルアプリケーションを作成したCustom Platformで起動
eb init
コマンドで初期化する。platform選択で13) Custom Platform
を選択。
$ cd eb_phoenix
$ eb init -r ap-northeast-1
Select an application to use
1) Custom Platform Builder
2) [ Create new Application ]
(default is 2):
Enter Application Name
(default is "eb_phoenix"): eb-phoenix
Select a platform.
1) Node.js
2) PHP
3) Python
4) Ruby
5) Tomcat
6) IIS
7) Docker
8) Multi-container Docker
9) GlassFish
10) Go
11) Java
12) Packer
13) Custom Platform
(default is 1): 13
Select a platform.
1) elasticbeanstalk-platform-phoenix (Owned by: xxxxxxxxxxxx)
(default is 1): 1
Do you want to set up SSH for your instances?
(Y/n): Y
Select a keypair.
1) sonodar
2) [ Create new KeyPair ]
(default is 1): 1
eb create
コマンドでEB環境を作成する。今回はお試しなのでシングル構成(-s
オプション)
$ eb create -s
Enter Environment Name
(default is eb-phoenix-dev): eb-phoenix-dev
Enter DNS CNAME prefix
(default is eb-phoenix-dev): eb-phoenix-dev
Creating application version archive "app-84db-170327_132118".
Uploading eb-phoenix/app-84db-170327_132118.zip to S3. This may take a while.
Upload Complete.
Application eb-phoenix has been created.
Environment details for: eb-phoenix-dev
Application name: eb-phoenix
Region: ap-northeast-1
Deployed Version: app-84db-170327_132118
Environment ID: e-7fshvxwyad
Platform: arn:aws:elasticbeanstalk:ap-northeast-1:xxxxxxxxxxxx:platform/elasticbeanstalk-platform-phoenix/1.0.0
Tier: WebServer-Standard
CNAME: eb-phoenix-dev.ap-northeast-1.elasticbeanstalk.com
Updated: 2017-03-27 04:21:21.816000+00:00
Printing Status:
INFO: createEnvironment is starting.
INFO: Using elasticbeanstalk-ap-northeast-1-xxxxxxxxxxxx as Amazon S3 storage bucket for environment data.
INFO: Created EIP: 52.197.66.130
INFO: Created security group named: awseb-e-7fshvxwyad-stack-AWSEBSecurityGroup-1T9MF5U46H463
INFO: Waiting for EC2 instances to launch. This may take a few minutes.
INFO: Adding instance 'i-065353dcfcb113901' to your environment.
INFO: Successfully launched environment: eb-phoenix-dev
以上。ElasticBeanstalkのHTTPエンドポイントにアクセスしてみるとPhoenixの画面が見れる。
Custom Platform テンプレートソース解説
TODO: あとで書く
ポイント
- ElasticBeanstalkのデプロイシーケンスを理解する
- PhoenixアプリケーションのDaemon/Service化にはUpstartを利用
- ElasticBeanstalkのEnvironmentをパースしてファイルに出力
- 今回のためにErlangのrpmを作成した (sonodar/erlang-rpm)
ハマったところ
ebp list
やebp delete
コマンドはCustom Platform Builder
が起動していないとエラーになる。
Custom Platform Builder
はCustom Platformのビルド時以外は不要のため、普段は環境を落としておいたほうがいいのだが、落とした状態でebp
コマンドを実行すると以下のように意味不明なエラーメッセージとともに失敗する。
ERROR: TypeError :: cannot concatenate 'str' and 'list' objects
ebp create
コマンドはIAMのCreateRole
権限がないと失敗する
ebp create
を初めて実行した際にPacker実行用環境であるCustom Platform Builder
が利用するaws-elasticbeanstalk-custom-platform-ec2-role
というIAMロールも自動生成される。
CreateRole権限がないとエラーになるため権限のあるアカウントか、以下のポリシーをアタッチしておくこと。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "GrantCreateRole",
"Action": [
"iam:Create*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
それか、あらかじめaws-elasticbeanstalk-custom-platform-ec2-role
をEC2用のロール(インスタンスプロファイル付き)として以下のポリシーで作っておく。
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PackerEC2Access",
"Action": [
"ec2:AttachVolume",
"ec2:AuthorizeSecurityGroupIngress",
"ec2:CopyImage",
"ec2:CreateImage",
"ec2:CreateKeypair",
"ec2:CreateSecurityGroup",
"ec2:CreateSnapshot",
"ec2:CreateTags",
"ec2:CreateVolume",
"ec2:DeleteKeypair",
"ec2:DeleteSecurityGroup",
"ec2:DeleteSnapshot",
"ec2:DeleteVolume",
"ec2:DeregisterImage",
"ec2:DescribeImageAttribute",
"ec2:DescribeImages",
"ec2:DescribeInstances",
"ec2:DescribeRegions",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSnapshots",
"ec2:DescribeSubnets",
"ec2:DescribeTags",
"ec2:DescribeVolumes",
"ec2:DetachVolume",
"ec2:GetPasswordData",
"ec2:ModifyImageAttribute",
"ec2:ModifyInstanceAttribute",
"ec2:ModifySnapshotAttribute",
"ec2:RegisterImage",
"ec2:RunInstances",
"ec2:StopInstances",
"ec2:TerminateInstances"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Sid": "BucketAccess",
"Action": [
"s3:Get*",
"s3:List*",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::elasticbeanstalk-*",
"arn:aws:s3:::elasticbeanstalk-*/*"
]
},
{
"Sid": "CloudWatchLogsAccess",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams"
],
"Effect": "Allow",
"Resource": "arn:aws:logs:*:*:log-group:/aws/elasticbeanstalk/platform/*"
}
]
}
[追記]
arn:aws:iam::aws:policy/AWSElasticBeanstalkCustomPlatformforEC2Role
というマネージドポリシーがあるからそれを使えばいいみたいだ。内容は上記インラインポリシーと同じ。
Custom Platform用のリポジトリとアプリケーション用のリポジトリは分けないといけない
Custom Platformテンプレート用のGitリポジトリとデプロイするソースのリポジトリは分けないといけない模様。
ソースリポジトリのサブディレクトリにCustom Platformビルド用のディレクトリを作成してebp init
などを実行すると以下のエラーになる。
$ ebp init
ERROR: This command is not supported for Application workspaces.
リポジトリの.elasticbeanstalk/config.ymlファイルに以下の記述があるので、ここを見ているようだ。
global:
# ... 略
workspace_type: Platform
拡張ヘルスチェック・・・?
よく知らないのだけど、ElasticBeanstalkの拡張ヘルスチェック機能というのがある。PIDファイルを監視してくれるらしい。
PhoenixはPIDをファイルに吐いてくれない。
ここを参考にUpstartの定義ファイルを作った。
参考
Dockerを使わない理由(あくまで個人的なイメージです)
- イメージの管理が面倒(Dockerイメージ用のCI/CDが必要)
- td-agentを使いたい場合、マルチコンテナ構成になって面倒
- Dockerボリュームのレイテンシが気になる
- インスタンスストア(エフェメラルディスク)を使いたい
- プラットフォームカスタマイズの頻度が高い
- EB on Dockerの場合、スケールはEC2単位?
- ECSと違い、コンテナ単位でのスケールができない?
- そもそも余剰リソースがなければDockerのスケールは意味がない