Laravel6をGoogle App Engineで動かす

# TL;DR

GCPのApp EngineでLaravel6.8を動かしてみました。

下記のチュートリアルに手順が示されています。

https://cloud.google.com/community/tutorials/run-laravel-on-appengine-standard?hl=ja

# 準備

プロジェクトを作り、課金を有効にしましょう。
Cloud SDKをローカルマシンにインストールして、`gcloud`コマンドを使えるようにします。
`gcloud`で作成したプロジェクトを選択します。

https://cloud.google.com/sdk/docs/downloads-interactive?hl=ja

# Laravelのインストール

ToDoアプリを作るという前提でインストールします（実際にこの記事で作るまでには至りませんが:joy:）
インストールされるのは2020-01-02現在最新のLaravel6.8.0です。

```sh
$ composer create-project --prefer-dist laravel/laravel todo
$ cd todo
$ php artisan serve
```

ここまででブラウザで表示出来ることを確認します。

# App Engine用の変更

ここからApp Engineのための変更を加えていきます。

## `app.yaml`の作成

App Engineは設定ファイルの`app.yaml`が必要です。

```app.yaml 
runtime: php72

env_variables:
  ## Put production environment variables here.
  APP_KEY: YOUR_APP_KEY
  APP_STORAGE: /tmp
  VIEW_COMPILED_PATH: /tmp
  SESSION_DRIVER: cookie
```

## アプリケーションキーの更新

Laravelのアプリケーションキーを`app.yaml`に追加します。

```sh
$ sed -i '' "s#YOUR_APP_KEY#$(php artisan key:generate --show --no-ansi)#" app.yaml
```

## `bootstrap/app.php`の修正

App Engine用にストレージパスを変更します。

```bootstrap/app.php
/*
|--------------------------------------------------------------------------
| Set Storage Path
|--------------------------------------------------------------------------
|
| This script allows you to override the default storage location used by
| the  application.  You may set the APP_STORAGE environment variable
| in your .env file,  if not set the default location will be used
|
*/
$app->useStoragePath(env('APP_STORAGE', base_path() . '/storage'));
```

チュートリアルには`beyondcode/laravel-dump-server`の削除とありますが、
Laravel6では初めから`beyondcode/laravel-dump-server`は含まれていないので大丈夫です。

# デプロイ

```sh
$ gcloud app deploy
```

どのリージョンにデプロイするか聞かれるので、今回は`asia-northeast1`(東京)を選択。
デプロイが成功すると、以下のコマンドでブラウザが開きます。

```sh
$ gcloud app browse
```

<img width="1192" alt="スクリーンショット 2020-01-01 21.34.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123511/89ad103a-cdf9-5cbd-44ee-e2677c128631.png">

ここまででまずファーストステップ完了。

デプロイの際に`.gcloudignore`が生成されました。
これにはデプロイから除外するファイルを記述します。
確認すると`vendor`などが含まれています。
そこで`.gcloudignore`に`.env`を追加します。
環境変数は`app.yaml`で渡すほうがいいと思います。

# Cloud SQLの使用

次にデータベースを使えるように設定します。
まずCloud SQL for MySQLの第2世代インスタンスを作成します。

## Cloud SQL Proxy

次にローカルマシン上でCloud SQLへのマイグレーションを実行出来るように、Cloud SQL Proxyをインストールします。
`INSTANCE_CONNECTION_NAME`は作成したMySQLインスタンスのインスタンス接続名です。

https://cloud.google.com/sql/docs/mysql/quickstart-proxy-test?hl=ja

```sh
$ curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64
$ chmod +x cloud_sql_proxy
$ ./cloud_sql_proxy -instances=INSTANCE_CONNECTION_NAME=tcp:3306
```

## データベースの作成。

Cloud SQL Proxyを使えるようになったので`gcloud`コマンドでデータベースを作ります。
`YOUR_INSTANCE_NAME`はインスタンス名で、インスタンス接続名とは違います。
以下では`laravel-todo`というデータベースを作っています。

```sh
$ gcloud sql databases create laravel-todo --instance=YOUR_INSTANCE_NAME
```

## マイグレーション

セッションテーブルとキャッシュテーブルをマイグレーションします。
準備として、`.env`にパスワードなどを追加しておきましょう。

```sh
php artisan session:table
php artisan cache:table
php artisan migrate
```

これでプロキシ経由でマイグレーションが実行されます。

## デプロイ

再び`app.yaml`を編集します。
パスワードやインスタンス接続名などを書き換えてください。

```app.yaml
runtime: php72

env_variables:
  ## Put production environment variables here.
  APP_KEY: YOUR_APP_KEY
  APP_STORAGE: /tmp
  VIEW_COMPILED_PATH: /tmp
  CACHE_DRIVER: database
  SESSION_DRIVER: database
  ## Set these environment variables according to your CloudSQL configuration.
  DB_DATABASE: YOUR_DB_DATABASE
  DB_USERNAME: YOUR_DB_USERNAME
  DB_PASSWORD: YOUR_DB_PASSWORD
  DB_SOCKET: "/cloudsql/YOUR_CONNECTION_NAME"
```

```sh
$ gcloud app deploy
```

ブラウザで確認すると、エラーとなってしまいました。
エラーは以下のコマンドでリアルタイムに確認出来ます。

```sh
$ gcloud app logs tail -s default
```

いろいろ調べたんですが、これという原因はわからず、確実にエラーが解消されるのはStorageにあるコンテナイメージのバケットを削除してからデプロイし直すことでした。対処方法がこれで本当にいいのかわかりませんが。。。
ブラウザでアクセスした後にデータベースの`sessions`テーブルを確認したら、ちゃんとデータが入っていたので、Cloud SQLが使えることもわかりました。

# その他のエラー
あと、

```
Class 'Facade\Ignition\IgnitionServiceProvider' not found
```

というエラーが出る場合もあります。
これは、`facade/ignition`を`require-dev`ではなく`require`のほうに移さないといけないっぽいです。

```sh
$ composer require facade/ignition
```

`gcloud app deploy`でデプロイされるのは`production`のようなんですが、`.env`もしくは`app.yaml`の`APP_DEBUG`が`true`になっていると、`facade/ignition`が必要になるかららしいです。

# アプリケーションの無効化

プロジェクトは削除したくないけど、一旦アプリケーションにアクセス出来ないようにしたい場合があると思います。
そのときは、App Engineの設定から「アプリケーションを無効にする」でアクセス出来ないようにします。

# まとめ

デプロイを繰り返すとエラーになったり不思議な現象に悩まされました:sob:
Storageのバケット削除で対処したけど本当にこれでいいのかわかりません。
しかし簡単にLaravelアプリをデプロイ出来るのは魅力的ですね:beer:

# 参考URL

https://cloud.google.com/community/tutorials/run-laravel-on-appengine-standard?hl=ja
https://cloud.google.com/sdk/docs/downloads-interactive?hl=ja
https://cloud.google.com/sql/docs/mysql/quickstart-proxy-test?hl=ja
https://stackoverflow.com/questions/58087153/laravel-with-app-engine-standard-class-facade-ignition-ignitionserviceprovider
https://qiita.com/hibohiboo/items/526566ffa007fe1ec84b