Rails + CloudFront +S3 でCDNを利用し高速配信を実現する

##はじめに
今回はアプリケーションサーバに配置されているアセットファイルを外部に配置し、CDNで配信できるようにする手順を簡単に説明できればと思っています。

|作業環境|  |  |
| -------- | ------ | ----------- |
|ストレージ|S3 |AWS |
|CDN| CloudFront | AWS |
|言語| Ruby| 2.6.5 |
|フレームワーク|Rails | 6.0.3 |
|パッケージ管理|Webpacker|4.3.0|
|Gem|asset_sync|2.13.0|
#####　＃本番環境の設定です

###作業手順
1. バケットを作成
2. RailsにてGemのインストール
3. asset_syncファイルをカスタマイズ
4. WebpackerのビルドファイルをS3に配置する
5. CloudFrontの設定



##その前に
###asset_syncとは？
クラウドとRailsのはしごの役目だと理解するのが簡単です。
S3やcloudfrontを使う際にはこちらのgemを使用して、ファイルを作成し、コンパイル時に自動的にクラウドにアップロードするとても便利なGemです。

###CDN(CloudFront)とは？
コンテンツデリバリネットワークの略称。
コンテンツをキャッシュサーバに配置して、サーバの負荷を減らすことができます。
さらにキャッシュを利用するので、アプリ自体が高速化します。
結果的にUXの向上も狙えるという画期的なシステムのこと。
このシステムをAmazonがサービスとして提供しているのがCloudFrontです。

###S3とは？
Amazonが出しているストレージサービスのこと。
Simple Storage Serviceこの頭文字s3つで、
名前の通りシンプルで使いやすく、話せば尽きないほどのメリットがあるオンラインストレージサービスです。
今回このサービスを使う目的は静的コンテンツを保存しておく役割として使用します。


##手順①　バケットを作成
まずコンソールにログインして、サービスの一覧からS3を選択
するとこのような画面に遷移します。
![test1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825677/2ac19c16-5298-0887-e485-b00e76a7428d.png)

このオレンジのバケットを作成を選択します。
任意のバケット名を入力する。
以下の画面のようにチェックがない状態にする。
![test2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825677/377665a5-774a-19e5-8537-072d76d104f4.png)

#####それ以外の項目はデフォルトで大丈夫です。


##手順②　Rails でGemのインストール
```Ruby
gem 'asset_sync'
gem 'fog-aws'
```

##手順③&④　asset_syncファイルを編集する
```Ruby
bundle exec rails g asset_sync:install --provider=AWS
```
上記のコマンドでファイルを作成します。
#
```config/initializers/asset_sync.rb
if defined?(AssetSync)
  AssetSync.configure do |config|
    config.fog_provider = 'AWS'
    config.fog_directory = 'xxx' # S3バケット名
    config.aws_access_key_id = 'xxx' # IAMユーザのアクセスキー
    config.aws_secret_access_key = 'xxx' # IAMユーザのシークレットキー
    config.aws_session_token = ENV['AWS_SESSION_TOKEN'] if ENV.key?('AWS_SESSION_TOKEN')
    config.fog_region = 'xxx' # S3バケットのリージョン
  end
end
```
作成したファイルに、xxxとしている部分を任意の値に変更します。

_⚠️環境変数にする必要がありますが、今回の記事とは内容が外れてしまうので、説明は省略します。_
#
```config/initializers/asset_sync.rb
    config.run_on_precompile = false
    config.add_local_file_paths do
      public_root = Rails.root.join("public")
      Dir.chdir(public_root) do
        packs_dir = Webpacker.config.public_output_path.relative_path_from(public_root)
        Dir[File.join(packs_dir, '/**/**')]
      end
    end
```
上記はWebpackerのビルド出力先の設定です。
こちらは、このままコピペで大丈夫です。
#
```lib/tasks/asset_sync.rake
if defined?(AssetSync)
  Rake::Task['webpacker:compile'].enhance do
    Rake::Task["assets:sync"].invoke
  end
end
```
#####lib/tasks下に_asset_sync.rake_ファイルを作成する。
こうすることで、コンパイル時にjsファイルなどが配置されているpackファイルを、S3に同期することができる。


```config/environments/production.rb
Rails.application.configure do
+ config.action_controller.asset_host = "http:/xxx.s3.amazonaws.com" # S3バケットのエンドポイント
end
```
xxxの部分にバケット名を記述する。
#
```Ruby
bundle exec rails assets:precompile RAILS_ENV=production
```
コンパイルしS3と同期する
![test3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825677/2e5ab096-9244-b334-da7d-689e54ef63b6.png)

このような画面になっていたら成功です。

##手順⑤　CloudFrontの設定
先ほどと同様に、コンソールからCloudFrontと検索します。
青ボタンの Create Distributionsというボタンをクリック。
![test4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825677/84ebc691-2d74-d354-0d86-6326295abb6c.png)
このような画面で、作成したS3のバケットを選択し、エンターを押すと。
デフォルトの設定が勝手に入力されるので。そのまま作成します。
![test5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825677/941f3127-ee7a-ec84-bf64-53f4a31642e1.png)

statusがデプロイになったらcloudfrontの設定は完了です。

##動作確認
ブラウザで検証ツールを開きます。
![test6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/825677/6c9181c1-6a21-b7f4-e5be-632c4f40d479.png)

HTMLのheadタグに参照先がcloudfront.netで表示されていれば成功です！！
お疲れ様でした！