Rails・クラウド初学者が初めてGoogle App Engine（GAE）スタンダード環境にRails7+MySQLアプリをデプロイするまでの顛末

初投稿です。Rails で本格的なWebアプリを作れるようになろうと独学中です。

アイデアが一定程度Railsアプリ（Rails7+MySQL）の形になってきたのでいざ動かさん、と
構築が簡単なようで費用負担も許容範囲に収まりそうな Google App Engine のスタンダード環境であれやこれや調べながら試行錯誤したのですが、
動くようになるまでかなり苦労した――元々インフラ周りが特に苦手なのが大きいですが――ので顛末を書き残しておきます。

## ローカル環境
ローカル環境はWindows 10 Pro、Ruby3.2.2、Rails7.1.2。
Docker 等の仮想環境や rbenv[^1] 等のバージョン切替などは特に入れていません。

## 基本手順

概ね公式ドキュメントや下記参考記事に則ったものなので詳細は割愛します。
その通りやっただけでは解決しなかった問題とその対処を次章以降で詳細に記します。
※Cloud SDK はインストール・セットアップ済前提

参考記事

https://mintaku-blog.net/gae-rails/

https://mintaku-blog.net/gae-rails-env/

https://qiita.com/junjis0203/items/c32b641946f3fb891069#rails%E3%81%AE%E5%8B%95%E3%81%8B%E3%81%97%E6%96%B9

https://qiita.com/hypermkt/items/213e59bedb6689fc862f

### ① [Google Cloud の管理画面](https://console.cloud.google.com/welcome)から以下を作成

「➡」以下の値を全て控えておく

- （Google Cloud のアカウント自体を新規に作成した場合のみ） **[請求先アカウント](https://console.cloud.google.com/billing)**[^2]
- **プロジェクト**（「[リソースの管理](https://console.cloud.google.com/cloud-resource-manager)」より）　➡プロジェクトID
- **[Cloud SQL](https://console.cloud.google.com/storage)**の**インスタンス**＆**ユーザー**＆**データベース**　➡ユーザ名/パス/接続名
  接続は「*プライベートIP*」（ネットワーク：*default*）を選択、その他設定項目は適当に[^3]
- **サービスアカウント**＆**keyfile**（[IAMと管理](https://console.cloud.google.com/iam-admin)＞[サービスアカウント](https://console.cloud.google.com/iam-admin/serviceaccounts)）
  ロールは *Cloud Storage＞ストレージ管理者*、*Cloud SQL＞Cloud SQLクライアント*（phpMyAdmin用）
  サービスアカウントが作れたら選択して『キー』タブ＞『鍵を追加』＞『新しい鍵を作成』＞『JSON』選択して『作成』を実行、
  DLしたjsonファイル＝keyfileをプロジェクト内に適宜配置　➡そのファイルパス
- **[Cloud Storage のバケット](https://console.cloud.google.com/storage/browser)**
  設定項目は適当に　➡バケット名
- **VPCコネクタ**（[「サーバーレス VPC アクセス」](https://console.cloud.google.com/networking/connectors)より）
    カスタムIP範囲：*10.8.0.0*(/28)、ネットワークは「*default*」でOK　➡コネクタ名

SQLインスタンス/VPCコネクタ作成時にAPI有効化が複数要求されるので全て有効化する

:::note info
リージョンは後述の AppEngine（`$ app create`で作成時に入力）含め全て揃える
安くて比較的近いのは台湾（asia-east1）　レイテンシ重視なら日本国内（asia-northeast1/2）、価格重視ならオレゴン（us-west1）等でも
:::
:::note warn
2024/7/8追記：
Cloud SQLの接続を「プライベートIP」とする前提で書いていますが、それに必要なVPCコネクタが少々金食い虫[^4]なので
セキュリティ面等に問題がなければ VPCコネクタが不要な「パブリックIP」の方が費用面ではよさそうです。
現時点でまだ試していないので、試した後に別途記事にしたいと思います。
  
どうしてもプライベートIPでないといけない場合、開発中の費用を抑えるには利用（終了）時にVPCコネクタを都度作成（・削除）する必要があります。（参考記事は下記）
これとセットでCloud SQLインスタンスの開始/停止も利用（終了）時に都度行うようにすれば、最低限のコスト（非利用時￥10/日程度）で開発用環境の維持が可能です。
:::

https://qiita.com/Koji_Hataya/items/8b7f1e4d205f2453f459

### ② credentails を作成
①で取得したDBのユーザー/PW/接続名や、シークレットキー（`$ rails secret` で取得）といった秘匿情報を
下記コマンドで本番環境用 credentials ファイルに登録します。

```
$ EDITOR="vi" rails credentials:edit -e production
```

:::note info
VScodeで編集したい場合は `EDITOR="vi"` のところを `EDITOR="code --wait"` とします。（参考記事は下記）
:::

https://qiita.com/zaki_zaki/items/dfc83a1fcd7dbc07af6b

編集結果はこんな感じになると思います。

```yaml:config/credentials/production.yml(.enc)
db:
  user: your_db_user_name
  pass: your_db_password
  socket: /cloudsql/your-project-name:region-name:your-db-name
secret_key_base: xxxxxxxx

# メール送信が必要ならその設定等も
```

:::note warn
2024/7/8追記：
当初記載では秘匿情報の管理手法が曖昧だったため、rails7.1以降で推奨の credentials での管理を前提とした記載に置き換えました
:::

> ※この辺の詳細はGAEの本筋からは外れるので詳細は credentials が主題の記事を参照願います。

### ③ app.yaml を作成

インスタンスの種類・性能、`entrypoint`（起動時コマンド）、VPCコネクタ名 等を指定
```yaml:app.yaml
# だいたいこんな感じになる

runtime: ruby32
env: standard
instance_class: F1

entrypoint:
  bundle exec rackup --port $PORT

env_variables:  # 詳細後述
  RAILS_SERVE_STATIC_FILES: true
  PIDFILE: "/tmp/puma.pid"
vpc_access_connector:
  name: <VPCコネクタ名>
```

### ④ Cloud Storage 設定記述
`config/storage.yml` に プロジェクト名・バケット名・①で取得した *keyfile のパス* を記載
```yaml:config/storage.yml
gcp:
  service: GCS
  project: "Your Project Name"
  credentials: <%= Rails.root.join("your_keyfile_path.json") %>
  bucket: your-storage-bucket-name
```

使用ストレージ（`config/environments/production.rb` の `active_storage.service`）を
storage.yml で指定した名称（上記の例だと **:gcp**）に設定
```ruby:config/environments/production.rb
config.active_storage.service = :gcp
```

*keyfile* は秘匿情報なので `.gitignore` へも登録

### ⑤ Gemfile に必要なgemを追加
```ruby:Gemfile
gem "google-cloud-storage"
gem "appengine"  # migration を app.yaml から行わせればなくても事足りる（詳細後述）
```

### ⑥ .gcloudignore を作成
デプロイ対象/対象外ファイルを指定
```:.gcloudignore
.gcloudignore
#!include:.gitignore  # .gitignore の内容取込み
.git
.gitignore
test/*

# 以下git管理外だがデプロイには必要なファイル/ディレクトリ（「!」で .gitignore 設定を打消し）
!/config/credentials/*.key  # ②で生成した credentials のキーファイル
!storage_credentials.json  # ①で取得・④で設定した Cloud Storage の keyfile
!/public/assets  # 詳細後述
```

### ⑦ 下記コマンドを逐次実行
```shell
# Gemfile に追加したパッケージのインストール
$ bundle install

# assets のプリコンパイル
# config.assets.compile = true なら不要だが本番では非推奨（詳細後述）
$ rails assets:precompile

# gcloud プロジェクトのセット
$ gcloud auth application-default set-quota-project <PROJECT ID>
$ gcloud config set project <PROJECT ID>

# 上記の手順中では有効化されない必要APIの有効化
$ gcloud services enable sqladmin.googleapis.com
$ gcloud services enable serviceusage.googleapis.com

# AppEngine のサービス（アプリ）を作成し初回デプロイ
$ gcloud app create
$ gcloud app deploy

# IAMポリシーの追加　※コロン後に空白入れないこと
$ gcloud projects add-iam-policy-binding <PROJECT ID> --member=serviceAccount:<PROJECT番号>@cloudbuild.gserviceaccount.com --role=roles/editor
# <PROJECT番号>は $ gcloud projects list で確認可能
```

:::note info
API有効化やリージョン選択等要求されたら応えること
IAMの設定はデプロイ前だとエラーになるのでこの順番で
:::

### ⑧ phpMyAdmin[^5] セットアップ

[公式チュートリアル](https://cloud.google.com/sql/docs/mysql/phpmyadmin-on-app-engine?hl=ja)は MySQL5.7以前・php5.5以前・phpMyAdmin4.9 以前の場合しかないので下記記事を参考に（これで MySQL8.0 でも行けました）

https://qiita.com/shobota/items/2dfc0f017d6ef7a1193a#php74phpmyadmin51x%E3%81%AE%E5%A0%B4%E5%90%88

## マイグレーションが実行できない（500エラーになる）

デプロイ＝ソースを転送後マイグレーションを appegine gem の機能を利用して
ローカルから下記コマンドで行う――というのはどの手順書にもありますが、
```shell
$ bundle exec rake appengine:exec -- bundle exec rake db:migrate
```
これが通らず下記のような感じの500エラーが返ってきてしまいます。

```
---------- CLEANUP ----------
Deleting the following versions:
 - your-project-id/default/appengine-exec-YYYYMMDDHHmmss
Deleting [default/appengine-exec-YYYYMMDDHHmmss]...done.
rake aborted!
JSON::ParserError: unexpected token at '<html><head> (JSON::ParserError)
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>500 Server Error</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Server Error</h1>
<h2>The server encountered an error and could not complete your request.<p>Please try again in 30 seconds.</h2>
<h2></h2>
</body></html>
'
```

インスタンスの性能を絞っているせいもあるのか、コールドスタート時（＝非スタンバイ状態でリクエストが投げられた際）は
アプリの起動（＝`app.yaml` の `entrypoint` に指定したコマンドの実行）から行われるためレスポンスが大幅に遅くなります。
マイグレーション直後もアプリの再起動が必要なため同様で、マイグレーションコマンドの後処理でサイトにアクセスする際に時間がかかって500を吐いているのかな…と想像しています。（全然見当違いかもしれませんが）

上記の想像が間違っていなければ、起動速度の大幅な改善しか解決の手立てがなくインスタンスの性能を上げるほかなさそうな気がしますが試していません[^6]。

対症療法としてマイグレーションは `$ rake appengine:exec` から行うのでなく
`app.yaml` の `entrypoint` を以下のように指定して起動時の前処理で実行することで
ひとまず見えている範囲ではエラーや警告はなく動かせています。
```yaml:app.yaml
entrypoint:
  bundle exec rake db:migrate && bundle exec rackup --port $PORT
```

参考

https://github.com/GoogleCloudPlatform/appengine-ruby/issues/45

## pidファイルが作れず 502 Bad Gateway になる

デプロイしても Nginx の 502 Bad Gateway 表示になりアプリのページが表示できないのでログを確認したところ
```
bundler: failed to load command: rackup (/workspace/.bundle/gems/ruby/3.2.0/bin/rackup)
/layers/google.ruby.bundle/gems/.bundle/gems/ruby/3.2.0/gems/puma-6.4.0/lib/puma/launcher.rb:312:in `write': No such file or directory @ rb_sysopen - tmp/pids/server.pid (Errno::ENOENT)
```
と `tmp/pids/server.pid` ファイルがなく書き込みができないと怒られていました。

AppEngine でも Puma サーバで Rails アプリを動かす場合 pidファイルは `config/puma.rb` で指定したパスに作成されます。
`$ rails new` 以降特に弄っていなければ下記のように  
`PIDFILE` 環境変数が設定されていればその値、未設定ならアプリケーションディレクトリ配下の `tmp/pids/server.pid` になっているかと思います。
```ruby:config/puma.rb
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }  # ◆
```

AppEngine ではアプリケーションにファイル・フォルダ作成権限があるのはルートの `/tmp` のみと何かで見た気がするので
その通りならば ちゃんと裏は取れていないのですが アプリケーションディレクトリ配下の `tmp/pids/` が作成できないため生じていると思われます。

対処法として考えられるのは以下３つ（1、3は動作確認済）。
後の方ほど強引度が上がっていきます…　アリなのかタブーなのかはよく分かりません🙄

1. `PIDFILE` 環境変数の設定
  環境変数の設定（`app.yaml` の `env_variables`）で `PIDFILE` に書込み可能なパス[^7]を指定
  
1. `config/puma.rb` の `pidfile` を書き換える
  `PIDFILE` 未設定時の値（上記◆印の `{ }` 内）を書込み可能なパス[^7]に変更
  
1. アプリケーション配下の `tmp/pids` をデプロイ時に `mkdir` してしまう
  前述の migration の件と同じ考え方で、`app.yaml` の `entrypoint` に `mkdir -p tmp/pids && ` を前付けしてもフォルダは作れて動かせます。
  アプリから作れないならデプロイ時のコマンドで作ってしまえ、という（

参考

https://www.appsloveworld.com/ruby-on-rails/100/96/error-while-deploying-rails-6-app-to-google-cloud-platform-app-engine

# assets が読み込めず 503（Service Temporarily Unavailable）になる

rails の標準出力に下記、もしくは類するエラーが出ている場合は
```
ActionView::Template::Error (The asset "application.css" is not present in the asset pipeline.)
```
precompile された assets、即ち `public` 配下の静的ファイルを参照できていないので
参照する設定になっているかどうか、そしてその対象が正しく配置できているか確認が必要です。

前者：設定については `config/environment/production.rb` 内の `config.public_file_server.enabled` が `true` になるような対処が必要です。
デフォルトでは `ENV["RAILS_SERVE_STATIC_FILES"].present?` になっているはずで、それをそのまま true に書き換えてももちろん動きはしますが
見ての通り `RAILS_SERVE_STATIC_FILES` 環境変数が存在していれば `true` になる仕組みなので `app.yaml` の `env_variables` で設定してやります（存在さえしていれば `present?` が `true` になるので値は何でも可）。
```yaml:app.yaml
env_variables:
  RAILS_SERVE_STATIC_FILES: true
```
https://qiita.com/aiandrox/items/408724ab8a4482fb5873

ちなみにHerokuや、AppEngineでもフレキシブル環境なら明示的に設定しなくともランタイムで既に設定されているそうです。

ここまでは言及している記事が上記以外にも多数ありますが、私の場合もう一点ハマりまして
`.gcloudignore` の設定不備で `public/assets` がデプロイ時に転送されていませんでした。
`public/assets` は通常git管理しないので `$ rails new` 時点から `.gitignore` に列挙されていますが
その内容を `.gcloudignore` にもまるっと取り込んでいる場合は、デプロイの対象にはなってくれないと困るので除外を打ち消す設定を追加する必要があります。
それになかなか気付きませんでした。。（assets周りの理解も浅かったことを痛感）
具体的には .gcloudignore を下記のように記述します。
```.gcloudignore
#!include:.gitignore  # ←これで .gitignore の内容をまるっと取り込んでいる場合は

!/public/assets       # ←この記載を入れる
```

`$ gcloud meta list-files-for-upload` でデプロイ対象ファイルのリストが出せるので
その中に public/assets も含まれていることを確認するとよいんじゃないかと思います。

https://stackoverflow.com/questions/40805182/see-the-files-that-will-be-deploy-to-google-appengine

なお `.gcloudignore` の設定は正当で `public/assets` がデプロイ対象になっていても
`$ rails assets:precompile` をローカルで行っていないとそもそも静的ファイルが作られず同様にエラーになります。
実験のため一旦ローカルの precompile した assets を `$ rails assets:clobber && rails assets:clean` で削除し再デプロイしたらエラーが再現できました。

https://qiita.com/GandT/items/4b3701a6ca51ff84370c

またプリコンパイルをデプロイ後 AppEngine 上で行えないか、`$ bundle exec rake appengine:exec -- bundle exec rake assets:precompile` とやってみたり
前述の migration 出来ない問題と同じ発想で `entrypoint` に追加してみたりといった実験も行いましたがいずれもダメでした。

ちなみに assets が存在しなかったら動的に生成（コンパイル）するという設定が `config.assets.compile = true` にすればできてしまうので
上記2点の設定や `assets:precompile` の実施有無など関係なくこれでエラー回避できることも確認済です。
ただ基本的にこの設定は開発環境用で、assets をキャッシュするので余計なメモリを食ったりそのキャッシュを当てに行く処理も走ったりでパフォーマンスが落ちるので本番環境ではタブーとのこと。
AppEngine だと費用にも影響があるかもしれないので、よほどパフォーマンスも出費も気にしない場合以外はやめておいた方がよさそうです。

https://stackoverflow.com/questions/8821864/config-assets-compile-true-in-rails-production-why-not

# その他こまごま

### Gemfile の Ruby バージョン指定

例えば Ruby3.2.2 で開発していて、Gemfile にもそのバージョンを
下記のようにマイナーバージョンまで細かく指定していると
```ruby:Gemfile
ruby "3.2.2"
```
`$ gcloud app deploy` 時に以下のように怒られて失敗します。
```
Your Gemfile cannot restrict the Ruby version to "3.2.2". Consider instead:  ruby '~> 3.2.0'
```

これはもうこの警告にある通り、下記のように書くことで通せます。
```ruby:Gemfile
ruby "~> 3.2.0"
```

何もその程度のことでエラーで落とさなくても・・・と思いましたが、
恐らく背景としては AppEngine runtime のラインナップがマイナーver.ごとに１つ（最新版?）でパッチver.全部を取り揃えてはおらず
厳格に指定されるとその通りのバージョンの runtime がない、ということになり得るので厳格なチェックにしているものと想像します。

### CloudSQL の接続がプライベートIPのみの場合の phpMyAdmin 設定
CloudSQL インスタンスの接続をプライベートIPのみとしている場合、phpMyAdmin のデプロイ設定ファイル（`app.yaml`）にもVPCコネクタの設定を入れる必要があります。
設定は rails アプリ側のそれと全く同じ記述でOKです（下記）。
```yaml:app.yaml
vpc_access_connector:
  name: <コネクタ名>
```

この設定がない場合、phpMyAdmin のログイン画面は出ますが正しいユーザーID/パスワードを入れても `mysqli::real_connect(): (HY000/2002): Connection refused` でログインできません（下記）。
![phpMyAdminログインエラー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688478/e9e9f65f-bb36-4fb3-a6ed-69bf22e610de.png)

当たり前といえば当たり前なのですが忘れがちなのでもしこの症状があれば要確認です。

https://cloud.google.com/knowledge/kb/connecting-to-private-ip-enabled-instances-from-app-engine-000004515

- - -

### 以下調査不能
改めてナレッジをまとめる際に再現等確認できたものは以上ですが、初回試行時は他にもかなーりあれこれ躓いてました。。 ~~（インフラ苦ｔ~~
以下記録が残ってなく裏も取れてないのであやふやな記述しかできず恐縮ですが記憶にある範囲で躓いた内容とその対処を記しておきます。

##### gcloud CLI（Cloud SDK） が古い問題

そんな人はあまりいないとは思うのですが、私の手元では gcloud CLI がだいぶ前にインストール・セットアップしたままでかなり古かったようで最初のうちの失敗はそれも原因にあったようです。
当てはまるなら下記をまず実行しておきましょう。
```
$ gcloud components update
```

> ※必要な状況なら実行するよう促されるので、エラーや警告をマメに見ている方なら適用済だとは思います

##### appengine gem のバージョン

最初 `Gemfile` にバージョン指定を記載せず `$ bundle install` したところ依存関係の影響?かどうやらかなり古いバージョンが入ってしまったようで
それ起因っぽいエラーもあったので下記のようにバージョン指定して `$ bundle install` しなおした記憶があります。
```ruby:Gemfile
gem "appengine", "~> 0.7.0"  # 実践時点の最新バージョン
```
ただそもそもこのgem、AppEngine にデプロイしたアプリのrakeタスクをローカルから実行するときに必要なだけなので、
前述のようにマイグレーションの実行コマンドを `app.yaml` に仕込んでしまえばなくても困ることはあまりなさそうです。

##### `tmp/sockets`, `app/assets/images` がないと怒られる

デプロイのトライ＆エラーを繰り返している最中、前述のpidファイルの問題と同じような事象がこれらのディレクトリでも起きたことがありました。（但し詳細なエラー・事象は記録がなく再現もできず不明）

`pidfile` 問題の対処法3.のように一度 `entrypoint` に `mkdir -p` を入れて強引に解決?しましたが
その後その `mkdir` を削除しても（そしてデプロイファイルの中間保存を削除し再度全アップロードしても：その手法は後述）問題なくデプロイできています。
当初の失敗はその際 実は `assets:precompile` に失敗していてそれが原因だったとか？などと考えたりもしますが `assets/image` はともかく `sockets` は関係ないでしょうし詳細は謎のままです。。[^8]
もし何がしか知見をお持ちの方おられましたら補足頂けますと幸いです。

## おまけ

#### ファイル名間違え

デプロイ対象外ファイルの指定を `.gcloudignore` ファイルで行いますが、なんか 'ignore' をtypoする手癖があるらしく（gitignoreもよくgitig **'o'** noreになってる）
ファイル名が .gcloudig **'o'** nore になっていたのに全然気付かなかったおかげで対象除外が全然効かないばかりか `.gitignore` の反映（取込み）すらできていないため莫大な数のファイルをアップロードする羽目になっていました。。
それでも Rails7 はファイル数が抑えられているので何千ファイルで収まりますが、アレコレ試している最中に一度 Rails6 に落とたりもしてみた際は AppEngine のデプロイファイル数上限（一万）に抵触してしまいデプロイできませんでした。😂

実際には `.gitignore` で無視するようなファイルの内転送が必要なのは前述の `public/assets` くらいで
それ以外は殆ど不要（動かすのに必要なものでも元々 AppEngine の runtime に入っているか、コンテナ立ち上げ時に bundler で構築される）だし
テストコードとかも普通は不要なはずなので `test` ディレクトリなんかもまるっと除外してしまえば 大規模なシステムでない限り数百のオーダーで収まるはずです。

#### デプロイするファイルの転送経路

ちなみにデプロイされるファイルは、AppEngine とは別にこれ用に自動で作られる Cloud Storage の専用バケットに格納してからデプロイし
2回目以降はそれと比較して変更が生じたファイルだけ専用バケットにアップロード➡デプロイ、という仕組みになっているようです。

バケットの中身を削除してまるまるアップロードしなおしたい場合は下記で削除できます。
```
$ gcloud storage rm -r gs://staging.<project ID>.appspot.com/*
```

なお中身でなくバケット自体を削除してしまうと悲惨なことになるので絶対にやらないようにしましょう。
運がよければ `$ gcloud beta app repair` で修復できますが（経験済）、ダメだったらプロジェクトから全て作り直すしかない・・・と思います[^9]。

#### エラーの詳細把握

以上のようにいろいろ躓きポイントがありかなり時間がかかりましたが、地味に一番時間を溶かしたのはそもそもエラーの詳細がどこに出るのか分かってなく
Google Cloud コンソールのログエクスプローラに全部出るもんだと思っていて（実際には `$ gcloud app logs tail` で標準出力を追わないと詳細が掴めない場合が多い）
具体的な情報がさっぱり得られない[^10]まま当てずっぽうで試行錯誤するしかなかった当初の状況でした。。　どれくらい溶かしたか恥ずかしくて書けないレベルです（）

いや、確かに `$ gcloud app deploy` した後にログを追うには
```
$ gcloud app logs tail -s <サービス名：通常は default>
```
してね、って言われるんですが、思い込みで試しもしないでログエクスプローラと同じ内容しか出てこないもんだと思い込んでいたので。。　思い込みﾎﾝﾄﾖｸﾅｲ

ただ逆に、場合によっては標準出力だけ追っても有用な情報に乏しくログエクスプローラの方を見ないと状況が把握できないこともあるようなので（どういう時だとそうなのかまだしっかり理解できていません。。）
勘所が掴めて来るまでは両方、というか手がかりがありそうなフシは片っ端から確認するのが大事なようです。（まあこれは言語とか環境とか関係なく全てについて言えることですね😅）

[^1]: そもそも rbenv は Windows には対応していないので仮想環境を入れない限り使えない
[^2]: 先に作っておかないと次のプロジェクト作成の際に課金が自動で有効にならない
[^3]: 最安構成にするなら Enterprise/サンドボックス/シングルゾーン/共有コア/HDD10GB
[^4]: バックで実質的にGCEを常時動かすため。当方の設定ではおよそ￥60/日かかっていた
[^5]: 普通 Rails はローカル SQLite、本番 PostgreSQL が定番ですが使い慣れたGUIクライアントのこいつを使いたかったので MySQL です。でもそういう需要って意外とあるのでは？
[^6]: お金もかかる？ちょこっと試すだけならそんなにかからない？
[^7]: `/tmp/puma.pid` とか。*/tmp/* で始まっていれば何でもOKなハズ
[^8]: 前述の assets 絡み `.gcloudignore` 不備も怪しいっちゃ怪しい
[^9]: 自動生成バケットの名が特殊で Cloud Storage のコンソールからは同じ名前のバケットが作れないため（どうにか作れる方法 or AppEngine 側のデプロイ用バケットを変更する方法がもしかしたらあるのかもしれませんが）
[^10]: `The request failed because the instance failed the readiness check.(503)` とか
`The request failed because the instance could not start successfully(500)` とか