Google App EngineへのLaravel環境デプロイが思っていたより難しかった件


GCPでLaravelを動かすだけだと思っていたのですが、思いのほか時間がかかったのと、一つで完結するような記事がなかったので、自分へのメモと今後Google Cloud Platformをはじめてみたい方向けにこの記事を残します

始める前に知っておくこと

天下のGoogle様のサービスだけあってできることは非常に多いですが、個人で通常利用する分には課金関連以外でのサポートを受けれません。そのため、基本的に技術的な問題に関してはコミュニティで質問することを推奨してます。
なので自分で調べたり、質問する力がないとすこしきついと感じました

また、詳しくはこの記事で説明していますが、AppEngineではデプロイするファイルの差分が10000以上だとエラーとなるため、回避手段もいくつかありますが、10000なんて必要なライブラリなどを入れていたらすぐに超えてしまうので、注意が必要です


ローカル環境を構築


まずはローカルにlarvelの環境を作り、正常に表示されることを確認します
$ composer create-project "laravel/laravel=5.7.*" sample
$ cd sample
$ php artisan serve

127.0.0.1:8000にブラウザでアクセスしてページが表示されていればOK

app.yamlを追加

先にローカル環境に作ったプロジェクトにapp.yamlを追加しておきます(.envとかと同じ階層でOK)
runtimeにはローカル環境で使っているPHPのバージョンを記載し、自分ならPHP Ver7.3なのでphp73
※現時点ではPHP7.4まで対応していますが、詳細はこちらで確認してください 

app.yaml
runtime: php73

env_variables:
  APP_KEY: YOUR_APP_KEY  ## .envのAPP_KEYを記載 ex) base64:Ts6Uz7mj0x~~~
  APP_STORAGE: /tmp
  VIEW_COMPILED_PATH: /tmp
  SESSION_DRIVER: cookie

app.yamlはインスタンスが崩れていたりするとデプロイ時にエラーを出力するので注意!

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'));

return $app;

不要なパッケージを削除しておく

存在するとエラーの原因になるので消しておく

$ composer remove --dev beyondcode/laravel-dump-server
$ composer remove --dev facade/ignition   //ちなみにLaravel 6.0を使っているならこちらを削除



Google App Engineにデプロイ


まずはGoogleCloudのコンソールで適当なプロジェクトを作っておきます

Google Cloud SDKをインストール


ローカル環境にGoogle Cloud SDKをインストール
自分の場合はUbuntuだったのですが、ほかの環境の方はここを確認
$ echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
$ sudo apt-get install apt-transport-https ca-certificates gnupg
$ echo "deb https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
$ curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
$ sudo apt-get update && sudo apt-get install google-cloud-sdk

Google Cloud SDKをセットアップ

gcloudコマンドが使えるようになったらローカル環境のフォルダに移動し、セットアップを行います
こちらも詳細はこちらに乗っていますが、以下の通りです

$ gcloud init
Pick configuration to use:
 [1] Re-initialize this configuration [default] with new settings 
 [2] Create a new configuration
Please enter your numeric choice:  1  //デフォルトの設定があればそれを使うので「1」入力。最初などは「2」で設定を登録しておきます
Choose the account you would like to use to perform operations for 
this configuration:
 [1] 登録していればここにメールアドレスが表示される
 [2] Log in with a new account
Please enter your numeric choice:  1 //メールアドレスが登録されていればそれを選択し、なければ「2」を押して、この後発行されるURLで追加できます
Pick cloud project to use: 
 [1] 存在すればgoogle cloudのプロダクト名が表示されます
 [2] 存在すればgoogle cloudのプロダクト名が表示されます
 [3] Create a new project
Please enter numeric choice or text value (must exactly match list 
item):  2 //事前に作成しておいたGoogle Cloudのプロダクトの番号を選択

[asia-east1]が東京、[asia-east2]が大阪リージョンなのでお好きなのを選んでください。a,b,cも任意のものを選択してください

Which compute zone would you like to use as project default?
 [1] [asia-east1-a]  
 [2] [asia-east1-b] 
 ...
 [14] Do not use default zone
 Please enter your numeric choice: 1 //使用するリージョンを決めます。ここは使いたいリージョンを選んでください

デプロイ

$ gcloud app deploy
Do you want to continue (Y/n)?  y

正常ならこんな画面に行くはずです

Cloud SQLとの接続(クラウドデータベースとの接続)

SQLインスタンスを作成する

コンソールからSQLインスタンスを作成しますが、最初はアクティブになってないので「SQL」で検索すると出てきます

自分はMysqlを選択しています

インスタンスIDは任意で大丈夫ですが、Mysqlのバージョンやリージョンはローカル環境に合わせましょう

インスタンスを作成したらダッシュボードに表示されている接続名"YOUR_CONNECTION_NAME"になるのでメモしておきましょう
また左の"ユーザー"からユーザーも作成できるので、.envで使っているユーザーと同じユーザーをつくっておきます(root以外を使っている場合)

データベースを作成する


SQLインスタンスのダッシュボード左のメニューから"データベース"を選択してローカル環境で使っているデータベースと同じ名前のデータベースを作っておきます
※コマンドでもデータベースを作成できます(gcloud sql databases create データベース名 --instance=インスタンス名)

ローカル環境でテーブルを作成


ローカル環境で以下のコマンドを実行し、テーブルを作成しておきます
$ php artisan make:auth
$ php artisan session:table
$ php artisan migrate --force

ローカル環境のテーブルをクラウドと同期

以下のコマンドをローカル環境で実行するとrootのパスワードが求められ、成功すると同じディレクトリにdatabase_tableというファイルが作成されます

$ mysqldump -u root -p -h localhost ローカル環境のデータベース名 > database_table

プロダクトのダッシュボードで「storage」を検索して、stogareのページを開き、任意の名称のパケットを作成します

作成したパケットを選択して、ローカルで作成したdatabase_tableをアップロードします

ファイルがアップデートできたらSQLインスタンスのダッシュボードに移行し、インポートを選択します

先ほどアップデートしたファイルを参照し、SQLの形式で自分の使うデータベースにインポートします

デプロイ

ローカル環境のapp.yamlを差し替えてデプロイを行います

app.yaml
runtime: php73


# この記載がないとcssとjsがnot foundになるので必須
handlers:
# Serve a directory as a static resource.
- url: /css
  static_dir: public/css
- url: /js
  static_dir: public/js


env_variables:
  ## Put production environment variables here.
  APP_KEY: YOUR_APP_KEY  ## .envのAPP_KEYを記載 ex) base64:Ts6Uz7mj0x~~~
  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        #クラウドのユーザーのパスワード
  ## for MYSQL, use DB_SOCKET:
  DB_SOCKET: "/cloudsql/YOUR_CONNECTION_NAME" #YOUR_CONNECTION_NAMEにはメモっていたものを記載
  ## for PostgreSQL, use DB_HOST:
  # DB_HOST: "/cloudsql/YOUR_CONNECTION_NAME" #Postgresqlの場合はこのように記載

$ gcloud app deploy
Do you want to continue (Y/n)?  y

正常にデプロイできると以下のような画面になるので、ユーザーの登録とログインができることを確認してください

エラー集

SQLSTATE[HY000] [2002] No such file or directory (SQL: select * from sessions where id = dgbEmZ9AufF9UD9kkeUxLlfeppZ1Z3erfe7UHQbHd limit 1)

Cloud SQLに上手く接続できていないときに発生し、原因は様々ですが自分の場合は以下の手段で解決しました

まずはMysqlでshow variables like '%sock%';を実行すると以下のような表示が出てくると思います

+-----------------------------------------+-----------------------------------------+
| Variable_name                           | Value                                   |
+-----------------------------------------+-----------------------------------------+
| performance_schema_max_socket_classes   | 0                                       |
| performance_schema_max_socket_instances | 0                                       |
| socket                                  | /tmp/mysql/mysql.sock              |
+-----------------------------------------+-----------------------------------------+

socketの値を第2引数に入れます

config\database.php
'mysql' => [
    'unix_socket' => env('DB_SOCKET','/tmp/mysql/mysql.sock'),
           ],
app.yaml
DB_SOCKET: "/cloudsql/YOUR_CONNECTION_NAME"

参考文献

https://cloud.google.com/community/tutorials/run-laravel-on-appengine-standard
https://qiita.com/kiyc/items/d86da4e5753220c121b9
https://memento-mori.jp/blog/back-end/google-app-engine_on_laravel
https://note.com/kawa1228/n/n4ab34e8f63fb
http://takaya030.hatenablog.com/entry/2017/07/17/181217
https://cloud.google.com/sdk/gcloud/reference/topic/gcloudignore
https://cloud.google.com/sql/docs/mysql/connect-admin-proxy?hl=ja
https://cloud.google.com/sql/docs/mysql/import-export/importing?hl=ja#console
https://github.com/GoogleCloudPlatform/cloudsql-proxy/issues/140
http://numa0323.hatenablog.jp/entry/2019/09/18/122436
https://laboradian.com/use-php72-with-ubuntu1604/