1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】Railsアプリをデプロイする方法について

Posted at

記事概要

AWSのサーバーにRuby on Railsのアプリをデプロイする方法について、まとめる

前提

  • Macを使用している
  • Ruby on Railsでアプリケーションを作成している
  • AWSのアカウントを保持している

構築イメージ

AWS上にサーバーを作成することは、家を建てることに似ている。「サーバー=家」として説明する

サーバーとは

インターネットの世界は、どこまでも続く砂漠のような空間。その砂漠の上にある家が、サーバーになる

もし自身のアプリケーションを世界中に公開したい場合、まずサーバーという家を作成する必要がある。しかし、広大なインターネットという砂漠の真ん中に家を建てるのは、とても不便。なぜなら、家の住所も決まっていないし、セキュリティ対策も不十分になってしまうため。

AWSを使うと、住所を決めたり、適切なセキュリティ対策を簡単に設定できる

AWSを使わずに自分で一から家を建てることもできるが、自分だけの敷地を作ったり、しっかりとした家を建てるための材料を集めたり、実際に家を建てる時間と労力を考えると、かなり大変な作業になる

家を建てる場所を決める(リージョンとアベイラビリティーゾーン)

新しく家を建てるときは、まずどこに家を建てるのか場所を決める。
同じく、AWSでサーバーを作成するときは、まずリージョンアベイラビリティーゾーンという場所を決める

リージョン

国や地域を指す

サーバーを作成するときには、どの「リージョン」にするのか場所を選ぶ
基本的には自分が住んでいる場所と近いリージョンを選ぶのが良い。メリットは下記2つ

  • 物理的に近くなるため通信速度が速くなる
  • データが存在する場所の近くにいたほうが法律を守りやすい

アベイラビリティーゾーン

リージョンの中の特定のデータセンター施設を指す
指定しなければ、サーバー作成時に自動で振り分けられる

自分の敷地を作り、区画で分ける(VPCとサブネット)

家を建てる場所を決めたら、その場所に自分だけの敷地を作る。この敷地をVirtual Private Cloud(VPC)という

Virtual Private Cloud(VPC)

自分専用の敷地を指す。VPCにより他のユーザーやインターネットから独立した場所で、サーバーという家を建てることができる

サブネット

VPCという敷地の中に区画を作って小さく分けることができる
一つの敷地に一軒の家だけでなく、いくつかの家を置きたい場合などにサブネットという区画で敷地を分けると便利

  • パブリックサブネット
    全世界に公開できる
  • プライベートサブネット
    VPCという自分専用の敷地の中でのやりとりに使用できる

設計図から家を建てる(AMIとEC2インスタンス)

どんな大きさの家にするのかなどの情報が入った設計図を選び、それに基づいて家を建てる

AWSではサーバーを作成するための設計図のことを、Amazon Machine Image(AMI)という

Amazon Machine Image(AMI)

AMIにはコンピュータの大きさやWindowsやLinuxなどのオペレーティングシステムの情報が含まれている。このAMIという設計図からサーバーを作成する

EC2インスタンス

AWS上に作成するサーバーのことであり、「Elastic Compute Cloud」の略。「インターネット上のコンピュータ」という意味

門を設置する(インターネットゲートウェイ)

VPCという自分専用の敷地から全世界と繋がるためには、門と住所が必要になる

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

全世界と繋がるための門

IPアドレス

全世界からサーバーへアクセスするための「住所」

パブリックIPアドレス

全世界からサーバーへアクセスできる住所
※サーバーを再起動したりすると住所が変わってしまう

プライベートIPアドレス

VPCという自分の敷地内でのみ、使える住所

変わらない住所を作る(EIP)

Elastic IP

全世界に対していつも同じ住所を提供したい場合に使用する
EIPはパブリックIPのひとつで、サーバーを止めたり再起動したときでも変わらないIPアドレス

家に出入口の玄関を作る(ポート)

家に出入りするための玄関を作り、アクセスルールを決める

ポート

アクセスの玄関の役割

それぞれのポートには番号が割り振られており、訪問者はポートの番号を指定すれば、そのポートからサーバーへ入ることができる。一つのサーバーで最大65,536個までのポートを設けることが可能

ただし、最初の1,024個のポート(0 - 1023番)は特別な訪問者が使うために予約されており、これらの玄関はサーバーの持ち主でも自由に使うことができない

例えば、通常のアクセス(HTTP通信)は80番のポートを使い、セキュリティが施されたアクセス(HTTPS通信)は443番のポートからサーバーへ入る

家に柵を作る(セキュリティーグループ)

全世界からサーバーへアクセスできるようになったが、誰でもサーバーというコンピュータを操作できてしまうのは避けたい。コンピュータを操作する人を限定するにはサーバーに錠と鍵をかけることが必要になる

セキュリティグループ

インターネットからの攻撃から、コンピュータを守る役割

セキュリティグループでアクセスの出入りをポートや決まったIPアドレスを指定して、許可する設定を行う。これによってアクセスを限定することができる

アクセスには外部からサーバーに向かうインバウンドと、サーバーから外部へ向かうアウトバウンドの2つの方向がある。セキュリティグループでどのポートからアクセスの出入りができるのかを設定する。それにより、サーバーのセキュリティを高めることができる

インバウンド

外部からサーバーへ向かう入り口のアクセス

インバウンドルール

外部からのアクセスを制御するためのルール

特定のIPアドレスからのSSH接続やHTTPアクセスを許可したい場合、セキュリティグループでインバウンドルールを設定

アウトバウンド

サーバーから外部へ向かう出口のアクセス

アクセスを制限してセキュリティを高めるため、サーバーに鍵をかけてコンピュータを操作できる人を限定することができる

家に錠と鍵を作る(キーペア)

キーペア

家の鍵を作る時、錠と鍵がちゃんと合うこと

AWSのキーペアも同じで、公開鍵と秘密鍵の2つの部分に分かれている。キーペアは、インターネットからEC2インスタンスを操作する人を限定するために必要。公開鍵はAWS側で見えるところに置かれる

公開鍵

公開鍵は家の錠前に例えられる。公開鍵はAWS側にあるので、見えるところに置かれている。公開鍵はAWS側で管理する

秘密鍵

秘密鍵は家の鍵と同じでユーザーが管理する鍵。とても大切なので、絶対に無くしてはいけない

秘密鍵があればAWSにある公開鍵を開け、EC2インスタンスの中に入ることができる。とても大切な秘密鍵を他人に見せたり渡したりしてはいけない

Secure Shell(ssh)

インターネットからEC2インスタンスの中に入るための手段

ユーザーが管理する秘密鍵を使い、AWS側にある公開鍵を開け、暗号や認証の技術を利用し、安全にEC2インスタンスを操作できる

AWS上のサーバーの構成図

Image from Gyazo

構成図の詳細は、こちらを参考にする

デプロイイメージ

Image from Gyazo

  1. ローカル開発環境(自分のPC)でWebアプリケーションを開発する
  2. GitHubにコードをプッシュする
  3. AWSでサーバー(EC2)を起動し、データベース(RDS)とストレージ(S3)をつなぐ
  4. GitHubからEC2にコードをプルして、EC2内でアプリを起動してデプロイを実行する

デプロイの流れ

Image from Gyazo

コマンド

aws ec2 create-key-pairコマンド

EC2インスタンスへログインするための公開鍵と秘密鍵のキーペアを作成するコマンド

コマンドを実行すると、公開鍵はAWS側に作成され、秘密鍵はユーザーが管理するためにダウンロードできる

# 「my-key-pair.pem」というファイル名で秘密鍵を作成
$ aws ec2 create-key-pair \
    --key-name my-key-pair \
    --key-type rsa \
    --key-format pem \
    --query "KeyMaterial" \
    --output text > my-key-pair.pem

aws ec2 describe-imagesコマンド

指定した条件に合ったAMIのIDを取得するコマンド

$ AMI_ID=$(aws ec2 describe-images --owners amazon \
     --filters 'Name=name,Values=amzn2-ami-hvm-2.0.*-gp2' 'Name=state,Values=available' \
     --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' \
     --output text \
     --region ap-northeast-1)

echoコマンド

変数の値を取得するコマンド

# AMI_IDという変数の中には以下のAMIのIDが入っている
$ echo $AMI_ID
#=> ami-058d2a108b2600a4f

aws ec2 run-instancesコマンド

EC2を作成するコマンド

$ INSTANCE_ID=$(
  aws ec2 run-instances \
    --image-id $AMI_ID \
    --count 1 \
    --instance-type t2.micro \
    --key-name my-key-pair \
    --region ap-northeast-1 \
    --query "Instances[0].InstanceId" \
    --output text
)

aws ec2 describe-instancesコマンド

作成したインスタンスの情報を取得するコマンド

$ aws ec2 describe-instances \
  --instance-ids $INSTANCE_ID \
  --region ap-northeast-1

aws ec2 allocate-addressコマンド

Elastic IPを作成するコマンド

コマンドの後ろにregionを指定することで、東京リージョンである「ap-northeast-1」にElastic IPが作成される

$ ALLOCATION_ID=$(aws ec2 allocate-address \
  --region ap-northeast-1 \
  --query 'AllocationId' \
  --output text)

aws ec2 associate-addressコマンド

EC2インスタンスとElastic IPを紐付けるコマンド

$ aws ec2 associate-address \
  --instance-id $INSTANCE_ID \
  --allocation-id $ALLOCATION_ID \
  --region ap-northeast-1

aws ec2 describe-addressesコマンド

Elastic IPが設定されているか確認するコマンド

$ aws ec2 describe-addresses

aws ec2 create-security-groupコマンド

セキュリティグループを作成するコマンド

$ GROUP_ID=$(aws ec2 create-security-group \
    --group-name mysg \
    --description "My security group" \
    --output text \
    --query 'GroupId' \
    --region ap-northeast-1)

aws ec2 authorize-security-group-ingressコマンド

インバウンドルールでポートを設定するコマンド

#任意の場所(0.0.0.0/0は全てのIPアドレス)からEC2インスタンスの80番ポート(HTTP)への接続を許可
$ aws ec2 authorize-security-group-ingress \
  --region ap-northeast-1 \
  --group-id $GROUP_ID \
  --protocol tcp \
  --port 80 \
  --cidr 0.0.0.0/0

aws ec2 modify-instance-attributeコマンド

インスタンスとセキュリティグループのIDを変数で指定し、紐づけるコマンド

$ aws ec2 modify-instance-attribute \
  --instance-id $INSTANCE_ID \
  --groups $GROUP_ID

aws ec2 describe-instancesコマンド

EC2インスタンスにセキュリティグループが紐付けられているかを確認するコマンド

$ aws ec2 describe-instances \
  --instance-ids $INSTANCE_ID \
  --region ap-northeast-1 | \
jq -r '.Reservations[].Instances[].SecurityGroups[]'

yumコマンド

Linuxにおけるソフトウェア管理の仕組み
MacOSにとってのhomebrewと同じ役割を果たす。yumコマンドを利用することで、yumの管理下にあるプログラムのバージョンを管理したり、一括でアップデートしたりできる

-yオプション

yumコマンドのオプション
yum installなどのコマンドでは、本当にインストールして良いのか [y/n](「Yes or No」の意味)が問われる。「Y(Yesのイニシャル)」を入力し、Enterキーを押して実行すればいいが、誤ってYキー以外を押してしまう場合もある
あらかじめオプションで「-y」を設定する事で「すべての問いにYesで自動的に答える」という設定してコマンドを実行できる

systemctlコマンド

Amazon LinuxやCentOSに含まれているもので、インストールしたソフトウェアの起動を一括して行えるツール

catコマンド

ファイル(あるいは値)の具体的な内容をターミナル上で確認できる

sudo(substitute user do)コマンド

「全部の権限を持った上でコマンドを実行する」という役割のオプション
「/etc以下のファイル」は強い権限がないと書き込み・保存ができないため、コマンドの頭に「sudo」をつける

envコマンド

設定されている環境変数を表示するためのコマンド
このコマンドで全環境変数を表示できる

grepコマンド

環境変数などを検索するときに使う

RAILS_ENV=productionコマンド

本番環境でコマンド実行する時につくオプション
実行しようとしているコマンドは、「RAILSのENV(環境)がproduction(本番環境)ですよ」という意味

psコマンド

現在動いているプロセスを確認するためのコマンド

killコマンド

現在動いているプロセスを停止させるためのコマンド

RAILS_SERVE_STATIC_FILES=1コマンド

Railsがコンパイルされたアセットを見つけられるように指定する役割があるコマンド

lessコマンド

ファイルの中身を確認できるコマンド

tail -fコマンド

最新のログを10行分だけ表示してくれるコマンド

用語

パッケージ

LinuxOS下におけるある役割/機能をもったプログラムの集合のこと
「ソフトウェア」や「ライブラリ」とも呼べる

MariaDB

MySQLの派生として開発されているオープンソースソフトウェア
MySQLとの互換性があり、「Amazon Linux 2」ではMariaDBを使用することになっている

※基本的にMariaDBとMySQLは同様のものと考えて、差し支えない

Unicorn

全世界に公開されるサーバ上でよく利用されるアプリケーションサーバー
unicorn_railsコマンドで起動できる

worker

分裂したUnicornの全プロセスのこと。プロセスを分裂させることで、リクエストに対してのレスポンスを高速にできる

worker_processesという設定項目で、workerの数を決定する
worker_processesの数を増やすことで、アプリケーションからのレスポンスを早くできる

Swapファイル

メモリの容量を一時的に増やすために準備されるファイルのこと

コンピューターが処理を行う際、メモリと呼ばれる場所に処理内容が一時的に記録される。メモリは容量が決まっており、容量を超えてしまうとエラーで処理が止まってしまう

EC2はデフォルトではSwapファイルを用意していないため、これを準備することでメモリ不足の処理エラーを防ぐ

secret_key_base

Cookieの暗号化に用いられる文字列

アセットファイル

画像・CSS・JavaScript等を管理しているファイル

アセットファイルを圧縮し、そのデータを転送する処理を「コンパイル」という。この作業を行わないと、本番環境でCSSが反映されずにビューが崩れてしまったり、エラーでブラウザが表示されない、などの問題が生じてしまう

開発中はアクセス毎にアセットファイルを自動的にコンパイルする仕組みが備わっているが、本番モードのときにはパフォーマンスを重視するため、アクセス毎にコンパイルが実行されないようになっている

プロセスid

プロセスを識別するための一意の数字
PIDがあることで、あるプログラムから別のプロセスを指定して操作したり、プロセスからプログラムを停止したりできる

エラーログ

エラーの詳細が書かれているログ(記録場所)のこと

production.log

サーバーログを記録する場所で、いわば「EC2内での出来事を記録している場所」

Rack

いわば翻訳プログラム。Rackが翻訳をすることにより、アプリケーションサーバーとアプリケーション本体がコミュニケーションを取ることができ、処理結果をWebサーバーに返すことができる

Nginx

Webサーバーの一種。ユーザーのリクエストに対して静的コンテンツのみ取り出し処理を行い、動的コンテンツの生成はアプリケーションサーバに依頼する

Capistrano

自動デプロイツールと呼ばれるものの一種

自動デプロイツールのメリット

デプロイ時に必要なコマンド操作が1回で済む
手動デプロイする場合に起こりがちな問題(コマンドの打ち間違い等)を解消できる

Capfile

Capistrano関連のライブラリのうち、どれを読み込むかを指定する

Capistranoの機能を提供するコードはいくつかのライブラリ(Gem)に分かれている。そのため、Capistranoを動かすにはいくつかのライブラリを読み込む必要がある

production.rb

デプロイについての設定を書くファイル

GitHubへの接続に必要なsshキーの指定、デプロイ先のサーバのドメイン、AWSサーバへのログインユーザー名、サーバにログインしてからデプロイのために何をするか、といった設定を記載する

DSL(Domain Specific Language)

ある特定の処理における効率をあげるために特化した形の文法を擬似的に用意したプログラム

  • 「set :名前, 値」
    いわば変数のようなもの。
    たとえば「set: Name, Value」と定義した場合、「fetch Name」とすることでValueが取り出せる
    一度setした値はdeploy.rbproduction.rbなどの全域で取り出すことができる

    「desc '◯◯'`」や「task:XX do」といった記述もDSLの一つ

releasesディレクトリ

Capistranoを通じて、デプロイされたアプリがひとまとめにされる

過去分のアプリが残っていることにより、デプロイ時に何か問題が発生しても前のバージョンに戻ることができる。過去分の保存数を指定しているのがdeploy.rbの「set :keep_releases」の記述

currentディレクトリ

releasesフォルダの中で一番新しいものが自動的にコピーされているような状態になっている
つまり、「現在デプロイされている内容=current内の内容」ということになる

sharedディレクトリ

バージョンが変わっても共通で参照されるディレクトリが格納されるディレクトリ
具体的には、log、public、tmp、vendorディレクトリが格納される

手順1(アプリ制作)

  1. 1ルート以上の「ルーティング ~ ビュー」を設定する
  2. 以降、GitHubのmainブランチで作業する

手順2(EC2の初期設定)

Image from Gyazo

手順2-1(AWSログイン)

  1. AWSアカウントにルートユーザーでログインする
  2. リージョンが「アジアパシフィック(東京)」になっていることを確認する
    ※あるリージョンで作成したサーバーや他の設定は、他のリージョンでは表示されないので注意する
  3. 画面上部の検索フォームに「cloudshell」と入力する
  4. ColudShellのページにアクセスすると、CloudShellが起動し、CLIの画面が表示される

手順2-2(キーペア作成)

Image from Gyazo

  1. 「my-key-pair.pem」というファイル名で秘密鍵を作成する
    $ aws ec2 create-key-pair \
        --key-name my-key-pair \
        --key-type rsa \
        --key-format pem \
        --query "KeyMaterial" \
        --output text > my-key-pair.pem
    
  2. 右上の「アクション」から「ファイルのダウンロード」を選択する
  3. 個別のファイルパスに以下をコピーして貼り付け「ダウンロード」をクリックする
    /home/cloudshell-user/my-key-pair.pem
    
    ※ダウンロードした秘密鍵を紛失するとEC2インスタンスを操作することができなくなってしまうため、絶対に無くさない。秘密鍵をインターネットに公開しないように適切に管理する

手順2-3(EC2作成)

Image from Gyazo

  1. 「Amazon Linux 2 AMI」という、AWSが独自にカスタマイズしたAMIを利用するため、東京リージョンの最新のAmazon Linux 2 AMIのIDを取得する
    $ AMI_ID=$(aws ec2 describe-images --owners amazon \
         --filters 'Name=name,Values=amzn2-ami-hvm-2.0.*-gp2' 'Name=state,Values=available' \
         --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' \
         --output text \
         --region ap-northeast-1)
    
  2. 変数の値を取得する
    $ echo $AMI_ID
    
  3. 変数の値を確認する
    ami-058d2a108b2600a4f
    
  4. インスタンス作成時にAMIの指定・インスタンスタイプの指定・キーペアの紐付け・リージョンの指定を行い、EC2を作成する
    $ INSTANCE_ID=$(
      aws ec2 run-instances \
        --image-id $AMI_ID \
        --count 1 \
        --instance-type t2.micro \
        --key-name my-key-pair \
        --region ap-northeast-1 \
        --query "Instances[0].InstanceId" \
        --output text
    )
    
  5. 作成したインスタンスの情報を取得する
    $ aws ec2 describe-instances \
      --instance-ids $INSTANCE_ID \
      --region ap-northeast-1
    
  6. 出力結果を確認し、:qを入力して元画面に戻る
    # 出力結果の例
    {
        "Reservations": [
            {
                "Groups": [],
                "Instances": [
                    {
                        "AmiLaunchIndex": 0,
                        "ImageId": "ami-058d2a108b2600a4f",
                        "InstanceId": "i-071a646dba9e8f72e",
                        "InstanceType": "t2.micro",
                        "LaunchTime": "2023-11-28T00:38:10+00:00",
                        "Monitoring": {
                            "State": "disabled"
                        },
                        "Placement": {
                            "AvailabilityZone": "ap-northeast-1a",
                            "GroupName": "",
                            "Tenancy": "default"
                        },
                        "PrivateDnsName": "ip-172-31-40-232.ap-northeast-1.compute.internal",
                        "PrivateIpAddress": "172.31.40.232",
                        "ProductCodes": [],
                        "PublicDnsName": "ec2-3-112-123-227.ap-northeast-1.compute.amazonaws.com",
                        "PublicIpAddress": "3.112.123.227",
                        "State": {
                            "Code": 0,
                            "Name": "pending"
                        },
                        "StateTransitionReason": "",
                        "SubnetId": "subnet-0f10d5ce377c2ab47",
                        "VpcId": "vpc-08fdfb0bc18e8441e",
                        "Architecture": "x86_64",
                        "BlockDeviceMappings": [
                            {
                                "DeviceName": "/dev/xvda",
                                "Ebs": {
                                    "AttachTime": "2023-11-28T00:38:11+00:00",
                                    "DeleteOnTermination": true,
                                    "Status": "attaching",
                                    "VolumeId": "vol-0aea37165a1bd32c7"
                                }
                            }
                        ],
                        "ClientToken": "2d5e87d9-c14d-432a-a4c8-c0001efa5515",
                        "EbsOptimized": false,
                        "EnaSupport": true,
                        "Hypervisor": "xen",
                        "NetworkInterfaces": [
    
          (以下省略)
    
    • Virtual Private Cloud(VPC)
      • "VpcId": "vpc-08fdfb0bc18e8441eにあたる
    • アベイラビリティーゾーン
      • "AvailabilityZone": "ap-northeast-1a"にあたる
        →東京リージョンを指すap-northeastの1aというアベイラビリティーゾーンにEC2が作成された
    • サブネット
      • "SubnetId": "subnet-0f10d5ce377c2ab47"にあたる

手順2-4(IPアドレスと紐付け)

Image from Gyazo

  1. Elastic IPを作成する
    Elastic IPを作成した後にElastic IPのIDであるAllocation ID指定してEC2とElasticアドレスを紐つける設定を行うため、Elastic IPの情報として「ALLOCATION_ID」変数を定義する
    $ ALLOCATION_ID=$(aws ec2 allocate-address \
      --region ap-northeast-1 \
      --query 'AllocationId' \
      --output text)
    
  2. 作成されたElastic IPアドレスの情報を確認する
    $ aws ec2 describe-addresses \
      --allocation-ids $ALLOCATION_ID \
      --region ap-northeast-1
    
    # 出力結果の例
    {
        "Addresses": [
            {
                "PublicIp": "18.179.217.48",
                "AllocationId": "eipalloc-07baaeb44893675bb",
                "Domain": "vpc",
                "PublicIpv4Pool": "amazon",
                "NetworkBorderGroup": "ap-northeast-1"
            }
        ]
    }
    
    • 新しく割り当てられたElastic IPアドレス
      • PublicIpの"18.179.217.48"にあたる部分がElastic IPアドレスの値
  3. EC2インスタンスとElastic IPを紐付ける
    $ aws ec2 associate-address \
      --instance-id $INSTANCE_ID \
      --allocation-id $ALLOCATION_ID \
      --region ap-northeast-1
    
  4. 出力結果を確認する
    # 出力結果の例
    {
        "AssociationId": "eipassoc-04957e15de5959eb8"
    }
    
  5. Elastic IPが設定されているか確認する
    $ aws ec2 describe-addresses
    
  6. 出力結果を確認する
    {
        "Addresses": [
            {
                "InstanceId": "i-0996f14d6fcd58340",
                "PublicIp": "18.177.127.90",
                "AllocationId": "eipalloc-023dcce066fdd83d4",
                "AssociationId": "eipassoc-04957e15de5959eb8",
                "Domain": "vpc",
                "NetworkInterfaceId": "eni-08432b1d09dc6fbff",
                "NetworkInterfaceOwnerId": "263931220713",
                "PrivateIpAddress": "172.31.44.23",
                "PublicIpv4Pool": "amazon",
                "NetworkBorderGroup": "ap-northeast-1"
            }
        ]
    }
    
    • Elastic IPアドレス
      • "PublicIp": "18.177.127.90"にあたる

手順2-5(セキュリティグループの作成)

Image from Gyazo

  1. セキュリティグループを作成する
    • 新規でセキュリティグループを作成する場合
      $ GROUP_ID=$(aws ec2 create-security-group \
          --group-name mysg \
          --description "My security group" \
          --output text \
          --query 'GroupId' \
          --region ap-northeast-1)
      
    • 既にセキュリティグループが存在している場合
      1. EC2コンソールを開く
      2. 新しく作成したEC2>アクション>セキュリティ>セキュリティグループを変更をクリック
      3. 「関連付けられたセキュリティグループ」に紐付けたいセキュリティグループを追加
      4. 不要なセキュリティグループを削除
      5. 保存ボタンをクリック(ポートの設定などは不要)
      6. 「GROUP_ID」変数を定義するため、CloudShellで下記を実行
        $ GROUP_ID='セキュリティグループID'
        
        ※セキュリティグループIDは、都度確認して入力すること
  2. ポートを設定する
    1. 全世界からHTTP(80番ポート)への接続を許可する
      $ aws ec2 authorize-security-group-ingress \
        --region ap-northeast-1 \
        --group-id $GROUP_ID \
        --protocol tcp \
        --port 80 \
        --cidr 0.0.0.0/0
      
    2. 結果を確認する
      # 出力結果の例
      {
          "Return": true,
          "SecurityGroupRules": [
              {
                  "SecurityGroupRuleId": "sgr-0200f8bf70962c5c4",
                  "GroupId": "sg-05678ae45c2ef0d42",
                  "GroupOwnerId": "263931220713",
                  "IsEgress": false,
                  "IpProtocol": "tcp",
                  "FromPort": 80,
                  "ToPort": 80,
                  "CidrIpv4": "0.0.0.0/0"
              }
          ]
      }
      
    3. 全世界からHTTPS(443番ポート)への接続を許可する
      $ aws ec2 authorize-security-group-ingress \
        --region ap-northeast-1 \
        --group-id $GROUP_ID \
        --protocol tcp \
        --port 443 \
        --cidr 0.0.0.0/0
      
    4. 結果を確認する
      # 出力結果の例
      {
          "Return": true,
          "SecurityGroupRules": [
              {
                  "SecurityGroupRuleId": "sgr-0f319d83164f17783",
                  "GroupId": "sg-05678ae45c2ef0d42",
                  "GroupOwnerId": "263931220713",
                  "IsEgress": false,
                  "IpProtocol": "tcp",
                  "FromPort": 443,
                  "ToPort": 443,
                  "CidrIpv4": "0.0.0.0/0"
              }
          ]
      }
      
  3. セキュリティを保ちながらSSH接続でEC2インスタンスの中で作業するためのインバウンドルールの設定を行う
    1. 22番ポート(SSH)にプライベートIPアドレスとパブリックIPアドレス(0.0.0.0/0は全てのIPアドレス)を許可する
      $ aws ec2 authorize-security-group-ingress \
        --region ap-northeast-1 \
        --group-id $GROUP_ID \
        --protocol tcp \
        --port 22 \
        --cidr 0.0.0.0/0
      
    2. 結果を確認する
      # 出力結果の例
      {
          "Return": true,
          "SecurityGroupRules": [
              {
                  "SecurityGroupRuleId": "sgr-0933b2a59225b1066",
                  "GroupId": "sg-05678ae45c2ef0d42",
                  "GroupOwnerId": "263931220713",
                  "IsEgress": false,
                  "IpProtocol": "tcp",
                  "FromPort": 22,
                  "ToPort": 22,
                  "CidrIpv4": "0.0.0.0/0"
              }
          ]
      }
      
    3. インスタンスとセキュリティグループのIDを変数で指定し、紐づける
      $ aws ec2 modify-instance-attribute \
        --instance-id $INSTANCE_ID \
        --groups $GROUP_ID
      
    4. EC2インスタンスにセキュリティグループが正しく紐付けられたかを、確認する
      $ aws ec2 describe-instances \
        --instance-ids $INSTANCE_ID \
        --region ap-northeast-1 | \
      jq -r '.Reservations[].Instances[].SecurityGroups[]'
      
    5. 結果を確認する
      {
           "GroupName": "mysg",
            "GroupId": "sg-0f89a29a7893e91ff"
      }
      
      "GroupName""mysg"という名前が付けられ、EC2に紐付けられているのが分かる

手順2-6(コンソールからEC2の確認)

Image from Gyazo
EC2インスタンスの初期設定を、マネジメントコンソールでも確認する

  1. リージョンが「アジアパシフィック(東京)」になっていることを確認する
  2. トップページに遷移したら、画面上部の検索フォームに「EC2」と入力する
  3. 検索結果から「EC2」を選択する
  4. インスタンス(実行中)をクリックする
  5. インスタンスIDをクリックする
    ※ID名は自分が作成したEC2のインスタンスIDになっているのを確認
  6. EC2インスタンスの概要が表示される
  7. Elastic IPアドレスが表示されていることを確認する
  8. セキュリティを選択し、インバウンドルールの「ポート範囲」「プロトコル」「ソース」が以下の通りになっているか確認する
    Image from Gyazo

手順2-7(EC2インスタンスへログイン)

Image from Gyazo

EC2インスタンスを作成すると、ec2-userというユーザーと対応するssh秘密鍵が生成される。本来はこのec2-userではなく、サービスを稼働させるためにより権限を小さくしたユーザーを作成して運用するが、ここでは簡易化のためにec2-userを使って作業を進める

  1. 「ec2-user」を使ってログインするため、ターミナル(ローカル)で下記コマンドを実行する
    % mkdir ~/.ssh
    
    # .sshというディレクトリを作成
    # File existsとエラーが表示されたとしても、.sshディレクトリは存在しているのということなので、そのまま進む
    
    % mv ~/Downloads/my-key-pair.pem ~/.ssh
    
    # mvコマンドで、my-key-pair.pemファイルを、ダウンロードディレクトリから、.sshディレクトリに移動
    
    % cd ~/.ssh
    % ls
    
    # .sshディレクトリ内に移動させたpemファイルが存在するか確認
    
    % chmod 600 my-key-pair.pem
    
    ※my-key-pair.pem はFinderのダウンロードフォルダから探す
  2. 「作成したEC2インスタンスに紐付けたElastic IP」を確認する
    1. EC2コンソールを開く
    2. サイドバーのインスタンス>インスタンスをクリックする
    3. 確認したいインスタンスにチェックを入れる
    4. 詳細タブの「Elastic IP アドレス」を確認する
  3. ターミナル(ローカル)で下記コマンドを実行する
    % ssh -i ~/.ssh/my-key-pair.pem ec2-user@(作成したEC2インスタンスに紐付けたElastic IP)
    
  4. ssh接続(以下のコマンド)を実行する
    ※以下の様なメッセージが表示された場合、「yes」と入力して実行
    % ssh -i my-key-pair.pem ec2-user@52.68.~~~~~~
    The authenticity of host '52.68.~~~~~~ (52.68.~~~~~~)' can't be established.
    RSA key fingerprint is eb:7a:bd:e6:aa:da:~~~~~~~~~~~~~~~~~~~~~~~~.
    Are you sure you want to continue connecting (yes/no)? 
    
    (ここで「yes」を入力し、実行する)
    
  5. ターミナルのコマンド待ちの際の左側の表示が、以下のようになればログイン成功
       ,     #_
       ~\_  ####_        Amazon Linux 2
      ~~  \_#####\
      ~~     \###|       AL2 End of Life is 2025-06-30.
      ~~       \#/ ___
       ~~       V~' '->
        ~~~         /    A newer version of Amazon Linux is available!
          ~~._.   _/
             _/ _/       Amazon Linux 2023, GA and supported until 2028-03-15.
           _/m/'           https://aws.amazon.com/linux/amazon-linux-2023/
    
    ※一定時間操作をせずにいるとタイムアウトしてしまう。その場合は、「ssh -i 〜」のコマンドを再度実行することでサーバーに接続できる

手順3(必要なツールのインストール)

  1. パッケージをアップデートするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する

    $ sudo yum -y update
    
  2. その他環境構築に必要なパッケージを諸々インストールするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する

    $ sudo yum  -y install git make gcc-c++ patch libyaml-devel libffi-devel libicu-devel zlib-devel readline-devel libxml2-devel libxslt-devel ImageMagick ImageMagick-devel openssl-devel libcurl libcurl-devel curl
    
  3. EC2にrbenvをインストールするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する

    # ①rbenvのインストール
    $ git clone https://github.com/rbenv/rbenv.git ~/.rbenv 
    
    # ②パスを通す
    $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile 
    
    # ③rbenvを呼び出すための記述
    $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
    
    # ④.bash_profileの読み込み
    $ source .bash_profile
    
    # ⑤ruby-buildのインストール
    $ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
    
    # ⑥rehashを行う
    $ rbenv rehash
    
    コマンド 役割
    gitから「rbenv」をクローン
    ②&③ パスを通す際に必要なコマンド。パスを通すとは、「どのディレクトリからもアプリケーションを呼び出せる状態にする」ということ
    設定したパスを読み込む
    gitから「ruby-build」をクローン
    使用しているRubyのバージョンにおいて、gemのコマンドを使えるようにするために必要なコマンド
  4. EC2にRubyをインストールするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する

    # Ruby 3.2.0のバージョンをインストール
    $ rbenv install 3.2.0
    
    # EC2インスタンス内で使用するRubyのバージョンを決める
    $ rbenv global 3.2.0
    
    # rehashを行う
    $ rbenv rehash  
    
    # Rubyのバージョンを確認
    $ ruby -v 
    

    ※Rubyのインストールには時間がかかる

手順4(データベースの設定)

Image from Gyazo

  1. MariaDBをEC2にインストールするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ sudo yum -y install  mariadb-server mysql-devel
    
  2. データベースを起動するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ sudo systemctl start mariadb
    
  3. 起動できたか確認するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ sudo systemctl status mariadb
       Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor preset: disabled)
       Active: active (running) since 金 2023-06-16 07:17:56 UTC; 7s ago
      Process: 15793 ExecStartPost=/usr/libexec/mariadb-wait-ready $MAINPID (code=exited, status=0/SUCCESS)
      Process: 15710 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir %n (code=exited, status=0/SUCCESS)
     Main PID: 15792 (mysqld_safe)
       CGroup: /system.slice/mariadb.service
               ├─15792 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
               └─15958 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysq...
    
    ※「active (running) 」と緑色の表示がされれば、データベースの起動は成功
  4. rootユーザーのパスワードを設定するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ sudo /usr/bin/mysql_secure_installation
    
    ※yumでインストールしたMariaDBには、デフォルトでrootユーザーでアクセスできるようになっている。ただし、パスワードは設定されていないので、パスワードを設定する必要がある
    1. Enter current password for root (enter for none): 」と表示されたらEnterキーを押す
    2. 「Set root password? [Y/n]」と表示されたら「Y」を入力してEnterキーを押す
    3. 「New password:」と表示されたら自身で決めたパスワードを入力する(※とくに画面には何も表示されないが入力できている)
    4. 「Re-enter new password:」と表示されたら、同じパスワードを入力する(※とくに画面には何も表示されないが入力できている)
    5. 「... Success!」と表示されればパスワードの設定は完了
    6. 「Remove anonymous users? [Y/n]」と表示されたら「Y」を入力してEnterキーを押す
    7. 「Disallow root login remotely? [Y/n]」と表示されたら「Y」を入力してEnterキーを押す
    8. 「Remove test database and access to it? [Y/n]」と表示されたら「Y」を入力してEnterキーを押す
    9. 「Reload privilege tables now? [Y/n]」と表示されたら「Y」を入力してEnterキーを押す
    10. プロンプトが表示されたら設定は完了
  5. 設定したパスワードが使えるか確認するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ mysql -u root -p
    
  6. 「Enter password:」とパスワードを入力するように表示されるので、さきほど設定したパスワードを入力し、Enterキーを押す
  7. 以下のように表示されれば、データベースの設定は終了
    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 142
    Server version: 5.5.64-MariaDB MariaDB Server
    
    Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    MariaDB [(none)]> 
    

手順5(EC2のRailsを起動)

Image from Gyazo

  1. EC2サーバーのssh鍵のペアを作成し、GitHubにssh鍵を登録するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ ssh-keygen -t rsa -b 4096
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa):
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in /home/ec2-user/.ssh/id_rsa.
    Your public key has been saved in /home/ec2-user/.ssh/id_rsa.pub.
    The key fingerprint is:
    3a:8c:1d:d1:a9:22:c7:6e:6b:43:22:31:0f:ca:63:fa ec2-user@ip-172-31-23-189
    The key's randomart image is:
    +--[ RSA 4096]----+
    |    +            |
    | . . =           |
    |  = . o .        |
    | * o . o         |
    |= *     S        |
    |.* +     .       |
    |  * +            |
    | .E+ .           |
    | .o              |
    +-----------------+
    
    ※途中で「passphrase」など3段階ほど入力を求められることがありますが、すべて何も入力せずにEnterキーを押す
  2. 公開鍵が含まれているファイルid_rsa.pubの中身を確認するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ cat ~/.ssh/id_rsa.pub
    
  3. 表示される公開鍵の情報をすべて(「ssh-rsa」から「末尾の文字」まで)コピーする
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLwt......
    # 表示された内容すべてをコピー
    
  4. コピーした公開鍵をGitHubに登録する
    1. こちらにアクセスする
    2. 右上にある「New SSH key」をクリックする
    3. 公開鍵のタイトルを設定し、コピーした公開鍵を貼り付ける
    4. Key typeは「Authentication keys」を選択する
    5. 「Add SSH key」をクリックして公開鍵を保存する
    6. ssh接続できるか以下のコマンドで確認するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ ssh -T git@github.com
      Hi <Githubユーザー名>! You've successfully authenticated, but GitHub does not provide shell access.
      
      • 途中でこのまま続けるかどうか、「yes/no」または「y/n」などの選択肢で聞かれることがある。その場合は「yes」を入力し、Enterキーを押す
      • 「Permission denied (publickey).」と表示された場合は、ssh鍵の設定が間違っているので、再度作業を確認する
  5. Unicornをインストールする
    1. GemのUnicornを追加する
      詳細は、こちらを参照
    2. config/unicorn.rbを手動作成する
    3. 下記を記述する
      config/unicorn.rb
      #サーバ上でのアプリケーションコードが設置されているディレクトリを変数に入れておく
      app_path = File.expand_path('../../', __FILE__)
      
      #アプリケーションサーバの性能を決定する
      worker_processes 1
      
      #アプリケーションの設置されているディレクトリを指定
      working_directory app_path
      
      #Unicornの起動に必要なファイルの設置場所を指定
      pid "#{app_path}/tmp/pids/unicorn.pid"
      
      #ポート番号を指定
      listen 3000
      
      #エラーのログを記録するファイルを指定
      stderr_path "#{app_path}/log/unicorn.stderr.log"
      
      #通常のログを記録するファイルを指定
      stdout_path "#{app_path}/log/unicorn.stdout.log"
      
      #Railsアプリケーションの応答を待つ上限時間を設定
      timeout 60
      
      #以下は応用的な設定なので説明は割愛
      
      preload_app true
      GC.respond_to?(:copy_on_write_friendly=) && GC.copy_on_write_friendly = true
      
      check_client_connection false
      
      run_once = true
      
      before_fork do |server, worker|
        defined?(ActiveRecord::Base) &&
          ActiveRecord::Base.connection.disconnect!
      
        if run_once
          run_once = false # prevent from firing again
        end
      
        old_pid = "#{server.config[:pid]}.oldbin"
        if File.exist?(old_pid) && server.pid != old_pid
          begin
            sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
            Process.kill(sig, File.read(old_pid).to_i)
          rescue Errno::ENOENT, Errno::ESRCH => e
            logger.error e
          end
        end
      end
      
      after_fork do |_server, _worker|
        defined?(ActiveRecord::Base) && ActiveRecord::Base.establish_connection
      end
      
      設定項目 詳細
      worker_processes リクエストを受け付け、レスポンスを生成するworker(ワーカー)の数を決める
      working_directory UnicornがRailsのコードを動かす際、ルーティングなど実際に参照するファイルを探すディレクトリを指定する
      pid Unicornは、起動する際にプロセスidが書かれたファイルを生成し、その場所を指定する
      listen どのポート番号のリクエストを受け付けることにするかを決定する。今回は、3000番ポートを指定
  6. アプリをクローンする
    1. リモートリポジトリに反映するため、コードをpushする
    2. EC2にローカルの全内容を反映するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      # mkdirコマンドで新たにディレクトリを作成
      $ sudo mkdir /var/www/
      
      # 作成したwwwディレクトリの権限をec2-userに変更
      $ sudo chown ec2-user /var/www/
      
    3. デプロイするアプリケーションのGitHubを開く
    4. 緑色で「Code」と表示されているボタンをクリックし、URLをコピーする
    5. コードをクローンするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ cd /var/www/
      $ git clone [コピーしたURL]
      
  7. ホームディレクトリに移動するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    # ホームディレクトリに移動
    $ cd
    
  8. ターミナル(EC2内で実行)にて、下記コマンドを実行する
    # 処理に時間がかかる可能性があるコマンド
    $ sudo dd if=/dev/zero of=/swapfile1 bs=1M count=512
    
    # しばらく待って、以下のように表示されれば成功
    512+0 レコード入力
    512+0 レコード出力
    536870912 バイト (537 MB) コピーされました、 7.35077 秒、 73.0 MB/秒
    
    $ sudo chmod 600 /swapfile1
    
    $ sudo mkswap /swapfile1
    # 以下のように表示されれば成功
    スワップ空間バージョン1を設定します、サイズ = 524284 KiB
    ラベルはありません, UUID=74a961ba-7a33-4c18-b1cd-9779bcda8ab1
    
    $ sudo swapon /swapfile1
    
    $ sudo sh -c 'echo "/swapfile1  none        swap    sw              0   0" >> /etc/fstab'
    
  9. gemをインストールするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    # クローンしたディレクトリに移動
    $ cd  /var/www/開発中のアプリケーション
    
    # rubyのバージョンを確認
    $ ruby -v
    ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux]
    
  10. ローカルで開発してきたアプリケーションでどのバージョンのbundlerが使われていたのか確認するため、ターミナル(ローカル)にて、下記コマンドを実行する
    % bundler -v
    Bundler version 2.4.1
    
  11. ローカルと同じバージョンのbundlerをEC2側にも導入するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    # 「2.4.1」の箇所は、ローカルで確認したbundlerのバージョンを記載
    $ gem install bundler -v 2.4.1
    
    # 以下のコマンドは、処理に数分以上かかる場合がある
    $ bundle install
    
  12. 環境変数を設定する
    1. secret_key_baseを作成するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ rails secret
      69619d9a75b78f2e1c87ec5e07541b42f23efeb6a54e97da3723de06fe74af29d5718adff77d2b04b2805d3a1e143fa61baacfbf4ca2c6fcc608cff8d5a28e8d
      
    2. 表示された英数の羅列を、メモする
    3. secret_key_baseを環境変数に設定するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ sudo vim /etc/environment
      
    4. 「i」と打ち込んで入力モードに切り替える
    5. 下記を入力する
      ※元々記述されている内容は編集しないこと
      # 手順4で設定したデータベースのrootユーザーのパスワードを入力
      DATABASE_PASSWORD='データベースのrootユーザーのパスワード'
      SECRET_KEY_BASE='さきほど作成したsecret_key_base'
      
    6. 「escキー」→「:wq」の順で実行し、保存する
    7. 本番環境をログアウトするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ exit
      logout
      Connection to 52.xx.xx.xx closed.
      
    8. 環境変数が反映されているか確認するため、ターミナル(ローカル)にて、下記コマンドを実行する
      $ ssh -i ~/.ssh/(キーペア名).pem ec2-user@(作成したEC2インスタンスと紐付けたElastic IP)
      
    9. 環境変数を確認するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ env | grep SECRET_KEY_BASE
      SECRET_KEY_BASE='secret_key_base'
      
      $ env | grep DATABASE_PASSWORD
      DATABASE_PASSWORD='データベースのrootユーザーのパスワード'
      
      $ env | grep AWS_SECRET_ACCESS_KEY
      AWS_SECRET_ACCESS_KEY='Secret access key'
      
      $ env | grep AWS_ACCESS_KEY_ID
      AWS_ACCESS_KEY_ID='Access key ID'
      
      $ env | grep BASIC_AUTH_USER
      BASIC_AUTH_USER='設定したユーザー名'
      
      $ env | grep BASIC_AUTH_PASSWORD
      BASIC_AUTH_PASSWORD='設定したパスワード'
      
      $ env | grep PAYJP_SECRET_KEY
      PAYJP_SECRET_KEY='sk_test_*************'
      
      $ env | grep PAYJP_PUBLIC_KEY
      PAYJP_PUBLIC_KEY='pk_test_*************'
      
  13. ポートを解放する
    1. EC2インスタンス一覧画面から、対象のインスタンスを選択する
    2. 「セキュリティ」のタブを開く
    3. 「セキュリティグループ」のリンクをクリックすると、インスタンスの属するセキュリティグループの設定画面に遷移する
    4. 「インバウンドルール」タブを選択する
    5. 「Edit inbound rules」をクリックする
    6. ルール編集ページに切り替わるので、下記を設定する
      タイプ プロトコル ポート範囲 送信元
      カスタムTCP TCP 3000 カスタム/0.0.0.0/0
    7. 「ルールを保存」をクリックする
  14. 本番環境でRailsを起動させる
    1. VSCodeで、database.ymlを下記のように編集する
      config/database.yml
      production:
        <<: *default
        adapter: mysql2
        database: (アプリ名)_production
        username: root
        password: <%= ENV['DATABASE_PASSWORD'] %>
        socket: /var/lib/mysql/mysql.sock
      
  15. GitHubにコードをpushする
  16. GitHubの内容をEC2に反映させる
    1. ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ cd /var/www/[リポジトリ]
      $ git pull origin main
      
    2. ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ rails db:create RAILS_ENV=production
      Created database '<データベース名>'
      
      $ rails db:migrate RAILS_ENV=production
      
      Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが発生した場合、DBが起動していない可能性がある。sudo systemctl start mariadbで、mysqlの起動を行ってみる
    3. Railsを起動するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ bundle exec unicorn_rails -c config/unicorn.rb -E production -D
      
  17. アセットファイルをコンパイルするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ rails assets:precompile RAILS_ENV=production
    
  18. Railsを再起動する
    1. Unicornのプロセスを確認するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ ps aux | grep unicorn
      
    2. 下記のような結果が表示される
      ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
      ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
      ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn
      
      ※大事なのは左から2番目の列。ここに表示されるのがプロセスのid(PID)になる。「unicorn_rails master」と表示されているプロセスがUnicornのプロセス本体なので、この時のプロセスidは「17877」
    3. UnicornのプロセスをKillするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ kill <確認したunicorn rails masterのプロセスid>
      
    4. 実行したプロセスを再度表示させ、終了できていることを確認する
      $ ps aux | grep unicorn
      
    5. 下記のような結果が表示される
      ec2-user 17918  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn
      
      ※プロセスが1つだけ残っているのは、「ps aux | grep unicorn」コマンドのプロセス
    6. ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
      
  19. ブラウザからhttp://Elastic IP:3000/にアクセスし、サイトが正常に表示されているか確認する

Railsの起動がうまくできなかった場合

ターミナルで「unicorn_rails」が起動しない

  1. ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
    master failed to start, check stderr log for details
    
  2. master failed to start, check stderr log for detailsと表示された場合、 config/unicorn.rbを確認する
    config/unicorn.rb
    省略
    
    #エラーのログを記録するファイルを指定
    stderr_path "#{app_path}/log/unicorn.stderr.log"
    
    省略
    
  3. unicornのエラーログを確認するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ less log/unicorn.stderr.log
    I, [2016-12-21T04:01:19.135154 #18813]  INFO -- : Refreshing Gem list
    I, [2016-12-21T04:01:20.732521 #18813]  INFO -- : listening on addr=0.0.0.0:3000 fd=10
    E, [2016-12-21T04:01:20.734067 #18813] Mysql2::Error::ConnectionError: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
    /var/www/furima/shared/bundle/ruby/2.6.0/gems/mysql2-0.5.3/lib/mysql2/client.rb:90:in `connect'
    /var/www/furima/shared/bundle/ruby/2.6.0/gems/mysql2-0.5.3/lib/mysql2/client.rb:90:in `initialize'
    /var/www/furima/shared/bundle/ruby/2.6.0/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/mysql2_adapter.rb:24:in `new'
    /var/www/furima/shared/bundle/ruby/2.6.0/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/mysql2_adapter.rb:24:in `mysql2_connection'
    /var/www/furima/shared/bundle/ruby/2.6.0/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:889:in `new_connection'
    
    ※ログファイルは「一番下から最新のログ」が表示される。「shiftキー」+「G」を実行すると、一番下まで一瞬で移動できる

ブラウザに「We’re sorry, but 〜」と表示されている

  1. ターミナル(EC2内で実行)にて、下記コマンドを実行する
     less log/production.log
    
    (production.logの表示)
    
    ※ログファイルは「一番下から最新のログ」が表示される。「shiftキー」+「G」を実行すると、一番下まで一瞬で移動できる

手順6(Webサーバーの設定)

Image from Gyazo

  1. Nginxを導入する
    1. ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ sudo amazon-linux-extras install nginx1
      
      Is this ok [y/d/N]:と出てきたら、yを選択する
    2. Nginxの設定ファイルを編集するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ sudo vim /etc/nginx/conf.d/rails.conf
      
    3. ターミナル上でファイルを開けたら、下記のように編集する
      /etc/nginx/conf.d/rails.conf
      upstream app_server {
        # Unicornと連携させるための設定
        server unix:/var/www/リポジトリ名/tmp/sockets/unicorn.sock;
      }
      
      # {}で囲った部分をブロックと呼ぶ。サーバの設定ができる
      server {
        # このプログラムが接続を受け付けるポート番号
        listen 80;
        # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
        server_name Elastic IP;
      
        # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
        client_max_body_size 2g;
      
      # 接続が来た際のrootディレクトリ
        root /var/www/リポジトリ名/public;
      
      # assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定
        location ^~ /assets/ {
          gzip_static on;
          expires max;
          add_header Cache-Control public;
        }
      
        try_files $uri/index.html $uri @unicorn;
      
        location @unicorn {
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_redirect off;
          proxy_pass http://app_server;
        }
      
        error_page 500 502 503 504 /500.html;
      }
      
      ※「リポジトリ名」と「Elastic IP」の部分は、自身のものに置き換える
    4. 「escキー」→「:wq」の順で実行し、保存する
    5. Nginxの権限を変更するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ cd /var/lib
      $ sudo chmod -R 775 nginx
      
    6. Nginx設定ファイルを起動して再読み込みするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ cd ~
      $ sudo systemctl start nginx
      $ sudo systemctl reload nginx
      
  2. Unicornの設定を変更する
    1. config/unicorn.rbを修正する
      -変更前-
      config/unicorn.rb
      省略
      
      listen 3000
      
      省略
      
      -変更後-
      (省略)
      
      listen "#{app_path}/tmp/sockets/unicorn.sock"
      
      (省略)
      
  3. GitHubにコードをpushする
  4. GitHubの変更点を本番環境へ反映させる
    # 開発中のアプリケーションに移動
    $ cd /var/www/開発中のアプリケーション
    
    # GitHubの内容をEC2に反映させる
    $ git pull origin main
    
  5. Unicornを再起動させるため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ ps aux | grep unicorn
    
    ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
    ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
    ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn
    
    $ kill プロセス番号
    
    $ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
    
  6. ブラウザからhttp://Elastic IP/にアクセスし、サイトが正常に表示されているか確認する

IPアドレスにアクセスしてもエラーが発生する場合

「502 bad gateway」と表示された

  1. ログを確認するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ sudo less /var/log/nginx/error.log
    

手順7(自動デプロイの設定)

Image from Gyazo

  1. GemであるCapistranoをインストールする
    詳細は、こちらを参照
  2. ターミナル(ローカル)にて、下記コマンドを実行する
    # アプリのディレクトリに移動
    % cd ~/[アプリ名]
    
    % bundle exec cap install
    
  3. Capfileに記述している内容を、すべて削除する
  4. Capfileに下記を記載する
    require "capistrano/setup"
    require "capistrano/deploy"
    require 'capistrano/rbenv'
    require 'capistrano/bundler'
    require 'capistrano/rails/assets'
    require 'capistrano/rails/migrations'
    require 'capistrano3/unicorn'
    
    Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
    
  5. デプロイについての設定ファイルを編集する
    1. config/deploy/production.rbの最終行に下記を追記する
      production.rb
      server '用意したElastic IP', user: 'ec2-user', roles: %w{app db web}
      
    2. config/deploy.rbを編集する
      deploy.rb
      # capistranoのバージョンを記載。固定のバージョンを利用し続け、バージョン変更によるトラブルを防止する
      lock 'Capistranoのバージョン'
      
      # Capistranoのログの表示に利用する
      set :application, 'ご自身のアプリケーション名'
      
      # どのリポジトリからアプリをpullするかを指定する
      set :repo_url,  'git@github.com:Githubのユーザー名/レポジトリ名.git'
      set :branch, 'main'
      
      # バージョンが変わっても共通で参照するディレクトリを指定
      set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system', 'public/uploads')
      
      set :rbenv_type, :user
      set :rbenv_ruby, 'このアプリで使用しているrubyのバージョン' #カリキュラム通りに進めた場合、’3.2.0’ です
      
      # どの公開鍵を利用してデプロイするか
      set :ssh_options, auth_methods: ['publickey'],
                                        keys: ['~/.ssh/ご自身のキーペア名.pem'] 
      
      # プロセス番号を記載したファイルの場所
      set :unicorn_pid, -> { "#{shared_path}/tmp/pids/unicorn.pid" }
      
      # Unicornの設定ファイルの場所
      set :unicorn_config_path, -> { "#{current_path}/config/unicorn.rb" }
      set :keep_releases, 5
      
      # デプロイ処理が終わった後、Unicornを再起動するための記述
      after 'deploy:publishing', 'deploy:restart'
      namespace :deploy do
        task :restart do
          invoke 'unicorn:restart'
        end
      end
      
      • 修正箇所は下記
        • Capistranoのバージョン
          「Capistranoのバージョン」は、Gemfile.lockに記載されている
        • アプリケーション名
        • GitHubのユーザー名 , レポジトリ名
        • このアプリで使用しているrubyのバージョン
        • 自身のキーペア名
  6. Unicornの設定ファイルを編集する
    config/unicorn.rb
    #サーバ上でのアプリケーションコードが設置されているディレクトリを変数に入れておく
    app_path = File.expand_path('../../../', __FILE__)  # 「../」が一つ増えている
    
    #アプリケーションサーバの性能を決定する
    worker_processes 1
    
    #アプリケーションの設置されているディレクトリを指定
    working_directory "#{app_path}/current"  # 「current」を指定
    
    #Unicornの起動に必要なファイルの設置場所を指定
    pid "#{app_path}/shared/tmp/pids/unicorn.pid"  # 「shared」の中を参照するよう変更
    
    #ポート番号を指定
    listen "#{app_path}/shared/tmp/sockets/unicorn.sock"  # 「shared」の中を参照するよう変更
    
    #エラーのログを記録するファイルを指定
    stderr_path "#{app_path}/shared/log/unicorn.stderr.log"  # 「shared」の中を参照するよう変更
    
    #通常のログを記録するファイルを指定
    stdout_path "#{app_path}/shared/log/unicorn.stdout.log"  # 「shared」の中を参照するよう変更
    省略
    
  7. Nginxの設定ファイルを編集する
    1. ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ sudo vim /etc/nginx/conf.d/rails.conf
      
    2. 「i」と打ち込んで入力モードに切り替える
    3. ファイルを編集する
      ※3, 17, 24行目を更新
      /etc/nginx/conf.d/rails.conf
      upstream app_server {
        # Unicornと連携させるための設定
        server unix:/var/www/リポジトリ名/shared/tmp/sockets/unicorn.sock;
      }
      
      # {}で囲った部分をブロックと呼ぶ。サーバの設定ができる
      server {
        # このプログラムが接続を受け付けるポート番号
        listen 80;
        # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
        server_name Elastic IP;
      
        # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
        client_max_body_size 2g;
      
      # 接続が来た際のrootディレクトリ
        root /var/www/リポジトリ名/current/public;
      
      # assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定
        location ^~ /assets/ {
          gzip_static on;
          expires max;
          add_header Cache-Control public;
          root /var/www/リポジトリ名/current/public;
        }
      
        try_files $uri/index.html $uri @unicorn;
      
        location @unicorn {
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_redirect off;
          proxy_pass http://app_server;
        }
      
        error_page 500 502 503 504 /500.html;
      }
      
    4. 「escキー」→「:wq」の順で実行し、保存する
    5. 再読込・再起動するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
      $ sudo systemctl reload nginx
      $ sudo systemctl restart nginx
      
  8. DBの起動を確認するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    ※「active」と表示されれば起動している
    $ sudo systemctl status mariadb
    
  9. unicornのプロセスをkillするため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    $ ps aux | grep unicorn
    
    $ kill プロセス番号
    
  10. Gemfile.lockの設定を追加するため、ターミナル(ローカル)にて、下記コマンドを実行する
    % bundle lock --add-platform x86_64-linux
    
  11. ローカルでの修正をすべてpushする
  12. 自動デプロイ
    1. ターミナル(ローカル)にて、下記コマンドを実行する
      # アプリのディレクトリに移動
      % cd ~/[アプリ名]
      
      % bundle exec cap production deploy
      
    2. エラーが表示されずに完了したら自動デプロイは完了
    3. ターミナル(ローカル)にて、下記コマンドを実行する
      $ sudo systemctl restart mariadb
      $ sudo systemctl restart nginx
      
  13. ブラウザからhttp://Elastic IPにアクセスし、サイトが正常に表示されているか確認する

IPアドレスにアクセスしてもエラーが発生する場合

ブラウザ上で「We’re sorry , but ~」が表示された

自動デプロイ後は、currentディレクトリの中にproduction.logが入ってくることに注意

  1. エラーログを確認するため、ターミナル(EC2内で実行)にて、下記コマンドを実行する
    # 自身のアプリケーションのディレクトリに移動
    $ cd /var/www/リポジトリ名
    
    # currentディレクトリに移動
    $ cd current
    
    # logディレクトリに移動
    $ cd log
    
    # logの中に入っているファイルの情報を表示
    $ ls
    production.log  unicorn.stderr.log  unicorn.stdout.log
    
    # production.logの最新のログを10行分表示
    $ tail -f production.log
    
    production.logが出力されていない場合、手動デプロイで行ったGemfileのrails_12factorのコメントアウトがされていない可能性が高いので確認

以降、自動デプロイを行う場合

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?