読者です 読者をやめる 読者になる 読者になる

VPC 内に Elastic Beanstalk + RDS の環境構築して Rails アプリをデプロイする

aws beanstalk rds rails

環境:
Mac
aws-cli 1.7.0
eb-cli 3.0.10
Ruby 2.1.5
Rails 4.2.0

今回のポイント

  • VPC の環境構築(Subnet, IGW, Route Table)
  • VPC 内に Elastic Beanstalk 環境構築
  • Elastic Beanstalk のプラットフォームは Rubyを選択、Rails アプリをデプロイする。
    • Rails でブログアプリケーションを作る例とする。
  • RDS(MySQL) を作成してアプリと連携する。Beanstalk 作成時ではなく別途作成して関連付けしない。
  • ELB、EC2、RDS は VPC内のパブリックサブネットに置く。
    • RDS はプライベートサブネットに置き、接続するには NAT インスタンス経由にすべきだろうけど、今回はパブリックサブネットにおいてインターネットから直接接続できるようにした。
  • 無料枠で試すので EC2、RDS インスタンスは t2.micro を選択。
  • 環境構築はコマンドライン(aws-cli, eb-cli)だけで行う。
    • 管理コンソールからやったほうが簡単だけど1ヶ月もすると手順を忘れてしまうので、すべてコマンドで作成して、同じ環境を再現できるようにしたかった。

VPC からの環境構築は今回はじめてやるので理解が間違ってるところがあるかもしれない。

事前準備

IAM でユーザ作成し、「Administrator Access」権限を付与、AWS CLIaws configureコマンドでregionaws_access_key_idaws_secret_access_keyを設定しておくこと。

ざっくりやること一覧

  • VPC 作成
  • Subnet 作成
  • IGW 作成
  • Rroute Table 作成
  • DB パラメータグループ作成
  • DB サブネットグループ作成
  • VPC セキュリティグループ作成
  • RDS インスタンス作成
  • Rails アプリケーション作成
  • Elastic Beanstalk 環境設定
  • Elastic Beanstalk 環境作成
  • Rails アプリのデプロイ
  • 環境の削除

VPC 環境構築

VPC 作成

VPC を作成する。

$ aws ec2 create-vpc --cidr-block 10.0.0.0/16
{
    "Vpc": {
        "InstanceTenancy": "default",
        "State": "pending",
        "VpcId": "vpc-d42ae5b1",
        "CidrBlock": "10.0.0.0/16",
        "DhcpOptionsId": "dopt-9ed4cafc"
    }
}

VPC に Name タグを追加する。

$ aws ec2 create-tags --resources vpc-d42ae5b1 --tags Key=Name,Value="vpc blog"

VPC の作成と一緒に

も作成される。これらの関係性は以下の図のようになっている。

VPC のセキュリティ - Amazon Virtual Private Cloud
http://docs.aws.amazon.com/ja_jp/AmazonVPC/latest/UserGuide/VPC_Security.html

f:id:xyk:20150218160355p:plain

Route Table(main) を確認する。

$ aws ec2 describe-route-tables --filters "Name=vpc-id,Values=vpc-d42ae5b1"

...

            "RouteTableId": "rtb-f072a695",
            "VpcId": "vpc-d42ae5b1",

...

Route Table(main) に Name タグを追加する。

$ aws ec2 create-tags --resources rtb-f072a695 --tags Key=Name,Value="rtb blog main"

ACL を確認する。

$ aws ec2 describe-network-acls --filters "Name=vpc-id,Values=vpc-d42ae5b1"

...

            "NetworkAclId": "acl-2ace1b4f",
            "VpcId": "vpc-d42ae5b1",

...

ACL に Name タグを追加する。

$ aws ec2 create-tags --resources acl-2ace1b4f --tags Key=Name,Value="acl blog"

VPC セキュリティグループ(default)を確認する。

$ aws ec2 describe-security-groups --filters "Name=vpc-id,Values=vpc-d42ae5b1"

...

            "GroupName": "default",
            "VpcId": "vpc-d42ae5b1",
            "OwnerId": "123456789012",
            "GroupId": "sg-bdc574d8"

...

VPC セキュリティグループに Name タグを追加する。

$ aws ec2 create-tags --resources sg-bdc574d8 --tags Key=Name,Value="sg blog default"
VPCDNS ホスト名を有効にする

VPC 内の RDS に外部から接続できるようにするため。
参考: VPC の DNS サポートを更新する

# 有効にする
$ aws ec2 modify-vpc-attribute --vpc-id vpc-d42ae5b1 --enable-dns-hostnames

# 確認
$ aws ec2 describe-vpc-attribute --vpc-id vpc-d42ae5b1 --attribute enableDnsHostnames

{
    "VpcId": "vpc-d42ae5b1",
    "EnableDnsHostnames": {
        "Value": true
    }
}

Subnet 作成

3つのサブネットを作成する。
3つともパブリックサブネットとする。
2つ目、3つ目は DB 用として使うので availability-zone を分ける。
自分のアカウントではap-northeast-1aap-northeast-1cの2つが使用可能となっている。

$ aws ec2 create-subnet --vpc-id vpc-d42ae5b1 --cidr-block 10.0.0.0/24 --availability-zone ap-northeast-1a

{
    "Subnet": {
        "VpcId": "vpc-d42ae5b1",
        "CidrBlock": "10.0.0.0/24",
        "State": "pending",
        "AvailabilityZone": "ap-northeast-1a",
        "SubnetId": "subnet-f23be885",
        "AvailableIpAddressCount": 251
    }
}

$ aws ec2 create-subnet --vpc-id vpc-d42ae5b1 --cidr-block 10.0.1.0/24 --availability-zone ap-northeast-1a

{
    "Subnet": {
        "VpcId": "vpc-d42ae5b1",
        "CidrBlock": "10.0.1.0/24",
        "State": "pending",
        "AvailabilityZone": "ap-northeast-1a",
        "SubnetId": "subnet-ff3be888",
        "AvailableIpAddressCount": 251
    }
}

$ aws ec2 create-subnet --vpc-id vpc-d42ae5b1 --cidr-block 10.0.2.0/24 --availability-zone ap-northeast-1c

{
    "Subnet": {
        "VpcId": "vpc-d42ae5b1",
        "CidrBlock": "10.0.2.0/24",
        "State": "pending",
        "AvailabilityZone": "ap-northeast-1c",
        "SubnetId": "subnet-d721d58e",
        "AvailableIpAddressCount": 251
    }
}

サブネットに Name タグを追加する。

$ aws ec2 create-tags --resources subnet-f23be885 --tags Key=Name,Value="subnet public blog web"
$ aws ec2 create-tags --resources subnet-ff3be888 --tags Key=Name,Value="subnet public blog db1"
$ aws ec2 create-tags --resources subnet-d721d58e --tags Key=Name,Value="subnet public blog db2"

インターネットゲートウェイ作成

インターネットゲートウェイ(IGW)を作成する。

$ aws ec2 create-internet-gateway

{
    "InternetGateway": {
        "Tags": [],
        "InternetGatewayId": "igw-85d63ce0",
        "Attachments": []
    }
}

IGW に Name タグを追加する。

$ aws ec2 create-tags --resources igw-85d63ce0 --tags Key=Name,Value="igw blog"

VPC に IGW をアタッチする。

$ aws ec2 attach-internet-gateway --internet-gateway-id igw-85d63ce0 --vpc-id vpc-d42ae5b1

確認する。

$ aws ec2 describe-internet-gateways --internet-gateway-id igw-85d63ce0
{
    "InternetGateways": [
        {
            "Tags": [
                {
                    "Value": "igw blog",
                    "Key": "Name"
                }
            ],
            "InternetGatewayId": "igw-85d63ce0",
            "Attachments": [
                {
                    "State": "available",
                    "VpcId": "vpc-d42ae5b1"
                }
            ]
        }
    ]
}

パブリックサブネット用のルートテーブル作成

デフォルトでサブネットが紐付くメインルートテーブルとは別に新たにカスタムルートテーブルを作成する。
こちらをパブリックサブネット用のルートテーブルとして使用する。

$ aws ec2 create-route-table --vpc-id vpc-d42ae5b1

{
    "RouteTable": {
        "Associations": [],
        "RouteTableId": "rtb-2073a745",
        "VpcId": "vpc-d42ae5b1",
        "PropagatingVgws": [],
        "Tags": [],
        "Routes": [
            {
                "GatewayId": "local",
                "DestinationCidrBlock": "10.0.0.0/16",
                "State": "active",
                "Origin": "CreateRouteTable"
            }
        ]
    }
}

ルートテーブルに Name タグを追加する。

$ aws ec2 create-tags --resources rtb-2073a745 --tags Key=Name,Value="rtb blog public"

パブリックサブネット用ルートテーブルにインターネットゲートウェイを関連付ける

$ aws ec2 create-route --route-table-id rtb-2073a745 --destination-cidr-block 0.0.0.0/0 --gateway-id igw-85d63ce0

サブネットのルートテーブルを切り替え

作成した3つのサブネットに設定されているメインルートテーブルから、新たに作成したパブリックサブネット用ルートテーブルに切り替える。

$ aws ec2 associate-route-table --route-table-id rtb-2073a745 --subnet-id subnet-f23be885

{
    "AssociationId": "rtbassoc-70924015"
}

$ aws ec2 associate-route-table --route-table-id rtb-2073a745 --subnet-id subnet-ff3be888

{
    "AssociationId": "rtbassoc-73924016"
}

$ aws ec2 associate-route-table --route-table-id rtb-2073a745 --subnet-id subnet-d721d58e

{
    "AssociationId": "rtbassoc-7d924018"
}

VPC 環境構築はここまで。


RDS 環境構築

ここからは RDS の環境構築を行う。

以前の投稿も参考に。

  • MySQL 5.6(5.6.22) を使う。
  • Beanstalk 環境作成時に同時に RDS も作成できるが、Beanstalk に関連付けすると Beanstalk 環境の削除時に RDS も一緒に削除しようとするので別途作成する。
  • 今回は Multi-AZ Deployment はしない。

DB パラメーターグループ作成

DB パラメーターグループmydbparamgroupを作成する。

$ aws rds create-db-parameter-group \
--db-parameter-group-name mydbparamgroup \
--db-parameter-group-family mysql5.6 \
--description "for myinstance"

{
    "DBParameterGroup": {
        "DBParameterGroupName": "mydbparamgroup",
        "DBParameterGroupFamily": "mysql5.6",
        "Description": "for myinstance"
    }
}

DB パラメーターグループのキャラクタセット関連のパラメータを更新する。

$ aws rds modify-db-parameter-group --db-parameter-group-name mydbparamgroup --parameters \
ParameterName=character_set_client,ParameterValue=utf8mb4,ApplyMethod=immediate \
ParameterName=character_set_connection,ParameterValue=utf8mb4,ApplyMethod=immediate \
ParameterName=character_set_database,ParameterValue=utf8mb4,ApplyMethod=immediate \
ParameterName=character_set_results,ParameterValue=utf8mb4,ApplyMethod=immediate \
ParameterName=character_set_server,ParameterValue=utf8mb4,ApplyMethod=immediate \
ParameterName=collation_connection,ParameterValue=utf8mb4_general_ci,ApplyMethod=immediate \
ParameterName=collation_server,ParameterValue=utf8mb4_general_ci,ApplyMethod=immediate \
ParameterName=skip-character-set-client-handshake,ParameterValue=0,ApplyMethod=pending-reboot

{
    "DBParameterGroupName": "mydbparamgroup"
}

続いて、init_connect パラメータを更新する。

$ aws rds modify-db-parameter-group --generate-cli-skeleton > init_connect.json

出力されたファイルを以下のように編集する。

{
    "DBParameterGroupName": "mydbparamgroup",
    "Parameters": [
        {
            "ParameterName": "init_connect",
            "ParameterValue": "SET SESSION time_zone = CASE WHEN POSITION('rds' IN CURRENT_USER()) = 1 THEN 'UTC' ELSE 'Asia/Tokyo' END;",
            "Description": "",
            "Source": "",
            "ApplyType": "",
            "DataType": "",
            "AllowedValues": "",
            "IsModifiable": true,
            "MinimumEngineVersion": "",
            "ApplyMethod": "immediate"
        }
    ]
}

そして DB パラメータグループを更新する。--cli-input-jsonオプションでファイルを指定。

$ aws rds modify-db-parameter-group --cli-input-json file://init_connect.json

# 終わったら不要なので削除
$ rm init_connect.json

DB サブネットグループを作成

DB サブネットグループmydbsubnetgroupを作成する。
DB 用に用意した2つのサブネットsubnet public blog db1subnet public blog db2を設定する。

$ aws rds create-db-subnet-group \
  --db-subnet-group-name mydbsubnetgroup \
  --db-subnet-group-description "DB SubnetGroup for myinstance" \
  --subnet-ids subnet-ff3be888 subnet-d721d58e

{
    "DBSubnetGroup": {
        "Subnets": [
            {
                "SubnetStatus": "Active",
                "SubnetIdentifier": "subnet-d721d58e",
                "SubnetAvailabilityZone": {
                    "Name": "ap-northeast-1c"
                }
            },
            {
                "SubnetStatus": "Active",
                "SubnetIdentifier": "subnet-ff3be888",
                "SubnetAvailabilityZone": {
                    "Name": "ap-northeast-1a"
                }
            }
        ],
        "DBSubnetGroupName": "mydbsubnetgroup",
        "VpcId": "vpc-d42ae5b1",
        "DBSubnetGroupDescription": "DB SubnetGroup for myinstance",
        "SubnetGroupStatus": "Complete"
    }
}

DB用 VPC セキュリティグループ作成

DB用 VPC セキュリティグループmyrdsを作成する。

ちなみに DB セキュリティグループと呼ばれるものがあるが、これは VPC 内ではない RDS に適用するもの。
昔の EC2-Classic Platform のアカウントのみ使える。

$ aws ec2 create-security-group \
    --group-name myrds \
    --description "RDS security group" \
    --vpc-id vpc-d42ae5b1

{
    "GroupId": "sg-14c77671"
}

DB用 VPC セキュリティグループに Name タグを追加する。

$ aws ec2 create-tags --resources sg-14c77671 --tags Key=Name,Value="sg blog rds"

RDS MySQL に外部から接続するために Inbound のルールを追加する。

$ aws ec2 authorize-security-group-ingress --group-id sg-14c77671 --protocol tcp --port 3306 --cidr 0.0.0.0/0

RDS インスタンス(MySQL)作成

RDS MySQL インスタンスを作成する。

  • db-instance-identifier はmyinstanceとする。
  • 上記で作成した DB パラメータグループをオプションで指定する。
  • セキュリティグループにデフォルト、上で作成したmyrdsの2つを追加する。
  • RDS MySQL に外部から接続したいので publicly-accessible を追加。
$ aws rds create-db-instance \
--db-instance-identifier myinstance \
--allocated-storage 5 \
--db-instance-class db.t2.micro \
--engine MySQL \
--engine-version 5.6.22 \
--master-username bloguser \
--master-user-password bloguser1234567890 \
--db-name blogdb \
--db-parameter-group-name mydbparamgroup \
--db-subnet-group-name mydbsubnetgroup \
--vpc-security-group-ids sg-bdc574d8 sg-14c77671 \
--storage-type standard \
--availability-zone ap-northeast-1a \
--no-multi-az \
--region ap-northeast-1 \
--publicly-accessible \
--no-auto-minor-version-upgrade

コマンドを実行すると RDS インスタンスの作成がはじまる。しばらく時間がかかるので待つ。
インスタンスの作成が完了したら、以下コマンドでエンドポイントを確認する。

$ aws rds describe-db-instances --db-instance-identifier myinstance | jq '.DBInstances[].Endpoint'
{
  "Port": 3306,
  "Address": "myinstance.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com"
}

PublicIp、PublicDnsName は以下コマンドで確認できる。
GUI 管理コンソールでは、EC2 Dashboard -> Network interfaces から確認できる。

$ aws ec2 describe-network-interfaces --filters "Name=description,Values=RDSNetworkInterface"

...
            "Description": "RDSNetworkInterface",
            "Association": {
                "PublicIp": "54.92.100.249",
                "PublicDnsName": "ec2-54-92-100-249.ap-northeast-1.compute.amazonaws.com",
                "IpOwnerId": "amazon-rds"
            },
...

上で調べた Endpoint または PublicIp、PublicDnsName のいずれかをホストに指定して MySQL に接続できるか確認する。

$ mysql -h myinstance.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -P 3306 -u bloguser -p -D blogdb
$ mysql -h ec2-54-65-198-252.ap-northeast-1.compute.amazonaws.com -P 3306 -u bloguser -p -D blogdb
$ mysql -h 54.65.198.252 -P 3306 -u bloguser -p -D blogdb

RDS 環境構築はここまで。


Rails アプリケーション作成

Rails プロジェクト新規作成

サンプルとしてブログアプリケーションを作成する。
DB には MySQL を使う。ローカル環境に MySQL インストール済み。

$ bundle exec rails new blog -d mysql --skip-bundle
$ cd blog

# アプリケーションサーバとして Puma を選択するので Gemfile に追加
$ echo "gem 'puma'" >> Gemfile

# gem インストール
$ bundle install --path vendor/bundle
scaffold 実行

scaffold コマンドでアプリの雛形を作成する。

$ bin/rails generate scaffold article title:string content:string
ルート修正

config/routes.rb

Rails.application.routes.draw do
  resources :articles
  root 'articles#index'
end
タイムゾーンの設定

config/application.rb

    config.time_zone = 'Tokyo'
    config.active_record.default_timezone = :local
マイグレーション実行

ローカル環境の MySQL に対してマイグレーションを実行する。

$ bin/rake db:create && bin/rake db:migrate
動作確認

ローカル環境でアプリを起動して MySQL にデータ登録、画面にデータ表示できるか確認する。

$ bin/rails s
本番 DB 設定

本番用の DB 設定を修正する。

config/database.yml

production:
  adapter: mysql2
  encoding: utf8mb4
  database: <%= ENV['RDS_DB_NAME'] %>
  username: <%= ENV['RDS_USERNAME'] %>
  password: <%= ENV['RDS_PASSWORD'] %>
  host: <%= ENV['RDS_HOSTNAME'] %>
  port: <%= ENV['RDS_PORT'] %>
Git コミット

Git リポジトリを作成してソースコード一式を add & commit する。

$ git init && git add -A && git commit -m "first commit"

Rails アプリケーション作成まここまで。


Elastic Beanstalk 環境構築

ここからは Elastic Beanstalk の環境構築を行う。

以前の投稿も参考に。

先ほど作成した Rails プロジェクトのディレクトリ内で以下手順を行う。

アプリケーション枠の作成

eb initコマンドでアプリケーション枠を作成する。SSH キーペアは作成してアップロード済み。

$ eb init blog \
--platform "Ruby 2.1 (Puma)" \
--keyname aws-eb

.gitignore が更新されるので add & commit する。

$ git commit -am "updated .gitignore"

Elastic Beanstalk 環境のカスタマイズ設定

EC2 インスタンスタイムゾーンを日本に変更するため、カスタマイズ設定ファイルを準備する。

.ebextensionsディレクトリを作成する。

$ mkdir -p .ebextensions/scripts

Timezone を設定するシェルスクリプトを作成する。

.ebextensions/scripts/timezone.sh

#!/bin/bash
cp -f /usr/share/zoneinfo/Japan /etc/localtime
sed -i -e 's/ZONE=.*$/ZONE="Asia\/Tokyo"/' /etc/sysconfig/clock
sed -i -e 's/UTC=.*$/UTC=false/' /etc/sysconfig/clock
echo 'ARC=false' >> /etc/sysconfig/clock

.ebextensions ディレクトリ直下に config ファイルを作成する。

この config ファイルはデプロイする度に実行される。
タイムゾーン設定は初回の EC2 インスタンス作成時のみ実行すればよいので、test コマンドを使って2回目以降は実行されないようにした。

.ebextensions/01_timezone.config

container_commands:
  01-change_timezone:
    test: '[ ! -f /root/.not-a-new-instance.txt ]'
    command: bash .ebextensions/scripts/timezone.sh
  02-create_check_file:
    test: '[ ! -f /root/.not-a-new-instance.txt ]'
    command: touch /root/.not-a-new-instance.txt

ここまでできたら Git に add & commit する。

$ git add -A && git commit -m "add extensions"

Elastic Beanstalk 環境の作成

eb createコマンドでインスタンスの作成を行う。オプションについてはこちら

  • 環境名はblog-productionとする。
  • 作成したVPC(vpc blog)を指定する。
  • ELB と EC2 には同じパブリックサブネット(subnet public blog web)を指定する。
  • ELB と EC2 をパブリックサブネットに置くので、それぞれelbpublicpublicipを設定する。
  • デフォルトのセキュリティグループ(sg blog default)を指定する。
  • cname オプションでcom-example-blog-productionを設定する。
    • cname オプションを設定することで ELB に CNAME をつけることができる。URL スワップ時に使用する。
  • sample オプションをつける。

sample オプションをつける理由:
eb createコマンドを実行すると、環境構築 -> Rails アプリデプロイ -> DB マイグレーションまで行われるが、config/database.yml の DB 関連のパラメータは環境変数から取得するようなっており、まだ環境変数は未設定なのでパラメータが取得できず、DBマイグレーションに失敗してしまう。

しかし、eb setenvによる環境変数の設定はeb create実行後でなければできない。

ワークアラウンドとして、1発目のデプロイでは--sampleオプションを与えて、カレントディレクトリの Rails プロジェクトではなく、サンプルアプリケーションをデプロイさせる方法で回避する。

$ eb create blog-production \
--sample \
--cname com-example-blog-production \
--instance_type t2.micro \
--region ap-northeast-1 \
--tier webserver \
--vpc.ec2subnets subnet-f23be885 \
--vpc.elbsubnets subnet-f23be885 \
--vpc.id vpc-d42ae5b1 \
--vpc.securitygroups sg-bdc574d8 \
--vpc.publicip \
--vpc.elbpublic

Environment details for: blog-production
  Application name: blog
  Region: ap-northeast-1
  Deployed Version: None
  Environment ID: e-3qvcc2mas3
  Platform: 64bit Amazon Linux 2014.09 v1.2.0 running Ruby 2.1 (Puma)
  Tier: WebServer-Standard-1.0
  CNAME: com-example-blog-production.elasticbeanstalk.com
  Updated: 2015-02-18 08:19:01.355000+00:00
Printing Status:
INFO: createEnvironment is starting.
INFO: Using elasticbeanstalk-ap-northeast-1-123456789012 as Amazon S3 storage bucket for environment data.
INFO: Created security group named: sg-cac677af
INFO: Created load balancer named: awseb-e-3-AWSEBLoa-19XNPJOJ2L4UJ
INFO: Created security group named: sg-d2c677b7
INFO: Created Auto Scaling launch configuration named: awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingLaunchConfiguration-1JJZT8EC6TQTN
INFO: Waiting for EC2 instances to launch. This may take a few minutes.
INFO: Created Auto Scaling group named: awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingGroup-XQ9W5EU82FGI
INFO: Created Auto Scaling group policy named: arn:aws:autoscaling:ap-northeast-1:123456789012:scalingPolicy:6c971967-dbd5-420c-b396-3e9077ca17c5:autoScalingGroupName/awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingGroup-XQ9W5EU82FGI:policyName/awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingScaleUpPolicy-1QMQK2YUBBKEQ
INFO: Created Auto Scaling group policy named: arn:aws:autoscaling:ap-northeast-1:123456789012:scalingPolicy:ec062391-358f-4296-af75-71b20f5d1677:autoScalingGroupName/awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingGroup-XQ9W5EU82FGI:policyName/awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingScaleDownPolicy-6YRVJB2IR2C2
INFO: Created CloudWatch alarm named: awseb-e-3qvcc2mas3-stack-AWSEBCloudwatchAlarmHigh-O9GN3OBFYQK3
INFO: Created CloudWatch alarm named: awseb-e-3qvcc2mas3-stack-AWSEBCloudwatchAlarmLow-18E1BGLOHWKS
INFO: Added EC2 instance 'i-f59d7eed' to Auto Scaling Group 'awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingGroup-XQ9W5EU82FGI'.
INFO: Application available at com-example-blog-production.elasticbeanstalk.com.
INFO: Successfully launched environment: blog-production

画面確認

$ eb open
# http://com-example-blog-production.elasticbeanstalk.com

Elastic Beanstalk 環境変数の設定

eb setenvコマンドで環境変数を設定する。

$ eb setenv \
SECRET_KEY_BASE=`bin/rake secret` \
RDS_DB_NAME=blogdb \
RDS_USERNAME=bloguser \
RDS_PASSWORD=bloguser1234567890 \
RDS_HOSTNAME=myinstance.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com \
RDS_PORT=3306

INFO: Environment update is starting.
INFO: Updating environment blog-production's configuration settings.
INFO: Successfully deployed new configuration to environment.
INFO: Environment update completed successfully.

確認

$ eb printenv
 Environment Variables:
     AWS_SECRET_KEY = None
     RDS_PORT = 3306
     RAILS_SKIP_ASSET_COMPILATION = false
     BUNDLE_WITHOUT = test:development
     RDS_PASSWORD = bloguser1234567890
     SECRET_KEY_BASE = 72ecc50883dd60d2668c5074053c5aae9c7acf5409eccab206053b2cf8e7039871d86ab349fa99cf208350ecbec5091dbd22a3f274b2cb242747d860f5fd6b93
     RACK_ENV = production
     PARAM5 = None
     PARAM4 = None
     PARAM3 = None
     PARAM2 = None
     PARAM1 = None
     RDS_USERNAME = bloguser
     RDS_DB_NAME = blogdb
     RAILS_SKIP_MIGRATIONS = false
     AWS_ACCESS_KEY_ID = None
     RDS_HOSTNAME = myinstance.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com

Rails アプリのデプロイ

ここでカレントディレクトリの Rails プロジェクトをデプロイする。

$ eb deploy
INFO: Environment update is starting.
INFO: Deploying new version to instance(s).
INFO: New application version was deployed to running EC2 instances.
INFO: Environment update completed successfully.

画面確認。

$ eb open

アプリ画面が表示されることを確認。
とりあえず適当なデータを1件登録してみる。

ここで Beanstalk で作成した EC2 インスタンスタイムゾーンと RDS に保存されたレコードの時間を確認する。

まず、EC2 インスタンスの PublicDns, PublicIp を確認する。

# 環境名 blog-production でフィルタする
$ aws ec2 describe-instances --filters "Name=tag-value,Values=blog-production" | jq '.Reservations[].Instances[] | {PublicDnsName,PublicIpAddress}'
# またはインスタンスID指定
# $ aws ec2 describe-instances --instance-ids i-f59d7eed --filters "Name=tag-value,Values=blog-production" | jq '.Reservations[].Instances[] | {PublicDnsName,PublicIpAddress}'

{
  "PublicDnsName": "ec2-54-65-4-37.ap-northeast-1.compute.amazonaws.com",
  "PublicIpAddress": "54.65.4.37"
}

EC2 インスタンスSSH ログインしてタイムゾーンを確認。

$ ssh -i ~/.ssh/aws-eb ec2-user@54.65.4.37

[ec2-user@ip-10-0-0-189 ~]$ date
2015年  2月 18日 水曜日 17:34:28 JST

RDS MySQL にコマンド接続して、セッションの現在時間、テーブルの登録データの日時を確認。

$ mysql -h myinstance.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -P 3306 -u bloguser -p -D blogdb

mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2015-02-18 17:41:00 |
+---------------------+
1 row in set (0.01 sec)

mysql> select * from articles;
+----+-------+---------+---------------------+---------------------+
| id | title | content | created_at          | updated_at          |
+----+-------+---------+---------------------+---------------------+
|  1 | foo   | bar     | 2015-02-18 17:35:40 | 2015-02-18 17:35:40 |
+----+-------+---------+---------------------+---------------------+
1 row in set (0.01 sec)

mysql> \q

次回以降のデプロイでは DB マイグレーションが自動実行されないように環境変数RAILS_SKIP_MIGRATIONSを false から true に変更しておく。

$ eb setenv RAILS_SKIP_MIGRATIONS=true

ここまでで環境構築からアプリデプロイまでの工程が完了した。


後片付け

ここからは、ここまで作成してきたもの削除して元に戻す作業を行う。

Elastic Beanstalk リソース群の削除

ELB、EC2 などの Beanstalk リソース群のすべてを削除する。

$ eb terminate

The environment "blog-production" and all associated instances will be terminated.
To confirm, type the environment name: blog-production
INFO: terminateEnvironment is starting.
INFO: Deleted CloudWatch alarm named: awseb-e-3qvcc2mas3-stack-AWSEBCloudwatchAlarmLow-18E1BGLOHWKS
INFO: Deleted CloudWatch alarm named: awseb-e-3qvcc2mas3-stack-AWSEBCloudwatchAlarmHigh-O9GN3OBFYQK3
INFO: Deleted Auto Scaling group policy named: arn:aws:autoscaling:ap-northeast-1:123456789012:scalingPolicy:ec062391-358f-4296-af75-71b20f5d1677:autoScalingGroupName/awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingGroup-XQ9W5EU82FGI:policyName/awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingScaleDownPolicy-6YRVJB2IR2C2
INFO: Deleted Auto Scaling group policy named: arn:aws:autoscaling:ap-northeast-1:123456789012:scalingPolicy:6c971967-dbd5-420c-b396-3e9077ca17c5:autoScalingGroupName/awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingGroup-XQ9W5EU82FGI:policyName/awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingScaleUpPolicy-1QMQK2YUBBKEQ
INFO: Waiting for EC2 instances to terminate. This may take a few minutes.
INFO: Deleted Auto Scaling group named: awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingGroup-XQ9W5EU82FGI
INFO: Deleted Auto Scaling launch configuration named: awseb-e-3qvcc2mas3-stack-AWSEBAutoScalingLaunchConfiguration-1JJZT8EC6TQTN
INFO: Deleted load balancer named: awseb-e-3-AWSEBLoa-19XNPJOJ2L4UJ
INFO: Deleted security group named: sg-d2c677b7
INFO: Deleted security group named: sg-cac677af
INFO: Deleting SNS topic for environment blog-production.
INFO: terminateEnvironment completed successfully.

RDS 関連の削除

RDS インスタンスの削除

データも削除されるので注意!

# スナップショットは作らず削除
$ aws rds delete-db-instance --db-instance-identifier myinstance --skip-final-snapshot

# スナップショットを作ってから削除
$ aws rds delete-db-instance --db-instance-identifier myinstance \
--no-skip-final-snapshot \
--final-db-snapshot-identifier myinstance-final-snapshot

インスタンス削除が完了するまで待つ。

DB パラメーターグループの削除

DB パラメーターグループmydbparamgroupを削除する。

$ aws rds delete-db-parameter-group --db-parameter-group-name mydbparamgroup
DB サブネットグループの削除

DB サブネットグループmydbsubnetgroupを削除する。

$ aws rds delete-db-subnet-group --db-subnet-group-name mydbsubnetgroup
VPC セキュリティグループの削除

VPC セキュリティグループmyrdsを削除する。

$ aws ec2 delete-security-group --group-id sg-14c77671

VPC 関連の削除

Subnet 削除
$ aws ec2 delete-subnet --subnet-id subnet-f23be885
$ aws ec2 delete-subnet --subnet-id subnet-ff3be888
$ aws ec2 delete-subnet --subnet-id subnet-d721d58e
カスタム Route Table 削除
$ aws ec2 delete-route-table --route-table-id rtb-2073a745
IGW を VPC からデタッチする
$ aws ec2 detach-internet-gateway --internet-gateway-id igw-85d63ce0 --vpc-id vpc-d42ae5b1
IGW 削除
$ aws ec2 delete-internet-gateway --internet-gateway-id igw-85d63ce0
VPC 削除
$ aws ec2 delete-vpc --vpc-id vpc-d42ae5b1

同時に

  • Route Table(main)
  • Network ACL
  • Security Group(default)

も削除される。

ちなみにコマンドから削除する場合は、親の VPC から削除することはできず、上記のように子の方から順に依存関係を解除しないとその親は削除できない。
一方、GUIの管理コンソールから削除する場合は、親の VPC から削除することが可能で、その下に紐付くものすべて削除される(インスタンスが残っている場合などは無理)。