#4: インフラについて簡単に理解する [RDS]DBサーバーを構築
- RDSについて
- プライベートサブネットの作成
- RDSを設置
- WebサーバーからRDSに接続する
RDS
今回構築するもの
- プライベートサブネットにDBを置くことで外部からのインターネットによる接続をできないようにして安全性を担保する。 - RDSは複数のアベイラビリティーゾーンに用意しておくことを推奨しているため、別のアベイラビリティーゾーンを用意しておく必要がある。そのため、2つ以上のプライベートサブネットを2つ以上の別のアべイラビリティゾーンにおく必要がある。
1. RDSについて
マルチAZというRDSの可用性(DBが死んでも復活させやすいこと)を保つシステムがあるが、このシステムを使うのに複数のアベイラビリティゾーンに複数のプライベートサブネットが必要。マルチAZについてはググったら色々出てくるので割愛。
例えばリンク: AWSでマルチAZ構成にする?しない?
2. プライベートサブネットの作成
前回同様
3.RDSの作成
DB用のセキュリティグループを作成
今回はMySQLを使ってDBを作るので、プライベートサブネットにはMySQLのポートのみ接続できる状態に設定する。
- セキュリティグループはMySWL/Auroraというものを選択すると3306ポートが開く。
- ソースにはどこから接続するかを選ぶのだが、個別に繋ぎたいサーバーのIPを選択しても良いが、複数台サーバがある時に全てを設定する必要があるため煩雑。それを避けるためソースにセキュリティグループを選択するとそのセキュリティグループ内にあるもの全てに対して接続を許可することができる。
作成後
RDS DBサブネットグループの作成
rdsインスタンスを起動する時にDBサブネットを選択するので、必要。 ※これがないと、RDSをサブネットに紐付けられないので必ず作成
RDS > サブネットグループから作成
前回作成した二つの別々のアベイラビリティゾーンにあるサブネットを追加してサブネットを作成する。 また、VPCも前回作成したものを選択。
DBパラメータグループ設定
オプショングループの作成
何かDBにオプションを設定したい時に使う。
RDSの作成
RDS > データベースからDBを作成する
4. WEBサーバーからRDSに接続する
MySQLをwebサーバーにインストール
sshでサーバーに接続
インストール
$ sudo yum -y install mysql
データベース のエンドポイント
RDSからエンドポイントを確認する。
$ 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ドメイン登録]
Route53
1.ドメインについて
ドメインの構造
・トップレベルドメイン ・第2レベルドメイン ・第3レベルドメイン ・第4レベルドメイン に分かれている。
ICANNという団体が管理していて一意性を保つためにそれぞれのトップレベルドメインにつき、一つの団体に管理を任せている。その団体がそれぞれリセラーにドメインを卸てそこから各人への販売が行われる。 ex) .jpはJPRSという団体が管理している。
2. DNSについて
ドメインを購入したあとはIPアドレスとドメイン名を紐づけることで名前解決が行われてどのドメイン名でどのIPアドレスなのかというのがわかる。
① ブラウザで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年目以降は高くなるといった場合があるのでそこに気をつけて購入する
検索するとこのように値段が表示されるので、今回は1円の.workで取得する
実際に購入
購入画面:
Whois情報とは: Whoisとは、ドメインの保持者の氏名、住所、電話番号などの登録者情報を誰でも閲覧できる情報提供サービスです。登録者情報はICANN(※)より一般公開することが義務づけられています。
Whois情報公開代行サービスをご利用いただくことで、ドメイン保持者の登録情報から「お名前.com」の情報に代えたうえで一般公開することができます。これによりドメイン保持者のプライバシーが保護されます。
なので、個人情報を登録したくない場合に代理で個人情報登録を行ってくれる
ドメインプロテクションとは: お名前.comで管理されているドメインの各種設定手続きの操作を制限することができるサービスです。
設定・変更する場合は、ドメイン登録者の承認が必要となり、承認を得ることで操作制限されている手続きを進めることができるため、誤操作や第三者の不正アクセスによる意図しない操作を遮断することができ、さらなるセキュリティ対策強化に期待することができます。
メールアドレスとパスワードを入力して次へ
名前などの登録
支払い方法入力画面
サーバー申し込みませんか?という画面が出てくるが今回はEC2を使うので無視
申し込み完了画面
ドメインの自動更新の設定をOF Fにする
さっきの画面のここから設定できる
自動更新がONになっているので、OFFにする ・変更したいドメインにチェックを入れて確認画面へ進むを押下
・規約に同意して上記内容を申し込むを押下
・こういった画面が出てくるが無視
・自動更新が解除される
これでドメインの登録完了
Route53について
今回はシンプルルーティングを設定する
Route53で DNSを設定する
Route53はネームサーバーの役割を担っており、Route53に問合せを投げることで特定ドメインのIPアドレスが返される。 現状ではお名前ドットコムのネームサーバーがIPアドレスを返すようになっているので、そこをRoute53に向き先を変更する必要がある。
AWSでRoute53のページを開き、ホストゾーンを作成していく
実際にホストゾーンを作成するとこんな感じ、 それぞれ ns-766.awsdns-31.net. ns-1052.awsdns-03.org. ns-1560.awsdns-03.co.uk. ns-297.awsdns-37.com. というネームサーバーがこのアドレスのネームサーバーとなっているよ。という表記。 (この時点ではまだネームサーバーは変更されていない)
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つの値を入れていく
こういった画面があるので、1, 2, 3, 4の順に貼り付ける(順番は特に関係ない)
反映までは時間がかかる
反映されたらdigコマンドで再度確認
AWSには最後に ns-1052.awsdns-03.org. のようにドットがついているがそれは省く。
ドメイン名にEC2インスタンスのIPアドレスを紐付ける
現状ではNSレコードトSOAレコードのみ登録されているのでAレコードを登録していく。 Aレコードとはここ(参照リンク)にあるようにホストのIPアドレスのことを指す。
Aレコード作成
まず、レコード作成をクリック
今回はシンプルルーティングで作成
名前のところには何も入力しない。 ・そのままの定義名でURLにアクセスしたいため
これで、しばらく時間が経ったら、ドメインのネームサーバーの変更が反映されたらドメイン名をブラウザに入力するとAレコードのIPが返されてブラウザから設定したサーバーを見れるようになる。
#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 |
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 インストールコマンド
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
ファイアーウォールの設定
- 現状ではファイアーウォールが通信をシャットダウンしてしまうのでサーバー上のアプリケーションを見ることができない。なので、ファイアーウォールの設定を変更して、アプリケーションを見れるようにする必要がある。
セキュリティグループを設定してファイアーウォールを調整する。
httpアクセスを許可するために80番ポートを開ける
HTTPを任意の場所から接続できるようにして、80番ポートを開ける設定。
そうすると、Apacheが起動しているサーバーに接続することが可能。
Gitリポジトリをメンテナンスして軽量化する
保存版
この方の記事が最高に欲しかった、かつまとまっていたので自分の保存用です。 ↓こっちをみてください。 qiita.com
これもいい
Gitリポジトリのメンテ?
Gitリポジトリにあるファイルは .git
がバージョン管理をしています。
今回はその .git
をメンテナンスする話です。
はじめに
こんな悩みを持ったことはないでしょうか。大型のプロジェクトでないと発生しないと思うので、個人プロジェクトではなかなか遭遇することはないでしょう。
今回は上記を解消するための リポジトリメンテナンス方法 をご紹介します。
!! 注意 !!
Gitリポジトリのメンテナンスは破壊的なため、Gitのコマンドを理解している方のみ行ってください。 この記事を読んで実行した結果、大切なリポジトリが壊れても当方は責任を負いかねます。
Gitオブジェクト(Git管理ファイル)の削減
Gitオブジェクトは .git/objects
の中身(00~FF)を指します。これが肥大化していると git clone
にかなりの時間がかかることになります。
リポジトリにあるファイルの差分や履歴を管理しているオブジェクトで、コミットが多くなればなるほど容量は膨れていきます。
このオブジェクトには知らず知らずにゴミをコミットしてしまっていることがあります。 :put_litter_in_its_place: そして、そのゴミが意図せずオブジェクトの容量を肥大化させている一因になることも多いです。
良くある一例で、npm install
を行い node_modules
以下に依存ファイルを取得・ビルドし、そのままコミットしたとします。
直後、.gitignore
に node_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アドレスの範囲
- ネットワーク部とホスト部に区分されている
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
サブネット作成
パブリックサブネットとプライベートサブネットに分け、パブリックサブネットではApachなどのWEBアプリケーションはインターネットを通して接続できるが、 DBはインターネットを通して接続できないようにする
AWS上でサブネットを作成 今回はprivateとpublicサブネットの2種類を作成
パブリックサブネットとプライベートサブネットに分け、パブリックサブネットではApachなどのWEBアプリケーションはインターネットを通して接続できるが、 DBはインターネットを通して接続できないようにする
IPアドレスとルーティング
パブリックサブネットを作成したが、このままではルートテーブルにこのIPがどのルーターと接続できるかの情報がないのでインターネットに接続することができない。そのため、ルートテーブルに今回作ったサブネットがどことつながっているかの表記をする必要がある。
インターネットゲートウェイ: VPCとインターネットを接続する仮想のルートテーブル 初期状態ではこのインターネットゲートウェイがないのでAWSで作成する必要がある。
- ルートテーブルはAWSの場合VPCと各サブネットに対して作成できる
- サブネットやインターネットゲートウェイ間にはルーターが動いている。ルーターは明示的に指定しないがサブネットを作成すると暗黙的にルーターが割り振られる
インターネットゲートウェイの作成
名前をつけて作成したら、ダッシュボードを確認。そうするとまだどこにも紐づけていないので、"detached"と表記されているものが表示されるはず。
detachedのインターネットゲートウェイを先ほど作成したVPCにアタッチする。 対象のインターネットゲートウェイを左クリックして、VPCにアタッチという項目で、対象のVPCを選択することでアタッチができる。簡単
ルートテーブルを作成してパブリックサブネットに紐付ける
・ルートテーブルを作成してパブリックサブネットに紐付ける
現状では一番したに一つだけ表示されているものだけで、「10.0.0.0/16は自身のIPアドレスだよ。それ以外のIPアドレスへの通信は破棄するよ」という意味。
デフォルトルートをインターネットゲートウェイに向けるように作成する
先ほどと同様のVPCに紐づくルートテーブルを作成
このルートテーブルはVPCにのみ割り当てられているので、それをパブリックサブネットにも割り当てる。
「関連づける作業」
デフォルトルートの作成: 0.0.0.0/0を追加して、Internet Gatewayを選ぶと関連づけ可能なものが出てくるのでそれをインターネットゲートウェイとして紐づける。 これでデフォルトルートがインターネットゲートウェイのパブリックサブネットを作成完了。これでパブリックサブネットはインターネットに接続することが可能。
ネットワークの設計で気をつけるポイント
こういうのみるといいかも: AWSで拡張性・耐障害性・セキュリティを考慮したクラウド構成のネットワーク設計
- プライベートIPアドレスだと重複がない限り割と自由に設定できるため - VPCのCIDR領域は大きめに設定しておくと後で枯渇せずに済む
VPCを分割するか?アカウントを分けるか?
どのタイミングでVPCを分割するか - 異なるシステムの場合はアカウントを分ける - 異なるシステムを同一アカウント内に入れると管理が煩雑になる - 同一システムの各環境は、VPCとアカウントのどちらを分けるか? - 環境が違う場合、アカウントもVPCも同一のものを使用するのはだめ - VPCを分けると、IAMの設定が一度で良い。反面、各環境のリソースが見えてしまい、事故の元にもなる - アカウントを分けると、他の環境のリソースが見えず、作業しやすい。反面、環境ごとにIAMの設定が必要 - 同一アカウントでVPCとリージョンを分けるのがおすすめ
サブネットの設計ポイント
Railsを本番環境にデプロイ(with Unicorn, Nginx, EC2, MySQL, Capistrano, Elastic IP)
こちらの記事をほぼまるまんまなのですが、少し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必要パッケージのインストールと設定
# 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
パッケージはこうなっていればいいらしい
(yを入力してEnterを押下する際にインストールパッケージとリポジトリが下記の様になっていることを確認する。)
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
ログの確認
- 下記コマンドを実行してMySQLのlogファイルを開く
$ sudo less /var/log/mysqld.log
- 開いたファイル内で下記の様な一行を見つける。
/var/log/mysqld.logYYYY-MM-DDTHH:MM:SS.260490Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: XXXXXXXXXXXX
- ファイルに記載された行のXXXXXXXXXXXXの部分がrootユーザの初期パスワードとなる。
MySQLログイン確認
- 開いているmysqld.logファイルを閉じる。
- 下記コマンドを実行してmysqldを停止する。
$ sudo service mysqld stop
- 下記コマンドを実行してmysqldを起動する。
$ sudo service mysqld start
- 下記コマンドを実行してmysqlにrootユーザでログインする。
- 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ユーザのパスワードが条件を満たしていない。)
パスワードの再設定
- 先の方法で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@とか
- 下記を実行して一旦MySQLからログアウトする。
mysql> exit
DBの作成
- 下記コマンドを実行してMySQLにrootユーザでログインする。(ログイン時のパスワードが先に設定し直したパスワードを入力する。)
$ mysql -u root -p
- MySQLログイン後下記を実行して「test」という名前のDBを作成する。
mysql> create database test;
- 下記を実行して「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
- 下記が表示されるので、エンターを押す
Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa):
- さらにエンターを押す(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 | +-----------------+
- SSH公開鍵を表示し、値をコピーするため、下記コマンドを実装
[ec2-user@ip-172-31-23-189 ~]$ cat ~/.ssh/id_rsa.pub
- 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にアクセス
エラー「Key is invalid. You must supply a key in OpenSSH public key format」が表示された場合、 貼り付けたコードに『 ssh-rsa 』が含まれているかご確認ください
[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)領域の作成
アプリケーションサーバの性能を決定する
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がつながるように「ポート」を開放する必要があります。
手順
EC2を開く
『実行中のインスタンス』を開く
インスタンスを選択
セキュリティグループの『launch-wizard-*』をクリック
インバウンドルール が表示される
『 インバウンド 』を選択
『 編集 』をクリック
左下の『ルールの追加』をクリック
タイプ:「カスタムTCPルール」、プロトコルを「TCP」、ポート範囲を「3000」、送信元を「カスタム」「0.0.0.0/0」に設定
画面左下の『 保存 』をクリック
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)
これでサイトが表示されず、下記が表示されたら、、、、、、、、、
もう一度、下記をやり直してください。
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秒くらいで出力できるようになった。