LoginSignup
55
67

More than 3 years have passed since last update.

【デプロイ】チーム開発でデプロイを担当したまとめ(参考リンク付き)

Last updated at Posted at 2019-08-25

この記事の目的

 
TECH::EXPERTの最終課題である「チーム開発でメルカリのコピーサイトを作る」ときにデプロイを担当させてもらいました。しかし、他のチームメンバーにはほとんど技術的なことだったり、エラー時の対応などをシェアしていなかったので、この記事の目的は他のメンバーにこの一ヶ月デプロイ担当として一体何をやっていたのか、チーム開発の中のデプロイ担当の役割を自分なりにお伝えする記事です。

※Capistrano,Unicorn,nginxの導入に関してはTECH::EXPERTのカリキュラムで一度やっているので、省きます。

デプロイの際に使ったサービス、言語など

チーム開発の際に使っていた言語とサービスのversionは以下の通りです

services or lang version
Ruby 2.5.1
Rails 5.2.3
Bundler 3.11.0
Mysql 14.14
unicorn 5.4.1
Capistrano 3.11.0
Nginx 1.14.1

S3導入後、環境ごとに画像の保存先を分岐させる

Chat-Spaceの実装では開発環境、本番環境ともに画像を投稿した場合はS3に保存されるような仕様になっていました。しかし、チーム開発においてChat-Spaceと同じような仕様(画像の保存先を環境ごとに条件分岐をさせない)にすると、デプロイを担当した人しか開発環境で画像投稿ができません(理由はAWSのアクセスキーとシークレットキーがないため。)

環境ごとに画像の保存先を変える仕様にする

では、実際に導入した手順について書いていきます。
 

①S3を導入する

まずはChat-Spaceと同様S3を導入させます。
今回はcarrierwaveのgemを使っています。

Gemfile

gem 'carrierwave'
gem 'fog-aws'

②image_uploaderで条件分岐のコードをかく

コードはこんな感じになります

app/uploader/image_uploader

# Choose what kind of storage to use for this uploader:
  if Rails.env.development? || Rails.env.test?
    storage :file
  else
    storage :fog
  end

developmentまたはtest環境のときは

storage :file

に保存して、

それ以外、つまりproduction(本番)環境のときは

storage :fog

に保存しています。
 

③carrierwave.rbにS3に保存するときのキーを渡してあげる

config/initializer/carrierwave.rb
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  if Rails.env.development? || Rails.env.test? #開発とテストは今まで通りに
    config.storage = :file
  elsif Rails.env.production? #本番はS3に保存する
    config.storage = :fog
    config.fog_provider = 'fog/aws'
    config.fog_credentials = {
      provider: 'AWS',     #AWSのアクセスキーとシークレットキーを環境変数で定義する
      aws_access_key_id: Rails.application.credentials.aws[:access_key_id], #credentails.ymlに鍵の本体があります
      aws_secret_access_key: Rails.application.credentials.aws[:secret_access_key],  #credentails.ymlに鍵の本体があります
      region: #'AWSで設定した地域(おそらく'ap-northeast-1') '
    }
    config.fog_directory  = #'S3のバケット名'
    config.asset_host = 'https://s3-ap-northeast-1.amazonaws.com/tech54-mercari-a'
  end
end

これで開発環境のときは、今まで通りに。本番はS3に保存されるようになったと思います。

考えられるエラーの原因

エラーが出たり、画像が期待する場所に保存されない、デプロイができないなどの原因はおそらく以下のうちのどれかが考えられます。

  • 条件分岐のコードが正しくかけていない
  • バケットの権限は正しく付与されているか
  • credentials.ymlのmaster.keyの鍵は鍵穴に一致する鍵か
  • credentials.ymlの中身とそれを使っている部分(今回であれば下のコードの.aws[:access_key_id]aws[:secret_access_key]の部分)

ちなみにこのコードにはcredentials.ymlの知識も入っています。

      aws_access_key_id: Rails.application.credentials.aws[:access_key_id],
      aws_secret_access_key: Rails.application.credentials.aws[:secret_access_key],

ここの部分です。
この流れで次は、Rails5.2から導入されたcredentials.ymlについて解説してみます。

もうここまできたら、あとはcredentials.ymlを使いこなすだけです。
(ただこのcredentials.yml)にかなり苦戦させられました…
 

credentials.yml.encでパスワードを管理する

結論から

config/credentials.yml.encプロダクションアプリの秘密を保存するためのファイルを追加しました。config/master.keyファイル内のキーまたはRAILS_MASTER_KEY環境変数で暗号化されたリポジトリに、サードパーティサービスの認証資格情報を直接保存できます。これは、最終的にRails.application.secretsはRails 5.1で導入された暗号化された秘密を置き換えます。さらに、Rails 5.2 はCredentialsの基礎となるAPIを開くので、他の暗号化された設定、キー、およびファイルを簡単に扱うことができます。これについては、Securing Rails Applications ガイドを読んでください。引用元:Ruby on Rails 5.2 Release Notes

つまり、要約すると

  • Rails 5.2 versionから登場したよ!sercret.ymlの代わりだよ!
  • credentials.yml.encに秘密鍵などを保存できるよ!
  • しかも、credentials.yml.encは暗号化されてるからgithubに上がってもなにかいてあるかわからないよ!
  • しかもしかも、credentials.yml.encはmaster.keyがないと編集したり、中身を見ることができないよ!
  • 極め付けはmaster.keyはデフォルトでgitignoreに入っているからgithubには上がらないよ!

つまりmaster.keyを意図的にgithubなどで公開しない限り、秘密は守られるってことです。

実際にS3のアクセスキーとシークレットキーをcredentials.yml.encに入れて保存してみる

この記事でcredentails.ymlについて書こうと思ったのですが、自分の理解がまだ不十分なところもあります。ミスリードを避けるために、お世話になったcredentails.ymlの記事を貼っておきます。実際に実装するときは以下の記事を参考にするとスムーズにいくと思います。

Rails5.2から追加された credentials.yml.enc のキホン
Rails5.2から導入されたcredentials.yml.encを極める

 個人的に詰まった部分

credentials.ymlで詰まった部分は主に2箇所ありました。

①credentials.ymlの中身がデフォルトでコメントアウトされていることに気がつかなかった

ターミナルでEDITOR=vim bin/rails credentials:editと打つと、以下のように出力されます

credentaials.yml
# aws:
#   access_key_id: 123  
#   secret_access_key: 345

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: <rake secretで取得した値>

この1〜3行目のコメントアウト(#)にまったく気がつかずに3時間くらい頭を抱えていました。笑

④本番のshared/config/master.ymlにmaster.keyをコピーできなかった

さっき上にあげた2つのリンクでこの方法が紹介されているのですが、まったくできなかったため、vim ~/.bash_profileでmaster_keyを無理やり使えるようにしました。(本当はよくない。環境変数にするのが正解っぽいです。)

ssh
vim ~/.bash_profile     #書き込み
source ~/.bash_profile  #読み込み

頻発したエラーとその対応、対策

実はこの一ヶ月間、rubyやrailsのコードが原因で「デプロイができない!」みたいなエラーはなかったです!これは実際に正確なコードを書いて、コメントおじさんをはじめとして、内容の濃いコードレビューをして、ローカル環境で確認してくださっていたから。本当にありがとうございました!

開発中におきたエラー集(随時追加予定)

実際にデプロイ作業中はエラーが頻発しました。ただ、いつも同じようなエラーだったり、原因は「またお前か…」みたいなことになるので、最終的にはRailsのエラーを解決するのとそんなに難易度は変わりません。
 
ここでは実際におきたエラーをジャンル別に分けて見ていきます。

1.身に覚えのないエラー=EC2インスタンスの再起動

これは先輩の発表会のときに聞いた言葉です。

「身に覚えのないエラーはとりあえずEC2インスタンスを再起動すれば大丈夫だから!」

これはマジでした。笑
例えば、よくあったのはbundle exec cap production deployで自動デプロイ中に「bundle installができません!」と怒られたとき。最初はbundlerとかを見てましたが、試しにEC2インスタンスを再起動させたところ、すんなり解決。身に覚えのないエラーに遭遇したら、AWSでEC2を再起動させましょう。

2.自動デプロイ中のエラー

自動デプロイの最中にエラーがおきた場合は、エラー文を読んであげると解決することが多いです。特にmaster.keyが正しいものではないとエラーが起きるので、そこもチェックしてみるといいかな。

Nginx,Mysql,Unicornの状態を確認する

ssh
$ sudo servise nginx status #nginxの状態を確認する
$ sudo service mysql status #mysqlの状態を確認する
$ bundle exec unicorn -c /var/www/freemarket_sample_54a/current/config/unicorn.rb -E production -D #unicornを立ち上げる

EC2を再起動後は自動的にこれらがSTOP状態になるので、Mginx,MySQL,Unicornを再起動させます。

Capistrano導入後のディレクトリ構造の変化

Capistranoを導入後はディレクトリの構成が変わります。例えばconfig/unicorn.rbが、shared/config/unicorn.rbになったり。unicorn.rbを参照する記述はsharedを参照する記述になっているか確認してみるといいです。

unicorn.rb
# Capistrano導入前。
listen "#{app_path}/tmp/sockets/unicorn.sock"
pid "#{app_path}/tmp/pids/unicorn.pid"
stderr_path "#{app_path}/log/unicorn.stderr.log"
stdout_path "#{app_path}/log/unicorn.stdout.log"

# Capistrano導入後。それぞれ、sharedの中を参照するよう変更
listen "#{app_path}/shared/tmp/sockets/unicorn.sock"
pid "#{app_path}/shared/tmp/pids/unicorn.pid"
stderr_path "#{app_path}/shared/log/unicorn.stderr.log"
stdout_path "#{app_path}/shared/log/unicorn.stdout.log"

3.MySQL系エラー

Can`t connect to local Mysql server through socket /tmp/mysql.sock(2)

原因:mysql.sockがないこと
解決策:mysql.sockをtouchコマンドで作成する

$ sudo touch /tmp/mysql.sock 

このエラーは「ローカルのMySQLに繋がない」ので、サーバー(ssh)ではなく、ローカルでこのコマンドを打ちます。
/tmp/mysql.sockの場所はdatabase.ymlに記載されている。

config/database.yml

default: &default #ローカル環境
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock

production:   #本番環境
  <<: *default
  database: freemarket_sample_54a_production
  username: root
  password: <%= ENV['DATABASE_PASSWORD'] %>
  socket: /var/lib/mysql/mysql.sock

デプロイ作業するときに役立ったリンク集

エラー全般系

Capistranoによる自動デプロイトラブルシューティング(随時追記予定)
↑この記事控えめに行ってヤバイです。だいたいこれで解決できる

credentials.yml.enc系

Rails5.2から導入されたcredentials.yml.encを極める
Rails 5.2の新機能Credentialsでパスワード等を管理する
Rails5.2から追加された credentials.yml.enc のキホン

Mysql,DB操作系

MySQLの既存のデータベースの見方MySQLデータベース初心者向け
EC2上のMySQLをsequel proを使って表示する
GitHubにpushしたmigrationファイルは安易に修正してはいけません
mysqlが起動できない(Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2))
mysqlが起動できない

AWS系

AWSの無料枠について
Amazon EC2 インスタンスの IP アドレッシング

公式リンク系

Ruby on Rails 5.2 Release Notes
carrierwaveuploader/carrierwave
fog/fog

55
67
1

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
55
67