第7回目(11/13)

※タイトル「状況について」は一時的なものでしたので削除

ALBのターゲットグループがうまく行かなかったため、最初から作り直しつつ、何が原因かを探しながらやっていたら結構な時間がかかってしまった。

1.構成図

スクリーンショット 2021-11-27 10.09.06

セキュリティグループ

スクリーンショット 2021-11-26 3.12.37

スクリーンショット 2021-11-26 3.16.26

2.作業手順

1.EC2の構築
 - 初期設定
 - Ruby・Rails
 - mysql・database.yml
2.RDSの構築
 - EC2とRDSの接続確認
3.Railsでテストページ作成
 - テストページ確認(ポート3000)
4.Nigex・Pumaの設定
 - Nigexのようこそ画面確認
 - バーチャルサーバの設定
 - Pumaの設定
 - グローバルIPアドレスでテストページ確認(ポート80)
5.Route53の設定
 - 無料ドメインを登録
6.ACMの設定
 - 証明書の発行
7.ALBの設定
 - EC2にてヘルスチェック用ファイルを作成
 - Nigexでヘルスチェック用ファイルを指定
 - ターゲットグループの設定
 - ロードバランサーの設定
8.ドメイン名でテストページ確認(ポート443)

3.EC2(Nginx+Puma+Rails)

役割
Nginx:Webサーバ
Puma:アプリケーションサーバ
Rails:アプリケーション

参考URL:※概略図と通信の流れを参照
https://serip39.hatenablog.com/entry/2020/12/23/235700

Nginx設定
バーチャルサーバの設定を行なった。
この設定をすることで複数のHTTPサーバを設定できる。

ここで設定する内容:
・Pumaとのソケット通信の設定 ※Puma側とpathが同じであること
・server_nameでグローバルIPを指定
・ヘルスチェック用ファイルの指定
・リバースプロキシの設定

参考URL:
https://qiita.com/HeRo/items/7063b86b5e8a2efde0f4

/etc/nginx/conf.d/todo.conf

upstream rails_app {
   # UNIXドメインソケット通信の設定
   server unix:/var/RailsApp/Todo/tmp/sockets/puma.sock fail_timeout=0;
}
server {
   listen       80;
   server_name  グローバルIP;

   root /var/RailsApp/Todo/public;
   index index.html;

   # ドキュメントルート配下を以下の先頭から順番に辿る
   try_files $uri @rails_app;

   # 上記の@rails_appが呼び出された場合のみ以下の設定を読み込む
   location @rails_app {
      	proxy_headers_hash_max_size 512;
      	proxy_headers_hash_bucket_size 128; 
      	proxy_set_header Host $http_host;
	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      	proxy_set_header X-Forwarded-For $http_x_forwarded_proto; 
	    proxy_set_header X-Forwarded-Proto $scheme;
	    proxy_set_header X-Real-IP $remote_addr; 
	    proxy_set_header origin 'http://kadai-todo.tk';
	    proxy_redirect off;
	    proxy_pass http://rails_app;
   }
}

Nginx本体のコンフィグ:
・Nginx起動時にこのコンフィグを見に行き、include /etc/nginx/conf.d/*.confでバーチャルサーバを読み込んでいる

ここで設定する内容:
・実行ユーザーがnginxになっているため変更する

/etc/nginx/nginx.conf

※抜粋

#user nginx;
user ec2-user;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
   worker_connections 1024;
}

http {
   log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';

   access_log  /var/log/nginx/access.log  main;

   sendfile            on;
   tcp_nopush          on;
   tcp_nodelay         on;
   keepalive_timeout   65;
   types_hash_max_size 4096;

   include             /etc/nginx/mime.types;
   default_type        application/octet-stream;

   # Load modular configuration files from the /etc/nginx/conf.d directory.
   # See http://nginx.org/en/docs/ngx_core_module.html#include
   # for more information.
   include /etc/nginx/conf.d/*.conf;

   server {
       listen       80;
       listen       [::]:80;
       server_name  _;
       root         /usr/share/nginx/html;

       # Load configuration files for the default server block.
       include /etc/nginx/default.d/*.conf;

       error_page 404 /404.html;
       location = /404.html {
       }

       error_page 500 502 503 504 /50x.html;
       location = /50x.html {
       }
   }

Puma設定
ここで設定する内容:
・デフォルトでポート3000を使うようになっているためコメントアウトする
・Nginxとのソケット通信の設定をしてポート80にする

参考URL:※接続の構成例を参照
https://qiita.com/rubytomato@github/items/44eb173c0111283a418c

※抜粋

#port ENV.fetch("PORT") { 3000 }
bind "unix://#{Rails.root}/tmp/sockets/puma.sock"

4.ALB

ターゲットグループ
・プロトコルバージョンは気を付けないとハマる。ALB側でHTTP2(最近使われるプロトコル?)を指定すると、Nginx側はHTTP1なのでうまく通信ができなくなる。なので、ALB側でHTTP1を指定した。ちなみに、ALB側でHTTP2を使うときは、Nginx側でHTTP2を有効にする設定が必要。

Client → HTTP2 → ALB → HTTP1 → Nginx

スクリーンショット 2021-11-26 2.20.41

ヘルスチェック
・Rails側でヘルスチェックを作ろうと思い、取り掛かったがうまく設定ができなかった。とりあえず、アプリが動くようにするためシンプルにHTMLファイルを作成した

5.Rails

/app/controllers/todo_controller.rb

class TodoController < ApplicationController
 def index
   @msg = 'Todoリスト'
   @data = TodoCore.all
 end
 
 def add
   if request.post?
     TodoCore.create(todo_params)
     goback
   else
     @adddata = TodoCore.new
   end
 end
 
 def edit
   @editdata = TodoCore.find(params[:id])
   if request.patch?
     @editdata.update(todo_params)
     goback
   end
 end

 def delete
   TodoCore.find(params[:id]).destroy
   goback
 end

 private
 def todo_params
   params[:todo_core].permit(:task, :contents, :start_date, :end_date, :image)
 end

 def goback
   redirect_to 'https://kadai-todo.tk/todo'
 end

end

/app/views/todo/index.html.erb

<!DOCTYPE html>
  <head>
      <meta charset="UTF-8">
      <title>Todo</title>
  </head>
  <body>
      <h1>Todo#index</h1>
      <p><%= @msg %></p>

      <table border = "1">
          <tr>
              <th>id</th>
              <th>タスク名</th>
              <th>タスク内容</th>
              <th>開始日</th>
              <th>終了日</th>
              <th>画像</th>
              <th>編集</th>
              <th>削除</th>
          </tr>
          
          <% @data.each do |obj| %>
          <tr>
              <td><%= obj.id %></td>
              <td><%= obj.task %></td>
              <td><%= obj.contents %></td>
              <td><%= obj.start_date %></td>
              <td><%= obj.end_date %></td>
              <td><%= image_tag obj.image.to_s %></td>
              <td><a href="/todo/edit/<%= obj.id %>">編集</a></td>
              <td><a href="/todo/delete/<%= obj.id %>">削除</a></td>
          </tr>
          <% end %>
      </table>
      <p Class="link"><a href="/todo/add">
          &lt;&lt; 追加</a></p>
  </body>
</html>

/app/views/todo/add.html.erb

<!DOCTYPE html>
  <head>
      <meta charset="UTF-8">
      <title>Todo add</title>
  </head>
  <body>
      <h1>Todo#add</h1>
      <%= form_for(@adddata, url:{controller:'todo',
                  action:'add'}) do |form| %>
          <div class="form-group">
              <label for="task">タスク名</label>
              <%= form.text_field:task,{class:"form-control"} %>
          </div>
          <br>
          <div class="form-group">
              <label for="contents">タスク内容</label>
              <%= form.text_area:contents,{class:"form-control"} %>
          </div>
          <br>
          <div class="form-group">
              <label for="start_date">開始日</label>
              <%= form.date_field:start_date,{class:"form-control"} %>
          </div>
          <br>
          <div class="form-group">
              <label for="end_date">終了日</label>
              <%= form.date_field:end_date,{class:"form-control"} %>
          </div>
          <br>
          <div class="form-group">
              <label for="image">画像</label>
              <%= form.file_field:image,{class:"form-control"} %>
          </div>
          <br>
          <%= form.submit "保存" %>
      <% end %>
  
  <p Class="link"><a href="/todo">
      &lt;&lt; トップページに戻る</a></p>
  </body>
</html>

/app/views/todo/edit.html.erb

<!DOCTYPE html>
  <head>
      <meta charset="UTF-8">
      <title>Todo edit</title>
  </head>
  <body>
      <h1>Todo#edit</h1>
      <%= form_for(@editdata, url:{controller:'todo',
                  action:'edit', id:@editdata.id}) do |form| %>
          <div class="form-group">
              <label for="task">タスク名</label>
              <%= form.text_field:task,{class:"form-control"} %>
          </div>
          <div class="form-group">
              <label for="contents">タスク内容</label>
              <%= form.text_area:contents,{class:"form-control"} %>
          </div>
          <div class="form-group">
              <label for="start_date">開始日</label>
              <%= form.date_field:start_date,{class:"form-control"} %>
          </div>
          <div class="form-group">
              <label for="end_date">終了日</label>
              <%= form.date_field:end_date,{class:"form-control"} %>
          </div>
          <div class="form-group">
              <label for="image">画像</label>
              <%= form.file_field:image,{class:"form-control"} %>
          </div>
          <%= form.submit "更新" %>
      <% end %>
  
  <p Class="link"><a href="/todo">
      &lt;&lt; トップページに戻る</a></p>
  </body>
</html>

/config/routes.rb

Rails.application.routes.draw do
 get 'todo/index'
 get 'todo',to: 'todo#index'

 get 'todo/add'
 post 'todo/add'
 
 get 'todo/edit/:id',to: 'todo#edit'
 patch 'todo/edit/:id',to: 'todo#edit'

 get 'todo/delete/:id',to: 'todo#delete'
end

・Railsで「CarrierWave+Fog-AWS」を使ってS3へアップロードする仕組みを作った
・画像をアップロードすると500系のエラーが発生した
 Nginxの /var/lib/nginx の所有者をec2-userに変更して解決した
https://qiita.com/rinkun/items/8f8bc19f98754b3b17c7

/config/initializers/carrierwave.rb

CarrierWave.configure do |config|
   config.fog_provider = 'fog/aws'
   config.fog_directory  = 'kadai-webapp'
   config.asset_host = 'https://s3-ap-northeast-1.amazonaws.com/kadai-webapp'
   config.fog_credentials = {
     provider:              'AWS',
     # アクセスキー
     aws_access_key_id:     'アクセスキー',
     # シークレットキー
     aws_secret_access_key: 'シークレットキー',
     # Tokyo
     region:                'ap-northeast-1',
   }
   # 環境ごとにS3のバケットを指定
   config.fog_directory = 'kadai-webapp'
   config.cache_storage = :fog
end

/app/models/todo_core.rb

class TodoCore < ApplicationRecord
   mount_uploader :image, ImageUploader
end

/app/uploaders/image_uploader.rb

class ImageUploader < CarrierWave::Uploader::Base
 # Include RMagick or MiniMagick support:
 # include CarrierWave::RMagick
 # include CarrierWave::MiniMagick

 # Choose what kind of storage to use for this uploader:
 #storage :file
 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

 # Provide a default URL as a default if there hasn't been a file uploaded:
 # def default_url(*args)
 #   # For Rails 3.1+ asset pipeline compatibility:
 #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
 #
 #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
 # end

 # Process files as they are uploaded:
 # process scale: [200, 300]
 #
 # def scale(width, height)
 #   # do something
 # end

 # Create different versions of your uploaded files:
 # version :thumb do
 #   process resize_to_fit: [50, 50]
 # end

 # Add an allowlist of extensions which are allowed to be uploaded.
 # For images you might use something like this:
 def extension_allowlist
   %w(png jpg)
 end
 def extension_whitelist
   %w(png jpg)
 end


 # Override the filename of the uploaded files:
 # Avoid using model.id or version_name here, see uploader/store.rb for details.
 # def filename
 #   "something.jpg" if original_filename
 # end
 def filename
   original_filename if original_filename
 end
end

/config/environments/development.rb

require "active_support/core_ext/integer/time"

Rails.application.configure do
 # Settings specified here will take precedence over those in config/application.rb.

 # In the development environment your application's code is reloaded any time
 # it changes. This slows down response time but is perfect for development
 # since you don't have to restart the web server when you make code changes.
 config.cache_classes = false

 # Do not eager load code on boot.
 config.eager_load = false

 # Show full error reports.
 config.consider_all_requests_local = true

 # Enable/disable caching. By default caching is disabled.
 # Run rails dev:cache to toggle caching.
 if Rails.root.join('tmp', 'caching-dev.txt').exist?
   config.action_controller.perform_caching = true
   config.action_controller.enable_fragment_cache_logging = true

   config.cache_store = :memory_store
   config.public_file_server.headers = {
     'Cache-Control' => "public, max-age=#{2.days.to_i}"
   }
 else
   config.action_controller.perform_caching = false

   config.cache_store = :null_store
 end

 # Store uploaded files on the local file system (see config/storage.yml for options).
 config.active_storage.service = :local

 # Don't care if the mailer can't send.
 config.action_mailer.raise_delivery_errors = false

 config.action_mailer.perform_caching = false

 # Print deprecation notices to the Rails logger.
 config.active_support.deprecation = :log

 # Raise exceptions for disallowed deprecations.
 config.active_support.disallowed_deprecation = :raise

 # Tell Active Support which deprecation messages to disallow.
 config.active_support.disallowed_deprecation_warnings = []

 # Raise an error on page load if there are pending migrations.
 config.active_record.migration_error = :page_load

 # Highlight code that triggered database queries in logs.
 config.active_record.verbose_query_logs = true

 # Debug mode disables concatenation and preprocessing of assets.
 # This option may cause significant delays in view rendering with a large
 # number of complex assets.
 config.assets.debug = true

 # Suppress logger output for asset requests.
 config.assets.quiet = true

 # Raises error for missing translations.
 # config.i18n.raise_on_missing_translations = true

 # Annotate rendered view with file names.
 # config.action_view.annotate_rendered_view_with_filenames = true

 # Use an evented file watcher to asynchronously detect changes in source code,
 # routes, locales, etc. This feature depends on the listen gem.
 config.file_watcher = ActiveSupport::EventedFileUpdateChecker

 # Uncomment if you wish to allow Action Cable access from any origin.
 # config.action_cable.disable_request_forgery_protection = true
 config.web_console.whitelisted_ips = '0.0.0.0/0'
 config.hosts << "kadai-todo.tk"
end

6.結果

・Todo画面で3つタスクを追加した画面

スクリーンショット 2021-11-27 9.50.09

・Todo画面で1つタスクを削除した画面

スクリーンショット 2021-11-27 9.54.50

・S3バケットの状態(画像ファイルの保存場所)

スクリーンショット 2021-11-27 13.14.15

スクリーンショット 2021-11-27 13.14.29


この記事が気に入ったらサポートをしてみませんか?