LoginSignup
11
10

More than 3 years have passed since last update.

Cloud Run上でLaravel×React(Mix使用)のサイトを爆速で動かす - Laravelをデプロイする

Last updated at Posted at 2020-09-07

こんにちは。松戸市でエンジニアの幸福を目指す企業、Joolenです。
現在、弊社では新規Webサービスを絶賛構築中です!
いきなりですが、新規サービスでは主に下記のフレームワークやクラウドサービスを利用しています。

  • Laravel(-mix)
  • React
  • Cloud Run
  • Cloud Storage(CDNとして利用)

この組み合わせ、驚くほどに良いです。何が良いかというと
1. 安い → Cloud Runのコスパが半端じゃない。(動いた分だけしか課金されない。無料枠も大きい:tada:)
2. 早い → 動的サイトとは思えないほど早い。開発チームメンバー全員が感動するレベル。
3. うまい → LaravelとReactどちらも、拡張性が高い。ライブラリも豊富!特盛!熱盛り!(「うまい」だけこじ付け:sweat_smile:)

ただ、この良さを引き出すためには色々と工夫が必要で、情報探しはかなり苦労しました。
(ありがとう、Github。ありがとう、StackOverflow。その他、有益な情報を公開されている世界中の皆さんに感謝です。)
ということで、Qiita読者の皆さんにもこの良さを伝えるべく、我々が何をしたのか惜しげなく公開していきたいと思います!(施されたら施し返す。恩返しです!)

ただ、ここではCloud Runとは何か?ということまでは説明しません。それについては公式サイトにお任せして、我々はこのサービスをどうやって活用しているのかという点に絞って説明をしていきたいと思います。

-はじめに- どのような設計なのか

システム構成としては下記のようなイメージです。(一部抜粋)
基本的に、クラウドサービスについてはGCP内で完結するようにしています。

アーキテクチャ.png

この構成を実現するために

次にStep by Stepでこのアーキテクチャをどうやって実現するかこの記事では、最適化したLaravelのデプロイまでに絞って説明していきます。

では早速、具体的な実現方法について説明していきましょう。

Cloud RunでLaravelを動かす。

最新のソースコードはGithubで公開されています。こちらも、是非、参考にしてください。

動作に最低限必要なファイルを作成する

1.Laravelのプロジェクトを作成する

任意の場所にディレクトリ を作り、作成したディレクトリの配下で

composer create-project laravel/laravel app

を実行します。これにより、Laravelのプロジェクトが作成されます。

2.Apacheの設定ファイルを記述する

作成したディレクトリの配下に、apache/000-default.confという名前でファイルを作りましょう。
ファイルの内容は以下を記載しておきます。

<VirtualHost *:80>

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html/public

        <Directory /var/www/html/>
                AllowOverride All
                Require all granted
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

3.php.iniを用意する

同じ階層の配下にphp/php.iniというファイルを用意します。本来であれば、要件によって細かく記述を変えるところではありますが、デモなので最低限の記述に止めます。

[php]
max_execution_time = 30
memory_limit = 512M
upload_max_filesize = 1M
post_max_size = 1M
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.revalidate_freq=60
opcache.max_accelerated_files=4000
opcache.validate_timestamps=1

;***** Added by go-pear
include_path=".:/lib/php"
;*****

4.Dockerfileを記述する

最後にDockerfileを作って下記のようにします。

FROM php:7.4-apache
WORKDIR /var/www/html

# 必要最低限のPHP拡張とNode.jsのインストール
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
RUN apt-get update \
  && apt-get install -y libzip-dev libpq-dev mariadb-client unzip git libfreetype6-dev libjpeg62-turbo-dev libpng-dev \
  && docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ \
  && docker-php-ext-install zip pdo_mysql mysqli gd exif opcache \
  && a2enmod rewrite \
  && apt-get -y install vim \
  && apt-get install -y nodejs \
  && git clone https://github.com/phpredis/phpredis.git /usr/src/php/ext/redis \
  && docker-php-ext-install redis 

EXPOSE 8080

ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_HOME /composer
ENV PATH $PATH:/composer/vendor/bin
ENV APACHE_LOG_DIR /var/log/apache2

# composerをインストール
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY ./apache/*.conf /etc/apache2/sites-enabled/
COPY ./php/php.ini /usr/local/etc/php/php.ini
COPY ./app /var/www/html

# composer install を高速化するためのライブラリをグローバルインストール
RUN composer global require hirak/prestissimo
RUN composer install --optimize-autoloader --no-dev
RUN php artisan key:generate  \
  && php artisan config:cache \
  && php artisan view:cache

RUN chmod 777 -R /var/www/html/storage/framework/ \
  && echo "Listen 8080" >> /etc/apache2/ports.conf 

5.念のためにローカルで動かす

下記のコマンドを実行して、http://localhost:8080で画面がみられれば成功です。

# buildして
docker build ./ -t cloud-run-demo
# 実行
docker run -p 8080:80 -d cloud-run-demo

出力される画面
image.png

6. Cloud Runへデプロイするための設定ファイルを作成する

GCPにアカウントがある前提で進めます。

まずは、.gcloudignoreというファイルをディレクトリ 直下に作成します。ファイル内容は下記の通りです。これは、composerで作られるvendornpmコマンドで作られるnode_modulesを除外することによりDockerコンテナのイメージサイズを小さくし、デプロイの速度を早めるために使っています。

*/node_modules/
*/vendor/

次に、cloudbuild.jsonというファイルを同じ階層に作ります。{your-project-id}の箇所は、GCPで作成したプロジェクトのIDとしてください。
ポイントは--cache-fromの記述で、これがあることで前回のビルドのキャッシュを取得できるため、次回からのデプロイが高速化されます:rocket:
:point_up:ただし、1ステップ目は最初のビルドに限りイメージが見つからない、というエラーが出ます。ご注意ください:point_up:

{
  "steps": [
    {
      "name": "gcr.io/cloud-builders/docker",
      "entrypoint": "bash",
      "args": [
        "-c",
        "docker pull gcr.io/{your-project-id}/cloud-run-demo:latest || exit 0"
      ]
    },
    {
      "name": "gcr.io/cloud-builders/docker",
      "args": [
        "build",
        "-t",
        "gcr.io/{your-project-id}/cloud-run-demo:latest",
        "--cache-from",
        "gcr.io/{your-project-id}/cloud-run-demo:latest",
        "-f",
        "Dockerfile",
        "."
      ]
    }
  ],
  "images": [
    "gcr.io/{your-project-id}/cloud-run-demo:latest"
  ]
}

7. いよいよCloud Runへデプロイする:tada:

下記のコマンドを実行すると、GCPのイメージリポジトリにビルドしたコンテナがpushされます。とても便利ですね。

gcloud builds submit --config cloudbuild.json --timeout="30m" --ignore-file ".gcloudignore"

次にGCPのコンソールからサービスを作成します。Webサービスなので、「未認証の呼び出しを許可」しましょう。

image.png

「次へ」を押した後、既存のコンテナ イメージから 1 つのリビジョンをデプロイする、を選択しましょう。先ほど、pushしたイメージが候補になっていると思います。
スクリーンショット 2020-09-03 17.25.47.png

次に「詳細設定を表示」して、コンテナポートを80にしておきます。
image.png

作成ボタンを押して、しばらくしたら完了です:tada:ローカルと同様に、Laravelのデフォルトのトップページが表示されば:ok:です。

Laravelを高速に動作させるためのコツ

ここで、上記設定を振り返りながらLaravelを高速に動かすためのポイントをいくつかご紹介します。

OPcacheを有効にする

かなりメジャーな手法であり、ある意味必須とも言える対応ですね。弊社では開発中に無効にしていたのですが、OPcacheを入れたことでレスポンスに100ms以上改善して驚きました。コードを変更しなくても、かなり効果がありますね。Dokcerfileの9行目の記述がポイントです。

  && docker-php-ext-install zip pdo_mysql mysqli gd exif opcache \

php.iniにも記述が必要ですので注意しましょう。

[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.revalidate_freq=60
opcache.max_accelerated_files=4000
opcache.validate_timestamps=1

Laravelのマニュアル(デプロイ)を読み、忠実に従う

こちらにきちんと記述があります。これに従いましょう。

Deployment(英語)
デプロイ(日本語)

Dockerfileでは31行目以降が、該当します。

RUN composer install --optimize-autoloader --no-dev
RUN php artisan key:generate  \
  && php artisan config:cache \
  && php artisan view:cache

:bangbang::bangbang::bangbang::bangbang:
cacheの流れではroute:cacheもパフォーマンス改善に有効です。しかし、デフォルトのままではroutes/web.phpに、コールバックメソッドがあるため、失敗します。そのため、デモのDockerfileの記述からは除外しています。もちろん、この記述を削除すれば問題なく動きますので、こちらも忘れずに入れると良いでしょう。
:bangbang::bangbang::bangbang::bangbang:

デフォルトのweb.php

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

//下記のcallbackが原因です。例えば
//Route::get('/','WelcomeController@index');
//などとすると、問題なく動きます。
Route::get('/', function () {
    return view('welcome');
});

上記の対策を全て行った場合、何も対策をしない場合を比べて200ms近くのパフォーマンスアップにつながりました。
人が体感できるレベルで早くなるので是非とも、上記を意識することをお勧めします。

ここまでのソースコードはGithubにPushされています。こちらも、是非、参考にしてください。

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10