AWS
EC2(Elastic Computing Cloud)を筆頭にAmazonが展開するwebサービス。
Amazon EC2(仮想サーバ)、Amazon S3(クラウドストレージ)、Amazon RDS(データベース)
デプロイまでの流れ
インスタンスの作成
elastic IPの取得・インスタンスとの関連付け
sshでサーバーに接続
~/.sshディレクトリで以下を実行。
$ ssh -i ダウンロードした鍵の名前.pem ec2-user@作成したEC2インスタンスと紐付けたElastic IP
最低限の環境を整える
sudo yum update
最低限必要なものをインストール
sudo yum install \
git make gcc-c++ patch \
libyaml-devel libffi-devel libicu-devel \
zlib-devel readline-devel libxml2-devel libxslt-devel \
ImageMagick ImageMagick-devel \
railsを始めるに当たって必要なパッケージをインストール
sudo yum install -y openssl-devel
nodejsをインストール
sudo curl -sL https://rpm.nodesource.com/setup_6.x | sudo bash -
sudo yum install nodejs
Node.js
サーバーサイドJavaScriptのパッケージ
rbenvとruby-buildをインストール
#rbenvのインストール
git clone https://github.com/sstephenson/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/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
#rehashを行う
rbenv rehash
rubyのインストール
rbenv install 2.5.1
rbenv global 2.5.1
rbenv rehash #rehashを行う
ruby -v # バージョンを確認
mysqlをインストール
sudo yum install mysql56-server mysql56-devel mysql56
mysqlを起動
service コマンドを利用。Amazon LinuxやCentOSに含まれ、インストールしたソフトウェアの起動を一括して行えるツール。
sudo service mysqld start
mysqld:daemonの略。linux用語でサーバーの意。
rootパスワードの設定
sudo /usr/libexec/mysql56/mysqladmin -u root password '設定したいパスワード'
Using a password on the command line interface can be insecure.
これが出る。passwordが丸見えだからセキュアじゃないよって意味。
アプリケーションサーバーの準備
Githubに接続
GithubにSSH鍵を登録
まずEC2サーバーでキーペアを生成
ssh-keygen -t rsa -b 4096
.ssh]$ ls
authorized_keys id_rsa id_rsa.pub
上記の2種類が作成される。この内publicの方の中身を確認。
cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2E***
githubへアクセスし、SSHキーを登録する。
※ssh-rsaからIPまでを含めた全体を登録する。
ssh-rsa AAAAB3NzaC1***== ec2-user@ip-111-11-11-111
Unicorn
アプリケーションサーバ
rails sコマンドの代わりにunicorn_railsコマンドで起動する。
Unicornをインストール
gemfileに以下を記述。
group :production do
gem 'unicorn', '5.4.1'
end
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(ワーカー)
リクエストを処理するunicornのプロセスのこと。適宜増える。
unicornはmaster1つと複数のworkerで構成される。
Unicornの設定
設定項目 | 詳細 |
---|---|
worker_processes | リクエストを受け付けレスポンスを生成するworker(ワーカー) の数を決めます。 |
working_directory | UnicornがRailsのコードを動かす際、ルーティングなど実際に参照するファイルを探すディレクトリを指定します。 |
pid | Unicornは、起動する際にプロセスidが書かれたファイルを生成します。その場所を指定します。 |
listen | どのポート番号のリクエストを受け付けることにするかを決定します。今回は、3000番ポートを指定しています。 |
ディレクトリの作成
#mkdirコマンドで新たにディレクトリを作成
[ec2-user@]$ sudo mkdir /var/www/
#作成したwwwディレクトリの権限をec2-userに変更
[ec2-user@]$ sudo chown ec2-user /var/www/
作成したディクトリのownerはrootになるので、ec2-userへ変更しておく。
/var/www/に移動してgit cloneする。
[ec2-user@]$ cd /var/www/
[ec2-user@ www]$ git clone https://github.com/user名/レポジトリ名.git
$ git clone https://github.com/user名/レポジトリ名.git
rail環境の再構築
まずローカル環境のrubyとbundlerのバージョンを確認。
ruby -v
bundler -v
サーバーでもruby -vを確認。違っていればバージョンを入れ直す。
続いてbundlerをバージョンを指定してインストール
gem install bundler -v 2.0.2
i18nをrails 5.2.2以下で使っている場合に注意がでる。
以下のように変更すればOK
config/environments/production.rb
config.i18n.fallbacks = true
↓
config.i18n.fallbacks = [I18n.default_locale]
環境変数
データベースのパスワードなどはセキュアに扱うためサーバー内の環境変数で扱います。
環境変数は /etc/environment というファイルに保存することで、サーバ全体に適用される。
secret_key_base
Cookieの暗号化に用いられる文字列。
Railsアプリケーションを動作させる際は必ず用意する。
config/secrets.yml と config/database.ymlで扱う。
以下のコマンドでsecret_keyを生成できる。
rake secret
環境変数を編集。
sudo vim /etc/environment
DATABASE_PASSWORD='MySQLのrootユーザーのパスワード' SECRET_KEY_BASE='作成したsecret_key_base'
を書き込んで保存して終了。
一旦サーバーからexitしてログインしなおすと環境変数として適応される。
portの解放
AWSのセキュリティーグループからインバウンドの編集へ。
カスタムTCP, port 3000として解放。
railsを起動する。
projectの階層で
unicorn_rails -c config/unicorn.rb -E production -D
-c config/unicorn.rb
は設定ファイルの指定、 -E production
は環境を「本番モードとして動作させる」。-D
は「Daemon(デーモン)」の略で、プログラムを起動させつつターミナルで別のコマンドを打てるようにするオプション。
データベースのアクセスで失敗するのでローカルプロジェクトを以下のように編集する。
終わったらpushしておく。
config/database.yml
production:
<<: *default
database: ~~~(個別に違う)
username: root
password: <%= ENV['DATABASE_PASSWORD'] %>
socket: /var/lib/mysql/mysql.sock
gitから差分を更新する。(pullする)
git pull origin master
production用のDBを作成する。
rails db:create RAILS_ENV=production
rails db:migrate RAILS_ENV=production
ユニコーンを起動する。
unicorn_rails -c config/unicorn.rb -E production -D
アセットファイルをコンパイル
開発中はアクセス毎にアセットファイル(画像・CSS・JSファイルの総称)を自動的にコンパイル(圧縮)するが、
本番モードのときにはパフォーマンスのためアクセス毎には実行されないようになっている。
このためコンパイルしないとレイアウトが崩れる。
以下を実行してコンパイルしてrailsを再起動する。
rails assets:precompile
unicornの再起動
unicornのプロセスを探す。
ps aux | grep unicorn
unicron_rails masterのプロセスIDを確認。
killコマンドで終了させる。
kill -9 プロセスID
unicornを再起動する。
この時、頭にRAILS_SERVE_STATIC_FILES=1を指定する。
これはコンパイルされたアセットをrailsに渡す指定。
$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
アクセス時のログは↓に記録されていくらしいが、なぜかblank。
stderrは書き込みがあるのになぜ?
log/unicorn.stdout.log
一応ここまででIP:3000にアクセスすれば動くはず。
NGINX
エンジンエックス。
sudo yum install nginx
設定ファイルを書き換える。
sudo vim /etc/nginx/conf.d/rails.conf
upstream app_server {
# Unicornと連携させるための設定。アプリケーション名を自身のアプリ名に書き換えることに注意。今回であればおそらくchat-space
server unix:/var/www/<アプリケーション名>/tmp/sockets/unicorn.sock;
}
# {}で囲った部分をブロックと呼ぶ。サーバの設定ができる
server {
# このプログラムが接続を受け付けるポート番号
listen 80;
# 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
server_name <Elastic IP>;
# 接続が来た際の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;
}
POSTメソッドでもエラーが出ないようにするために、下記のコマンドも実行し、
権限を変更。
cd /var/lib
sudo chmod -R 775 nginx
(デフォルトではnginxは770に指定されていた)
unicorn.rbを編集
project/confiig/unicorn.rbを編集する。
listen 3000
↓以下のように修正
listen "#{app_path}/tmp/sockets/unicorn.sock"
これでデプロイ作業は終了!
AWS S3
2段階認証にするためにauthyを導入。
AWS
Identity and Access Managementの「セキュリティステータス」でMFAの管理を選択
S3を使う専用のIAM userを作成し、S3fullAccess権限を付与。
同時に2段階認証へ。
git-secrets
git-secretsは、AWSが提供しているツール。
パスワード、secret_keyなどの秘密にしたい情報を、誤ってコミットされることを防ぐ。
=秘密情報を含むcommitができなくなる。
ローカルにインストール。
brew install git-secrets
projectフォルダに移って以下を入力
git secrets --install
secretsの条件を設定
以下のコマンドでsecret_key, access_keyなど、アップロードしたくないAWS関連の秘密情報を一括で設定
git secrets --register-aws --global
以下のコマンドで設定を確認できる。
git secrets --list
以下のコマンドで今後作成するproject全てにgit-secretsが適用される。
=git管理下に含めた時点でgit-secretsも有効になる。
$ git secrets --install ~/.git-templates/git-secrets
$ git config --global init.templatedir '~/.git-templates/git-secrets'
GitHub Desktop経由でgit secretsを利用する
GitHub Desktop経由でgit secretsを利用する場合は追加の設定が必要
以下のコマンドをうつ。
sudo cp /usr/local/bin/git-secrets /Applications/GitHub\ Desktop.app/Contents/Resources/app/git/bin/git-secrets
S3のパブリックアクセス管理
- アクセスコントロールポリシー
- バケットポリシー
バケットポリシーで以下を入力してバケットにuserを許可する。
{
"Version": "2012-10-17",
"Id": "Policy1544152951996",
"Statement": [
{
"Sid": "Stmt1544152948221",
"Effect": "Allow",
"Principal": {
"AWS": "************①****************"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::************②**********"
}
]
}
画像アップロード先を変更
1.fog-awsというgemをインストールする
2.image_uploader.rbを編集する
3.CarrierWaveの設定ファイルを作成する
4.環境変数を設定する
gemfileに下を記述し、bundle install
group :production doではなく、全てなので一番下にでも入れてください。
gem 'fog-aws'
app/uploads/image_uploader.rbファイルを以下のように変更。
storage :file → storage :fog
class ImageUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
include CarrierWave::MiniMagick
storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
CarrierWaveの設定ファイルを新規作成。
/config/initializers直下に、carrierwave.rbを作成
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
application.secrets.aws_secret_access_keyとidは、一旦secrets.ymlに設定してそこから参照させるようにする。
.gitignoreに追加
secrets.ymlにデリケートな情報を持たせるので、このファイルを.ignoreに追加する。
config/secrets.yml
.gitignoreに記載した変更は、一度gitの監視下に置かれてしまったファイルには適用されない。
.gitignoreに記載した変更を反映させるためには、config/secrets.ymlをgitの監視から外す必要がある。
次のコマンドで、config/secrets.ymlをgitの監視から外す。
git rm --cached config/secrets.yml
環境変数を指定
$ vim ~/.bash_profile
export AWS_SECRET_ACCESS_KEY='ここにCSVファイルに乗っている値をコピー'
export AWS_ACCESS_KEY_ID='ここにCSVファイルに乗っている値をコピー'
$ source ~/.bash_profile
ローカル環境とサーバーの両方で上を行う。
secrets.ymlに登録
config/secrets.ymlを以下のように編集。
development:
secret_key_base: ~~~~~~~~
aws_access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
aws_secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>
test:
secret_key_base: ~~~~~~~~
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"] %>
環境変数を呼べるように変更。
全体の流れとしてはログインユーザーにしか参照できない環境変数にAWSのキーを登録。
→ railsがyml内にそれを呼び出し
→ それをもってAWSと通信する。
この状態ならGIT上には環境変数はどうやっても乗らないのでセキュア。
この理論ならsecrets.yml自体もセキュアなのでgitであげちゃっても大丈夫そうだけどどうなんだろう?
capistranoの記述を変更
自動デプロイで利用するためには、明示的に環境変数を指定する。
config/deploy.rbに以下を追記
set :default_env, {
rbenv_root: "/usr/local/rbenv",
path: "/usr/local/rbenv/shims:/usr/local/rbenv/bin:$PATH",
AWS_ACCESS_KEY_ID: ENV["AWS_ACCESS_KEY_ID"],
AWS_SECRET_ACCESS_KEY: ENV["AWS_SECRET_ACCESS_KEY"]
}
さらに先ほど.gitignoreにsecrets.ymlを追加したため、デプロイしてもgitにpushされないため、明示的にproduction環境にアップロードしてあげる必要がある。
# 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を参照するようになる。
ロードバランサ
ELB
Elastic Load Balancing
CLB(Classic Load Balancer)、ALB(Application Load Balancer)、NLB(Network Load Banancer)の3種類
ELBを使う時の注意点
ロードバランサによって最初に振り分けられたサーバと別のサーバに振り分けられると、そこで一連の流れが途切れてしまいまた最初からやり直しが必要だったりする。
- ELBを作成した後に”維持設定の編集”をクリック
- “ロードバランサーによって生成された Cookie の維持を有効化”を選択
- 設定情報を持つ秒数を入力
コメント