はじめに
はじめまして。レターファンの創業者でエンジニアの今成です。
全然情報がなくて困ったから書くしかない!と思って、気づいたら半年以上経ってしまいました。
はじめての Qiita なので温かな目で読んでください。
概要
前提
- Nuxt.js プロジェクトは既に存在し、ローカルで起動できる
- Nuxt.js は SSR(Server Side Rendering) モードである
- GCP のプロジェクトも既に存在する
- 上述の範囲のことや、IAM まわりについては触れません
概略図
③ の Firebase Hosting は経由しなくても、まったく問題ありません。番外編3 で説明します。
環境分けについて
Dcokerfile や cloudbuild.yaml で環境変数を指定せずに、gcloud コマンドで環境を識別します。
準備
0. Google Cloud CLI をインストール
公式ドキュメントがわかりやすいので、リンクだけ貼っておきます。
Cloud SDK のインストール | Google Cloud
Cloud SDK の初期化 | Cloud SDK のドキュメント | Google Cloud
1. 環境変数の設定
Nuxt.js における環境変数の設定方法は色々ありますが、Nuxt.js のデフォルトの runtimeConfig
を使用します。
かつての dotenv
を利用する方法などではうまくいかないので気をつけてください。
dotenv
を使用している人は こちらの記事 で移行してください。
nuxt.config.js の設定
環境変数は nuxt.config.js ファイルにすべて記述します。
その際、ランタイム環境変数(runtimeConfig)とは別にビルド時に必要な環境変数も指定します。
本記事では、実行環境を表す環境変数として NODE_ENV
を利用します。
また、server
オプションで、起動させるポートとホストも設定できるようにします。
export default {
// ビルド時に必要な環境変数を設定
env: {
NODE_ENV: process.env.NODE_ENV,
},
// ランタイム時に必要な環境変数を設定
publicRuntimeConfig: {
NODE_ENV: process.env.NODE_ENV,
EXAMPLE: process.env.NODE_ENV !== "production" ? "開発環境" : "本番環境",
// ...
},
server: {
port: process.env.PORT || 3000,
host: process.env.HOST || "0.0.0.0",
timing: false,
},
// ...
}
2. Dockerfile の作成
nuxt.config.js と同じ階層に Dockerfile を作成します。
この Dockerfile を元に Container Registry にコンテナを作成します。
FROM node:14.4.0-alpine
ARG _NODE_ENV
WORKDIR /app
# タイムゾーンを東京に固定したい場合はこれを記述【★】
# RUN apk --no-cache add tzdata && \
# cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
# apk del tzdata
ENV NODE_ENV ${_NODE_ENV}
ENV LANG C.UTF-8
ENV PORT 8080
ENV HOST 0.0.0.0
COPY package.json ./
RUN npm install
COPY . .
RUN npm run build
CMD [ "npm", "run", "start" ]
タイムゾーンの設定について
サーバーサイドで Date.getHours()
系のメソッドを利用すると、世界標準時を基準に取得されてしまいます。
それを日本標準時で行いたい場合は【★】を書いてください。
【Docker】AlpineとMariaDBのtimezone設定
3. cloudbuild.yaml の作成
nuxt.config.js と同じ階層に cloudbuild.yaml を作成します。
steps:
- name: "gcr.io/cloud-builders/docker"
args:
[
"build",
"--build-arg",
"_NODE_ENV=$_NODE_ENV",
"-t",
"asia.gcr.io/$PROJECT_ID/$_SERVICE_NAME:$_TAG_NAME",
".",
]
substitutions:
_NODE_ENV: "production"
_TAG_NAME: "latest"
_SERVICE_NAME: "任意のサービス名"
images: ["asia.gcr.io/$PROJECT_ID/$_SERVICE_NAME:$_TAG_NAME"]
変数値の置換
$PROJECT_ID
はデフォルトで Cloud Build が提供する変数値です。GCPのプロジェクトIDが自動的に置換されます。
変数値(環境変数)を自作したい場合は、_
から始まる変数値を用います。(例:_NODE_ENV
)
この変数値を置換する方法は次の2通りがあり、
- cloudbuild.yaml で substitutions として指定する
- gcloud コマンドの引数として、ビルド実行時に指定する
2つ目の方が優先されます。したがって、1つ目の方法でデフォルト値を指定しておくことをおすすめします。
変数値の置換 | Cloud Build のドキュメント | Google Cloud
例:実行環境 _NODE_ENV
の伝達
--build-arg _NODE_ENV=$_NODE_ENV
によって、ビルド時の環境を substitutions
(変数値の置換) の _NODE_ENV
から Dockerfile の ARG の NODE_ENV
を経由して nuxt.config.js 内の process.env.NODE_ENV
に(ビルド時の環境変数として)パスしています。
4. .gcloudignore の設定
不要なファイルも一緒にビルドされないよう、.gcloudignore というファイルを作成します。
内容は .gitignore とまったく同じで問題ないです。
cp .gitignore .gloudignore
デプロイ
gcloud コマンドを実行する前に、適切なGCPプロジェクトを選択しているか確認してください。
1. Cloud Build でビルド
cloudbuild.yaml と同じ階層で以下のコマンドを実行し、コンテナを Container Registry に配置します。
5〜10分程度かかります。
gcloud builds submit --config=cloudbuild.yaml --substitutions=_NODE_ENV=環境名,_TAG_NAME=バージョン番号,_SERVICE_NAME=サービス名
cloudbuild.yaml の substitutions にデフォルト値として指定したものを利用する場合、コマンドライン引数 --substitutions に含める必要はありません。
2. Cloud Run にデプロイ
以下のコマンドを実行し、Cloud Run にデプロイします。
gcloud run deploy --platform managed --port 8080 --region asia-northeast1 --image=asia.gcr.io/プロジェクトID/サービス名:バージョン番号
プロジェクトIDには実行中のGCPのプロジェクトIDを、サービス名には _SERVICE_NAME
として指定したものを、バージョン番号には _TAG_NAME
として指定したものを入れてください。
数秒〜数十秒後に、サービス名(Service name)が聞かれますので、Enterを押してください。
次に、初回だけ、未認証のアクセスを許可するか聞かれます。通常、サイトを公開するときは許可するので y
を入力してください。
※ もし後から未認証のアクセスを許可したい場合は、番外編2 を見てください。
Service name (サービス名):
# -> Enterを押す
Allow unauthenticated invocations to [サービス名] (y/N)?
# -> y を入力し、Enterを押す
そうすると数十秒後に完了し、アクセスできるURLが出力されます。このURLにアクセスすると、サイトが確認できるはずです。
番外編
1. コールドスタート対策
王道は最小インスタンス数を設定することです。ただ、この方法はインスタンスが最低1つ起動しているため、インスタンス料金が常に発生します。
そこで、CGPのモニタリングの稼働時間チェックというサービスを利用します。
方法は この記事 に載っています。
私の場合、Check Frequency を 10 minutes、Response Timeout を 5 seconds に指定しています。
2. 未認証のアクセスを後から許可する
Cloud Run のコンソール を開き、許可したいサービスを選択後、右上の「情報パネルを表示」から「権限」の「プリンシパルを追加」から allUsers
に Cloud Run 起動元
のロールを付与します。
3. Firebase Hosting の設定
Firebase Hosting のリダイレクトの設定は最初に一度だけ行います。
3-0. Firebase プロジェクトを設定
.firebaserc や firebase.json ファイルが存在しない場合、この節の設定が必要です。
公式ドキュメント や Qiita などを読み、nuxt.config.js と同じ階層で Firebase CLI を実行してください。
ただし、Hosting のセットアップで What do you want to use as your public directory?
と聞かれますが、使用しないので適当に答えて構いません。(デフォルト値の public で問題ないです)
3-1. Cloud Run へのリダイレクトを記述
以下のように "rewrites"
を追加します。これで、serviceId
に指定した Cloud Run に自動でリダイレクトされます
{
"hosting": {
"rewrites": [{
"source": "**",
"run": {
"serviceId": "cloudbuild.yamlで設定した _SERVICE_NAME",
"region": "asia-northeast1"
}
}]
}
}
3-2. デプロイターゲット:Firebaseの環境分け
開発環境と本番環境で別のGCPプロジェクトを扱う場合、コマンドライン引数で環境を区別してデプロイすることができます。
本記事では詳しくは触れません。公式ドキュメント や Qiita などを読んでください。
以降の説明は、.firebaserc が以下のようになっている場合を例に説明します。
{
"projects": {
"dev": "example-dev",
"prod": "example-prod"
},
"targets": {
"example-dev": {
"hosting": {
"main": [
"example-dev"
]
}
},
"example-prod": {
"hosting": {
"main": [
"example-prod"
]
}
}
}
}
3-3. Firebase Hosting をデプロイ
以下のコマンドを実行し、デプロイします。
firebase deploy --only hosting --project dev
dev
の部分は、.friebaserc の projects で指定した値で識別します。
デプロイが完了すると、Cloud Run から提供されるドメイン以外に、Firebase Hosting で設定したドメインでもアクセスできるようになります。
最後に
レターファンは、憧れのタレントやアスリートからビデオレターが届くサービスを提供しています。
Webエンジニアだけでなく、Flutterエンジニアなど絶賛募集中です!
ご興味がありましたら是非こちらのサイトをご覧ください!
参考記事
Nuxt(SSR)をCloud Runに自動デプロイする(GitHub連携) - くらげになりたい。
SSRモードのNuxt製アプリをCloud Runでデプロイする方法 | ぐるたかログ
SSRなNuxt.jsを環境ごとにDocker化する時の環境変数の扱いについて - Qiita