Laravel6.0をGoogle Cloud PlatformのGoogle App EngineのPHP7.2環境で動かしたメモ

## 概要
Laravel6.0をGoogle Cloud Platform(GCP)のGAEで動かそうとしたら、色々ハマったのでメモ。
firebaseを試していたGCPのプロジェクトで行っていたら、GCPで課金設定した途端にBlazeプランにアップグレードされてびっくりした。びっくりしてSparkプランに戻したら課金設定解除されてCloud Build APIが使えなくなるなどした。
試すときはfirebase使ってないGCPのProjectでやると心臓にやさしいとおもう。

[今回のソース](https://github.com/hibohiboo/develop/tree/236d7b57afafdb6601ed8a7241aa0e9d88b80401/tutorial/lesson/php/laravel)

とりあえず、トップページが表示されるところまでは持っていけた。
現在、セッションでエラーがでているっぽいので、「[Laravel5.5 を Google App Engine で動かす](https://qiita.com/fullkawa/items/4d6b080385de5523835c)」や「[Laravel5.8をGAE Standard環境にデプロイする](https://qiita.com/Syy12345-Unity/items/9900512c091e01a4f31d)」でやってる環境変数の追加が必要そう。エラーは下記。

```
 "/var/www/storage/framework/sessions" directory does not exist.
```


## 環境

* Windows 10 Home
* Vagrant 2.2.5
* virtualbox 6.0.12
* Ubuntu 18.04 LTS (Bionic Beaver)
* Docker version 19.03.2, build 6a30dfc
* docker-compose version 1.24.1, build 4667896b
* Laradoc 
* Laravel 6.0
* Google Cloud SDK 255.0.0
  * bq 2.0.45
  * core 2019.07.19
  * gsutil 4.41

## 構造

Laravelについては、[前回、XDebugを設定した環境](https://qiita.com/hibohiboo/items/463fc4d13d20b1a8cf37)のソースを使用する。
今回は、これをほぼそのままGAEにアップロードしてビルドしたのだけれど、そのせいでハマった気がする。リポジトリからビルドできるならそちらのほうがシンプルなのかも。
GCPのためのCUIツールはdockerで用意した。

```yaml
- bin # コマンドを打つのが面倒なので出来るだけshellにしておきたい
  - gcp_bash.sh # Google Cloud SDKをインストールしているコンテナにログイン
  - bash.sh # Laravel の開発環境用コンテナにログイン
- gcp # gcloudを使う用のコンテナ設定
  - bin
    - bash.sh
  - docker
    - docker-compose.yml
    - .env
    - gcloud
      - Dockerfile
      - .bashrc
- laravel_docker
  + laradock
  + sampleapp # laravelのソース
```

<details><summary>gcloudを使うためのコンテナのdocker設定は本筋ではないので折りたたんでおく。気になる人はクリック。</summary><div>

dockerで構築する方法は、「[Laravelの実行環境をDockerで構築する](https://qiita.com/yoshiplur/items/fa875e111f908cd8786c)」が詳しい。
ここではlaradockにまかせてしまっている。

### laravel の開発環境へアクセスするためのshell

```bash:bin/bash.sh
#!/bin/bash

# このシェルスクリプトのディレクトリの絶対パスを取得。
bin_dir=$(cd $(dirname $0) && pwd)
parent_dir=$(cd $bin_dir/.. && pwd)
docker_dir=$(cd $parent_dir/laravel_docker/laradock && pwd)
cd $docker_dir
docker-compose exec --user=laradock workspace bash 
```

### gcloudのコンテナへアクセスするためのshell

```bash:bin/gcp_bash
#!/bin/bash

bin_dir=$(cd $(dirname $0) && pwd)
parent_dir=$(cd $bin_dir/.. && pwd)
gcp_dir=$(cd $parent_dir/gcp && pwd)

bash $gcp_dir/bin/bash.sh
```

```bash:gcp/bin/bash.sh
#!/bin/bash

bin_dir=$(cd $(dirname $0) && pwd)
parent_dir=$bin_dir/..
docker_dir=$parent_dir/docker
container_name=${1:-gcloud}

# $container_nameの有無をgrepで調べる
docker ps | grep $container_name

# grepの戻り値$?の評価。 grep戻り値 0:一致した 1:一致しなかった
if [ $? -eq 0 ]; then
  # 一致したときの処理
  cd $docker_dir && docker-compose exec $container_name bash
else
  # 一致しなかった時の処理
  # コンテナを立ち上げて接続
  cd $docker_dir && docker-compose run $container_name /bin/bash
fi
```


### gcloudコンテナのソース

```yaml:gcp/docker/docker-compose.yml
version: "3"
services:
  gcloud:
    build: ./gcloud
    env_file: .env
    volumes:
      - ../../laravel_docker/sampleapp:/var/www
    working_dir: /var/www
```



```gcp/docker/.env
CLOUDSDK_CORE_PROJECT=プロジェクトID
```

```docker:gcp/docker/gcloud/Dockerfile
FROM python:3.6.9-alpine3.10
RUN apk update
RUN apk add  curl tar

# https://cloud.google.com/sdk/docs/quickstart-linux?hl=en
WORKDIR /usr/src/gcp
RUN curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-255.0.0-linux-x86_64.tar.gz
RUN tar zxvf google-cloud-sdk-255.0.0-linux-x86_64.tar.gz google-cloud-sdk
RUN apk add bash
COPY .bashrc /root/.bashrc
RUN /usr/src/gcp/google-cloud-sdk/install.sh
```

```bash:gcp/docker/gcloud/.bashrc
# The next line updates PATH for the Google Cloud SDK.
if [ -f '/usr/src/gcp/google-cloud-sdk/path.bash.inc' ]; then . '/usr/src/gcp/google-cloud-sdk/path.bash.inc'; fi

# The next line enables shell command completion for gcloud.
if [ -f '/usr/src/gcp/google-cloud-sdk/completion.bash.inc' ]; then . '/usr/src/gcp/google-cloud-sdk/completion.bash.inc'; fi
```

</div></details>

## 公開手順

[run-laravel-on-appengine-standard](https://cloud.google.com/community/tutorials/run-laravel-on-appengine-standard?hl=ja)を基本的には踏襲する。ただ、[run-laravel-on-appengine-flexible](https://cloud.google.com/community/tutorials/run-laravel-on-appengine-flexible)に書かれている手順も必要であった。

### app.yamlの作成

公式の手順通り、app.yamlを作成する。

```yaml:laravel_docker/sampleapp/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の開発環境コンテナにログインして、Keyを作成する。

```console
./bin/bash
sed -i "s#YOUR_APP_KEY#$(php artisan key:generate --show --no-ansi)#" app.yaml
```

app.phpに追記。

```diff:laravel_docker/sampleapp/bootstrap/app.php
$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);
+ # [START] Set the storage path to the environment variable APP_STORAGE
+ /*
+ |--------------------------------------------------------------------------
+ | Set Storage Path
+ |--------------------------------------------------------------------------
+ |
+ | This script allows us 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'));
+ # [END]
```

開発サーバの削除

```console
./bin/bash
composer remove --dev beyondcode/laravel-dump-server
```

[run-laravel-on-appengine-standard](https://cloud.google.com/community/tutorials/run-laravel-on-appengine-standard?hl=ja)の手順にはないが、composer.jsonを編集する。

```diff:laravel_docker/sampleapp/composer.json
{
    "name": "laravel/laravel",
    // 省略
    "prefer-stable": true,
    "scripts": {
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ],
+        "gcp-build": [
+            "composer install --no-dev"
+        ],
+        "post-install-cmd": [
+            "chmod -R 755 bootstrap/cache",
+            "php artisan cache:clear"
+        ]
    }
}
```

`post-install-cmd`を追加しないと、ローカルでテストしたときの設定のキャッシュ(bootstrap/cache/)が使われて以下のエラーとなる。

```
There is no existing directory at "/var/www/storage/logs" and its not buildable: Read-only file system
```

`gcp-build`を追加しないと、メモリ不足で500エラーが返ってくる。

ここからは、gcloudでの作業になる。

```
./bin/gcp_bash.sh
gcloud auth login
gcloud app deploy
```

`gclud auth login`で、表示されるリンクをブラウザで開いて、GCP登録のGoogle アカウントで認証する。ログインする権限を間違えると以下が出る。

```
ERROR: (gcloud.app.deploy) Permissions error fetching application [apps/プロジェクトID]. Please make sure you are using the correct project ID and that you have permission to view applications on the project.
```

認証に成功した状態で、`gcloud app deploy`とすると、次が表示される。東京は asia-northeast1 。

```
Please choose the region where you want your App Engine application
located:
 [1] asia-east2    (supports standard and flexible)
// 省略。
 Please enter your numeric choice:  
```

情報の確認がある。 Y。

```
target url:      [https://プロジェクトID.appspot.com]


Do you want to continue (Y/n)?
```

Cloud Build API が有効になっていないと上記の後に失敗する。今回は無料体験と300$もらっているので、Cloud Build APIへの課金を有効にした。

```
Updating service [default]...failed.
ERROR: (gcloud.app.deploy) Error Response: [7] Access Not Configured. Cloud Build has not been used in project whitemap before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudbuild.googleapis.com/overview?project=whitemap then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
```

ビルドに不要なファイルやディレクトリは省いてしまったほうがいい。 `.env`と`/storage`を追加。

```config:laravel_docker/sampleapp/.gcloudignore
# This file specifies files that are *not* uploaded to Google Cloud Platform using gcloud.
# For more information, run: $ gcloud topic gcloudignore
.gcloudignore
# If you would like to upload your .git directory, .gitignore file or files
.git
.gitignore

# PHP Composer dependencies:
/vendor/
.env
/storage/
```

## 参考

[Build](https://cloud.google.com/cloud-build/docs/?_ga=2.97529884.-2054062782.1506606940)
[Stack over flow](https://stackoverflow.com/questions/58087153/laravel-with-app-engine-standard-class-facade-ignition-ignitionserviceprovider)
[GCP Laravel](https://cloud.google.com/community/tutorials/run-laravel-on-appengine-standard?hl=ja)
[Laravel Framework on App Engine Standard for PHP 7.2](https://github.com/GoogleCloudPlatform/php-docs-samples/tree/master/appengine/php72/laravel-framework)
[app.yaml 構成ファイル](https://cloud.google.com/appengine/docs/standard/php7/config/appref#example)
[Laravel6.0 の基本のタスクリスト](https://qiita.com/ucan-lab/items/36f6e89abad26a68f69a)
[Laravel の標準ディレクトリの変更方法 まとめ](https://qiita.com/kd9951/items/45f4cfc19bfc99a90a02)
[laravel プロジェクトを作成し GAE に展開する](https://qiita.com/bleru/items/153a228ad88d04b58d90)
[GCP Laravel](https://cloud.google.com/community/tutorials/run-laravel-on-appengine-flexible)
[Laravel5.5 を Google App Engine で動かす](https://qiita.com/fullkawa/items/4d6b080385de5523835c)
[Laravelの開発環境をDockerを使って構築する](https://qiita.com/ucan-lab/items/17c806973e69792ada99)
[Laravel6系で始めるか、Laravel5系を使うべきか迷う人へ](https://qiita.com/willow710kut/items/ae3fc659a5c7215fc499)
[UbuntuでLaradockを使ったLaravel開発環境構築](https://qiita.com/miurabo/items/abfe6d948ee4c066d7d4)
[環境構築から始めてLaravel 6 + Vue.jsでタスク一覧を作るチュートリアル](https://qiita.com/2bo/items/d5201dbad296fd0b876b)
[Laravel5.8をGAE Standard環境にデプロイする](https://qiita.com/Syy12345-Unity/items/9900512c091e01a4f31d)
[Laravelの実行環境をDockerで構築する](https://qiita.com/yoshiplur/items/fa875e111f908cd8786c)