WEB系プログラミングに関する雑記ブログ

このブログは、主にWEB系の話(プログラミング、IT系のニュースなど)をします。

CDNとは?

CDNの仕組みについて、まとめます。

CDNとは?

コンテンツデリバリネットワーク(Content Delivery Network, CDN)とは、 Webコンテンツをインターネット経由で効率よく配信するためのネットワークです。

CDNを導入する目的

CDNを導入する目的は、ズバリ

「サーバー側の負荷を軽くする」ということです。

CDNを使うことで、オリジンサーバの負荷を減らし、レスポンスの速度を上げる、 またデータのダウンロードを安定させるというメリットがあります。

CDNの仕組みを説明するには、

オリジンサーバ

キャッシュサーバ

の仕組みを知る必要があります。

オリジンサーバーとは

オリジンサーバとは、「元々のデータが入っているサーバ」のことです。

パソコンの画面にサイトを表示する時には、 htmlやcss、画像など色んなファイルをダウンロードしています。

最初にWebページにアクセスした際、 サイトを表示するためには、このオリジンサーバに入っているデータを取得することで、 ブラウザ上で閲覧することができます。

キャッシュサーバとは

キャッシュサーバとは、CDNのことで、 オリジンサーバから取得したデータを一時保存しておく場所です。

キャッシュサーバは別名エッジサーバとも言います。

最初の段階では、キャッシュサーバにデータは何も入っていません。 しかし、初回にオリジンサーバからデータを取得した後、 2回目以降のアクセスはキャッシュサーバから直接配信され、 オリジンサーバへのアクセスは発生しません。

ただ、キャッシュされる時間というのは限りがあります。

例えば、キャッシュ時間を1分と設定していたとすると、

初回アクセスした時にオリジンサーバからデータを取得してから1分間は、 キャッシュサーバからデータを配信しますが、

1分経過後は、再度オリジンサーバへデータを取得にいきます。

このようにして、 キャッシュサーバにあるデータが更新されるようにしています。

Ec2にALB+ACMを導入してみた

今回は、

AWSのec2インスタンス常時SSL化で通信を行うために、

ACMをインストールしたALBを導入してみました。

私が今回、ALBを導入するにあたっての前提としては、 以下のような状態でした。

・ec2インスタンスを使用

・Route53を使用

ACMを取得済み

そもそもALBとは?

ALBってそもそも何?っていうところなのですが、

ALBは

  • Application

  • Load

  • Balancer

の略で、AWSが提供しているロードバランサの一つです。

ロードバランサというのは、 複数あるサーバーにアクセスの負荷分散をさせたり、 メンテナンスや障害時に切り離しを行うためのものです。

ただ、今回は、自分の作成したアプリにhttps通信できるようにしたかったので、

ACMとALBを使うことで実現したいと思い、導入をしてみました。

導入方法

まず、AWSコンソールにログインし、「サービスを検索する」のところで、 ec2を検索し、ec2ダッシュボードへ移ります。

f:id:katsu-puchi:20190720104547p:plain

まず、ALBを作成する前に、 ターゲットグループを作成します。

ターゲットグループというのは、

通信のリクエストをどこに割り振るのか、

ALBが対象にしているサーバを登録しているグループのことです。

ターゲットグループを選択。

f:id:katsu-puchi:20190720104758p:plain

「ターゲットグループを作成」をクリック。

すると、こんな画面が出てきます。 f:id:katsu-puchi:20190720110020p:plain

ターゲットグループ名は何でもいいです。

他の設定に関しては、特に何もいじらずに、デフォルトのままで作成をクリック。 ターゲットグループが作成されます。

次に、ロードバランサーをクリック。

ロードバランサーの作成をクリックすると、

以下のような画面が出るので、

一番左のApplication Load Balancerをクリック。

f:id:katsu-puchi:20190720110412p:plain

「基本的な設定」の部分で名前の入力がありますが、 名前は何でも構いません。

スキームやIPアドレスタイプはそのままで。

f:id:katsu-puchi:20190720112309p:plain

ロードバランサープロトコルには、 HTTPSを追加します。(ロードバランサーのポートは自動的に443が入ります。)

アベイラビリティーゾーンの設定では、 選択肢の中から、少なくとも2つ以上のアベイラビリティーゾーンを選択します。

なおこの際、ec2インスタンスが属しているアベイラビリティーゾーンを含む必要があります。 f:id:katsu-puchi:20190720112318p:plain

そして、次の手順: セキュリティ設定の構成をクリック。

ACMから証明書を選択するを選び、

証明書の名前のところで、デプロイしたいACMを選択します。

セキュリティポリシーの選択は、

特にデフォルトのままで進めます。

次の手順をクリック。

セキュリティグループの設定が出ますので、 新しいセキュリティグループの設定をクリックし

下記のように、httpとhttps通信を許可する設定をします。

f:id:katsu-puchi:20190720112325p:plain

次の手順をクリック。

ターゲットグループで、 既存のターゲットグループを選択。

そして、先ほど作成したターゲットグループを選択します。

次の手順をクリックし、

ターゲットの登録に問題がなければ、確認をクリックします。

これで、ロードバランサーは作成されました!

次に、route 53から、 ALBに接続できるよう設定を行います。

「サービス」からroute53を検索し、ダッシュボードを表示します。

ホストゾーンをクリックし、 ec2インスタンスと紐づいたドメインを選択。

するとレコードセットの画面が表示されるので、

Aタイプのレコードを選択し、レコードの編集のところで、 エイリアス「はい」を選択します。

f:id:katsu-puchi:20190720114058p:plain

そして、エイリアス先として、 先ほど作成したALBを選択します。

これで、ALBを通じた通信が可能になりました!

ただ、このままだと、

「httpでもhttpsでも接続できる」

という状態なので、常時SSL化をするには、 http通信できたリクエストを、httpsにリダイレクトするという設定を行います。

今回は、webサーバ(nginx)に設定を記述しました。


[ec2-user@ip-172-31-25-189 ~]$ sudo vim /etc/nginx/conf.d/rails.conf

そして、以下の記述を追加します。

server {
~省略~

  if ($http_x_forwarded_proto != https) {
    return 301 https://$host$request_uri;
  }

~省略~

この記述の意味は、

httpでアクセスが来たものに関しては、 httpsにリダイレクトします。

という意味です。

これを記述すると、httpでリクエストが来ても、httpsにリダイレクトされるので、 常時SSL化することができます!

お名前.comで取得したドメインをRoute53に登録する

DNSの基本的な仕組みも理解したので、

ここに簡単にまとめておきたいと思います。

なおDNSに関する基本的な用語は記事下にまとめておきましたので、 よければ参照してください!

やりたいこと

お名前.comで取得したドメインAWSのRoute53を使って、 ec2インスタンスにつなげる。

基本的な流れはこうです。

  1. お名前.comのDNSサーバにアクセスする。

  2. NSレコードから、AWSのRoute53にアクセスする。

  3. Route 53のAレコードで、登録されているElastic IPアドレスにアクセスする。

導入

まずはAWSにログインして、サービス一覧からroute53を選択します。

ホストゾーンを作成します。

左上にあるホストゾーンの作成をクリック。 f:id:katsu-puchi:20190718133139p:plain

ドメイン名を入力すると、ホストゾーンが作成され、 同時にNSレコードとSOAレコードが自動生成されます。

f:id:katsu-puchi:20190718133536p:plain

では次に、Aレコードを作成します。

レコードセットの作成をクリックます。

f:id:katsu-puchi:20190718133731p:plain

名前は空のまま、 エイリアスも「いいえ」のままで、 値のところにElastic IPアドレスを入力し、作成ボタンをクリックします。

次に、お名前.comの設定を行います。

お名前.comにログインし、ドメイン設定をクリックします。

ネームサーバーの変更をクリック

f:id:katsu-puchi:20190718134402p:plain

「他のネームサーバーを利用」タブをクリック

f:id:katsu-puchi:20190718134524p:plain

ネームサーバ情報を入力のところで、

先ほどのRoute53のホストゾーンで表示されていた、 NSタイプの値4つを入力します。

これであとは確認画面へ進み、問題なければ完了します。

Nginxの設定

私は、ec2インスンスのウェブサーバーとしてnginxを使っていたのですが、

上記までの設定を終えて、ドメイン名でアクセスしてみると、

次の画面が出てきました。

f:id:katsu-puchi:20190718135547p:plain

ec2インスタンス内のnginxの設定を開き、

server_name , ドメイン名;

と記述することで、アクセスできるようになりました!

今回の記事で出てきた基本用語を下にまとめておきます。

DNSとは?

IPアドレスドメインを紐付けするためのシステムのこと。

IPアドレスとは、ネットワーク上の住所を表すものです。 「3.113.56.130」といったような数字の羅列で表されます。

一方で、ドメインとは、

hogehoge.com

というような、文字で表されるURLのことです。

~.jpとかよく見ますよね。あれもドメインです。

ホストゾーンとは

パブリックホストゾーンは、あるドメイン、たとえば example.com とそのサブドメイン (acme.example.com や zenith.example.com) のトラフィックをインターネットまたは特定のドメインでルーティングする方法についての情報を保持するコンテナです。ホストゾーンを作成した後で、ドメインサブドメイントラフィックをどのようにルーティングするかを指定するレコードを作成します。(AWSドキュメントを参照 https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/CreatingHostedZone.html

ちょっと分かりづらいですが、要するに、 "自分の管理する範囲におけるIPアドレスドメイン名の対応情報が書かれているところ"という感じです。

NSレコードとは?

管理を委託しているDNSサーバーにアクセスするための情報が書かれているところ。

Aレコードとは?

ドメイン名と連携しているIPアドレスが書かれているところ。

Rspecにfactory_botとfakerを導入してみる

Rspecにfacroy_botとfakerを導入してみたので、

方法を残しておきます。

factory_botとは?

ダミーのインスタンスを作成できるgemのこと。

factoryを使ってインスタンスを定義しておけば、

テストをする際に、特定のメソッドを使って簡単にインスタンスが作成できます。

fakerとは?

ダミーのデータを自動生成してくれるgemのこと。

導入

では早速、factory_botとfakerを組み合わせて、

ダミーのインスタンスを作成し、テストを行います。

まずは、gemfileにgemを追加します。

gemfile


group :development, :test do
  #省略
  gem 'factory_bot_rails'
  gem 'faker'
end

そして、bundle installします。

次に、specディレクトリの下にfactoriesというフォルダを作成します。

そして、その中にusers.rbというファイルを作ります。

FactoryBot.define do
  pass = Faker::Internet.password(8)

  factory :user, class: User do
    name                  { Faker::Name.name }
    email                 { Faker::Internet.email }
    password              { pass }
    password_confirmation { pass }
  end
end

このように記述することで、 インスタンスを生成するたびに、 その都度ダミーのデータをランダムで作成してくれます。

実際にfacotry_botを使ってインスタンスを生成する時は、 下記のようなメソッドを使います。

#factory_botの記述をもとに作成

user = FactoryBot.build(:user)



#createの場合はテスト用のDBに値が保存される

user = FactoryBot.create(:user)

引数にシンボル型で取ったクラス名のインスタンスを、factory_botの記述をもとに作成します。 buildもcreateメソッドの両方ともインスタンスを生成しますが、

違いとしては、createはテスト用のDBに値が保存されるという点です。

ただし、テスト用のDBに値が保存されても、テストが終了すれば保存された値は消去されます。

また、設定を追加することで、「FactoryBot」の記述を省略することもできます。

rails_helperに以下の記述を追加します。

RSpec.configure do |config|
  #下記の記述を追加
  config.include FactoryBot::Syntax::Methods

  #省略

end

この設定を踏まえた上で、テストを書いてみます。



require 'rails_helper'

describe User do
  describe '#create' do

    it "is invalid without a nickname" do
      user = build(:user, name: "")
      user.valid?
      expect(user.errors[:nickname]).to include("can't be blank")
    end

  end
end

導入前の記述と比べてみると、このような形になります。


#導入前

require 'rails_helper'

describe User do
  describe '#create' do
    it "is invalid without a name" do
      user = User.new(name: "", email: "test@gmail.com", password: "123456", password_confirmation: "123456")
      user.valid?
      expect(user.errors[:nickname]).to include("can't be blank")
    end
  end
end

#導入後

require 'rails_helper'

describe User do
  describe '#create' do
    it "is invalid without a nickname" do
      user = build(:user, name: "")
      user.valid?
      expect(user.errors[:nickname]).to include("can't be blank")
    end
  end
end

Rspec 単体テストの導入

Railsアプリでの単体テストとして、Rspecを導入しましたので、 導入方法および簡単なテストの記述について説明したいと思います。

gemを追加します。

まずは、

Gemfile

group :development, :test do

~省略~
  gem 'rspec-rails'
end


group :development do
  gem 'web-console'
end

gemfileをインストールしたら、 bundle installをします。

その後に、Rspecの基本設定をします。

ターミナルから、以下のコマンドを入力してください。

ターミナル

rails g rspec:install


すると、以下のファイルが作成されます。

      create  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb


rails_helper.rbというのは、 Rspecを利用する際に、共通の設定を書いておくファイルのことです。


今回は、ユーザー新規登録のテストを書いてみます。


spec/models/user_spec.rbを作成します。

そして、基本となるコードを書いてみます。


require 'rails_helper'
describe User do
  describe '#create' do
    it "is invalid without a name" do
    end
  end
end


上記の記述について、説明します。

describe do

end

というのは、

期待する結果をまとめて記述(describe)しています。 このケースでは User モデルがどんなモデル なのか、 どんな振る舞いをするのかということを説明しています。


it ~ do

end

のところで、実際に動作するテストコードのまとまりを記述します。


上記の例では、

「名前の入力がないと登録ができない」ということを確認したいため、

it "is invalid without a name" do

end

と記述しています。


それでは実際に、テストを記述してみます。

     user = User.new(name: "", email: "test@gmail.com", password: "123456", password_confirmation: "123456")
     user.valid?
     expect(user.errors[:nickname]).to include("can't be blank")


1行目の

user = User.new(name: "", email: "test@gmail.com", password: "123456", password_confirmation: "123456")

のところで、userクラスのインスタンスを作成しています。


2行目の

user.valid?

で作成されたインスタンスが、

userクラスのバリデーションに引っかかっているかどうかを確認しています。


valid?メソッドの返り値は、 true、falseですが、falseが返り値の場合、 errorsメソッドを使うことで、エラーの原因を確認することができます。


3行目の expect(user.errors[:name]).to include("can't be blank")

というのは、 インスタンスが持つエラー文が期待したものとなっているかどうかを確認しています。


expectというのは期待するという意味、 includeというのは含むという意味です。

そのため、3行目は

「userインスタンスのnameカラムに関するエラー文には、can't be blankという言葉が含まれる。」

ということを確認しています。


それでは、今日はこのあたりで、、、

また、別の記事でfactory_botを使った単体テストについて書きたいと思います。

EC2インスタンスのDBにあるテーブル及びカラムを確認する方法

プログラミングスクールでチーム開発を行なっているのですが、

データベースの中身を確認したいことが多々あり、

コマンドが上手く通らないことが起きてしまい少しハマったので、

ここにまとめておきます。


今回は、

  • ローカル環境のDBにあるテーブル、カラムを確認する方法
  • EC2インスタンス内にあるデータベースを確認する方法


この2つを説明します。

ローカル環境のDBにあるテーブル、カラムを確認する方法

terminalで以下のコマンドを入力するとDBにあるテーブルやカラムを確認できます。

まず最初に見たいアプリのディレクトリまでcd で移動しておきます。

~$ cd 移動したいディレクトリ名


ディレクトリ名$ rails dbconsole;



mysql>



#データベース一覧を見る

mysql> show databases;



#テーブル一覧を見る

mysql> show tables;



#テーブルのカラム一覧を見る

mysql> show column from テーブル名;



EC2インスタンス内にあるデータベースを確認する方法

ec2本番環境では以下のコマンドで確認できます。


[ec2-user@ip-XXX-XX-XX-XXX ~]$ mysql -u root -p


Enter password:  パスワードを入力


mysql> 

本番環境では、デフォルトだと、 毎回データベース名まで入力をする必要があります。


#データベース一覧を見る
mysql> show databases;



#テーブル一覧を見る

mysql> show tables from データベース名;



#テーブルのカラム一覧を見る

mysql> show column from テーブル名 from from データベース名;


ただ、毎回入力するのは面倒です。。

そこで、下記のコマンドを入力すると、データベース名を省略することができます。


mysql> use `データベース名`;