hiyoko-programingの日記

プログラミングを勉強したてのひよっ子。   エンジニア目指して勉強中。

S3を使った画像をアップロード その2

https://tech-master.s3.amazonaws.com/uploads/curriculums//5863da25f2597781a122214675deb6d0.png

今まで作ったChatSpaceでは、投稿した画像がアプリ内のpublicフォルダに保存される。これを、以下の2ステップで変更していく。

STEP1

ローカルのChatSpaceの画像保存先をS3に変更する。そのために、以下の2つの作業を行う。

  • S3のバケット(データの保存場所)を用意する
  • ChatSpaceの設定を変更し、保存先がS3になるようにする

STEP2

S3に保存できるようになったChatSpaceをEC2にデプロイする。それによって、本番環境のChatSpaceからS3への画像アップロードができるようになる。

 

 

【STEP1】ローカルからS3にアップロードできるようにする

ここからは、S3に画像をアップロードするための設定を行なっていく。

https://tech-master.s3.amazonaws.com/uploads/curriculums//57439855818bbe91fb77ea4e642e74e7.png

完成までの作業量が多いので、2つのステップに分けて進めていく。
これから取り組むのは、上図のSTEP1。

まずS3の準備を行い、次に「ローカル開発環境のChatSpace」からS3にアップロードできる状態を目指す。

画像のアップロード先をS3に変更

Railsの設定を変更していく。

今までは、CarrierWaveによる画像のアップロード先がアプリ内のpublicフォルダだった。これをS3に変更する。そのために、以下の手順で進める。

1.インターネット上にファイルをアップロードするためのGem(fog-aws)をインストールする
2.アップロードにfogを使うよう設定する
3.fogのアップロード先の情報を設定する
4.AWSのキーを安全に扱えるようにする

1.fog-awsをインストール

必要なGemのインストールを行う。

 fog

画像をアップロードする際、外部のストレージを選択しアップロードするのを補助してくれるGem。

AWSに最適化されたfog-awsをインストールする。

 fog-awsをインストール

Gemfile
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 前略

group :development do
  # Access an IRB console on exception pages or by using <%= console %> in views
  gem 'web-console', '~> 2.0'

  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
end

gem 'carrierwave'
gem 'fog-aws'

開発・テスト・本番環境いずれでも使えるようにするため、group ~ end で囲まれていない部分に追記。

この状態で、bundle installコマンドを実行。

2.アップロードにfogを使用するための設定を行う

今までは、アップロード先がpublicフォルダになっていた。これをfogを使う設定をするため、image_uploader.rbを編集する。

 image_uploader.rbを編集

app/uploaders/image_uploader.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# encoding: utf-8

class ImageUploader < CarrierWave::Uploader::Base

  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick
  process resize_to_fit: [800, 800]

  # Choose what kind of storage to use for this uploader:
  storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/# {model.class.to_s.underscore}/# {mounted_as}/# {model.id}"
  end

# 後略

storageを「:file」から「:fog」に変更することで、アップロードにfogを使う指定をしている。

3.fogのアップロード先の設定

CarrierWaveの設定ファイルを新規作成する。

 carrierwave.rbを編集

アプリケーションのルートから/config/initializers直下に、carrierwave.rbというファイルを作成する。

app/config/initializers/carrierwave.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  config.storage = :fog
  config.fog_provider = 'fog/aws'
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: Rails.application.secrets.aws_access_key_id,
    aws_secret_access_key: Rails.application.secrets.aws_secret_access_key,
    region: 'ap-northeast-1'
  }

  config.fog_directory  = 'ここにバケット名を入れます'
  config.asset_host = 'https://s3-ap-northeast-1.amazonaws.com/ここにバケット名を入れます'
end

バケット名の部分は、自身で付けられた名前を入力する。

regionで設定してある「ap-northeast-1」は、アジアパシフィック(東京)を表している。

もしも他のリージョンを使用する場合は、インターネットで検索してから入力する。

config.asset_hostは「https://s3-ap-northeast-1.amazonaws.com/bucket-name」のような記述になっていることを確認。

4.安全にAWSのキーを扱えるよう設定

S3で使用するキーの設定を行う。万が一漏洩すると巨額の被害を被る恐れがあるので、しっかり内容を理解しながら着実に進める。

ChatSpaceでAWSのキーを扱う際は、以下の3箇所で設定を行うことで安全性を確保する。まずはこの全体像を把握する。

https://tech-master.s3.amazonaws.com/uploads/curriculums//cfe823e769005b19c1a4a4e3f92f4298.png

ここでのポイントは、AWSのidやパスワードそのものは環境変数」だけに設定するということ。

環境変数に代入されているデータは誤操作によって漏れてしまうことがないため、安全性が高い。

環境変数の値を「secrets.yml」から読み込んで、さらにその内容を「carrierwave.rb」が読み込むという構造になっている。

それぞれの内容を詳しく確認しながら、実際に設定を行なっていく。

環境変数を設定する

S3の接続に必要な認証情報を、環境変数として設定していく。

S3の設定時にダウンロードしたCSVファイルを開く。その中に、aws_access_key_idaws_secret_access_keyというカラムがあるので、こちらに書かれた値を設定していく。

この作業においては、コマンドは基本的にどこのディレクトリで入力していただいても問題ない。特に理由がなければホームディレクトリまたはルートディレクトリで実行する。

 環境変数の設定の仕方

環境変数は、変数の一種なのでパソコンをシャットダウンすると消えてしまう。それだと毎回設定しなくてはいけないので、シェルの起動時に自動で読み込まれるファイルに設定内容を記述しておく。

また、その設定ファイルがmacOS10.15以降変更になったため、バージョンによって手順も異なっている。

 macOSのバージョンを確認

環境変数の設定方法はmacOSのバージョンによって異なる。そのため、以下の手順で確認を行う。

デスクトップの左上にあるアイコンをクリックして、「このMacについて」を選択。

https://tech-master.s3.amazonaws.com/uploads/curriculums//4a71a0bc6d7fed48409e3986d5374365.png

この画面で、macOSのバージョンを確認することができる。
https://tech-master.s3.amazonaws.com/uploads/curriculums//da640a7ab3bb96d25ddef246401b5764.png

自身のパソコンがバージョン10.15(macOS Catalina)より新しいか、それとも10.14(Mojave)以前なのかを確認し、下記の操作を行う。

MacOSがCatalina以降の場合

環境変数の設定を.zshrcというファイルに記述。

ターミナル
1
2
3
4
5
6
7
8
# ローカル環境
$ vim ~/.zshrc

# iを押してインサートモードに移行し、下記を追記する。既存の記述は消去しない。
export AWS_SECRET_ACCESS_KEY='ここにCSVファイルに乗っている値をコピー'
export AWS_ACCESS_KEY_ID='ここにCSVファイルに乗っている値をコピー'

# 編集が終わったらescapeキーを押してから:wqと入力して保存して終了

 ファイル編集時の注意

上記の設定は、現在の設定に「追加」する。既存の設定を削除してしまうとパソコンが正常に動作しなくなる危険性がある。

記述ができたら、以下のコマンドを実行して設定を反映させる。

ターミナル
1
2
3
# ローカル環境
# 編集した.zshrcを読み込み直して、追加した環境変数を使えるようにする
$ source ~/.zshrc

ローカル環境変数の設定が完了したら、「secrets.ymlの設定をしよう」に進む。

MacOSがMojave以前の場合

ここでは、バージョンが10.14以前のパソコンでの操作を解説。
10.15以降の場合は実行しないよう注意。

ターミナル
1
2
3
4
5
6
7
8
# ローカル環境
$ vim ~/.bash_profile

# iを押してインサートモードに移行し、下記を追記する。既存の記述は消去しない。
export AWS_SECRET_ACCESS_KEY='ここにCSVファイルに乗っている値をコピー'
export AWS_ACCESS_KEY_ID='ここにCSVファイルに乗っている値をコピー'

# 編集が終わったらescapeキーを押してから:wqと入力して保存して終了

 ファイル編集時の注意

上記の設定は、現在の設定に「追加」する。既存の設定を削除してしまうとパソコンが正常に動作しなくなる危険性がある。

ターミナル
1
2
3
# ローカル環境
# 編集した.bash_profileを読み込み直して、追加した環境変数を使えるようにする
$ source ~/.bash_profile

これで環境変数が設定は完了。

 secrets.ymlを設定する

※ここからはOSに関係なく、Mojave以前の方もCatalinaの方も同じ作業。


secrets.ymlの設定を行い、環境変数の値を読み込むようにする。

 YAMLファイル

拡張子がymlのファイルは、YAMLと呼ばれる種類のファイル。
設定ファイルとしてよく使われ、Rubyのハッシュのように「:(コロン)」で区切って「キー」「バリュー」を設定することができる。

ここで編集するsecrets.ymlもYAMLファイル。

app/config/secrets.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Be sure to restart your server when you modify this file.

# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!

# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rails secret` to generate a secure secret key.

# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.

development:
  secret_key_base: cb2965bfebd75267542611a74ab612b9754f98・・・・・
  aws_access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
  aws_secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>

test:
  secret_key_base: 7362cb8e960adf75f110e17bb4cd1f2d4edc3d・・・・・

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

15行目でaws_access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>という設定を追加している。

右側のENV[" "]という書き方は、環境変数を読み込むためのRubyのメソッド。括弧の中には環境変数名を指定する。

つまりaws_access_key_idというキーに対して、環境変数AWS_ACCESS_KEY_IDの値をセットするという意味。

このように、secrets.ymlには直接パスワードなどを記載していない。そのため、万が一このファイルが漏洩しても第三者にはパスワードはわからない。この仕組みを取ることで安全性を確保することができる。

 carrierwave.rbの設定を確認

CarrierWaveからこの設定を読み込めるようにする必要がある。

しかし実はこの設定は先ほどすでに行なっている
どのような記述をしたか確認する。

app/config/initializers/carrierwave.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  config.storage = :fog
  config.fog_provider = 'fog/aws'
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: Rails.application.secrets.aws_access_key_id,
    aws_secret_access_key: Rails.application.secrets.aws_secret_access_key,
    region: 'ap-northeast-1'
  }

  config.fog_directory  = 'ここにバケット名を入れます'
  config.asset_host = 'https://s3-ap-northeast-1.amazonaws.com/ここにバケット名を入れます'
end

今回関係あるのは10, 11行目。10行目を見てみる。

値に「Rails.application.secrets.aws_access_key_id」という記述がある。
この前半の「Rails.application.secrets」という書き方によって、secrets.ymlの設定内容を呼び出すことができる。

続けて「aws_access_key_id」と書いてあるので、secrets.ymlで設定した「aws_access_key_id」の値という意味になる。

ここまでの設定を行うことで、「環境変数」→「secrets.yml」→「carrierwave.rb」の順にデータを読み込めたことになる。

最後に図で確認しておく。

https://tech-master.s3.amazonaws.com/uploads/curriculums//7293c26fd83d6e969e05e17e1047aea8.png

.gitignoreを編集

開発を行う上で、Gitを使ってGitHubソースコードをpushすることはよくある。

ただし、他人に知られてはいけない内容については、Gitの管理から外してアップロードされないようにする必要がある。

「.gitignore」というファイルに設定を行うことで、Gitの管理下から除外することができる。

ここまでの設定によって、secrets.ymlにはパスワードの記述はない。そのため、今の段階でアップロードしても問題はないが、secrets.ymlは各種パスワードを扱うためのファイルである。必ず以下の操作を行って、pushされないようにする。

.gitignore
1
2
# ファイルの最下部に下記を追記
config/secrets.yml

.gitignoreに記載した変更は、一度gitの監視下に置かれてしまったファイルには適用されない。今.gitignoreに記載した変更を反映させるためには、config/secrets.ymlをgitの監視から外す必要がある。次のコマンドを実行して、config/secrets.ymlをgitの監視から外す。

ターミナル
1
$ git rm --cached config/secrets.yml

正しくアップロードできるか確認する

ここまで実装できたら、アップロードしたファイルがS3に保存されるか確認する。

 メッセージの投稿を行う

ローカル開発環境のChatSpaceから、画像つきの投稿を行う。

 S3の状態を確認

S3のバケットを見て、ファイルがアップロードされているか確認。
正常に投稿できていれば、バケットを選択した際に「uploads」というディレクトリができている。

https://tech-master.s3.amazonaws.com/uploads/curriculums//defda52ed49263ae461c39d5b7f2eecc.png

さらに下の階層にたどっていくと、以下のような形式でアップロードした画像が保存されていることが確認できる。

https://tech-master.s3.amazonaws.com/uploads/curriculums//55b28534b355c7cee5e01f9b9f7a9c09.png

必ずS3へのアップロードができることを確認してから次に進む。

アップロードができない時のチェック項目

S3にアップロードができない場合は、原因の特定と対応を行う。

 

エラーメッセージを確認

開発をしているときに起こるエラーは、大まかに2種類ある。

①エラーメッセージが出て処理が中断する
②エラーメッセージは出ないが、意図した通りに動作をしない

①の場合は比較的対応がしやすい。エラーメッセージは、改善のための重要なヒントをくれているので、注意深く内容を確認する。

 

たとえば、下記のメッセージでは何が起きているか。

https://tech-master.s3.amazonaws.com/uploads/curriculums//70645c2bf53bbe9784c91c1f848ddcb2.png

エラーを読む時のコツとして、大事そうな部分をGoogleで検索してみる。

上の例だと、「404 Not Found」というエラーが出ている。
検索してみると、この404というのはあるURLにリクエストを送ったけれども見つからなかった時に帰ってくるHTTPステータスコードだということがわかる。

S3にアップロードしようとして、そのURLがないと言われているので、バケットの指定が正しくないのではという仮説を立てることができる。

このように、まずエラーメッセージの確認を行って、それでも原因が判明しない場合は以下の項目を確認する。

以下のポイントを確認する

1. 環境変数が正しく設定されているか確認

環境変数を設定し、それをCarrierWaveから使えるようにするには、以下の3箇所の設定が正しい必要がある。どこまでうまくいっていて、どこからうまくいっていないのか順番に調べていく。

https://tech-master.s3.amazonaws.com/uploads/curriculums//a371c597e1ca8573d7bb6aaf52eb0b21.png

環境変数およびsecrets.ymlの設定が正しいか

①ChatSpaceがあるフォルダで、「rails c」を実行。

②コンソール内で、以下のコマンドを実行。

コンソール
1
2
Rails.application.secrets.aws_access_key_id
Rails.application.secrets.aws_secret_access_key

Rails.application.secrets」+「.キーの名前」を実行する事でsecrets.ymlの設定を呼び出すことができる。
上の2つのコマンドを実行して、正しくAWSのキーとパスワードが表示されれば、ここまでの設定は正しいと言うことになる。

うまくいった場合

下記の「carrierwave.rbの設定を確認しよう」以下を実行。

うまくいかなかった場合

以下の確認を行う。

bash_profileの内容を確認する

ターミナル
1
cat ~/.bash_profile

表示されたbash_profileの中に、以下の記述があるか確認。

~/.bash_profile
1
2
export AWS_SECRET_ACCESS_KEY='AWSのシークレットキー'
export AWS_ACCESS_KEY_ID='AWSのアクセスキー'

記載がなかった場合は、カリキュラムに戻って追加。

bash_profileの内容を反映させる

ターミナル
1
source ~/.bash_profile

bash_profileにコマンドを書いただけでは設定は反映しない。
念のためsourceコマンドを実行する。

carrierwave.rbの設定を確認

環境変数について、ここまでの確認で問題がなければ「carrierwave.rb」の設定を確認する。

config/initializers/carrierwave.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  config.storage = :fog
  config.fog_provider = 'fog/aws'
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: Rails.application.secrets.aws_access_key_id,
    aws_secret_access_key: Rails.application.secrets.aws_secret_access_key,
    region: 'ap-northeast-1'
  }

  config.fog_directory  = 'ここにバケット名を入れます'
  config.asset_host = 'https://s3-ap-northeast-1.amazonaws.com/ここにバケット名を入れます'
end

このような記述になっているか確認。
バケット部分の記述については、この後に確認をしていく。

2. バケットの指定が正しいか確認

上記のcarrierwave-rbでS3のバケット名を指定している。その内容が正しいか確認する。

https://tech-master.s3.amazonaws.com/uploads/curriculums//84728f09685777b5226ecf61e54d6bee.png

AWSのサービスからS3を選択し、バケットを表示させる。
バケットの指定は「バケット名」「リージョン」の両方を正しく行う必要がある。

以下の2点をチェック。

バケット名が正しく設定できているか
・S3のリージョンが「アジアパシフィック(東京)」になっているか

 

【STEP2】本番環境からS3にアップロードできるようにする

今まで変更したきた内容でデプロイをし直して、本番環境のChatSpaceでもS3に画像がアップロードされるようにする。

https://tech-master.s3.amazonaws.com/uploads/curriculums//86afb76f3749e54a11a4bd0b1ed5b4ad.png

しかし、そのままデプロイし直しても動作しない。

その原因は環境変数である。

環境変数とはOSが提供する変数のこと。ローカル環境と本番環境とでは動作している端末が別なので、環境変数も全くの別物である。

そのため、本番環境用の環境変数を別途設定する必要がある。

本番環境の環境変数を設定する

本番環境の設定変更をするので、sshでリモートのサーバーにログインしてから作業する。以下の手順を行う。

 環境変数の設定ファイルを変更

1
2
3
4
5
6
7
8
# 本番環境
$ ssh -i [pem鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]
(ダウンロードした鍵を用いて、ec2-userとしてログイン)
$ sudo vim /etc/environment
# iを押してインサートモードに移行し、下記を追記する。既存の記述は消去しない。
AWS_SECRET_ACCESS_KEY='ここにCSVファイルに乗っている値をコピー'
AWS_ACCESS_KEY_ID='ここにCSVファイルに乗っている値をコピー'
# 編集が終わったらescapeキーを押してから:wqと入力して保存して終了

この作業によって、本番環境の「environment」というファイルにキーの情報を書き込んだ。
先ほどは、同じ操作を「.bash_profile」というファイルに対して行った。

 環境変数の設定を反映させる

変更した内容を環境変数に反映させるため、以下を実行。

ターミナル
1
2
3
4
5
6
7
# 本番環境
# 編集した環境変数を適用するために一旦ログアウトします。
$ exit
$ ssh -i [pem鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]
# 環境変数が適用されているか確認しましょう。
$ env | grep AWS_SECRET_ACCESS_KEY
$ env | grep AWS_ACCESS_KEY_ID

本番環境での環境変数の設定方法についての補足

ここで、本番環境での環境変数を「environment」というファイルに書き込んだ理由について解説すると、

ローカルでは「.bash_profile」に記述することで、環境変数の設定を行った。本番環境にも.bash_profileはあるので、そこに記述しても良さそうである。

しかし、それでは環境変数の設定ができない。理由はデプロイにCapistranoを利用しているためだ。

通常は、ユーザーがログインを行うと「.bash_profile」が読み込まれ、その内容が実行される。

しかし、Capstranoを使用した場合はその読み込みが行われないため、別の方法で環境変数を設定する必要がある。それが「/etc/environments」に記述する、という方法。

本番環境での環境変数読み込みの設定を行う

環境変数の内容は、secrets.ymlから参照した上で、CarrierWaveが使用する流れになっていた。

先ほどは、開発環境用のsecrets.ymlの設定を行いましたが、今回は本番環境用の設定を行う。

 secrets.ymlを編集

以下の通り設定を変更する。

config/secrets.yml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Be sure to restart your server when you modify this file.

# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!

# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rails secret` to generate a secure secret key.

# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.

development:
  secret_key_base: cb2965bfebd75267542611a74ab612b9754f98・・・・・
  aws_access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
  aws_secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>

test:
  secret_key_base: 7362cb8e960adf75f110e17bb4cd1f2d4edc3d・・・・・

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
  aws_access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
  aws_secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>

ここでの設定方法は、ローカル開発環境でのやり方と全く同じ。

Capistranoの設定を変更する

ここで、1つ問題になることがある。

今secrets.ymlの設定を変更しましたが、そもそもこのファイルはGitで管理されないようにしていた。

そのため、Capstranoで自動デプロイを行っても本番環境には送られない。

この問題を解決するために、Capistranoの設定を変更する。

 deploy.rbを編集する

以下の内容でファイルの編集を行う。

app/config/deploy.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# secrets.yml用のシンボリックリンクを追加
set :linked_files, %w{ config/secrets.yml }

# 元々記述されていた after 「'deploy:publishing', 'deploy:restart'」以下を削除して、次のように書き換え

after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'unicorn:restart'
  end

  desc 'upload secrets.yml'
  task :upload do
    on roles(:app) do |host|
      if test "[ ! -d #{shared_path}/config ]"
        execute "mkdir -p #{shared_path}/config"
      end
      upload!('config/secrets.yml', "#{shared_path}/config/secrets.yml")
    end
  end
  before :starting, 'deploy:upload'
  after :finishing, 'deploy:cleanup'
end

set :linked_filesで指定されたファイルは、元々のディレクトリを参照する代わりに、shared/元々のディレクトリ構成を参照するようになる。今回の例で言うと、config/secrets.ymlを参照する代わりに、shared/config/secrets.ymlを参照するようになる。

desc upload secrets.yml以下の記述は、ローカル環境にあるconfig/secrets.ymlを本番環境のshared/config/secrets.ymlに反映するための設定を行なっている。これで、.gitignoreに記載されているsecrets.ymlを、Githubを経由せずにデプロイすることができる。

変更内容をデプロイ

ここまでの作業を本番環境に反映させる。

 GitHubにアップロードする

変更内容をコミットしてGithubにプッシュ(publish)する。

 自動デプロイを実行する

以下のコマンドを実行してデプロイを行う。

ターミナル(ローカル)
1
$ bundle exec cap production deploy

エラーが出ずにデプロイが完了することを確認する。

https://tech-master.s3.amazonaws.com/uploads/curriculums//d521065ca36823ced32584c940db6ceb.png

上で行ったように、コードを変更した後に本番環境に反映させるための操作は以下の2つ。

GitHubへのpush
②「bundle exec cap production deploy」の実行
 
Capistranoを使用する事で上図の②〜⑤までが自動的に処理される。しかし、その前にGitHubへのアップロードは自分で行う必要があるので注意が必要。

正しくアップロードできるか確認

ここまでできたら、本番環境のアプリからアップロードしたファイルがS3に保存されるか確認する。

 メッセージの投稿を行う

本番環境のChatSpaceから、画像つきの投稿を行う。

 S3の状態を確認

最初に今の時点でS3にいくつのファイルがアップロードされているか確認。

https://tech-master.s3.amazonaws.com/uploads/curriculums//1a7557a852cbd393b886089f4be95d56.png

次に「本番環境」のChatSpaceから画像投稿を行い、もう一度S3のファイルを確認する。
今投稿したファイルがS3上で確認できれば成功。

動作確認ができたらプルリクエストを作成して次に進む。

本番環境からのアップロードがうまくいかない時の対応方法

 

エラーメッセージを確認する

ローカルでは、仮想サーバーを起動したターミナルを見ればエラーメッセージが表示されていた。
しかし、本番環境ではローカルのターミナルに当たるものがない。

確認方法はいくつかあるが、Capistranoでの自動デプロイができるのか、それともエラーが出てしまうのかによって以下の方法を試す。

Capistranoが動く場合

以下の設定を行うと、本番環境でもローカル開発環境と同じように、ブラウザにエラーメッセージが表示されるようになる。

config/environments/production.rb
1
2
3
(前略)
  config.consider_all_requests_local = true
(後略)

「config/environments/production.rb」のファイルの中から、上記の記述を見つける。もともと「false」になっているので、「true」に変更する。

この変更を本番環境に反映させる必要があるので以下の2つの操作を行う。
GitHubへのプッシュ
②「bundle exec cap production deploy」の実行

なお、エラー対応が終わったら、忘れずにfalseに戻してデプロイをし直す。

Capistranoがエラーになる場合

Capistranoがエラーになってしまう場合は、上記の方法が取れない。
エラーログを直接確認する。

エラーの内容によって、主に以下の2つのファイルにログが書き込まれる。
どちらに該当するかわかりにくい場合は、両方とも確認する。

Unicornのエラーログの確認方法

ターミナル
1
cat /var/www/(アプリ名)/current/log/unicorn.stderr.log 
ターミナル
1
cat /var/www/(アプリ名)/current/log/production.log

最初は、エラーログを読むのは少し難しいので、以下にいくつかポイントを参考にする。

Railsアプリのエラーログの確認方法

エラーログを確認するときは、以下の点に気をつける

エラーログの見方

・ファイルの下に行くほど新しいログが載っている
・いつのログなのかを必ず確認

いつ起きたエラーに対するログなのかを確認することが重要。

まず、ログの中にタイムスタンプがあったら、そこに9時間を足す(標準時での出力になるため、日本は9時間の時差がある)。その時刻と、今の時刻を見比べて今起きたエラーなのかをチェックする。

以下のポイントを確認

エラーメッセージが出ない場合や、原因を特定できない場合は以下のチェックを行う。

1. 環境変数が正しく設定できているか確認

リモートでの環境変数が正しく設定されていないとS3へのアクセスができない。下記のコマンドで確認を行う。

ローカルのターミナル
1
ssh -i ~/.ssh/<pemファイルの名前> ec2-user@<IP>

まずsshでリモートにログインする。

リモートのターミナル
1
> env | grep AWS

出力された結果が、AWSのキー、パスワードと一致するか確認。

なお、「|」は複数の処理を行うためのもの。「A | B」と書くことで、Aの処理が終わったらBの処理をする、という指定ができる。

envは、現在設定されている環境変数を確認するためのコマンド。

grepは文字の検索をして絞込みを行ってくれるコマンド。そのあとに「AWS」と付ける事で、「AWS」という文字列を含んだ行のみ表示がされる。

つまり、「env | grep AWS」とコマンドを実行する事で、環境変数の中に「AWS」という文字を含んだものだけを出力してほしい、という意味になる。

2. 変更後のコードが本番に反映しているか確認する

ローカル開発環境での変更が、本番環境にうまく反映していないこともよくある。以下の確認を行う。

GitHubを確認

プッシュ先のGitHubを直接確認してみる。
最後に変更したファイルをGitHubでチェックして、変更点が反映しているか確認。

万が一プッシュができていない場合は、もう一度プッシュを行う。

リモートのファイルを確認

GitHubにプッシュがされていたとしても、EC2へのプルで失敗していることもある。以下の確認をしてみる。

ローカルのターミナル
1
ssh -i ~/.ssh/<pemファイルの名前> ec2-user@<IP>

まずsshでリモートにログインをする。

最新のファイルは以下のフォルダ内に格納されているので、実際にファイルの内容を見て、最後の変更が反映しているか確認する。

1
/var/www/(アプリ名)/current/app

このフォルダ以下にファイルが格納されている。catコマンドで内容を確認。

3. サーバーを再起動

コードが最新になっているのにアプリに反映しないのは、サーバーの再起動ができていない場合がある。念の為、NginxおよびUnicornの再起動をしてから、再度アプリでチェックしてみる。

Nginxの再起動

リモートのターミナル
1
sudo service nginx restart

Unicornの再起動

リモートのターミナル
1
2
3
> ps aux |grep unicorn
# Unicornのプロセスidを確認する
> kill -9 (unicornのプロセスid)
ローカルのターミナル
1
> bundle exec cap production deploy

issueを作成する

issueとは

Githubに備わった機能で課題管理に使われることが多いが、議論や報告、連絡といった手段でも使用される。

 

issueを作成

ChatSpaceのGithubページを開いて、issuesのタブをクリック。
https://tech-master.s3.amazonaws.com/uploads/curriculums//45529b82a1697443e5c0ab4f093a5905.png

「New issue」と記載されているボタンをクリック。
https://tech-master.s3.amazonaws.com/uploads/curriculums//51b26a294075b0ea91100f6891483c84.png

Titleに「【依頼】ChatSpace挙動確認」、コメントに 自身のChatSpaceのIPアドレス を入力し、右下のSubmit new issueを押す。
https://tech-master.s3.amazonaws.com/uploads/curriculums//48ae971299eaa635ab50f5b7729fcd54.png

これでissueは完成!