現役高校生が水泳記録管理サービスを作った話/その3：Google Cloud編


# はじめに

この記事は、Qiita Advent Calendar 4日目の記事です。
以下の記事より、すべての記事をご覧になれます。

https://qiita.com/0_terarin_0/items/0f367210e2465f7772c9

# 筆者について

- 現在高校２年生
- 水泳部マネージャー
- 生徒会長
- とある団体の代表

# 本編

この記事では、本番同然の環境にまで持っていきテストするところまでを書きます。
まず前提として、AWSなどの他のサービスは使わずGoogle Cloudのみで完結させます。

## 計画

Google CloudおよびFirebaseの以下のサービスを利用しようと計画しました。

- Compute Enginge
- Cloud DNS
- Firebase Authentication
- Firestore

それぞれ採用に至った理由を以下に記します。

### Compute Engine

他のApp Engineなどを利用しようかとも思ったのですが、僕自身普段からLinuxを利用しているわけでもないので、勉強として一から構築するCompute Engineを利用してみることにしました。最初は、一番最安のE2-microを利用しようと考えていたのですが、後述するマシン性能の不足で最終的にはe2-smallを利用することになりました。

https://cloud.google.com/compute/vm-instance-pricing?hl=ja#e2_sharedcore_machine_types

### Cloud DNS

ドメインはGoogle Domainで取得したのですが、そのままGoogle DomainでDNS設定をいじるよりもCloud DNSで一つ纏めちゃった方が楽やなと思ってこちらを利用することにしました。お金がかかるといえ月数十円ですので、利便性の方を優先しました。

https://cloud.google.com/dns/docs/overview?hl=ja

### Firebase Authenication

前日の記事と一部被るところはありますが、将来的にネイティブアプリでのローンチを考えていた点、認証を完全に実装し切る自信がなかった点、できるだけ簡単にソーシャルログインを掲載したい点などからFirebase Authenicationを利用することにしました。ちなみに、本サービスではGoogle,Microsoft,Yahoo,GitHubでのログインをサポートしています。何よりも無料っていうのがいいですね！

https://firebase.google.com/docs/auth?hl=ja

### Firestore

こちらはRealtime Databaseという別のサービスとどちらを利用するか悩んだのですが、Raltime Databaseの優位性を活かせる条件にはなってないと考え、Firestoreを利用することにしました。

https://firebase.google.com/docs/database?hl=ja

## それぞれつまづいた点やこれやっとくべきっていう点

### e2-microのマシンパワー不足

昨日の記事から書き続けてるように、e2-microはマシンパワーが足りませんでした。試しにneofetchをインストールしただけでSSHが切断されるような有様でした。ということで、e2-microではなくe2-smallを利用することにしました。

### anyenvなどでのバージョン管理

実は一番最初はDjangoがきちんと動きませんでした。なんでやなんでやと思って考えると、自分のMacにインストールされているPythonのバージョンとCompute Engineのマシン上のPythonのバージョンに違うことに気づきました。そこで、anyenvをインストールしてバージョンを管理することを決めました。

https://github.com/anyenv/anyenv

### URL直打ち対応していない問題

すっかり忘れていたのですが、ReactはURLの直打ちにはデフォルトに対応してないことを思い出しました。なので、Expressを利用して管理することにしました。

https://expressjs.com/ja/

ちなみに、サービス本体のディレクトリは```/individual/```以下です。したがって、ビルド前に以下の内容を```package.json```に追加する必要があります。

```json:package.json
{
  "homepage": "/individual",
}
```

また、Expressの設定も必要です。

```javascript:/views/individual.js
//新しくファイルを作成
const path = require('path');
var express = require('express');
var router = express.Router();

router.use(express.static(path.join(__dirname, '../individual')));
router.get('/*', function (req, res, next) {
  res.sendFile(path.join(__dirname, "../individual/index.html"));
});

module.exports = router;
```

```javascript:/app.js
//追記する内容だけ記載しています。
var individualRouter = require('./routes/individual')
app.use('/individual/', individualRouter);
```

また、ビルドが完了したファイルはすべて```/individual/```配下に入れてあります。
また、僕の場合はルートに紹介ページを作成しましたのでそこに利用するページはページでまた上記と同じような設定をしています。

### Firestoreのルールどうする問題

最初僕自身とんでもない誤解をしていました。というのも、Firestoreでルールを変更してしまうとFirebase Admin SDKからアクセスしても設定が変更できなくなると。でも実際はそんなことがなくて、僕が利用しているFirebase Admin SDKは基本的にこのルールに沿うことはありません。以下にわかりやすく図示したいと思います。

```
*ルール関係なし
Backend Server => (Via Firebase Admin SDK) => Firestore

*ルールが適用される
Client => (Directly) => Firestore
```

僕が実装したかった内容は、「Firebase Authへのログインが初回ログインだった場合に限って、ユーザー用コレクションを一つ作成する。」というものでした。したがって、ルールには「Firebase Authにログインしている場合にのみ```/users```にのみ書き込みを許可する。」というものになります。これ以降は僕が参考にした以下の記事にお任せしたいと思います。

https://qiita.com/KosukeSaigusa/items/18217958c581eac9b245

### Nginxでのリバースプロキシ

今回はサブドメインごとにバックエンドとフロントエンドを分けています。

- ```www.sokfi.net```配下→フロントエンド
- ```api.sokfi.net```配下→バックエンド
- ```beta.sokfi.net```配下→検証用

したがって、それぞれVirtual Hostを利用してリバースプロキシを設定する必要があります。こちらに関しても以下の記事を参考にさせていただきました。

https://www.google.com/search?q=nginx+virtualhost&oq=nginx+virtualhost&sourceid=chrome&ie=UTF-8

また、SSLの設定もお忘れなきよう。

https://qiita.com/shin4488/items/8738e13b92143c88aab6

それに従って、セキュリティルールで80番と443番に穴を開ける必要もあります。こちらも忘れなきよう。

# 最後に

さあ、もうサービスローンチ手前となりました！このまま最終チェックを経てローンチ…のはずでしたが、最後に一山残っていました。ちょっとだけヒント！僕は元々EUのやり方が嫌いでしたが今回でキッパリ嫌いになりました！（やり方が嫌いなだけです、言うてることは理解はしてるつもり！！！）ということで、今後のアドカレ 23 の記事をお楽しみにしてください。

https://qiita.com/0_terarin_0/items/0f367210e2465f7772c9