2020-06-01に更新

GCEからCloud Runに引っ越してみた

当サービスCrieitをGoogle Compute EngineからCloud Runに引っ越ししてみました(2020/4)。選定理由、実際にやったこと、懸念点などを色々書いてみます。

費用についても書きたいのですが、まだ引っ越ししたばかりのためわかりません。1,2ヶ月ほど経ったら追記しますので気になる方はフォローやブックマークなどしておいてください。

※当記事は一部有料です。後半の実際にRunを使う方しか興味がなさそうな内容あたりは有料となっています。使ってみた感じやRunに関係ない引っ越しメモ等は無料です。費用については無料部分に書きます。

元々の構成

Compute Engineの1台構成です。f1-microインスタンスを利用しておりMySQLもこの中にインストールしているのでAlways FreeのおかげでWebサーバー、DBサーバー自体は無料運用です。ファイルなどはStorageです。

ちなみにLaravelで作られており、詳しい構成は下記に書かれています。
Crieitの構成

新しい構成

WebサーバーにCloud Run、DBサーバーはCloud SQL(db-f1-micro)にしました。Cloud SQLは無料枠がないため費用がかかりますが、とりあえず広告費用内でまかなえるので以前からそのうち使おうと思っていました。全部1台のサーバーに入れているのはやはりなんとなく怖かったため。

なぜ引っ越したのか

たまに落ちる

Compute Engineは普通のサーバーですので、やはり何らかの状況によって時々落ちるというかフリーズします。多分なにかボットのアクセスが激しい時にスワップしてしまってそのままになってしまうのだと思いますが。

とは言っても約2年くらい運営してきてそんな感じで止まることはめったにありませんでした。たまに数分だけ重いとMackerelから通知が来たりはしていましたが。ただ、最近1日に2回も大きなフリーズがあったので、さすがに怖くなったのが引っ越すことになった一番のきっかけかもしれません。

むちゃくちゃ遅い

リリースする時に深く考えず、us-eastに構築してしまいました。これのせいでもうとにかくすごく遅い。あらゆるページで表示されるまでに1秒位かかっていました。こちらも元々そのうちwestに引っ越したいなと思っていました。

なぜCloud Runを選択したのか

サーバーを管理したくなかった

最初から決めていたわけではなく、App EngineとCloud Runを試して決めよう、という感じでやっていました。どちらもマネージドで、自分でサーバーを管理する必要がありません。とにかくCloud SQLに費用を払うことになってでもサーバーを管理したくなくなったというのが一番の理由です。

結局Runの方を選んだのですが、理由としてはApp Engineはデプロイするために、結構ローカル開発環境を本番向けに変えたりスイッチしたりする必要があります。もちろんデプロイを自動化すればいい話ですが、そもそもその前に一旦試してみるのが面倒になってやめました。最初にCloud Runの実験をしていたのですが、そちらはDockerイメージ内で適当にファイルを調整すればいいのでローカル環境を汚さず簡単に試せて非常に良いと感じました。

デプロイが簡単

ローカルでコマンドをいくつか実行するだけでデプロイできます。バッチとしてまとめているので1コマンドで行けるようになりました。

@echo off
FOR /F %%i in ('git rev-parse HEAD') do set HASH=%%i
set IMAGE=gcr.io/プロジェクトID/イメージ名:%HASH%

@echo on
call gcloud builds submit --tag %IMAGE% --project プロジェクトID
call gcloud run deploy Runのサービス名 --image %IMAGE% --project プロジェクトID --region asia-northeast1 --platform managed --quiet

今回はやっていませんがCIによる自動化もコマンドベースなので簡単そうです。

GitHub Actionsを使うとCloud Runへのデリバリが最高に捗るぞ🚀 - Qiita

東京リージョンが使える

App EngineもCloud Runも東京リージョンが使えます。GCEのようにアメリカだけ無料、とかではないので安心です。ただまあネットワーク料がかかってくると思いますのでそちらは気になりますが。

実験したところ元々1秒くらいかかっていたページの表示が300~500ミリ秒くらいになっていました。すごく速いというわけではなさそうですが、とりあえず元々遅すぎたのでだいぶいい感じにはなりました。

安い?

Cloud Run自体はこんな感じで実際に使ったリソースの分しか消費されないので無料枠内で結構いけてしまうのかな…? と感じました。これはでも実際どうかわからないため、1、2ヶ月ほどしたら追記します。

追記)ネットワーク料金が14円で、CPU、メモリは費用内で無料でした。やはりデプロイ時に設定するメモリ料での計算でなく、実際に使った量だけみたいです。

ロールバックも簡単

これは実際に使ってみて気づきましたが、デプロイのリビジョンが残っているため何か不具合などがあってロールバックしたくなったときも簡単に戻すことができます。このあたりはGAE等ほかの簡単デプロイ系サービスでも同じかもしれませんが。

実際にやったこと

ストレージの引っ越し

まずはアップロードされた画像が入っているストレージだけ先に引っ越しました。というのも、Crieitの場合アップロード画像は直接ストレージのURLを使うわけではなく、Now経由でCDNキャッシュさせて費用を節約させています(NowのエッジキャッシュでCloud Storage節約サーバー作成)。ということで、引っ越しても画像のURLが変わるわけではありませんし、独立して先に引っ越しできるため先に移動しました。

具体的には下記の方法です。転送機能が用意されています。S3やAzureからも可能のようです。Cloud Storage間であればコマンドでも可能です。僕の場合は1GBもなかったので一瞬で終わりました。

バケットの移動と名前変更

通信料金も変わると思いますが、引っ越すまでの期間であればたいして影響も無いでしょう。とりあえずこれで一つやることが完全に減らせました。

ファイル保存している部分の調整

セッションやキャッシュはデフォルトでファイル保存になっています。しかしCloud Runは必要に応じてインスタンスが立ち上がったりするためファイルだと正常にセッションの維持などができません。そのためデータベース保存に変更しました。具体的にはまず下記でマイグレーションファイルを生成して実行します。

php artisan session:table
php artisan cache:table

そしてあとは環境変数をdatabaseに変えます。

CACHE_DRIVER=database
SESSION_DRIVER=database

まあここは他にもRedisを使ったり自由で良いと思います。

あとはログの出力も変更しておきます。これもファイルだとログを見ることもできないため、stderrにしておきます。こうすると自動的にCloud Runのコンソール上でログを見ることができます(その他にもいくつか方法はあります)。

LOG_CHANNEL=stderr

DBの設定

今回はCloud SQLを使っています。接続にはCloud SQL Proxyを使っています。例えばLaravelの場合、下記のようにソケットを指定します。

DB_SOCKET=/cloudsql/インスタンス接続名

インスタンス名はCloud SQLの詳細画面で確認できます。

DBの移行

DBの移行は、元々使っているGoole Compute EngineにMySQLをインストールしていたので、mysqldumpを利用しました。サーバー上のデータをmysqldumpでダンプし、そしてcloud_sql_proxyを実行するとCloud SQLにソケットでアクセスできるようになりますので、それでインポートしました。具体的なインポート方法は下記のようになります。

mysql -u ユーザー名 -p -S /cloudsql/インスタンス接続名 < dump.sql

参考)
Cloud SQL Proxy を使用した接続
GCEでcloud_sql_proxyが実行できない時

メンテナンスモード

ストレージもDBも、ユーザー操作中に移行を行うと一部データが失われてしまう可能性があります。そのためメンテナンスモードにしておく必要があります。

Laravelの場合、メンテナンスモードのコマンドが元々あるようなのでそちらを利用しました。メンテナンスモードに入るときは php artisan down 復帰するときは php artisan up です。

downの場合はメッセージや許可IPなども指定できます。

Maintenance Mode - Configuration - Laravel - The PHP Framework For Web Artisans

引っ越しの場合は新しいサーバーにアクセスが行くようになったらもう古いサーバーは使われませんので、upする必要もないかもしれません。

結局ネックとなるのはDBの同期です。Cloud Runの設定も含め、これ以外で事前にできることはなるべく済ましておきました。

プロキシ用の設定

元々Nginxを使っていた場合などは関係ない場合もありますが、プロキシ経由でなく直接アプリケーションにアクセスさせていた場合、このあたりの設定をする必要があります。例えばLaravelではTrustProxiesというミドルウェアのproxiesを許可するように設定しておく必要があります。

    protected $proxies = '*';

その他うまく動かない場合はSSLやホスト名の設定も問題ないか見てみる必要があります。Nginxのパターンとはちょっと違う可能性もありそうです。

バッチ等はどうしたか

Cloud RunはSSHアクセスできませんので、コマンドの実行や定期処理などは考える必要があります。一応公式としてはCloud Schedulerを使うということになっています。

Running services on a schedule

ただし、httpアクセスになるためちょっとコードを調整したりする必要もあり面倒です。そのため、今回はGCEからの移転ということもあり、定期処理や時々コマンドを実行したいときはもうそのGCE上で行うようにすることにしました。アプリケーションのDB接続もCloud SQLに行うようにしてあります。リージョンも違うので遅いとは思いますがどれも一瞬実行するだけなので問題は恐らく無いでしょう。Cloud SQLへの接続はcloud_sql_proxyをSystemdでサービス化して行っています(参考 GCP Cloud SQLにCloud SQL Proxyで接続しよう。Systemd化してデーモン化! | システムガーディアン株式会社)。

以下は有料です。下記のような内容を書いています。

  • 実際に作ったDockerfileの例(Laravel & Apache)
  • vendorフォルダが無視されることへの対処
  • .envファイルが無視されることへの対処
  • ポートの指定について
  • Dockerイメージのビルド方法(Cloud Buildの利用)
  • Cloud Runのサービスを作成する具体的な手順とエラーにならないようにするための注意点
  • 独自ドメインの利用方法
  • ステージング環境の作成例
  • Cloudflareで525 SSL handshake failedエラーが出た場合
ツイッターでシェア
みんなに共有、忘れないようにメモ

だら@Crieit開発者

Crieitの開発者です。 Webエンジニアです(在宅)。大体10年ちょい。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel, React, Flutter, Vue.js, Node, RoR 趣味:Elixir, Phoenix, Nuxt, Express, GCP, AWS等色々 PHPフレームワークちいたんの作者

コメント