Webアプリを楽々デプロイ!herokuもいいけど、Amazon Elastic Beanstalkもおすすめ!


今回はAmazon Elastic Beanstalk(アマゾンエラスティックビーンスターク)の導入とトラブルシューティングの話です。

最近Web業界ではherokuが話題になっています。簡単にデプロイ・公開できますし、750時間/月なら無料ですし、スケールアウトもheroku公式のGUIからDyno(サーバ)数を増やせば良いので簡単です。もちろんherokuも良いのですが、Amazon Elastic Beanstalkも負けていません。1年間だけであれば無料枠もありますし。

今日はこのAmazon Elastic Beanstalkを使っていきます。始めはGUIでサンプルアプリを作成する手順を紹介します。次にコマンドラインからアプリを作成する手順を紹介します。コマンドラインと言ってもそれほど難しくないので、慣れたらコマンドラインおすすめです。

Amazon Elastic Beanstalkって?

Amazonが提供するPaaSです。

Elastic Beanstalk Management Console

アプリケーションを簡単にデプロイする仕組みとプラットフォームの集合です。プラットフォームと言っても実態はAmazon EC2などで、Elastic Beanstalk経由で作成すると、EC2インスタンスが自動で作成されます。AWSの既存サービスの集合体と言っても良いですが、便利な機能が多数あるのでおすすめです。

準備

以下を準備しておきます。

  1. AWSのアカウント取得 参考:Amazon S3を使ってみた!(zip配布用途でAWS登録~運用まで) S3の作成までは必要ありませんが、アカウント登録までは必要です。
  2. 開発環境 お好きな言語やフレームワークを用意すれば良いですが、今回はNode.jsを例に挙げます

GUIからAmazon Elastic Beanstalkアプリを作ってみる

GUIからアプリ作成

まずはGUIをぽちぽちやってサンプルを作ってみます。

TOPページからCreate Applicationを押して必要事項を以下の要領で入れていきます。画像ではtsuka-sampleなどとなっていますが、自分が分かりやすいように自由に入力してください。

Create Application1

以下の画面ではサーバをどのような構成にするかを設定します。Predefined configurationはご自身の言語に合わせて選択します。今回はNode.jsで行きます。Environment typeは2つありますが、どちらでも良いです。ここではLoadbalancing, auto scalingを選択します。こちらを選択するとEC2インスタンスに加えてロードバランサやオートスケールの設定が追加されます。

AWS無料枠にロードバランサも含まれているようなので、今回はありでやります。

Create Application2

以下はそのままContinueします。

Create Application3

以下もそのままContinueします。ただし、注意があってEnvironment URLとなっている部分はインターネットに公開されます。つまり、画像ではtsukasample-envとなっていますが、これが既に存在する場合は弾かれてしまいます。

sampleなどとありきたりな値は既に取得されているので弾かれます。

Create Application4

ここもそのままContinueします。

Create Application5

ここもそのままContinueします。もし後で生成されたEC2インスタンスに入りたいのであれば、EC2 key pairで予め作成しておいたキーを設定しておくと良いです。これらも結局は後で変更できますし、あまりインスタンスに入る必要もないので、空で問題ありません。

Create Application6

最後に確認画面が出るため、OKを押して完了です。

矢印がくるくる回っていますが、これは現在インスタンスが作成されていたり、デプロイされているということです。暫く待ちます。(1分〜3分)

tsukaSample-env - Dashboard7

完了しました!

tsukaSample-env - Dashboard8

「tsukasample-env.elasticbeanstalk.com」というようにリンクが張られているので早速アクセスしてみます。

Elastic Beanstalk9

デフォルトのサンプルアプリが動いています!以上で完成です。EC2の管理画面もぜひ確認してください。自分が選択・設定したEC2インスタンスやロードバランサが作成されています。

GUIから自作サンプルをデプロイする

次は自作のサンプルを動かしてみます。まずは以下のようなserver.jsを作成して、Node.jsで動かしてみます。画面にres.end()のHTMLを表示する簡単な例です。

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end('<h1>Amazon Elastic Beanstalk tsuka-sample</h1><p>Hello World</p>');
}).listen(3000, '127.0.0.1');
console.log('Server running at http://127.0.0.1:3000/');
node server.js

Page Image10

表示されました。確認はできたので、いよいよGUI経由でElastic Beanstalkにアップロードします。

server.jsをzip圧縮します。ここで圧縮に少し注意が必要です。圧縮は必ずserver.jsがルートに来るようにしなければなりません。解凍したときに何かフォルダがあってその中にserver.jsがある、というような状況だと502 Bad Gatewayになります。

NG

myapp.zip
└ myapp
 └ server.js

OK

myapp.zip
└ server.js

圧縮した上記のアプリをアップロードするとデプロイが始まるのですが、残念ながらこのままでは正しく動きません。502 Bad Gatewayが出ます。

答えはAmazon Elastic BeanstalkのNode.jsアプリはポート8081で動作することを想定しているためです。上記のコードはlistenが3000ポートなのでダメ、だと言う訳です。

答えは簡単ですが、実際にエラーが出たときはログを見て解決することを推奨します。ここでEC2インスタンスにアクセスしてログを見る必要はありません。

ログを見てトラブルシュート

管理ページの左側のLogを押した後で、Snapshot Logsボタンを押します。こうすることでログファイルをかき集めて1つにしてくれます。

tsukaSample-env - Logs11

errorで検索すると案の定それっぽいものが見つかります。

-------------------------------------
/var/log/nginx/error.log
-------------------------------------
2014/03/13 10:06:17 [error] 2154#0: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 172.31.29.100, server: , request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8081/", host: "tsukasample-env.elasticbeanstalk.com"

connect failedでportが8081なので「ん?」と思えます。

修正〜完了

上記のサンプルコードを以下のようにして、ポートを8081に変更します。

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end('<h1>Amazon Elastic Beanstalk tsuka-sample</h1><p>Hello World</p>');
}).listen(8081, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8081/');

これをまたzipにしてアップロードすると正しく動きます。

Page Image12

もし、デプロイに失敗してもElastic Beanstalkは過去のバージョンを保存しておいてくれますので、そこから復元することができます。

Upload and Deploy -> All versionsで一覧を表示して好きなものを選べば元に戻せます。これでもしものときも安全ですね!

tsuka-sample - Application Versions13

CUIからAmazon Elastic Beanstalkアプリをデプロイする

追加準備

  1. gitインストール コマンドを使います。
  2. AWS Elastic Beanstalk Command Line toolインストール http://aws.amazon.com/code/6752709412171743 以降でebコマンドを使うために必要です。 DL後、/usr/localなど適当なところに解凍し、PATHを通しておけば良いです。私はhomebrewを使っているのでbrew install aws-elasticbeanstalkでインストールしました。
  3. AWS access keyとAWS secret keyの取得管理画面右上の名前の部分をクリックしてSecurity Credentialsをクリックします。以下のような画面が表示されるので、Access Keysの部分からCreate New Access Keyボタンを押して生成・メモします。

IAM Management Console14

gitコマンドやebコマンドを使ってデプロイ

こちらも参考になるため、あわせてご覧下さい。

AWS Elastic Beanstalk - Ebを使ってコマンドラインから簡単操作! - Amazon Web Services ブログ

まず前述のserver.jsを再利用していくことにします。違いが分かるようにメッセージを一部変えておきます。

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end('<h1>Amazon Elastic Beanstalk tsuka-sample</h1><p>From eb command</p>');
}).listen(8081, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8081/');

pタグ部分をFrom eb commandとしました。最終的にこれが画面に出るアプリがデプロイできればOKです。

では早速。

# server.jsのディレクトリへ移動
cd [hoge]

# gitリポジトリ作成
git init .

# eb initで生成するアプリのサーバ設定などを行う
# ここではまだ設定ファイルを作っているだけです
eb init

# 以下のようなメッセージが出るので順次答えていきます
# 利用する環境がTomcatやNode.js、SingoleInstanceかLoadBalancerか、などで変わります。ご注意ください。
To get your AWS Access Key ID and Secret Access Key,
  visit "https://aws-portal.amazon.com/gp/aws/securityCredentials".
# 既に一度入力したことがあるならEnter、未入力なら先ほど取得したものを入力
Enter your AWS Access Key ID (current value is "******"):
#既に一度入力したことがあるならEnter、未入力なら先ほど取得したものを入力
Enter your AWS Secret Access Key (current value is "******"):
Select an AWS Elastic Beanstalk service region.
Available service regions are:
1) US East (Virginia)
2) US West (Oregon)
3) US West (North California)
4) EU West (Ireland)
5) Asia Pacific (Singapore)
6) Asia Pacific (Tokyo)
7) Asia Pacific (Sydney)
8) South America (Sao Paulo)
Select (1 to 8): 6
Enter an AWS Elastic Beanstalk application name (auto-generated value is "test"): 
tsuka-sample
Enter an AWS Elastic Beanstalk environment name (auto-generated value is "tsuka-sample-env"): 
tsukaSample-env
Select an environment tier.
Available environment tiers are:
1) WebServer::Standard::1.0
2) Worker::SQS/HTTP::1.0
Select (1 to 2): 1
Select a solution stack.
Available solution stacks are:
1) 32bit Amazon Linux 2014.02 running PHP 5.5
2) 64bit Amazon Linux 2014.02 running PHP 5.5
3) 32bit Amazon Linux 2014.02 running PHP 5.4
4) 64bit Amazon Linux 2014.02 running PHP 5.4
5) 32bit Amazon Linux 2013.09 running PHP 5.4
6) 64bit Amazon Linux 2013.09 running PHP 5.4
7) 64bit Amazon Linux 2013.09 running PHP 5.5
8) 32bit Amazon Linux 2013.09 running PHP 5.5
9) 32bit Amazon Linux running PHP 5.3
10) 64bit Amazon Linux running PHP 5.3
11) 32bit Amazon Linux 2014.02 running Node.js
12) 64bit Amazon Linux 2014.02 running Node.js
13) 32bit Amazon Linux 2013.09 running Node.js
14) 64bit Amazon Linux 2013.09 running Node.js
15) 64bit Windows Server 2008 R2 running IIS 7.5
16) 64bit Windows Server 2012 running IIS 8
17) 32bit Amazon Linux 2014.02 running Tomcat 7 Java 7
18) 64bit Amazon Linux 2014.02 running Tomcat 7 Java 7
19) 32bit Amazon Linux 2014.02 running Tomcat 7 Java 6
20) 64bit Amazon Linux 2014.02 running Tomcat 7 Java 6
21) 32bit Amazon Linux 2013.09 running Tomcat 7 Java 7
22) 64bit Amazon Linux 2013.09 running Tomcat 7 Java 7
23) 32bit Amazon Linux 2013.09 running Tomcat 7 Java 6
24) 64bit Amazon Linux 2013.09 running Tomcat 7 Java 6
25) 32bit Amazon Linux running Tomcat 7
26) 64bit Amazon Linux running Tomcat 7
27) 32bit Amazon Linux running Tomcat 6
28) 64bit Amazon Linux running Tomcat 6
29) 32bit Amazon Linux 2013.09 running Python 2.7
30) 64bit Amazon Linux 2013.09 running Python 2.7
31) 32bit Amazon Linux 2013.09 running Python
32) 64bit Amazon Linux 2013.09 running Python
33) 32bit Amazon Linux running Python
34) 64bit Amazon Linux running Python
35) 32bit Amazon Linux 2014.02 running Ruby 1.9.3
36) 64bit Amazon Linux 2014.02 running Ruby 1.9.3
37) 64bit Amazon Linux 2014.02 running Ruby 1.8.7
38) 32bit Amazon Linux 2014.02 running Ruby 1.8.7
39) 32bit Amazon Linux 2013.09 running Ruby 1.8.7
40) 64bit Amazon Linux 2013.09 running Ruby 1.8.7
41) 32bit Amazon Linux 2013.09 running Ruby 1.9.3
42) 64bit Amazon Linux 2013.09 running Ruby 1.9.3
Select (1 to 42): 12
Select an environment type.
Available environment types are:
1) LoadBalanced
2) SingleInstance
Select (1 to 2): 1
Create an RDS DB Instance? [y/n]: n
Attach an instance profile (current value is "[Create a default instance profile]"):
1) [Create a default instance profile]
2) aws-elasticbeanstalk-ec2-role
3) [Other instance profile]
Select (1 to 3): 2

# 以下のコマンドで実際にアプリケーション(インスタンス)を作成する
eb start

# gitに変更をコミット
git add server.js
git commit -m "initial check-in"

# Elastic Beanstalkにpushしてデプロイを指示する
git aws.push

これでデプロイまでできました!早速URLを覗いてみるとちゃんとデプロイできています!

Page Image15

ここまでgitコマンド、ebコマンド、git aws.pushと非常に少ない手順で実施できました。これなら覚えられますね!

今回eb initのときにいくつか入力を行いました。このとき既にGUIで作成していたアプリ名tsuka-sampleと環境名tsukaSample-envを入力しました。そのため、eb start時にインスタンス等が生成されず、既に存在する環境にデプロイすることができました。もちろん、GUIでアプリや環境を作成していない場合、eb start時に自動で新規作成されます!

コードを変更したときはgit add, commit, aws.pushなどを繰り返せばOKです。

その他便利機能

eb startで作成されるアプリの環境をカスタマイズする

さて、ここまででも十分ですが、もう一つこれは良いかも!と思った機能を紹介します。

Elastic Beanstalkの管理画面にConfiguration -> Environment Propertiesがあります。ここでは自分で自由に環境変数を設定することができます。

tsukaSample-env - Configuration16

例えば上記のように設定するとNODE_ENV変数にproductionが設定された状態でアプリケーションが動作するようになります。これでNODE_ENV=空のときはポート3000かつローカルDB参照モードでアプリを動かし、NODE_ENV=productionのときはポート8081かつ本番用DB参照モードでアプリを動かす、といったコーディングが可能になります。

さて、このページには色々な設定がありますが、実はこれはebコマンドを使うデプロイでも設定することができます。

git initしたフォルダの下の.ebextensionsフォルダにstatic.configというファイルを作成し、以下のように記述します。

option_settings:
  - option_name: NODE_ENV
    value: production

.configファイルの設定の仕方は色々あるので、AWS公式ガイドなどを見ると良いかと思います。

EC2インスタンス作成後にyum installさせるだとか、任意のコマンドを発行させる、だとかもできますので、柔軟に環境を設定できるかと思います。

モニタリング

本格的なサービス運営だとか、サーバの状態調査だとかにはモニタリングが必要です。Elastic Beanstalkにはその機能が自動で備わっています。

anime-lineup-env - Monitoring17

アプリ起動直後はデータが無くて何も出ませんが、ある程度起動しておくと上記のように表示されます。これは便利ですね。

Amazon Elastic Beanstalkいかがでしょうか。まだまだ評価できていない部分や知らない部分も多いですが、現状ではかなり使えると思っています。みなさんも趣味やプロジェクトで使ってみてはいかがでしょうか。