zatsu na benkyou matome saito

勉強したことをまとめるだけのサイト、数学、プログラミング、機械学習とか

#4: インフラについて簡単に理解する [RDS]DBサーバーを構築

  1. RDSについて
  2. プライベートサブネットの作成
  3. RDSを設置
  4. WebサーバーからRDSに接続する

RDS

今回構築するもの

スクリーンショット 2020-11-03 22.16.34.png (224.2 kB) - プライベートサブネットにDBを置くことで外部からのインターネットによる接続をできないようにして安全性を担保する。 - RDSは複数のアベイラビリティーゾーンに用意しておくことを推奨しているため、別のアベイラビリティーゾーンを用意しておく必要がある。そのため、2つ以上のプライベートサブネットを2つ以上の別のアべイラビリティゾーンにおく必要がある。

1. RDSについて

スクリーンショット 2020-11-03 22.19.39.png (369.8 kB)

マルチAZというRDSの可用性(DBが死んでも復活させやすいこと)を保つシステムがあるが、このシステムを使うのに複数のアベイラビリティゾーンに複数のプライベートサブネットが必要。マルチAZについてはググったら色々出てくるので割愛。

例えばリンク: AWSでマルチAZ構成にする?しない?

2. プライベートサブネットの作成

前回同様

3.RDSの作成

スクリーンショット 2020-11-03 22.55.09.png (254.0 kB)

DB用のセキュリティグループを作成

今回はMySQLを使ってDBを作るので、プライベートサブネットにはMySQLのポートのみ接続できる状態に設定する。

  • セキュリティグループはMySWL/Auroraというものを選択すると3306ポートが開く。
  • ソースにはどこから接続するかを選ぶのだが、個別に繋ぎたいサーバーのIPを選択しても良いが、複数台サーバがある時に全てを設定する必要があるため煩雑。それを避けるためソースにセキュリティグループを選択するとそのセキュリティグループ内にあるもの全てに対して接続を許可することができる。 スクリーンショット 2020-11-03 23.56.57.png (153.3 kB)

作成後

スクリーンショット 2020-11-03 23.57.36.png (94.2 kB)

RDS DBサブネットグループの作成

rdsインスタンスを起動する時にDBサブネットを選択するので、必要。 ※これがないと、RDSをサブネットに紐付けられないので必ず作成

RDS > サブネットグループから作成

前回作成した二つの別々のアベイラビリティゾーンにあるサブネットを追加してサブネットを作成する。 また、VPCも前回作成したものを選択。

スクリーンショット 2020-11-04 0.01.24.png (158.0 kB)

DBパラメータグループ設定

スクリーンショット 2020-11-04 0.05.04.png (75.0 kB)

スクリーンショット 2020-11-04 0.03.27.png (64.4 kB)

オプショングループの作成

何かDBにオプションを設定したい時に使う。 スクリーンショット 2020-11-04 0.05.40.png (71.2 kB)

RDS オプショングループ

RDSの作成

RDS > データベースからDBを作成する

4. WEBサーバーからRDSに接続する

スクリーンショット 2020-11-08 0.02.23.png (199.9 kB)

MySQLをwebサーバーにインストール

sshでサーバーに接続

インストール

$ sudo yum -y install mysql

データベース のエンドポイント

RDSからエンドポイントを確認する。

スクリーンショット 2020-11-08 0.23.10.png (181.4 kB)

mysqlコマンドでmysqlに接続する。

$ mysql -h tokyo-ecole-staging01.cxrffzyjnal4.ap-northeast-1.rds.amazonaws.com -u root -p

接続できると、ターミナルに以下のように表示される。

$ mysql -h aws-and-infra-web.cxrffzyjnal4.ap-northeast-1.rds.amazonaws.com -u root -p -P 3306
Enter password: 

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 1097
Server version: 8.0.15 Source distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> 

この設定を.envなどのDB設定のファイルに接続することで、railsなどからDBに接続可能。

#3: インフラについて簡単に理解する[Route53ドメイン登録]

  1. ドメインについて
  2. DNSについて
  3. ドメインの購入
  4. Route53について
  5. Route53でDNSを設定

Route53

1.ドメインについて

ドメインの構造

トップレベルドメイン ・第2レベルドメイン ・第3レベルドメイン ・第4レベルドメイン に分かれている。

スクリーンショット 2020-11-03 11.26.50.png (220.2 kB)

ICANNという団体が管理していて一意性を保つためにそれぞれのトップレベルドメインにつき、一つの団体に管理を任せている。その団体がそれぞれリセラーにドメインを卸てそこから各人への販売が行われる。 ex) .jpはJPRSという団体が管理している。

2. DNSについて

スクリーンショット 2020-11-03 11.32.29.png (471.1 kB)

ドメインを購入したあとはIPアドレスドメイン名を紐づけることで名前解決が行われてどのドメイン名でどのIPアドレスなのかというのがわかる。

スクリーンショット 2020-11-03 11.34.29.png (952.6 kB)

①
ブラウザでhttp://www.example.comなどのURLを打ち込む

②、③、④
フルリゾルバにアクセスされて、フルリゾルバがトップレベル階層のルートを管理している「ルートネームサーバー」にcomで終わるドメインを管理しているサーバーのIPアドレスを教える。

⑤、⑥
comで終わるルートの管理をしているネームサーバー「comネームサーバー」の場所がわかったのでそちらに問い合わせる。今回はexample.comがつぎの階層なのでcomネームサーバーはexample.comネームサーバーのIPをフルリゾルバに伝える。

⑦、⑧
www.example.comのIPを知りたいので「example.comネームサーバー」に「www.example.comのIPアドレスは何?」と問い合わせる。そうすると、「93.184.216.34がwww.example.comのIPアドレスだよ」と帰ってくるので

⑨、⑩
フルリゾルバはスマホに対してもらったIPアドレスを教える。その後、スマホのブラウザからIPアドレス93.184.216.34に接続することでホームページが表示される。

3.ドメインの購入

お名前ドットコムで実際にドメインを購入する(安いもの) https://www.onamae.com/

・1年目はキャンペーンで安いけど2年目以降は高くなるといった場合があるのでそこに気をつけて購入する

スクリーンショット 2020-11-03 11.56.32.png (161.9 kB)

検索するとこのように値段が表示されるので、今回は1円の.workで取得する

料金一覧ページ スクリーンショット 2020-11-03 11.58.07.png (236.3 kB)

実際に購入

購入画面: スクリーンショット 2020-11-03 12.00.31.png (183.8 kB)

Whois情報とはWhoisとは、ドメインの保持者の氏名、住所、電話番号などの登録者情報を誰でも閲覧できる情報提供サービスです。登録者情報はICANN(※)より一般公開することが義務づけられています。

Whois情報公開代行サービスをご利用いただくことで、ドメイン保持者の登録情報から「お名前.com」の情報に代えたうえで一般公開することができます。これによりドメイン保持者のプライバシーが保護されます。

なので、個人情報を登録したくない場合に代理で個人情報登録を行ってくれる

ドメインプロテクションとは: お名前.comで管理されているドメインの各種設定手続きの操作を制限することができるサービスです。

設定・変更する場合は、ドメイン登録者の承認が必要となり、承認を得ることで操作制限されている手続きを進めることができるため、誤操作や第三者不正アクセスによる意図しない操作を遮断することができ、さらなるセキュリティ対策強化に期待することができます。

SSL証明とは: ・httpsにするやつ。

メールアドレスとパスワードを入力して次へ

名前などの登録

スクリーンショット 2020-11-03 12.07.01.png (113.1 kB)

支払い方法入力画面

スクリーンショット 2020-11-03 12.11.48.png (164.7 kB)

サーバー申し込みませんか?という画面が出てくるが今回はEC2を使うので無視

申し込み完了画面

スクリーンショット 2020-11-03 12.14.18.png (209.3 kB)

ドメインの自動更新の設定をOF Fにする

さっきの画面のここから設定できる スクリーンショット 2020-11-03 12.15.28.png (217.2 kB)

ドメイン機能一覧から、ドメインの自動更新を選択 スクリーンショット 2020-11-03 12.20.16.png (182.1 kB)

自動更新がONになっているので、OFFにする スクリーンショット 2020-11-03 12.21.40.png (298.0 kB) ・変更したいドメインにチェックを入れて確認画面へ進むを押下

スクリーンショット 2020-11-03 12.23.06.png (314.8 kB) ・規約に同意して上記内容を申し込むを押下

スクリーンショット 2020-11-03 12.24.03.png (298.6 kB) ・こういった画面が出てくるが無視

スクリーンショット 2020-11-03 12.24.49.png (288.1 kB) ・自動更新が解除される

これでドメインの登録完了

Route53について

スクリーンショット 2020-11-03 14.07.10.png (403.4 kB)

今回はシンプルルーティングを設定する

Route53で DNSを設定する

Route53はネームサーバーの役割を担っており、Route53に問合せを投げることで特定ドメインIPアドレスが返される。 現状ではお名前ドットコムのネームサーバーがIPアドレスを返すようになっているので、そこをRoute53に向き先を変更する必要がある。

スクリーンショット 2020-11-03 14.16.32.png (254.4 kB)

AWSでRoute53のページを開き、ホストゾーンを作成していく

スクリーンショット 2020-11-03 14.20.38.png (1.1 MB)

実際にホストゾーンを作成するとこんな感じ、 それぞれ ns-766.awsdns-31.net. ns-1052.awsdns-03.org. ns-1560.awsdns-03.co.uk. ns-297.awsdns-37.com. というネームサーバーがこのアドレスのネームサーバーとなっているよ。という表記。 (この時点ではまだネームサーバーは変更されていない)

スクリーンショット 2020-11-03 14.26.03.png (164.7 kB)

digコマンドでネームサーバーについての情報をみる

$ dig aws-infra-yuks.work NS + short

[ec2-user@ip-10-0-10-10 ~]$ dig aws-infra-yuks.work NS +short
dns1.onamae.com.
dns2.onamae.com.

お名前ドットコムのネームサーバーが表示されるのでまだRoute53のものは設定されていない。 お名前ドットコムでドメインを購入した時点dねお名前ドットコムのホストゾーンがお名前ドットコムのNSを使ってください。と指定されているからで、ROute53のものを指定するにはお名前ドットコムのページで設定する必要がある。

お名前ドットコムのログイン画面を開いて、Route53をホストゾーンとして設定する

お名前ドットコムの「ドメイン一覧」に移動する 手順書: https://www.onamae.com/guide/p/67

AWSのRoute53を見た時に表示される、この4つの値を入れていく

スクリーンショット 2020-11-03 14.40.39.png (117.5 kB)

こういった画面があるので、1, 2, 3, 4の順に貼り付ける(順番は特に関係ない) スクリーンショット 2020-11-03 14.41.51.png (170.5 kB)

反映までは時間がかかる

反映されたらdigコマンドで再度確認 スクリーンショット 2020-11-03 14.43.32.png (176.2 kB)

AWSには最後に ns-1052.awsdns-03.org. のようにドットがついているがそれは省く。

ドメイン名にEC2インスタンスIPアドレスを紐付ける

スクリーンショット 2020-11-03 14.45.38.png (82.7 kB)

現状ではNSレコードトSOAレコードのみ登録されているのでAレコードを登録していく。 Aレコードとはここ(参照リンク)にあるようにホストのIPアドレスのことを指す。

Aレコード作成

まず、レコード作成をクリック スクリーンショット 2020-11-03 14.48.46.png (149.4 kB)

今回はシンプルルーティングで作成 スクリーンショット 2020-11-03 14.49.13.png (192.7 kB)

名前のところには何も入力しない。 ・そのままの定義名でURLにアクセスしたいため

スクリーンショット 2020-11-03 14.50.14.png (168.7 kB)

これで、しばらく時間が経ったら、ドメインのネームサーバーの変更が反映されたらドメイン名をブラウザに入力するとAレコードのIPが返されてブラウザから設定したサーバーを見れるようになる。

スクリーンショット 2020-11-03 14.54.20.png (100.6 kB)

#2: インフラについて簡単に理解する[EC2]

ウェルノウンポート(TCP)一覧(抜粋)

ポート番号 プロトコル
20 FTP(データ転送)
21 FTP(コントロール)
22 SSH
23 Telnet
25 SMTP
53 DNS
80 HTTP
110 POP3
443 HTTPS

ウェルノウンポート(UDP)一覧(抜粋)

ポート番号 プロトコル
53 DNS
67 DHCP(サーバ)
68 DHCP(クライアント)

登録済ポート番号(自分で使うもの抜粋)

ポート番号 アプリケーション名
3000 Ruby on Rails
3306 MySQL
5432 PostgreSQL
9000 PHP-FPM

スクリーンショット 2020-11-03 1.19.18.png (536.2 kB)

sudo lsof -i -n -P

どのポートでどのサービスが待っているかを表示するコマンド

[ec2-user@ip-10-0-10-10 ~]$ sudo lsof -i -n -P
COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rpcbind  2693      rpc    6u  IPv4  17079      0t0  UDP *:111 
rpcbind  2693      rpc    7u  IPv4  17082      0t0  UDP *:735 
rpcbind  2693      rpc    8u  IPv4  17083      0t0  TCP *:111 (LISTEN)
rpcbind  2693      rpc    9u  IPv6  17084      0t0  UDP *:111 
rpcbind  2693      rpc   10u  IPv6  17085      0t0  UDP *:735 
rpcbind  2693      rpc   11u  IPv6  17086      0t0  TCP *:111 (LISTEN)
chronyd  2706   chrony    1u  IPv4  17295      0t0  UDP 127.0.0.1:323 
chronyd  2706   chrony    2u  IPv6  17296      0t0  UDP [::1]:323 
dhclient 2920     root    6u  IPv4  17857      0t0  UDP *:68 
dhclient 3020     root    5u  IPv6  18151      0t0  UDP [fe80::484:59ff:fe7c:3fcc]:546 
master   3163     root   13u  IPv4  19137      0t0  TCP 127.0.0.1:25 (LISTEN)
sshd     3389     root    3u  IPv4  20940      0t0  TCP *:22 (LISTEN)
sshd     3389     root    4u  IPv6  20951      0t0  TCP *:22 (LISTEN)
sshd     4801     root    3u  IPv4 110006      0t0  TCP 10.0.10.10:22->126.140.213.190:58552 (ESTABLISHED)
sshd     4819 ec2-user    3u  IPv4 110006      0t0  TCP 10.0.10.10:22->126.140.213.190:58552 (ESTABLISHED)

(LISTEN)

(LISTEN)と書かれているものが、他のPCから接続を待ち受けているポート(サービス)

(ESTABLISHED)

(ESTABLISHED)と書かれているものは、現在通信を行っているポート

Apacheのインストール

yum update コマンド(最初)

sudo yum update -y

Apache インストールコマンド

sudo yum -y install httpd

Apache起動コマンド

sudo systemctl start httpd.service systemctlはサービスを動作させる時に使用するコマンドで、今回はhttpdというapacheサービスを起動するのに使用している。

Apache status確認コマンド

sudo systemctl status httpd.service

[ec2-user@ip-10-0-10-10 ~]$ sudo systemctl status httpd.service
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: active (running) since 月 2020-11-02 16:31:30 UTC; 19s ago
     Docs: man:httpd.service(8)
 Main PID: 13864 (httpd)
   Status: "Total requests: 0; Idle/Busy workers 100/0;Requests/sec: 0; Bytes served/sec:   0 B/sec"
   CGroup: /system.slice/httpd.service
           ├─13864 /usr/sbin/httpd -DFOREGROUND
           ├─13865 /usr/sbin/httpd -DFOREGROUND
           ├─13866 /usr/sbin/httpd -DFOREGROUND
           ├─13867 /usr/sbin/httpd -DFOREGROUND
           ├─13868 /usr/sbin/httpd -DFOREGROUND
           └─13869 /usr/sbin/httpd -DFOREGROUND
  • active(running)となっていれば起動している

ps -axu これでも確認できる。

ps = Linuxで起動しているサービスを表示する -ax = すべてのプロセスを表示 u = メモリの使用率などをともに表示

[ec2-user@ip-10-0-10-10 ~]$ ps -axu
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.5 125584  5480 ?        Ss   11月01   0:02 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root         2  0.0  0.0      0     0 ?        S    11月01   0:00 [kthreadd]
root         4  0.0  0.0      0     0 ?        I<   11月01   0:00 [kworker/0:0H]
root         6  0.0  0.0      0     0 ?        I<   11月01   0:00 [mm_percpu_wq]
root         7  0.0  0.0      0     0 ?        S    11月01   0:00 [ksoftirqd/0]
root         8  0.0  0.0      0     0 ?        I    11月01   0:00 [rcu_sched]
root         9  0.0  0.0      0     0 ?        I    11月01   0:00 [rcu_bh]
root        10  0.0  0.0      0     0 ?        S    11月01   0:00 [migration/0]

以下のようにすると絞り込みができる。

[ec2-user@ip-10-0-10-10 ~]$ ps -axu | grep httpd
root     13864  0.0  0.9 257348  9540 ?        Ss   16:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache   13865  0.0  0.6 298456  6448 ?        Sl   16:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache   13866  0.0  0.6 298456  6448 ?        Sl   16:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache   13867  0.0  0.6 298456  6448 ?        Sl   16:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache   13868  0.0  0.6 495128  6448 ?        Sl   16:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache   13869  0.0  0.6 298456  6448 ?        Sl   16:31   0:00 /usr/sbin/httpd -DFOREGROUND
ec2-user 13967  0.0  0.0 119436   952 pts/0    S+   16:34   0:00 grep --color=auto httpd

Apache自動起動コマンド

サーバーを停止や再起動した時にApacheが自動で起動するようにするコマンド

$ sudo systemctl enable httpd.service

[ec2-user@ip-10-0-10-10 ~]$ sudo systemctl enable httpd.service
Created symlink from /etc/systemd/system/multi-user.target.wants/httpd.service to /usr/lib/systemd/system/httpd.service.

自動起動が設定されているか確認するコマンド

[ec2-user@ip-10-0-10-10 ~]$ sudo systemctl is-enabled httpd.service
enabled
  • enabledとなっていればOK

ファイアーウォールの設定

  • 現状ではファイアーウォールが通信をシャットダウンしてしまうのでサーバー上のアプリケーションを見ることができない。なので、ファイアーウォールの設定を変更して、アプリケーションを見れるようにする必要がある。 スクリーンショット 2020-11-03 1.40.45.png (278.8 kB)

セキュリティグループを設定してファイアーウォールを調整する。

スクリーンショット 2020-11-03 1.41.39.png (258.0 kB)

httpアクセスを許可するために80番ポートを開ける

HTTPを任意の場所から接続できるようにして、80番ポートを開ける設定。 スクリーンショット 2020-11-03 1.46.09.png (85.4 kB)

そうすると、Apacheが起動しているサーバーに接続することが可能。 スクリーンショット 2020-11-03 1.46.59.png (130.6 kB)

Gitリポジトリをメンテナンスして軽量化する

保存版

この方の記事が最高に欲しかった、かつまとまっていたので自分の保存用です。 ↓こっちをみてください。 qiita.com

これもいい

qiita.com

qiita.com

qiita.com

Gitリポジトリのメンテ?

Gitリポジトリにあるファイルは .git がバージョン管理をしています。 今回はその .git をメンテナンスする話です。

はじめに

  • リポジトリに容量の大きいファイルをコミットしてしまった
  • git clone がやたらと時間がかかる(知らない間に容量の大きいファイルがコミットされている可能性がある)
  • 複数あるリポジトリを統合したい

こんな悩みを持ったことはないでしょうか。大型のプロジェクトでないと発生しないと思うので、個人プロジェクトではなかなか遭遇することはないでしょう。

今回は上記を解消するための リポジトリメンテナンス方法 をご紹介します。

!! 注意 !!

Gitリポジトリのメンテナンスは破壊的なため、Gitのコマンドを理解している方のみ行ってください。 この記事を読んで実行した結果、大切なリポジトリが壊れても当方は責任を負いかねます。

Gitオブジェクト(Git管理ファイル)の削減

Gitオブジェクトは .git/objects の中身(00~FF)を指します。これが肥大化していると git clone にかなりの時間がかかることになります。 リポジトリにあるファイルの差分や履歴を管理しているオブジェクトで、コミットが多くなればなるほど容量は膨れていきます。

このオブジェクトには知らず知らずにゴミをコミットしてしまっていることがあります。 :put_litter_in_its_place: そして、そのゴミが意図せずオブジェクトの容量を肥大化させている一因になることも多いです。

良くある一例で、npm install を行い node_modules 以下に依存ファイルを取得・ビルドし、そのままコミットしたとします。 直後、.gitignorenode_modules を書き忘れていることに気づき、慌てて git rm -rf node_modules をしたとしてもダメです。 一度コミットしてしまったものは既に管理対象となって通常の方法では消しさることはできません。 (そう、消したい過去を消去することができないのと同じです。)

このようなリポジトリは最初の方は問題ないですが、ファイルが増えてくると git clone に時間がかかってくるので履歴を消去したほうが時間の節約になります。

◆ 調査方法

1. Gitリポジトリをclone

$ git clone git@github.com:kaneshin/dotfiles.git ~/dotfiles

既にリポジトリをcloneしている場合はガベコレをします。

$ git gc --auto

2. .git/objects のファイルサイズ

du コマンドを使用して、 .git/objects のファイルサイズを測ります。

$ du -sh .git/objects
295M    .git/objects 

3. git_find_big.sh スクリプト

Maintaining a Git Repositoryにある git_find_big.sh というスクリプトを使用します。

このスクリプトリポジトリにあるファイルの容量降順で一覧してくれます。 一覧はデフォルト10件表示となっていますが、件数を変更することも可能です。

objects=`git verify-pack -v .git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head`

↑ を ↓ のように head コマンドにライン数を渡します。

objects=`git verify-pack -v .git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head -n 100`

4. git_find_big.sh スクリプト実行

コミット履歴があればあるほど処理に時間がかかります。

$ ./git_find_big.sh
All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file.
size   pack   SHA                                       location
34442  31741  AAAAAAb732e07f17cf71f1d8584a48aXXXXXXXXX  dotfiles/node_modules/protractor/selenium/selenium-server-standalone-2.45.0.jar
10784  3428   AAAAAAe5f77536e4b078fd5d1957f87XXXXXXXXX  dotfiles/node_modules/chromedriver/lib/chromedriver/chromedriver

上記のような一覧を得ることが出来ます。 普段、あまり気にせずにGitへコミットしていると思いますが、今一度無駄なファイルが入っていないかの確認も面白いので試してみるのもいいと思います。

◆ ファイルを歴史から抹消する方法

歴史の書き換えでgit filter-branchコマンドを使用します。これを使いこなすことが出来ればあなたもリポジトリクラッシャーメンテナーになることができます。

このfilter-branchの使い方は簡単ですが、とても強力で破壊的です。

例)

git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD

HEADを対象としてコマンドを実行することができます。--all とすれば全てのブランチに対して実行します。

さて、実際のメンテの流れです。

0. バックアップを取る

# clone
$ git clone git@github.com:foo/bar.git /tmp/bar
$ cd /tmp/bar

# リモートのブランチを全てチェックアウト
$ git branch -r | sed -e "s#origin/##" | xargs -I{} git checkout -b {} origin/{}

# バックアップとして全てのブランチを別リモート先へプッシュ
$ git remote add tmp git@github.com:foo/bar-tmp.git
$ git push --force tmp --all

1. 履歴抹消対象ファイル

# 配列で抹消ファイルをセットする
$ TARGETS=(
  "shared-local-instance.db"
  "dump.rds"
  "*.log"
  "node_modules/"
)

# 半角スペースでjoinする
$ target=$(printf " %s" "${TARGETS[@]}")
$ target=${target:1}

2. 履歴抹消する

全てのブランチを対象にするため -- --all で実施する recursiveで行いたくない場合は git rm -r-r を削除してください。

$ git filter-branch --index-filter "git rm -r --cached --ignore-unmatch ${target}" -- --all

実行すると、削除対象ファイルが存在した場合に下記のようなログが出力されます。

Rewrite 1a8b35d383ae6472ef7ab8591aca3540f0771744 (3806/29089)rm 'include/swift/ABI/Class.h'
rm 'include/swift/ABI/MetadataValues.h'
rm 'include/swift/AST/AST.h'
rm 'include/swift/AST/ASTContext.h'
rm 'include/swift/AST/ASTVisitor.h'
rm 'include/swift/AST/ASTWalker.h'
rm 'include/swift/AST/Attr.def'
rm 'include/swift/AST/Attr.h'
rm 'include/swift/AST/Builtins.def'
rm 'include/swift/AST/Builtins.h'
rm 'include/swift/AST/Component.h'
rm 'include/swift/AST/Decl.h'
rm 'include/swift/AST/DeclContext.h'
rm 'include/swift/AST/DeclNodes.def'
rm 'include/swift/AST/DiagnosticEngine.h'
rm 'include/swift/AST/Diagnostics.def'
...

3. 履歴改変後のものをプッシュする

$ git push origin --all --force

もしくは、新しくリポジトリを作成して新しい方へプッシュするのもアリです。

◆ 結果

これは実際に実行したときの結果ログです。

[kaneshin@ip-172-0-0-0] /tmp                                                    
$ git clone git@github.com:foo/bar.git                               
Cloning into 'bar'...                                                        
remote: Counting objects: 202026, done.                                               
remote: Compressing objects: 100% (2547/2547), done.                                  
remote: Total 202026 (delta 4158), reused 3859 (delta 3859), pack-reused 195620       
Receiving objects: 100% (202026/202026), 292.02 MiB | 9.04 MiB/s, done.               
Resolving deltas: 100% (116884/116884), done.                                         
Checking connectivity... done.                                                        

# ... リモートからバックアップを消去する

[kaneshin@ip-172-0-0-0] /tmp                                                    
$ git clone git@github.com:foo/bar.git                               
Cloning into 'bar'...                                                        
remote: Counting objects: 140976, done.                                               
remote: Compressing objects: 100% (3913/3913), done.                                  
remote: Total 140976 (delta 8047), reused 7926 (delta 7926), pack-reused 129137       
Receiving objects: 100% (140976/140976), 148.73 MiB | 3.59 MiB/s, done.               
Resolving deltas: 100% (90626/90626), done.                                           
Checking connectivity... done.      

ピックアップして見てみると

Receiving objects: 100% (202026/202026), 292.02 MiB | 9.04 MiB/s, done.               
↓
Receiving objects: 100% (140976/140976), 148.73 MiB | 3.59 MiB/s, done.               

削減した結果、292MB から 148MB になりました。 およそ半分にまで削減できたので、うれしい限りです。無駄なファイルをコミットしたまま放置はダメですね。

おわりに

今回の話はAtlassianが紹介している 「Maintaining a Git Repository」 の紹介でした。 Gitは使えば使うほどしっくり来ますが、たまにはリポジトリのメンテナンスもしてあげてください。

複数リポジトリ統合の話しは別の機会に

#1: インフラについて簡単に理解する[IAM]

IAMユーザーの作成について

AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得 このコースをやる上で使えそうな項目をメモ

IPアドレス

IPアドレスの範囲

https://img.esa.io/uploads/production/attachments/16686/2020/11/01/92866/f1725873-24bf-4237-9088-ab4f4b4ed184.png

  • ネットワーク部とホスト部に区分されている

CIDR表記

192.168.128.0/24 だった場合は前から3区切り目までがネットワーク部で、最後の8ビットは任意に決めれる。というルールの表記 それぞれのドットの3桁が8ビットで構成されているので、2つ目までのドットをネットワーク部とするのであれば000.000.000.000/16というように16ビットまでがネットワーク部ですよいうことを指定している

サブネット表記

CIDRとは違う表記の方法で以下のように表記する 192.168.1.40/24と同じ

IPアドレス:       192.168.1.40
サブネットマスク: 255.255.255.0
  ↓
まとめた表記:     192.168.1.40/255.255.255.0

サブネット作成

https://img.esa.io/uploads/production/attachments/16686/2020/11/01/92866/329b95bc-9aad-45c5-8f4d-262360f0f4dd.png

パブリックサブネットとプライベートサブネットに分け、パブリックサブネットではApachなどのWEBアプリケーションはインターネットを通して接続できるが、 DBはインターネットを通して接続できないようにする

AWS上でサブネットを作成 今回はprivateとpublicサブネットの2種類を作成 スクリーンショット 2020-11-02 0.17.28.png (94.6 kB)

パブリックサブネットとプライベートサブネットに分け、パブリックサブネットではApachなどのWEBアプリケーションはインターネットを通して接続できるが、 DBはインターネットを通して接続できないようにする

IPアドレスとルーティング

スクリーンショット 2020-11-02 0.11.54.png (362.9 kB)

パブリックサブネットを作成したが、このままではルートテーブルにこのIPがどのルーターと接続できるかの情報がないのでインターネットに接続することができない。そのため、ルートテーブルに今回作ったサブネットがどことつながっているかの表記をする必要がある。

インターネットゲートウェイVPCとインターネットを接続する仮想のルートテーブル 初期状態ではこのインターネットゲートウェイがないのでAWSで作成する必要がある。

スクリーンショット 2020-11-02 0.20.45.png (271.2 kB)

  • ルートテーブルはAWSの場合VPCと各サブネットに対して作成できる
  • サブネットやインターネットゲートウェイ間にはルーターが動いている。ルーターは明示的に指定しないがサブネットを作成すると暗黙的にルーターが割り振られる

インターネットゲートウェイの作成

スクリーンショット 2020-11-02 0.25.22.png (82.0 kB)

VPC > インターネットゲートウェイから 作成する。

名前をつけて作成したら、ダッシュボードを確認。そうするとまだどこにも紐づけていないので、"detached"と表記されているものが表示されるはず。

detachedのインターネットゲートウェイを先ほど作成したVPCにアタッチする。 対象のインターネットゲートウェイを左クリックして、VPCにアタッチという項目で、対象のVPCを選択することでアタッチができる。簡単

ルートテーブルを作成してパブリックサブネットに紐付ける

・ルートテーブルを作成してパブリックサブネットに紐付ける スクリーンショット 2020-11-02 0.33.05.png (171.7 kB)

現状では一番したに一つだけ表示されているものだけで、「10.0.0.0/16は自身のIPアドレスだよ。それ以外のIPアドレスへの通信は破棄するよ」という意味。

デフォルトルートをインターネットゲートウェイに向けるように作成する

先ほどと同様のVPCに紐づくルートテーブルを作成

スクリーンショット 2020-11-02 0.37.03.png (50.7 kB) このルートテーブルはVPCにのみ割り当てられているので、それをパブリックサブネットにも割り当てる。

「関連づける作業」 スクリーンショット 2020-11-02 0.39.07.png (224.0 kB)

スクリーンショット 2020-11-02 0.40.14.png (75.5 kB)

デフォルトルートの作成: 0.0.0.0/0を追加して、Internet Gatewayを選ぶと関連づけ可能なものが出てくるのでそれをインターネットゲートウェイとして紐づける。 これでデフォルトルートがインターネットゲートウェイのパブリックサブネットを作成完了。これでパブリックサブネットはインターネットに接続することが可能。

スクリーンショット 2020-11-02 0.42.36.png (52.2 kB)

ネットワークの設計で気をつけるポイント

こういうのみるといいかも: AWSで拡張性・耐障害性・セキュリティを考慮したクラウド構成のネットワーク設計

スクリーンショット 2020-11-02 0.45.05.png (327.3 kB) - プライベートIPアドレスだと重複がない限り割と自由に設定できるため - VPCのCIDR領域は大きめに設定しておくと後で枯渇せずに済む

VPCを分割するか?アカウントを分けるか?

どのタイミングでVPCを分割するか - 異なるシステムの場合はアカウントを分ける - 異なるシステムを同一アカウント内に入れると管理が煩雑になる - 同一システムの各環境は、VPCとアカウントのどちらを分けるか? - 環境が違う場合、アカウントもVPCも同一のものを使用するのはだめ - VPCを分けると、IAMの設定が一度で良い。反面、各環境のリソースが見えてしまい、事故の元にもなる - アカウントを分けると、他の環境のリソースが見えず、作業しやすい。反面、環境ごとにIAMの設定が必要 - 同一アカウントでVPCとリージョンを分けるのがおすすめ

サブネットの設計ポイント

  • 将来に必要なIPアドレス数を見積もって設定する
    • /24が標準的
  • サブネットの分割は、ルーティングとアベイラビリティゾーンを基準に行う
    • サブネットに割り当てられるルートテーブルは1つ
    • インターネットアクセスの有無、拠点アクセスの有無などのルーティングポリシーに応じて分割する
    • 高可用性のために、2つ以上の阿部イラビリティゾーンを使用する

Railsを本番環境にデプロイ(with Unicorn, Nginx, EC2, MySQL, Capistrano, Elastic IP)

qiita.com

こちらの記事をほぼまるまんまなのですが、少しMySQLの箇所が違ったので自分用にです。
@gyu_outputsさんの記事を参考にやるだけで十分環境構築できるので、そちらを参照されると良いと。
というか本家の方が圧倒的にまとめられているので...

AWS EC2 Linux2 Rails 本番環境構築

参考: 独学向けRailsアプリをAWSにデプロイする方法まとめ【入門】 - Qiita 消されたとき用のファイル https://drive.google.com/drive/folders/1jI_nABae3a2nghEJ-hl7wavbfHuWbr1J?usp=sharing

$ sudo yum remove mariadb-libs

# Node.jsをインストール
$ [ec2-user@ip-172-31-25-189 ~]$ sudo yum -y install nodejs

rbenvとruby-buildをインストール

$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

$ source .bash_profile
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ rbenv rehash

Rubyをインストール

$ rbenv install --list
# でインストールできるものを確認
$ rbenv install 2.7.0

$ rbenv global 2.5.1
$ rbenv rehash
$ ruby -v

MySQLをインストール

MySQLのインストール 独学向けRailsアプリをAWSにデプロイする方法まとめ【入門】 - Qiitaじゃうまくいかなかった ので、こっちで(AWS EC2 AmazonLinux2 MySQLをインストールする - Qiita

手順はこうらしい。

概要

  1. MySQL必要パッケージのインストールと設定
  2. mysqldのステータス確認
  3. rootアカウントにてMySQLにログイン

1. MySQL必要パッケージのインストールと設定

# 1.    sshを使用してインスタンスにログインする。

# 2. yum update
$ sudo yum update

# 3. 下記コマンドを実行してインスタンス作成初期からインストールされているMariaDB用パッケージを削除する。
$ sudo yum remove mariadb-libs

# 4. 下記コマンドを実行してMySQLのリポジトリをyumに追加する。
$ sudo yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm

# 5. 下記コマンドを実行してMySQLに必要なパッケージ(mysql-community-server)を取得する。(yを入力してEnterを押下する際にインストールパッケージとリポジトリが下記の様になっていることを確認する。)

# これでOK↓
================================================================================
 Package                アーキテクチャー
                               バージョン               リポジトリー       容量
================================================================================
インストール中:
 mysql-community-server x86_64 8.0.21-1.el7             mysql80-community 499 M
依存性関連でのインストールをします:
 mysql-community-client x86_64 8.0.21-1.el7             mysql80-community  48 M
 mysql-community-common x86_64 8.0.21-1.el7             mysql80-community 617 k
 mysql-community-libs   x86_64 8.0.21-1.el7             mysql80-community 4.5 M
 ncurses-compat-libs    x86_64 6.0-8.20170212.amzn2.1.3 amzn2-core        308 k

トランザクションの要約
================================================================================
インストール  1 パッケージ (+4 個の依存関係のパッケージ)

$ sudo yum install --enablerepo=mysql80-community mysql-community-server

# 6. 下記コマンドを実行してMySQLに必要なパッケージ(mysql-community-devel)を取得する。(yを入力してEnterを押下する際にインストールパッケージとリポジトリが下記の様になっていることを確認する。)

# こうなった
===============================================================================================================================================
 Package                                  アーキテクチャー          バージョン                      リポジトリー                          容量
===============================================================================================================================================
インストール中:
 mysql-community-devel                    x86_64                    8.0.21-1.el7                    mysql80-community                    8.0 M

トランザクションの要約
===============================================================================================================================================
インストール  1 パッケージ

総ダウンロード容量: 8.0 M
インストール容量: 58 M
Is this ok [y/d/N]: 

$ sudo yum install --enablerepo=mysql80-community mysql-community-devel

# 7. 下記コマンドを実行してインストールされたMySQLに関係のあるパッケージを出力する。
$ yum list installed | grep mysql

# 8. 先のコマンドの結果が下記の様になれば必要パッケージのインストールは完了である。

[ec2-user@ip-172-31-30-254 ~]$ yum list installed | grep mysql
mysql-community-client.x86_64      8.0.21-1.el7                      @mysql80-community
mysql-community-common.x86_64      8.0.21-1.el7                      @mysql80-community
mysql-community-devel.x86_64       8.0.21-1.el7                      @mysql80-community
mysql-community-libs.x86_64        8.0.21-1.el7                      @mysql80-community
mysql-community-server.x86_64      8.0.21-1.el7                      @mysql80-community
mysql80-community-release.noarch   el7-3                             installed  


# 9. 下記コマンドを実行してlogファイルを作成する。
$ sudo touch /var/log/mysqld.log

# 10. 下記コマンドを実行してmysqldを起動する。
$ sudo service mysqld start


  1. パッケージはこうなっていればいいらしい f:id:dorcushopeino1:20200930101631p:plain

  2. (yを入力してEnterを押下する際にインストールパッケージとリポジトリが下記の様になっていることを確認する。) f:id:dorcushopeino1:20200930101642p:plain

2. mysqldのステータス確認

# 1. 下記コマンドを実行してmusqldの状態を確認する。
$ systemctl status mysqld.service

# こうなった
# 下記の様に出力されれば正常にmysqldが起動できている。

[ec2-user@ip-172-31-30-254 ~]$ systemctl status mysqld.service
● mysqld.service - MySQL Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: active (running) since 火 2020-09-29 17:04:23 UTC; 1min 16s ago
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
  Process: 14678 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
 Main PID: 14751 (mysqld)
   Status: "Server is operational"
   CGroup: /system.slice/mysqld.service
           └─14751 /usr/sbin/mysqld

 9月 29 17:04:17 ip-172-31-30-254.ap-northeast-1.compute.internal systemd[1]: Starting MySQL Server...
 9月 29 17:04:23 ip-172-31-30-254.ap-northeast-1.compute.internal systemd[1]: Started MySQL Server.

# 3. 下記コマンドを実行してmysqldがインスタンスの起動と同時に起動するように設定する。
$ sudo chkconfig mysqld on

rootアカウントにてMySQLにログイン

別記事に書いてあるって。AWS EC2 AmazonLinux2 MySQL rootユーザの初期パスワードの確認方法 - Qiita

ログの確認

  1. 下記コマンドを実行してMySQLのlogファイルを開く
$ sudo less /var/log/mysqld.log
  1. 開いたファイル内で下記の様な一行を見つける。
/var/log/mysqld.logYYYY-MM-DDTHH:MM:SS.260490Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: XXXXXXXXXXXX
  1. ファイルに記載された行のXXXXXXXXXXXXの部分がrootユーザの初期パスワードとなる。

MySQLログイン確認

  1. 開いているmysqld.logファイルを閉じる。
  2. 下記コマンドを実行してmysqldを停止する。
$ sudo service mysqld stop
  1. 下記コマンドを実行してmysqldを起動する。
$ sudo service mysqld start
  1. 下記コマンドを実行してmysqlにrootユーザでログインする。
  2. Enter password: には 先ほどログファイルに出力されていたXXXXXXXXXXXXの部分を入力する。
$ mysql -u root -p

# 先ほどのパスワードで
$ mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.21

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

※ 初期パスワードをリセットしたい方は下記を参照してパスワードを再設定する。:AWS EC2 AmazonLinux2 MySQLを使えるようにする 参考文献: MySQLの初期パスワードのありか

パスワードの再設定

AWS EC2 AmazonLinux2 MySQLを使えるようにする - Qiita

先の方法でMySQLにrootユーザでログイン後に下記を実行する。(ERROR 1819 (HY000): Your password does not satisfy the current policy requirementsの様なエラーが出た場合、入力されたrootユーザのパスワードが条件を満たしていない。)

パスワードの再設定

  1. 先の方法でMySQLにrootユーザでログイン後に下記を実行する。(ERROR 1819 (HY000): Your password does not satisfy the current policy requirementsの様なエラーが出た場合、入力されたrootユーザのパスワードが条件を満たしていない。)
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '大文字、小文字、特殊文字(アスタリスク等)を含む新しいrootユーザのパスワード’';
Query OK, 0 rows affected (0.00 sec)
# Password1111@とか
  1. 下記を実行して一旦MySQLからログアウトする。
mysql> exit

DBの作成

  1. 下記コマンドを実行してMySQLにrootユーザでログインする。(ログイン時のパスワードが先に設定し直したパスワードを入力する。)
$ mysql -u root -p
  1. MySQLログイン後下記を実行して「test」という名前のDBを作成する。
mysql> create database test;
  1. 下記を実行して「test」データベースが作成されたことを確認する。
mysql> show databases;

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

WEB AppをEC2にクローンする

現段階 EC2サーバにアプリケーションのコードをクローンしようとしてもpermission deniedとエラーが出てしまいます。

原因 Githubから見てこの許可していないEC2インスタンスを拒否する

対策 EC2インスタンスSSH公開鍵をGithubに登録する。

SSH鍵をGithubに登録すると、Githubはそれを認証してクローンを許可をだす

作業

EC2サーバのSSH鍵ペアを作成 EC2にログイン キーペア作成のためコマンドを入力

[ec2-user@ip-172-31-23-189 ~]$ ssh-keygen -t rsa -b 4096
  1. 下記が表示されるので、エンターを押す
Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa):
  1. さらにエンターを押す(2回)
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 

これで下記の表示ができれば、成功してます。

Your identification has been saved in /home/ec2-user/.ssh/id_rsa.
Your public key has been saved in /home/ec2-user/.ssh/id_rsa.pub.
The key fingerprint is:
3a:8c:1d:d1:a9:22:c7:6e:6b:43:22:31:0f:ca:63:fa ec2-user@ip-172-31-23-189
The key's randomart image is:
+--[ RSA 4096]----+
|    +            |
| . . =           |
|  = . o .        |
| * o . o         |
|= *     S        |
|.* +     .       |
|  * +            |
| .E+ .           |
| .o              |
+-----------------+
  1. SSH公開鍵を表示し、値をコピーするため、下記コマンドを実装
[ec2-user@ip-172-31-23-189 ~]$ cat ~/.ssh/id_rsa.pub
  1. catで表示させた公開鍵(長いテキスト)をコピー
[ec2-user@ip-172-31-30-254 tokyo_ecole]$ cat ~/.ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDK9o1p6yQ9U95dIfN4Mmhs9V6fPNZfJYStdm6/
(中略・・・)
NRJICEDar5OSjyTHyWF8x8e7CHE5E8bWX8A159rbSyv1Aqy7W4gcUSXcRNdeYSGwnyFNYMGXYJ6QPcGl3c5/JubFuK6VPsB8sZUt3joS1y96/unSYjdQ== ec2-user@ip-172-31-30-254.ap-northeast-1.compute.internal

コピーした公開鍵をGithubにアクセスして登録する https://github.com/settings/keysにアクセス

  1. 画面右上の緑色の『 NEW SSH KEY 』をクリック

  2. タイトルを記入する(なんでも可能)

  3. 公開鍵(ssh-rsaから)を貼り付け

エラー「Key is invalid. You must supply a key in OpenSSH public key format」が表示された場合、 貼り付けたコードに『 ssh-rsa 』が含まれているかご確認ください

  1. 『 Add SSH KEY 』をクリックして保存。
  2. GithubのPWを入力

  3. 完了

  4. 登録できているか確認

[ec2-user@ip-172-31-23-189 ~]$ ssh -T git@github.com

下記の表示が出た場合: 『 yes 』を選択

The authenticity of host 'github.com (IP ADDRESS)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)?

この際に

Warning: Permanently added the RSA host key for IP address '52.111.11.11' to the list of known hosts. と表示された場合は, EC2に入り直しましょう。更新されたのでエラーなく入れます。 成功すると、下記の表示になるはずです。

または、下記が表示された場合: 『 yes 』を選択

The authenticity of host 'github.com (IP ADDRESS)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no)?

成功すると下記の表示が出る

[ec2-user@ip-172-31-23-189 ~]$ ssh -T git@github.com
Hi <Githubユーザー名>! You've successfully authenticated, but GitHub does not provide shell access.

App側でUnicornのインストール

EC2にGit クローンする前に、準備としてUnicornをインストールさせましょう Gemfileにgem'unicorn'を追加

::ここの時点で一回アプリをクローンしてしまう::

$ gem install unicorn, ‘5.4.1’

config/unicorn.rbを作成

追加したunicorn.rbに下記を記述 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

production.rbを開き、下記の記述をコメントアウトする

config/environments/production.rb
config.assets.js_compressor = :uglifier
config/environments/production.rb
#config.assets.js_compressor = :uglifier

アプリケーションの保存先となるディレクトリを作成

ディレクトリの作成

#/var/wwwディレクトリを作成(後述するCapistranoの初期値がwwwなので、ディレクトリをwwwに設定しています)
[ec2-user@ip-172-31-23-189 ~]$ sudo mkdir /var/www/

作成したディレクトリをchownコマンドで権限設定

#作成したwwwディレクトリの権限をec2-userに変更
[ec2-user@ip-172-31-23-189 ~]$ sudo chown ec2-user /var/www/

作成したディレクトリに移行

[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/

git clone でAppをEC2にダウンロード GithubからGit cloneするためのリポジトリURLを取得

git clone で作成したディレクトリにappをクローン

[ec2-user@ip-172-31-23-189 www]$ git clone リポジトリURL

Githubのアカウント名とPWを入力し、 ダウロードが開始される

remote: Enumerating objects: 298, done.
remote: Counting objects: 100% (298/298), done.
remote: Compressing objects: 100% (190/190), done.
remote: Total 298 (delta 109), reused 274 (delta 86), pack-reused 0
Receiving objects: 100% (298/298), 58.53 KiB | 365.00 KiB/s, done.
Resolving deltas: 100% (109/109), done.

完了

これで、EC2にAppがクローンされています。

EC2にgemをインストール

EC2のメモリを増強する

Swap(スワップ)領域を設定

Swapは、EC2のメモリが限界に達したとき、補う形でメモリの容量を増やす機能です。 デフォルトではSwap領域が設定されていないので、設定しましょう

手順

ホームディレクトリに移行

[ec2-user@ip-172-31-25-189 ~]$ cd 

下記のコマンドを実行

[ec2-user@ip-172-31-25-189 ~]$ sudo dd if=/dev/zero of=/swapfile1 bs=1M count=512

うまくいくと、下記の表示が出ます

512+0 レコード入力
512+0 レコード出力
536870912 バイト (537 MB) コピーされました、 5.19011 秒、 103 MB/秒

次は権限に制限をかけましょう(chmodコマンド)

[ec2-user@ip-172-31-25-189 ~]$ sudo chmod 600 /swapfile1

スワップ(swap)領域を作成する - mkswap

[ec2-user@ip-172-31-25-189 ~]$ sudo mkswap /swapfile1
#成功すると下記の表示が出ます
Setting up swapspace version 1, size = 512 MiB (536866816 bytes)
no label, UUID=909ccec6-4533-4a64-aea1-06a28fc4e3a8

スワップ(swap)領域を有効化する - swapon

[ec2-user@ip-172-31-25-189 ~]$ sudo swapon /swapfile1

エラーが出なければ成功です。

エラー「swapon: /swapfile1: スワップヘッダの読み込みに失敗しました: 無効な引数です」が表示された場合は、一つ前の手順に戻ってmkswapコマンドを実施してください。

下記のコマンドを実施してください。

🚨長いので、気をつけてください

[ec2-user@ip-172-31-25-189 ~]$ sudo sh -c 'echo "/swapfile1  none        swap    sw              0   0" >> /etc/fstab'

これで完了

参考になる記事:linux スワップ(swap)領域の作成

参考になる記事:linux スワップ(swap)領域の作成

アプリケーションサーバの性能を決定する

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

production.rbを開き、下記の記述をコメントアウトする

config/environments/production.rb
config.assets.js_compressor = :uglifier
config/environments/production.rb
#config.assets.js_compressor = :uglifier

アプリケーションの保存先となるディレクトリを作成 ディレクトリの作成

#/var/wwwディレクトリを作成(後述するCapistranoの初期値がwwwなので、ディレクトリをwwwに設定しています)
[ec2-user@ip-172-31-23-189 ~]$ sudo mkdir /var/www/

作成したディレクトリをchownコマンドで権限設定

#作成したwwwディレクトリの権限をec2-userに変更
[ec2-user@ip-172-31-23-189 ~]$ sudo chown ec2-user /var/www/

作成したディレクトリに移行

[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/

gemのインストール

まずは、EC2にダウンロードしたWEB Appを開く

[ec2-user@ip-172-31-23-189 www]$ cd  /var/www(作成したディレクトリ)/アプリ名

Rubyのバージョンを確認する

[ec2-user@ip-172-31-23-189 <アプリ名>]$ ruby -v

指定したrubyのバージョンが表示されれば成功です。

ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]

ローカル上のターミナルでbundlerのバージョンを確認する EC2ではなく、ローカル環境のWEB Appを開き、下記コマンドを実施

$ bundler -v

するとバージョンが表示されます

Bundler version 2.0.2 これと同じバージョンをEC2で入れます。 🚨下記のバージョンをそのまま (2.0.1)を入れるとエラーが発生するので注意

[ec2-user@ip-172-31-23-189 <アプリ名>]$ gem install bundler -v 2.0.1

EC2でbundle installをして、gemをインストール

[ec2-user@ip-172-31-23-189 <アプリ名>]$ bundle install

エラーがなければ、gemのインストール完了です。

エラーが発生した場合 下記のエラーが表示された場合、インストールするべき bundler -vが間違っています

Traceback (most recent call last):
    2: from /home/ec2-user/.rbenv/versions/2.5.1/bin/bundle:23:in `<main>'
    1: from /home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems.rb:308:in `activate_bin_path'
/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems.rb:289:in `find_spec_for_exe': can't find gem bundler (>= 0.a) with executable bundle (Gem::GemNotFoundException)

エラーがある場合は、アプリ側の bundlerのバージョンを確認してください

$ bundler -v
>Bundler version 2.0.2

[ec2-user@ip-172-31-23-189 <アプリ名>]$ bundler -v
>Bundler version 2.0.1
>バージョンが違うので、エラーがおきます

インストール完了後、下記の表示があった場合

Post-install message from chromedriver-helper:

  +--------------------------------------------------------------------+
  |                                                                    |
  |  NOTICE: chromedriver-helper is deprecated after 2019-03-31.       |
  |                                                                    |
  |  Please update to use the 'webdrivers' gem instead.                |
  |  See https://github.com/flavorjones/chromedriver-helper/issues/83  |
  |                                                                    |
  +--------------------------------------------------------------------+

gem'chromedriver-helper'のサポートが終了しているので、代わりとなるgem 'webdrivers'をインストールすることを推奨しているメッセージとなります。

 group :test do
   # ...
-  gem 'chromedriver-helper'
+  gem 'webdrivers'

環境変数の設定

前回までの流れ EC2インスタンスを作成 Elastic IP でEC2インスタンスのパブリックIPを固定 セキュリティグループを編集して、HTTPでWEBサイトの入り口を作る。 EC2にRails等をインストールして、環境設定をする いよいよAppをEC2にダウンロード(クローン) gemをインストール

今回の内容 環境変数を設定する。

環境変数とは何か? 環境変数は簡単に説明すると、PWを公開しないための変数と思ってください。

Githubは開発するに際に非常に便利です コードのバックアップのような役割も担うし、他の開発チームとコードを共有することができる。

しかし、PWは公開したくないはずです。 このPW(パスワード)などの公開したくない情報を環境変数というもので隠してしまいます。

変数はX=3のように 文字(X)の意味(3)を定義します。 環境変数の場合、環境変数 = 'PW' のように、パスワードを変数の値とします。 こうすることで、コードに記述されている環境変数だけでは、パスワードを特定できないので、 悪用されない仕組みとなります。

環境変数で定義したPWは、開発者のみが’鍵(暗号化を解除するための数値)’を持っており、鍵を持っている人間しか、実際の値をみることができません。

secret_key_baseの取得 secret_key_baseは「railsアプリ」でクッキーを暗号化するものになります。 クッキーとは、webを参照した時の履歴のようなものを残し、次回から素早くアクセスできるものになります。 クッキーは外部から参照されるとよくないので暗号化します。

[ec2-user@ip-172-31-23-189 <アプリ名>]$ rake secret

うまくいくと、

cdfasdfadgfsadfdgc314751a8dadfadf7c8b9a1dc888e...

という感じで表示されます。 これをコピーしておきましょう 環境変数を設定 環境変数を記述する場所を開きましょう

[ec2-user@ip-172-31-23-189 <アプリ名>]$ sudo vim /etc/environment

編集をするために「i」を入力

すると 『 -- 挿入 -- 』と表示されるので、入力が可能となります。 では、環境変数を定義していきましょう

DATABASE_PASSWORD='MySQLのrootユーザーのパスワード' SECRET_KEY_BASE='先程コピーしたsecret_key_base' 入力が完了したら、キーボード左上にある『 esc 』を押します。 すると挿入の表示が消えます。 保存するために 『 :wq 』 と入力しましょう

すると見慣れたターミナルの画面に戻ります

設定した環境変数を反映させるために、一度本番環境をログアウトしましょう。

[ec2-user@ip-172-31-23-189 ~]$ exit

もう一度EC2にログイン (ターミナル上で↑を押すと、入力してきたコマンドが出てくるので、それでssh -iを見つけてエンターすれば大丈夫です)

$ ssh -i ファイル名.pem ec2-user@[Elastic IPの値]

環境変数が無事に設定されているか確認

[ec2-user@ip-172-31-23-189 ~]$ env | grep SECRET_KEY_BASE
SECRET_KEY_BASE='secret_key_base'
[ec2-user@ip-172-31-23-189 ~]$ env | grep DATABASE_PASSWORD
DATABASE_PASSWORD='MySQLのrootユーザーのパスワード'

これで以上です。

何かAPIを導入したい際は、API秘密鍵を同じようにして環境変数として設定します。

Railsの起動

ポートの解放 config/unicorn.rb に listen 3000 と記述しましたが、これはRailsのサーバを3000番ポートで起動するということを意味するのでした。 HTTPがつながるように「ポート」を開放する必要があります。

手順

  1. EC2を開く

  2. 『実行中のインスタンス』を開く

  3. インスタンスを選択

  4. セキュリティグループの『launch-wizard-*』をクリック

  5. インバウンドルール が表示される

  6. 『 インバウンド 』を選択

  7. 『 編集 』をクリック

  8. 左下の『ルールの追加』をクリック

  9. タイプ:「カスタムTCPルール」、プロトコルを「TCP」、ポート範囲を「3000」、送信元を「カスタム」「0.0.0.0/0」に設定

  10. 画面左下の『 保存 』をクリック

Railsの起動

Rails 5.1以前の場合

database.ymlに下記を追加します

config/database.yml(ローカル)
production:
  <<: *default
  database: アプリ名
  username: root
  password: <%= ENV['DATABASE_PASSWORD'] %>
  socket: /var/lib/mysql/mysql.sock

追記が完了したら、EC2でも反映させます。 EC2とGithubは接続できているため、git pullコマンドを利用します。

ターミナル(EC2)

[ec2-user@ip-172-31-23-189 <アプリ名>] git pull origin master

データベースの作成をする

ターミナル(EC2)

[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'

アプリのディレクトリを開いてからコマンドを実行しましょう

#うまくいかない = アプリ名を指定していない
[ec2-user@ip-172-31-23-189 ~( ここが指定されていない )]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'

#アプリ名(リポジトリ)を指定しているのでちゃんと処理がされる
[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'

rails db:migrateを実行して、migrationを完了させる。

ターミナル(EC2)

[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails db:migrate RAILS_ENV=production

エラーが出る場合

Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが起こった場合、mysqlが起動していない可能性があります。

ターミナル(EC2)

sudo service mysqld start

#再起動をさせたい場合は、
sudo service mysqld restart

というコマンドをターミナルから打ち込み、mysqlの起動を試してみましょう。

参考記事 Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

ユニコーンを起動

[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/[リポジトリ]
[ec2-user@ip-172-31-23-189 <app名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D

Rails5.2以降の場合

credentials.ymlの設定 ターミナル(ローカル)

アプリ名 $ EDITOR=vim bin/rails credentials:edit

すると編集画面が表示されます。 しかし文字入力ができないので、 『 i 』を押して、----INSERT----モードに変更します

下記を入力します。

credentials.yml
db:
  database: アプリ名
  username: root
  password: 設定したPW
  socket: /var/lib/mysql/mysql.sock

passwordははじめてAWSでデプロイする方法⑤(EC2の環境構築、Ruby, MySQL)の『MySQLのrootパスワードの設定』で設定しています。

次に、database.ymlにcredential.ymlで設定した環境変数を記述します

config/database.yml
production:
  <<: *default
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>

本番環境のshared/configにmaster.keyを作成

手順

ローカル環境にある,master.keyの中身を確認する rails newで作成された、ローカルのmaster.keyを確認する。

$ vi config/master.key

すると下記のようにmaster.keyの中身が表示されます。

fadfdfdgaf44623535y....

この表示された、master.keyの値をコピーしましょう

表示されたmaster.keyをコピーします。 これを本番環境で貼り付けていきます。

本番環境でmaster.keyを作成 EC2のアプリのconfigを開きましょう

#本番環境
[ec2-user@ip-172-31-23-189 ~]$ cd /var/ここはそれぞれ違います/[アプリ名]
[ec2-user@ip-172-31-23-189 <アプリ名>]$ cd shared/config

そうしたら、本番環境上でmaster.keyを作成します

[ec2-user@ip-172-31-23-189 config]$ vi master.key

ローカル環境のmaster.keyの値を入力

fsdgagaf08deg424~~~~~

『 i 』を押すと----INSERT-----と表示がされて、文字入力ができます。 ここにコピーしたローカルのmaster.keyの値を貼り付けします。

『 esc 』ボタンを押した入力モードを終了 『 :wq 』入力して保存します

これで本番環境でもmaster.keyが設定されています。

ユニコーンを起動

[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/[リポジトリ]
[ec2-user@ip-172-31-23-189 <app名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D

エラーが発生した場合 can't find gem bundler (>= 0.a) with executable bundle can't find gem bundler (>= 0.a) with executable bundle 対応

原因:bundlerのバージョンが、gitcloneしたAppとEC2で異なるため失敗している。 解決策

ローカルのbundlerを確認

$ bundle -v
Bundler version 2.0.2

これで2.0.2のバージョンを利用しているとわかる。

EC2

[ec2-user@ip-172-31-23-189 <app名>]$ gem install bundler -v 2.0.2

これで最後にbundle installをして完了

EC2

[ec2-user@ip-172-31-23-189 <app名>]$ bundle install

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

Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが起こった場合、mysqlが起動していない可能性があります。

ターミナル(EC2)

sudo service mysqld start


#再起動をさせたい場合は、
sudo service mysqld restart
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (13)
database.ymlとcredentials.ymlの中身に漏れがないか確認をしてください

credentials.yml
db:
  database: アプリ名
  username: root
  password: 設定したPW
  socket: /var/lib/mysql/mysql.sock
config/database.yml
production:
  <<: *default
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>
 #ここのsocketが抜けていないか???

サイトにアクセスしてみる ブラウザで http://<サーバに紐付けたElastic IP>:3000/ にアクセスしてみましょう ブラウザにCSSの反映されていない(ビューが崩れている)画面が表示されていれば成功です。

アセットコンパイルする

レイアウトが崩れてしまっているでしょう。

開発中には正常に表示されていたのに、本番ではうまく表示されないのはなぜでしょうか?

これは、開発中はアクセス毎にアセットファイル(画像・CSS・JSファイルの総称)を自動的にコンパイル(圧縮)する仕組みが備わっていますが、本番モードのときにはパフォーマンスのためアクセス毎には実行されないようになっているためです。

ターミナル(EC2)

[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails assets:precompile RAILS_ENV=production

成功した場合

Yarn executable was not detected in the system.
Download Yarn at https://yarnpkg.com/en/docs/install
I, [2020-01-18T12:51:01.4345644 #1265]  INFO -- : Writing /var/app/web-share/public/assets/member_photo_noimage_thumb-224a733c50d48aba6d9fdaded809788bbeb5ea5f6d6b8368adaebb95e58bcf53.png
I, [2020-01-18T12:51:02.2615123#1265]  INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js
I, [2020-01-18T12:51:02.2626434 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js.gz
I, [2020-01-18T12:51:08.484546 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css
I, [2020-01-18T12:51:08.485454 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css.gz
エラーが出る場合
ActiveRecord::AdapterNotSpecified: 'production' database is not configured. Available: ["default", "development", "test", "database", "username", "password", "socket"]

下記を修正してください

config/database.yml
production:
  <<: *default # ここが抜けているはず
  database: <%= Rails.application.credentials.db[:database] %>
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  socket: <%= Rails.application.credentials.db[:socket] %>

追記したら

ターミナル(EC2)

[ec2-user@ip-172-31-23-189 <アプリ名>] git pull origin master

再度

ターミナル(EC2)

[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails assets:precompile RAILS_ENV=production

今度は成功するはずです

成功した場合

Yarn executable was not detected in the system.
Download Yarn at https://yarnpkg.com/en/docs/install
I, [2020-01-18T12:51:01.4345644 #1265]  INFO -- : Writing /var/app/web-share/public/assets/member_photo_noimage_thumb-224a733c50d48aba6d9fdaded809788bbeb5ea5f6d6b8368adaebb95e58bcf53.png
I, [2020-01-18T12:51:02.2615123#1265]  INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js
I, [2020-01-18T12:51:02.2626434 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js.gz
I, [2020-01-18T12:51:08.484546 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css
I, [2020-01-18T12:51:08.485454 #1265]  INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css.gz

Railsの再起動 コンパイルが成功したら反映を確認するため、Railsを再起動します。しかし、まずは今動いているUnicornをストップします。

EC2のターミナルから以下のように入力します。「aux」と打っているのは、psコマンドのオプションです。表示結果を見やすくしてくれます。また、| grep unicornとしているのはpsコマンドの結果からunicorn関連のプロセスのみを抽出するためです。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn


ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn

大事なのは左から2番目の列です。ここに表示されるのがプロセスのid、つまりPIDになります。 「unicorn_rails master」と表示されているプロセスがUnicornのプロセス本体です。この時のPIDは、17877となっています。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill <確認したunicorn rails masterのPID>

killコマンド:現在動いているプロセスを停止させるためのコマンドです

再度、プロセスを表示させ終了できていることを確認しましょう。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn

...
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn

3つあった項目が一つになっています

では、Railsを起動させましょう!

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D

もう一度、ブラウザで http://<Elastic IP>:3000/ にアクセスしてみましょう。今度はレイアウト崩れも無くサイトが正常に表示されていることでしょう。

参考 【Rails5.2】credentials.yml.encとmaster.keyでのデプロイによる今までとの変更点 【備忘録】credentials.yml.encにdatabase設定を保存する

Nginxのインストールと設定

Nginxをインストール 下記のコマンドでインストール(できなかった)

[ec2-user@ip-172-31-30-254 lib]$ sudo yum -y install nginx
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
amzn2-core                                                                                                                                                                                                          | 3.7 kB  00:00:00     
35 packages excluded due to repository priority protections
No package nginx available.
Error: Nothing to do


nginx is available in Amazon Linux Extra topic "nginx1"

To use, run
# sudo amazon-linux-extras install nginx1

Learn more at
https://aws.amazon.com/amazon-linux-2/faqs/#Amazon_Linux_Extras

となってできなかったので、言われている通り、

[ec2-user@ip-172-31-30-254 lib]$ sudo amazon-linux-extras install nginx1
Installing nginx
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Cleaning repos: amzn2-core amzn2extra-docker amzn2extra-nginx1 mysql-connectors-community mysql-tools-community mysql80-community nodesource yarn
22 metadata files removed
14 sqlite files removed
0 metadata files removed
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
amzn2-core                                                                                                                                                                                                          | 3.7 kB  00:00:00     
amzn2extra-docker                                                                                                                                                                                                   | 3.0 kB  00:00:00     
amzn2extra-nginx1                                                                                                                                                                                                   
・
・
・

で、できたっぽい

Nginxの設定ファイルを編集 Nginxにアクセスされたときの動作を記載する設定ファイルを作成する。 設定ファイルは、/etc/nginx/conf.dフォルダ配下に作成する。拡張子が.confのものがすべて読み込まれる設定になっている。 Rails5をNginx経由で接続させるためのNginxの設定。Nginx+Puma+Rails5 - プログラミングで遊ぶ!

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

下記を貼り付ける (ディレクトリの場所などは、自分にあった場所を指定してください)

rails.conf

upstream app_server {
  # Unicornと連携させるための設定。
  # アプリケーション名を自身のアプリ名に書き換えることに注意。今回であればおそらく
  server unix:/var/〇〇〇(アプリをまとめているディレクトリ)/〇〇〇〇〇〇<アプリケーション名>/tmp/sockets/unicorn.sock;
}

# {}で囲った部分をブロックと呼ぶ。サーバの設定ができる
server {
  # このプログラムが接続を受け付けるポート番号
  listen 80;
  # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
  server_name 18.〇〇〇.〇〇〇.〇〇(Elastic IP);

  # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
  client_max_body_size 2g;

# 接続が来た際の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;
}

3行目の<アプリケーション名> となっている箇所は、ご自身のものに変更してください。 11行目の<Elastic IP>となっている箇所も同様に、ご自身のものに変更してください。 14行目の<アプリケーション名> となっている箇所は、ご自身のものに変更してください。

Nginxの権限を変更 POSTメソッドでもエラーが出ないようにするために、下記のコマンドも実行してください。

[ec2-user@ip-172-31-25-189 ~]$ cd /var/lib
[ec2-user@ip-172-31-25-189 lib]$ sudo chmod -R 775 nginx  
Nginxを再起動して設定ファイルを再読み込み
[ec2-user@ip-172-31-25-189 lib]$ cd ~
[ec2-user@ip-172-31-25-189 ~]$ sudo service nginx restart

ローカルでunicorn.rb修正 listen 3000

↓以下のように修正

listen "#{app_path}/tmp/sockets/unicorn.sock"
Githubで変更点をpushしたら、本番環境でも反映させます。

ターミナル(EC2)

[ec2-user@ip-172-31-25-189 ~]$ cd /var/www/アプリ名
[ec2-user@ip-172-31-23-189 <アプリ名>]$ git pull origin master

Unicornを再起動

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn

ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn

続いて、unicorn_rails master(一番上)のプロセスをkillします。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill <確認したunicorn rails masterのPID(上のコードでは17877)>

unicornを起動します

[ec2-user@ip-172-31-23-189 <アプリ名>]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D

ブラウザからElastic IPでアクセス https:// (Elastic IP)

これでサイトが表示されず、下記が表示されたら、、、、、、、、、

f:id:dorcushopeino1:20200930131047p:plain

もう一度、下記をやり直してください。

Nginxの設定ファイルを編集

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

下記を貼り付ける (ディレクトリの場所などは、自分にあった場所を指定してください)

rails.conf
upstream app_server {
  # Unicornと連携させるための設定。
  # アプリケーション名を自身のアプリ名に書き換えることに注意。今回であればおそらく
  server unix:/var/〇〇〇(アプリをまとめているディレクトリ)/〇〇〇〇〇〇<アプリケーション名>/tmp/sockets/unicorn.sock;
}


# {}で囲った部分をブロックと呼ぶ。サーバの設定ができる
server {
  # このプログラムが接続を受け付けるポート番号
  listen 80;
  # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない
  server_name 18.〇〇〇.〇〇〇.〇〇(Elastic IP);

  # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
  client_max_body_size 2g;

# 接続が来た際の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;
}

これで無事にサイトが表示されたら、完了です!

自分はうまくいかなかったので[INETドメインなソケット]なるものを使用して設定した。それとSELinux = permissiveにした

www.slideshare.net

MySQL - 【AWS・Rails】nginxで(111: Connection refused)エラー。|teratail

UNIXドメインなソケットを利用する理由がなければ、INETドメインなソケットを利用されてみてはいかがでしょうか。 私はUNIXドメインソケットについて、トラブルが多いので利用を避けています。

*/var/www/projects/{アプリ名}/config/unicorn.conf.rb 

listen  = 3000

/etc/nginx/conf.d/{アプリ名}.conf

upstream unicorn_server {
      server 127.0.0.1:3000;
}

そうするとうまく行った。

Railsアプリでログ情報などの大量のcsvエクスポート(出力)をWEBアプリ上で行う

出力データが大量すぎて時間がかかる

クライアントからログ情報を分析したいとのことでログ情報をDBから出力するような機能を作ったが
実際に実運用が始まってからログを出力した結果、1, 2日くらいのログであれば時間はかかるがcsv出力できた。しかし、全期間になると時間がかかりすぎて使い物にならない。というような事態に陥った。実際に試してみると15分たっても出力されず、「確かにこれは使えないなぁ。。。」という状態だったので、直接SQLを叩いてログ出力をするようにした。

それまでに使っていた方法

RailsでDBのデータをCSV出力しよう|已むに已まれぬ雑記帳|note このような感じでよくあるcsv出力をCSVライブラリを使用して出力していた。(これかな。。 library csv (Ruby 2.7.0 リファレンスマニュアル)
今回、生SQLでクエリを発行してログ出力するのもCSVライブラリを使っているがちょっとだけ使い方が違う。
to_sqlメソッドを使ってActiveRecordで発行されるSQLを生SQLに変換して、それを出力している。

app/services/large_csv_exporter_service.rb

class LargeCsvExporterService
  require 'csv'

  attr_accessor :table, :column, :host, :username, :password, :database

  def initialize(table, column, host, username, password, database)
    @table = table
    @column = column
    @host = host
    @username = username
    @password = password
    @database = database
  end

  def set_file_name(file_name)
    @csv_file_name = file_name
  end

  def set_query(query)
    results = @client.query(query)
    results
  end

  def write_csv(results)
    # File.write(@csv_file_name, encoding: Encoding::SJIS) unless File.exist? @csv_file_name
    CSV.open("./tmp/csv_export/#{@csv_file_name}", "w:sjis") do |csv|
      csv << results.fields
      results.each do |row|
        csv << row.values
      end
    end
  end

  def export_csv_file
    filepath = "./tmp/csv_export/#{@csv_file_name}"
    stat = File::stat(filepath)
    return filepath, stat, @csv_file_name
  end

  def delete_created_csv_file
    if File.exist?("./tmp/csv_export/#{@csv_file_name}")
      File.delete("./tmp/csv_export/#{@csv_file_name}")
    end
  end

  def set_client
    # cache_rows: falseでメモリを使わないようにしている
    @client = Mysql2::Client.new(
      host: host,
      username: username,
      password: password,
      database: database,
      stream: true,
      cache_rows: false,
    )
  end
end

serviceをcontrollerのなかで使っている。真ん中あたりのcsv_export = LargeCsvExporterService.new("access_logs", "*", ENV["DB_D_HOST"], ENV["DB_D_USERNAME"], "", ENV["DB_D_NAME"])らへんから。ENV["DB_D_HOST"]とかで、.env(dotenv)のDB名とかユーザー名とかを参照している。
綺麗なコードは書けないので、多めに見てください。

app/controllers/admins/access_logs_controller.rb

    def export_csv(params_q)
      @q = AccessLog.order(id: :asc).ransack(params_q)
      user_type_param = params[:q][:user_type].empty? ? ["user", "admin", "supplier"] : params[:q][:user_type].split(':')[1]
      methoda_type_param = params[:q][:method_type] == "ALL_TYPE" ? AccessLog.distinct.pluck(:method_type).compact : params[:q][:method_type]
      access_dates = AccessLog.order(access_date: :asc).to_a
      from_time = params[:q][:created_at_gteq].empty? ? access_dates.first.access_date : params[:q][:created_at_gteq].to_time
      to_time = params[:q][:created_at_lt].empty? ? access_dates.last.access_date : params[:q][:created_at_lt].to_time

      sql_query = AccessLog.where(user_type: user_type_param).where(method_type: methoda_type_param).where(created_at: [from_time..to_time]).to_sql

      csv_export = LargeCsvExporterService.new("access_logs", "*", ENV["DB_D_HOST"], ENV["DB_D_USERNAME"], "", ENV["DB_D_NAME"])
      csv_export.set_file_name("AccessLog_#{Time.zone.now.strftime("%Y%m%d%S")}.csv")
      csv_export.set_client
      # results = csv_export.set_query("SELECT * FROM access_logs WHERE created_at BETWEEN '#{from_time}' AND '#{to_time}' AND method_type = '#{methoda_type_param}' AND user_type = '#{user_type_param}'" )
      results = csv_export.set_query(sql_query)
      csv_export.write_csv(results)
      filepath, stat, csv_file_name = csv_export.export_csv_file
      send_result = send_file(filepath, :filename => csv_file_name, :length => stat.size)
      # csv_export.delete_created_csv_file
    end

sqlクエリはこんな感じのが1行で出力される

SELECT `access_logs`.* 
FROM   `access_logs` 
WHERE  `access_logs`.`user_type` = 'user' 
       AND `access_logs`.`method_type` IN ( 'GET', 'POST' ) 
       AND `access_logs`.`created_at` BETWEEN 
           '2020-08-25 00:00:00' AND '2020-09-27 23:55:35' 

まぁ、こんな感じで、実際に時間は計測していないが10万件くらいのファイルでも10秒くらいで出力できるようになった。