20200601のMySQLに関する記事は6件です。

mysqlの複製

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQLでテーブル上のデータの消去

使い方

データを消去するにはDELETE文を使います。

DELETE FROM table_name [WHERE where_condition]

テーブル名talbeからidカラムが10のデータを消去する。

DELETE FROM table WHERE id=10;

テーブルからすべてのデータを消去する。

DELETE FROM table;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

さくらVPSにMySQLをインストール

環境は以下の記事をご参照ください。centOs7です。
さくらのVPSにSSH接続+最低限のセキュリティ対策

ルートユーザーに切り替え

毎回sudoつけるの面倒なので

$ su -

MariaDBの削除

centOsにはデフォルトでMariaDBがインストールされています。不要なので削除。

$ sudo yum remove mariadb-libs
$ sudo rm -rf /var/lib/mysql

yumにMySQLのリポジトリを登録

npmなどと違い、yumにはデフォルトで登録されていないリポジトリが結構あります。
MySQLはデフォルトで登録されていない(or 古いバージョンしか登録されていない)ので、リポジトリを追加します。
ここではバージョン5.7系を追加しています。(たぶん57の部分を他の数字に変えれば他のバージョンを追加できるはず)

$ rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm

インストール

$ yum install -y mysql-community-server mysql-devel
$ mysqld --version

起動設定

$ systemctl start mysqld.service # 起動
$ systemctl enable mysqld.service # 自動起動設定

初期設定

まずは初期パスワードを確認。(lCCqZ>=Q!9Yo)

$ cat /var/log/mysqld.log | grep password
[Note] A temporary password is generated for root@localhost: lCCqZ>=Q!9Yo

対話形式で初期設定

$ mysql_secure_installation

Securing the MySQL server deployment.

Enter password for user root: # ログファイルから取得した初期パスワードを入力

The existing password for the user account root has expired. Please set a new password.

New password: # rootユーザの新規パスワードを入力(大文字小文字英数字+特殊文字で8文字以上で設定)

Re-enter new password: # 確認用にもう一度入力
The 'validate_password' plugin is installed on the server.
The subsequent steps will run with the existing configuration
of the plugin.
Using existing password for root.

Estimated strength of the password: 100
Change the password for root ? ((Press y|Y for Yes, any other key for No) : y # 本当にパスワードを変更して良いかの確認

By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y # 匿名ユーザー(名前もパスワードも設定されていないユーザー。デフォルトで設定されているけどセキュリティ上消した方が良い)を削除
Success.


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y # localhost以外からrootアカウントでログインできないようにする
Success.

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.


Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y # testデータベースを削除
 - Dropping test database...
Success.

 - Removing privileges on test database...
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y # リロードして設定を反映する
Success.

All done!

日本語対応

mysqlにログイン

$ mysql -u root -p

文字コードを確認。latin1のところをutf8に変更したい。

mysql> show variables like "chara%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
mysql> exit
$ vi /etc/my.cnf
/etc/my.cnf
# ファイル末尾に以下を追記
character-set-server=utf8

[client]
default-character-set=utf8

再起動してlatin1→utf8に変更されていることを確認

$ systemctl restart mysqld.service
$ mysql -u root -p
mysql> show variables like "chara%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

タイムゾーン設定

デフォルトのタイムゾーンを確認。SYSTEM→Asia/Tokyoに変更したい。

$ mysql -u root -p
mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | JST    |
| time_zone        | SYSTEM |
+------------------+--------+
$ /usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo > ~/timezone.sql 
# タイムゾーンのインポート。↑が失敗したら↓を試す
$ mysql_tzinfo_to_sql /usr/share/zoneinfo

$ mysql -u root -p -Dmysql < ~/timezone.sql
$ vi /etc/my.cnf
/etc/my.cnf
末尾に以下を追記
[mysqld]
default-time-zone = 'Asia/Tokyo'
$ systemctl restart mysqld.service
$ mysql -u root -p
mysql > show variables like '%time_zone%';
+------------------+------------+
| Variable_name    | Value      |
+------------------+------------+
| system_time_zone | JST        |
| time_zone        | Asia/Tokyo |
+------------------+------------+
2 rows in set (0.00 sec)

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

さくらのVPSにMySQLをインストール

環境は以下の記事をご参照ください。centOs7です。
さくらのVPSにSSH接続+最低限のセキュリティ対策

ルートユーザーに切り替え

毎回sudoつけるの面倒なので

$ su -

MariaDBの削除

centOsにはデフォルトでMariaDBがインストールされています。不要なので削除。

$ sudo yum remove mariadb-libs
$ sudo rm -rf /var/lib/mysql

yumにMySQLのリポジトリを登録

npmなどと違い、yumにはデフォルトで登録されていないリポジトリが結構あります。
MySQLはデフォルトで登録されていない(or 古いバージョンしか登録されていない)ので、リポジトリを追加します。
ここではバージョン5.7系を追加しています。(たぶん57の部分を他の数字に変えれば他のバージョンを追加できるはず)

$ rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm

インストール

$ yum install -y mysql-community-server mysql-devel
$ mysqld --version

起動設定

$ systemctl start mysqld.service # 起動
$ systemctl enable mysqld.service # 自動起動設定

初期設定

まずは初期パスワードを確認。(lCCqZ>=Q!9Yo)

$ cat /var/log/mysqld.log | grep password
[Note] A temporary password is generated for root@localhost: lCCqZ>=Q!9Yo

対話形式で初期設定

$ mysql_secure_installation

Securing the MySQL server deployment.

Enter password for user root: # ログファイルから取得した初期パスワードを入力

The existing password for the user account root has expired. Please set a new password.

New password: # rootユーザの新規パスワードを入力(大文字小文字英数字+特殊文字で8文字以上で設定)

Re-enter new password: # 確認用にもう一度入力
The 'validate_password' plugin is installed on the server.
The subsequent steps will run with the existing configuration
of the plugin.
Using existing password for root.

Estimated strength of the password: 100
Change the password for root ? ((Press y|Y for Yes, any other key for No) : y # 本当にパスワードを変更して良いかの確認

By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y # 匿名ユーザー(名前もパスワードも設定されていないユーザー。デフォルトで設定されているけどセキュリティ上消した方が良い)を削除
Success.


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y # localhost以外からrootアカウントでログインできないようにする
Success.

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.


Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y # testデータベースを削除
 - Dropping test database...
Success.

 - Removing privileges on test database...
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y # リロードして設定を反映する
Success.

All done!

日本語対応

mysqlにログイン

$ mysql -u root -p

文字コードを確認。latin1のところをutf8に変更したい。

mysql> show variables like "chara%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
mysql> exit
$ vi /etc/my.cnf
/etc/my.cnf
# ファイル末尾に以下を追記
character-set-server=utf8

[client]
default-character-set=utf8

再起動してlatin1→utf8に変更されていることを確認

$ systemctl restart mysqld.service
$ mysql -u root -p
mysql> show variables like "chara%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

タイムゾーン設定

デフォルトのタイムゾーンを確認。SYSTEM→Asia/Tokyoに変更したい。

$ mysql -u root -p
mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | JST    |
| time_zone        | SYSTEM |
+------------------+--------+
$ /usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo > ~/timezone.sql 
# タイムゾーンのインポート。↑が失敗したら↓を試す
$ mysql_tzinfo_to_sql /usr/share/zoneinfo

$ mysql -u root -p -Dmysql < ~/timezone.sql
$ vi /etc/my.cnf
/etc/my.cnf
末尾に以下を追記
[mysqld]
default-time-zone = 'Asia/Tokyo'
$ systemctl restart mysqld.service
$ mysql -u root -p
mysql > show variables like '%time_zone%';
+------------------+------------+
| Variable_name    | Value      |
+------------------+------------+
| system_time_zone | JST        |
| time_zone        | Asia/Tokyo |
+------------------+------------+
2 rows in set (0.00 sec)

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「失敗から学ぶRDBの正しい歩き方」を読んで[備忘録]

はじめに

自分の備忘録と情報共有のために、私が読んだ技術書について各章のサマリーと感想をまとめました。
書評と言った類いの記事ではないですが、覗いていただければ幸いです。
(備忘録としても兼ねているので、個人的に刺さったものについて強調を入れています。)

今回は「失敗から学ぶRDBの正しい歩き方」について書かせていただきます。

本の内容

DB、SQLにおけるアンチパターンの解説した本。全20個のアンチパターンについて現場エピソードから対応・対策法、心構えが述べられている。各章簡潔にまとめられているため、リズムよく読み進められる。

技術書というよりはDBに向き合うための心構え、姿勢を学ぶための読み物に近い。
なので、オススメしたい層としてはその他の設計本に鼻を折られた初級エンジニアさん(自分然り)が当てはまるだろう。

読む目的

テーブル設計についての基本知識と実務での心構えを広く浅く学ぶ。

-> 採用面接でテーブル設計についての技術試験があったがうまく答える事ができず、最低限のことは頭に入れておく必要があると思ったから。
また、実務で設計について取り組んだ事がなかったが、おそらく次の職場で担当することもあるかと思い、先取りとしての読書。

各章要約

1.データベースの迷宮

その場しのぎの命名、カラム追加はするな。後から見たときのそのカラムを名前から把握しやすいものをつけよ。

2.失われた事実

履歴を保存せよ。後から遡ったときに、遍歴が辿れないと、トラブル時の状況把握で使える情報が減ってしまう。
->払い戻しなどの取り消し処理に対応できるか、発送状況などのステータス変化を追えるか等のパターンについて確認する。

3.やりすぎたJOIN

JOINは掛け算であり、SQLの中でもっとも負荷の高い操作。テーブルが増えると指数関数的に処理負担も増加する。
対策として、JOINを使わずに欲しいレコードを取得できないか、テーブルを小さくしてJOINできないかを考える。

4.効かないインデックス

インデックスが効かなくなる5つの要因を抑えてアンチパターンを避ける。

5.フラグの闇

「とりあえず削除フラグ」は、クエリの複雑化、UNIQUE制約が使えない、カーディナルが低くなる等の問題を含むのでやめる。
対応策としては「事実のみを保存する」こと。テーブルに状態を保存するな。
-> 会員テーブルに削除フラグを持たせるのではなく、削除済み会員テーブルを作る等

6.ソートの依存

RDBはソートが苦手。なので、ソート前にデータをちいちゃくする、INDEXを利用するのがよい。
INDEXを利用したソートにはWHERE句狙いのソート、ORDER BY狙いのソートがある。

大きいデータをソートしたい場合の対応方法
1.アプリ側でのソートする
2.NOSQLを利用
3.キャッシュを利用する

7.隠された状態

テーブルにビジネスロジックを持たせるような設計はしてはいけない。
汎用性を持たせることを目的としてアンチパータンに陥ることが多いが、これらは正規化によって解決できる。

考え方としては以下が有効
1.データに複数の意味を持たせない
2.1つのデータの責務を小さくする。
3.常に状態が見えるようにするために事実のみを保存する。

8.JSONの甘い罠

JSON型にはRDBの特徴と引き換えに、スキーマから解放されるというメリットがある。
しかし、それによって以下の問題が生じる。
1.データの生合成が保てない
2.検索の複雑化
3.更新コストの増加

スキーマレスに逃げることによって生じるデメリットは大きく、以下に該当すれば不採用とした方がが吉。
1.正規化できそう(多くの場合、できる事が多い)
2.頻繁に更新を行いたいか

基本的にJSON型は最後の切り札として考える。

9.強すぎる制約

システムの仕様、ビジネスロジックに依存した強い制約をテーブルに用いるべきではない。
これらの制約は仕様変更に弱く、思わぬ弊害を生む可能性がある。
大切なのはバランスであり、テーブルの責務とアプリケーションの責務を正しく把握することが必要がある。
妥協せずにDBと向き合うのだ。

10.転んだ後のバックアップ

「バックアップは設定して終わりじゃない」。バックアップ関連の不具合はシミュレーションの怠りにより発生することが多い。

□ アンチパターン防止策。
1.定期的にバックアップーリストアを行う。-> バックアップ後は確認のため、ステージング環境で簡易リストアするのも有効。
2.バックアップ・リストア手順書を作る。(ユースケースも用意)
3.チーム内で定期的を訓練する。必ず複数人がバックアップできるようにし、属人化を防ぐ
ここらへんの心構えはDB初心者には嬉しい。

11.見られないエラーログ

エラーログの運用における重要性を認識し、設計を怠らない。
-> ログはシステムからの警告。無視すれば痛い目に合う。
ログはその深刻度のよって、出力パターンを分けるべきであり、出力された時に緊急度を認知できるようにすべき。
同時に、通知の仕組み、可視化の仕組みも、設計段階で考えれば運用を育てることにも繋がる。

12.監視されないデータベース

モニタリングはサービスの品質を可視化する。
エラーログと同様に、重要性に対する認識の欠如によって発生する問題が多い。
-> モニタリングの文化を育てることが大切

☆死活監視->チェック監視->メトリック監視と言った流れでステップアップさせていくのが定石

13.知らないロック

DBごとにロックの振る舞いはことなる。正しい知識を持つことで気づきにくいロックを防ぐことができる。

例)
PostgreSQLではSELECTでもロックを取るので、このタイミングでLOCK TABLEが実行されるとデッドロックが発生する。
-> MySQLではLOCK TABLEが実行時にトランザクションをコミットするため上記の問題は発生しない。

14.ロックの功罪

トランザクションの分離レベルを理解せよ。トランザクションの分離レベルは設定によってはトランザクション中の振る舞いに影響を与え、以下の関連現象を引き起こす。

□ 関連現象:
1.ダーティーリード-> 自分がコミットしていないデータが別Tに見れてしまう。
2.ファジーリード-> 別Tがコミットしたデータが参照できてしまう。
3.ファントムリード->別Tがコミットした追加、削除したデータが見れてしまう。
4.ロストアップデート->複数Tが並列にデータを更新した場合、後に実行したTの結果でデータが上書きされる。
(T->トランザクション)

ロックの役割は並列度を保ったまま、データの整合性を維持することである。
が、その多用は並列度を下げ、パフォーマンスに影響を与える。
=> 毒にも薬にもなるロックの功罪

15.簡単すぎる不整合

テーブルは基本的に正規化すべき。非正規にせざる得ないように見えても、代替案をよく検討する必要がある。
(CHECK制約、ENUM型という代案もあるがいずれも変更にはALTERが必要。)
一度、非正規化が始まれば、変更することは容易ではなく、技術的負債を追うことになる。
実装都合で非正規化するなどもっての外である。

16.キャッシュ中毒

キャッシュは速度面で問題なければ、基本的に使わないほうがいい。キャッシュを利用すべきかどうか、しっかりと検討すべし。
計算処理の重いデータに対してキャッシュを使えば、劇的なパフォーマンス向上につながるが、キャッシュしたデータの状態を把握することが難しいというデメリットもある。
-> 障害発生時、問題の切り分けが難しくなる。

参考:
キャッシュの悪夢 -> mixi/メルカリ

17.複雑なクエリ

クエリが複雑化する要因は主に2つ

  • 無知ゆえの剛腕 ->スキル不足ゆえに力技で解決されたクエリ
  • 腐ったテーブルに腐ったクエリ -> テーブルが複雑ゆえに、クエリも複雑になった

対策として、有識者によるレビュー、コーディング規約等の制約、大きなクエリの分割(責務の把握)、テーブル設計の最適化、等が上げられる。

18.ノーチェンジコンフィグ

コンフィグの設定は属人化しやすく、放置されることが多い。役割、意味を知り適切に管理することが大切。

□ コンフィグで管理できること
1.DBのパフォーマンス
2.DNのセキュリティー
3.DBの振る舞い -> トランザクションの分離など

□ コンフィグの管理はどうすべきか
1.Infrastructure as Code -> インフラをコードで管理するという考え方。Ansibleなどのプロビジョニングツールも有効
2.Databse as a Service -> RDSとかフルマネージドサービスを使うことによって、高品質に設定されたDBを利用できる

19.塩漬けバージョン

バージョンアップは文化。目先の運用を優先してバージョンアップを怠るべきではない。

□ バージョンアップをするための順序
1. バージョンアップの方法の決定
2. コンフィグの確認
3. リハーサル
4. バージョンアップ作業

20.フレームワーク依存症

フレームワークは開発効率の向上という点で有益である一方、テーブルをフレームワークに依存した設計にすることでアンチパターンの温床にもなり得る。

□フレームワーク依存によるデメリット

  • スロークエリの発行元を追うことが難しい。
  • DB側の機能やデータの整合性が失われる。

以下、アンチパターンへの対策

  • ORMが発行するSQLを意識する(RDB用に最適化されたものでないこともある)。
  • DOAに基づき、Modelの中でテータを取り出すそうと取り出したデータを加工するそうを分ける。 -> いずれにせよ、メリットとデメリットのトレードオフを意識して設計をするのが大切。

参考)紹介されていたアンチパターン
-> こうゆうのがあるんだなで塩づけ

  • マジックビーンズ
  • STI
  • ポリモーフィックス

感想

冒頭にも書いたが、知識以上に、DBに向き合うため際に姿勢について大変参考になった。
多くの場合、アンチパターンは知識不足、その場しのぎの設計によって起きる。知識不足の剛腕とはほんとよく言ったものだ。
これはアプリケーションにおいてもそうだと思うが、良い設計をするためには、仕様から目を逸らさずに正面から向き合い続ける必要がある。DBにおいても、実装優先の設計では自分たちの首を絞めることになり、何も知らずに任された後任者は尚のことしんどい思いをする。愚直に学び続けるは必須だろう。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vagrant+Docker+Rails+Nuxt.js+MySQL+SSL化

はじめに

ポートフォリオ作成まで、環境構築が辛すぎたのでその過程を書きました。
完全に全ての技術に対して初心者だったので、毎日絶望していました。

ポートフォリオのために快適な開発環境をまず作りたくて試行錯誤していました。
Docker for Macが重すぎ、しかもfrontendとbackendに分けて、
しかもNginxを使ってSSL化までする記事がなさすぎて絶望したので実験しながら作りました。

今後忘れないために備忘録として・・・。
とりあえずそれぞれHello World出来るまで。

こんな人へ

とりあえずサクサクっと開発環境をつくりたいぜ。
Dockerとかの知識はちょっとあるぜ。

これを読むとわかること/おおまかな流れ

  • Vagrant環境構築
  • Nuxt.js環境構築
  • Docker環境構築
  • nuxtとRails(APIモード)とMySQLの開発環境構築
  • Nginxの環境構築
  • SSL化(オレオレ証明書)

 環境

Mac OS
ruby:2.6.3
Rails 5.2.4.3

フォルダ構成

app
├─docker-compose.yml
├─mutagen.yml
├─Vagrantfile
├─back #Rails
| ├─Dockerfile
| ├─Gemfile
| └─Gemfile.lock
├─front #Nuxst.js
| └─Dockerfile
├─nginx #nginx
| └─nginx.conf
└─ssl #nginxに読み込ませる鍵
  ├─server.crt
  ├─server.csr
  └─server.key

Vagrant

おおまかな流れ

  • VirtualBoxをinstall
  • Vagrantをinstall
  • Vagrantfile作成
  • Mutagenをinstall
  • VagrantにSSH接続する

Vagrant/Virtualboxダウンロード

https://www.vagrantup.com/
https://www.virtualbox.org/

brew cask install virtualbox
brew cask install vagrant

VagrantBox

VagrantBox(OS)のダウンロード
今回はubuntuで構築します。

vagrant box add ubuntu/xenial64
vagrant box list #確認しておきましょう

Vagrant plugin

vagrant plugin install vagrant-disksize vagrant-hostsupdater vagrant-mutagen vagrant-docker-compose

Vagrantセットアップ

作業フォルダの作成(名前はなんでも)

mkdir app
cd app

Vagrantfileの作成

/app
vagrant init ubuntu/xenial64

Vagrantfileを以下の内容に書き換えてください。

/app/Vagrantfile
Vagrant.configure('2') do |config|
  config.vm.box = 'ubuntu/xenial64'

  config.vm.hostname = 'app' #任意のホストネーム

  config.vm.network :private_network, ip: '192.168.50.10' #ここがVagrant内にアクセスするIP

  config.vm.provider :virtualbox do |vb|
    vb.gui = false
    vb.cpus = 4 #割り当てるCPUコア数
    vb.memory = 4096 #割り当てるメモリ
    vb.customize ['modifyvm', :id, '--natdnsproxy1', 'off']
    vb.customize ['modifyvm', :id, '--natdnshostresolver1', 'off']
  end

  config.disksize.size = '30GB' #ディスクサイズ
  config.mutagen.orchestrate = true

  config.vm.synced_folder './', '/home/vagrant/app', type: "rsync",
    rsync_auto: true,
    rsync__exclude: ['.git/', 'node_modules/', 'log/', 'tmp/']

  config.vm.provision :docker, run: 'always'
  config.vm.provision :docker_compose
end

MutagenのInstall

ファイル同期ソフトであるmutagenのインストールをします。
https://mutagen.io/

brew install mutagen-io/mutagen/mutagen
/app
touch mutagen.yml
vim mutagen.yml
/app/mutagen.yml
sync:
  app:
    mode: "two-way-resolved"
    alpha: "./"
    beta: "app:/home/vagrant/app" #同期させるフォルダ/Vagrantfileで設定したホストネームと合わせてください。
    ignore:
      vcs: true
      paths:
        - "/node_modules"
        - "/log"
        - "/tmp"

Vagrant起動

/app
vagrant up

はじめてVirtualBoxを入れたタイミングで「セキュリティとプライバシー」で弾かれるそうなのでダウンロードしたアプリケーションの許可をして再度upしてください。

: No such file or directory @ rb_sysopen - /Users/hoge/.ssh/config (Errno::ENOENT)

また、こんな感じのエラーが出たら、

touch /Users/hoge/.ssh/config

.ssh/configを作成してあげましょう。

仮想環境にssh接続

vagrant ssh
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-179-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

 * MicroK8s passes 9 million downloads. Thank you to all our contributors!

     https://microk8s.io/

2 packages can be updated.
0 updates are security updates.

New release '18.04.4 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


Last login: Sat May 30 12:32:45 2020 from 10.0.2.2

こんな感じのログが出るとSSH接続完了です。

ちなみに

vagrant halt

も覚えておくと良いです。
同期されてねー!とか思ったらやります。vagrant環境の破棄です。(Vagrantfileが有る限りupで再度作成できるので安心)

参考記事

Docker For Macが遅い:対策の実験
Vagrantを使う「Mac最速のDocker環境」を初心者向けに解説【遅いMac for Dockerを卒業】
vagrantとDockerで環境構築をした
Docker for MacからVagrant + CoreOSに切り替えた

Docker

Dockerfile

/front/Dockerfile
FROM node:12.5.0-alpine

ENV HOME="/app" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

WORKDIR ${HOME}

RUN apk update && \
    apk upgrade && \
    npm install -g n && \
    yarn install &&\
    rm -rf /var/cache/apk/* s

ENV HOST 0.0.0.0

おそらく最低限の構成(もっとシンプルにできたら教えてください。)
npmとyarnをinstallしてます。VagrantなのでIPをバインディング
以下参照
rails s -b 0.0.0.0 のオプション-bの意味/バインディングアドレスとは

/back/Dockerfile
FROM ruby:2.6.3-alpine3.10

#おまじない的
ENV RUNTIME_PACKAGES="linux-headers libxml2-dev make gcc libc-dev nodejs tzdata mysql-dev mysql-client yarn" \
    DEV_PACKAGES="build-base curl-dev" \
    HOME="/app" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

WORKDIR ${HOME} #ワークスペースの確保

ADD Gemfile ${HOME}/Gemfile #GemfileをDocker内にコピー
ADD Gemfile.lock ${HOME}/Gemfile.lock #Gemfile.lockをDocker内にコピー

RUN apk update && \
    apk upgrade && \
    apk add --update --no-cache ${RUNTIME_PACKAGES} && \
    apk add --update --virtual build-dependencies --no-cache ${DEV_PACKAGES} && \
    bundle install -j4 && \
    apk del build-dependencies && \
    rm -rf /usr/local/bundle/cache/* \
    /usr/local/share/.cache/* \
    /var/cache/* \
    /tmp/* \
    /usr/lib/mysqld* \
    /usr/bin/mysql*

ADD . ${HOME}

ところどころわからないところがありますが・・・。ご存知の方コメントくださると有り難いです。

/app/docker-compose.yml
version: "3"

services:
  db:
    image: mysql:5.7
    env_file:
      - ./back/environments/db.env
    restart: always
    volumes:
      - db-data:/var/lib/mysql:cached

  back:
    build: back/
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    env_file:
      - ./back/environments/db.env
    volumes:
      - ./back:/app:cached
    depends_on:
      - db
    ports:
      - 3000:3000

  front:
    build: front/
    command: yarn run dev
    volumes:
      - ./front:/app:cached
    ports:
      - 8080:3000
    depends_on:
      - back

  nginx:
    image: nginx
    ports:
      - 443:443
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./ssl/server.crt:/etc/nginx/ssl/server.crt
      - ./ssl/server.key:/etc/nginx/ssl/server.key


volumes:
  public-data:
  tmp-data:
  log-data:
  db-data:

Gemfile

/app/back/Gemfile
source 'https://rubygems.org'
gem 'rails', '~>5'
/app/back
touch Gemfile.lock

docker-composeを使ってbuild

vagrant内/app
docker-compose build

Nuxt.js

/app
$ docker-compose run --rm front npx create-nuxt-app

? Project name                   --> sample   # アプリ名
? Project description            --> sample    # アプリの説明
? Author name                    --> me        # アプリの作成者
? Choose the package manager     --> Npm
? Choose UI framework            --> None
? Choose custom server framework --> None
? Choose Nuxt.js modules         --> Axios
? Choose linting tools           --> -
? Choose test framework          --> None
? Choose rendering mode          --> Universal (SSR)
Vagrant内/app
docker-compose up front

http://192.168.50.10:8080にアクセスしてHello World!

参考記事

Nuxt.js + Rails(API) on DockerのHello Worldするべ!

Rails

今回のRailsはAPIモードで作成するので、 --api引数をば

/app
docker-compose run --rm back rails new . -f -d mysql --api
back/config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch('MYSQL_USER') { 'root' } %>
  password: <%= ENV.fetch('MYSQL_PASSWORD') { 'password' } %>
  host: db

development:
  <<: *default
  database: webapp_development

test:
  <<: *default
  database: webapp_test

DBの環境変数のファイルを作ります。

/app/back
mkdir environments
/app/back/environments
vim db.env
/app/back/environments/db.env
MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_USER=username
MYSQL_PASSWORD=userpassword

DB権限設定をするためのSQLを作ります。

/app/back/db
vim grant_user.sql
grant_user.sql
GRANT ALL PRIVILEGES ON *.* TO 'username'@'%';
FLUSH PRIVILEGES;

DBへクエリを流し込む

Vagrant内/app
docker-compose build
docker-compose up
Vagrant内/app
docker-compose ps

ちゃんとDBが動いている状態を確認

Vagrant内/app
docker-compose exec db mysql -u root -p -e"$(cat back/db/grant_user.sql)"

先ほど設定したrootpasswordを入力

Vagrant内/app
docker-compose exec db mysql -u username -p -e"show grants;"

権限の確認
先ほど設定したuserpasswordを入力

+------------------------------------------------+
| Grants for user_name@%                         |
+------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'username'@'%' |
+------------------------------------------------+

こうなればOK

Vagrant内/app
docker-compose exec app rails db:create

http://192.168.50.10:3000にアクセスしてHello World!

参考記事

Docker + Rails + Puma + Nginx + MySQL

Nginx

app/nginx/nginx.conf
worker_processes auto;

events {
  worker_connections 1024;
}

http {
  server {
    listen 443  ssl;
    ssl_certificate     /etc/nginx/ssl/server.crt; #SSL証明書
    ssl_certificate_key /etc/nginx/ssl/server.key; #秘密鍵

    proxy_set_header    Host    $host;
    proxy_set_header    X-Real-IP    $remote_addr;
    proxy_set_header    X-Forwarded-Host       $host;
    proxy_set_header    X-Forwarded-Server    $host;
    proxy_set_header    X-Forwarded-For    $proxy_add_x_forwarded_for;

    location /api/ {
      proxy_pass http://192.168.50.10:3000;
      proxy_buffering off;
    }

    location / {
      proxy_pass http://192.168.50.10:8091;
      proxy_buffering off;
    }
  }
}

オレオレ証明書の作成

app/
#秘密鍵の作成
sudo openssl genrsa -out app/ssl/server.key 2048
#CSR(証明書署名要求)の作成
sudo openssl req -new -key app/ssl/server.key -out app/ssl/server.csr
#CRT(SSLサーバ証明書)の作成
sudo openssl x509 -days 3650 -req -signkey app/ssl/server.key -in app/ssl/server.csr -out app/ssl/server.crt 
Vagrant内/app
docker-conpose up

https://192.168.50.10:8080にアクセスしてHello World!

Chromeで警告が出る場合

自分で発行したサーバー証明書(オレオレ証明書)をブラウザに登録する方法
こちらを参考に、ブラウザに証明書を登録してください。

参考記事

Nuxt.jsでlocalhostをSSL化する方法

最後に

かなり駆け足・長文になってしまい申し訳ありません。
読んでくださってありがとうございます。
とりあえずの備忘録として書きましたので、間違っていたらコメントで教えていただけると有り難いです。

Vagrant環境内で、Nuxt.jsとRails、しかもDockerで構築してNginxでリッスン、しかもSSL化とかいう記事は無くて
それぞれの記事をつなぎ合わせてようやく完成しました。

Docker、Vagrant、Nginx、Rails、Nuxt.jsに関しては完全に初心者です。
初めて作成するにはかなり無謀なチャレンジでした・・・。

優しいマサカリ投げていただけると嬉しいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む