ちょっと話題の記事

Rails on DockerをElastic Beanstalkにデプロイする

2015.04.10

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

 

 

 

AWSアップデート祭りを横目に、認定デベロッパー目指して一人Elastic Beanstalkをあれこれ触っている、八幡です。

個人的な趣味もあり、AWSのサービスについて学ぶときはRubyやRailsを媒介者とすることが多いのですが、今回Elastic Beanstalkに"Rails on Docker"をデプロイしてみましたのでその手順をご紹介します。

構成

Rails-on-Docker-on-EB

Elastic BeanstalkはRDS有りのシングルインスタンス環境です。

RailsアプリはRuby on Rails チュートリアルのサンプルアプリを使いました。(動かしたのはDevelopment環境です。)

Elastic BeanstalkにRails on Dockerをデプロイするやり方は幾通りか考えられるかと思いますが、今回はRailsアプリのソース、Dockerfile、Dockerrun.aws.jsonをローカルマシンに準備して、それらを基にEC2インスタンス上でDockerイメージをビルドする方式でやってみました。

前提

  • ローカルマシン : Mac OSX 10.10.3
  • 作成済みのAWSリソース
    •  Key Pair
    • VPC(EC2用のPublic Subnet×1, RDS用のPrivate Subnet×2)

EB CLIのインストール

Elastic Beanstalkの環境作成やDockerコンテナのデプロイはEB CLIを使って行いますので、予めローカルマシンにインストールしておきます。

$ pip install awsebcli
$ eb --version
EB CLI 3.2.2 (Python 2.7.9)

Railsアプリの準備

DockerにデプロイするRailsアプリを準備します。

Github上のリポジトリをクローンした後、database.ymlを作成します。

$ git clone https://github.com/railstutorial/sample_app_rails_4.git
$ cd sample_app_rails_4
$ cp config/database.yml.example config/database.yml

database.ymlにRDSへ接続するための設定を追加します。DBの情報は環境変数から読み込むようにします。

database.yml

development:
  adapter: mysql2
  database: ENV.fetch('RDS_DB_NAME')
  username: ENV.fetch('RDS_USERNAME')
  password: ENV.fetch('RDS_PASSWORD')
  host: ENV.fetch('RDS_HOSTNAME')
  port: ENV.fetch('RDS_PORT')

RDS有りのElastic Beanstalk環境を作成するとこれらの「RDS_*」はじまりの環境変数が自動的に設定され、Elastic Beanstalkへのデプロイ処理時にDockerコンテナに渡されます。

なおサンプルアプリではdatabase.yml.gitignoreに含まれているので、この設定を削除しておきます。

.gitignore

# Ignore other unneeded files.
database.yml ←この行を削除(またはコメントアウト)する

Gemfileにはmysql2を追加します。

Gemfile

gem 'mysql2'

これでRailsアプリの準備は完了です。

Dockerfile, Dockerrun.aws.jsonの作成

Railsアプリのプロジェクトルート(今回の場合はsample_app_rails_4ディレクトリ直下)にDockerfileを作成します。公式レポジトリにあるRailsイメージを参考に、以下の内容で作成しました。

Dockerfile

# RubyのバージョンはサンプルアプリのGemfileでの指定と合わせる
FROM ruby:2.0

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

ADD Gemfile /usr/src/app/
ADD Gemfile.lock /usr/src/app/
ADD start.sh /usr/src/app/bin/
RUN chmod +x /usr/src/app/bin/start.sh
RUN bundle install

ADD . /usr/src/app

RUN apt-get update && apt-get install -y nodejs --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y mysql-client --no-install-recommends && rm -rf /var/lib/apt/lists/*

EXPOSE 3000
CMD ["bin/start.sh"]

Dockerイメージのビルドの段階では上述の「RDS_*」はじまりの環境変数がコンテナから参照できないため、DBマイグレーション実行&Railsを起動するスクリプト(start.sh)を作成し、docker run時に同スクリプトを実行する形としました。

start.shの中身は以下のとおりです。

start.sh

#!/bin/bash
bundle exec rake db:migrate
bundle exec rails server

Dockerrun.aws.jsonではDockerコンテナで公開するポートを設定します。

Dockerrun.aws.json

{
  "AWSEBDockerrunVersion": "1",
  "Ports" : [{ "ContainerPort": "3000" }]
}

ここまでの変更をコミットしておきます。

$ git add .
$ git commit -m "prepare for eb deployment"

Elastic Beanstalkのアプリケーション作成

ここからはEB CLIを使って作業を行います。まずはじめにeb initコマンドでElastic Beanstalkアプリケーションを作成します。

$ eb init eb-docker-rails --platform docker --keyname aws-eb
Application eb-docker-rails has been created.

eb-docker-railsがアプリケーション名です。オプションとしてプラットフォーム(docker)とキーペア名(aws-eb)を指定します。

クレデンシャル情報はAWS CLIと共通のものが使われます。クレデンシャル情報未設定の場合はeb initの初回実行時に入力を求められます。(アクセスキーとシークレットキー。)

Elastic Beanstalkの環境(ELB, EC2, RDS)作成

続いてeb createコマンドでElastic Beanstalkの環境(EC2, RDS)を作成します。

環境作成には時間がかかるので、--timeoutでコマンド実行のタイムアウトを長めに設定しておきます。(30分など)

eb createはElastic Beanstalkの環境の作成〜アプリケーション(今回の場合はDockerコンテナ)のデプロイまでを実行します。今回は--sampleで一旦AWSで用意されているサンプルアプリケーションをデプロイする形にしました。(環境の作成後に、改めてRailsアプリを含んだDockerコンテナをデプロイします。)

--singleを指定するとELBなしのシングルインスタンス構成の環境が作成されます。

その他のオプションについてはeb create --help公式リファレンスをご参照ください。

$ eb create eb-docker-rails-dev \
--cname eb-rails-dev \
--database \
--sample \
--single \
--vpc \
--vpc.id vpc-34c81951 \
--vpc.publicip \
--vpc.ec2subnets subnet-e1bd1996 \
--vpc.securitygroups sg-2a72f14f \
--vpc.dbsubnets subnet-d2bd19a5,subnet-13629c4a \
--database \
--database.username ebroot \
--database.password <password> \
--instance_type t2.micro \
--tier webserver \
--timeout 30

# 今回はELBは使用しないので、以下はそのままEnter
Enter a comma-separated list of Amazon ELB subnets: [Enter]
Do you want the load balencer to be public? (Select no for internal) (y/n): [Enter]

「Successfully launched environment: <環境名>」と表示されれば作成完了です。

デプロイ

作成したElastic Beanstalkの環境へDockerコンテナをデプロイします。デプロイはeb deployで一撃です。Dockerコンテナのビルドに時間がかかるので、eb createと同様にタイムアウトを長めに設定しておきます。

$ eb deploy --timeout 30

eb deployを実行するとRailsアプリのソース、Dockerfile, Dockerrun.aws.json一式がzip形式でs3にアップロードされ、Dockerコンテナのデプロイが実行されます。「INFO: Environment update completed successfully.」と表示されればデプロイ完了です。

動作確認

eb openを実行するとWebブラウザが自動的に起動しElastic Beanstalkのエンドポイント(URL)にアクセスします。

以下の画面が表示されればデプロイ成功です。

Ruby on Rails Tutorial Sample App 2015-04-10 15-49-56

まとめ

Elastic BeanstalkはRuby環境にも対応しているためRailsアプリを直接デプロイすることも可能ですが、 OSやWebアプリケーションサーバは選択肢が限定されます(Amazon Linux + Passenger or Puma)。 Dockerであればこれらの縛りを受けることがないため、Rubyの実行環境の選択肢が広がります 。なお、実運用観点ではRDSの文字コードやタイムゾーンなどあれこれ追加で設定が必要かと思いますが、今回はDocker on Elastic Beanstalkの検証が主目的のためその辺は省略しています。

EC2 Container ServiceもGA&東京に来たということで、今度はそちらでもRailsを動かしてみたいと思います。

参考URL