Docusaurusのドキュメントを App Engine から Cloud Run へ移行する
この記事は、Google Cloud Champion Innovators Advent Calendar 2024 19 日目の記事です。
こんにちは。Zennチームでは、おもに開発メンバー向けの内部ドキュメントがあり、そこで仕様やアーキテクチャ記録しています。あまり手間はかけたくないが、ソースコードと一緒にGitHubでバージョン管理できると嬉しい、という理由から Docusaurus を利用しています。
お作法にしたがって Markdown ファイルをかけば、マニュアル向けのHTMLとしてビルドでき、Node.js での serve が可能です。
App Engine から Cloud Run へ移行したい
Docusaurus はビルドからサーバー起動まで docusaurus
コマンドが面倒をみてくれるため、この点で苦労することはありません。1点、内部ドキュメントということから、特定のメンバーだけアクセス可能にしたいという要件がありました。これに対して、私たちは App Engine へデプロイし、IAP で保護する方法をとっていました。
閲覧するタイミングは限定的であり、アクセスするのは開発メンバーであるため、ゼロスケールするよう設定しています。必然的にアクセス時はコールドスタートになるのですが、App Engine スタンダード環境のVMだと少し起動にラグがあり(5秒ほど)、ほんのちょっとのストレスを感じていました。このことから、コンテナベース、もっというと Cloud Run へ移行したいなと思っていたのですが、Cloud Run で動くアプリを IAP で保護するには、Cloud Load Balancing を挟まねばなりません。内部ドキュメントのためにそこまでするのも…ということで移行は見送りになっています。
しかしいつ移行することになっても良いよう、Cloud Run で動かすところまでやってみたいと思いました。本稿では Docker イメージを作成し、Cloud Runへデプロイするところをやってみます。
ビルド方法をDockerへ変更
ドキュメントについて、App Engine では app.yml
にてアプリケーションの設定を行い、yarn build
でビルド、 yarn start
で起動していました。Cloud Run への移行にあたり、Dockerイメージをビルドしてイメージからデプロイすることにしました。ですのでまずはDockerfileを用意します。
FROM node:20-slim AS builder
WORKDIR /app
COPY package.json ./
COPY yarn.lock ./
RUN yarn install --frozen-lockfile --production=false
COPY . .
RUN yarn build
FROM node:20-slim AS runner
ENV NODE_ENV=production
WORKDIR /app
# 不要なファイルがCOPYされないよう、ホワイトリスト運用しています
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY /app/node_modules ./node_modules
COPY /app/.docusaurus ./.docusaurus
COPY /app/build ./build
COPY /app/public ./public
COPY /app/docs-custom.css ./
COPY /app/docs-sidebars.js ./
COPY /app/docusaurus.config.js ./
COPY /app/package.json ./
CMD ["yarn", "start"]
マルチステージビルドを行うほどではないかもしれませんが、少しでもデプロイするイメージサイズを小さくするため必要なファイルのみ移すようにしています。なお、Dockerfileについては公式ドキュメントでガイドラインが用意されており、そちらに従うでも構いません。公式のDockerfileではわざわざファイルを移動することはせず、FROM prod AS serve
のようにしてビルド成果物を使っていますね。
package.json
も注意が必要です。Cloud Run が決めたポート番号で起動する必要があるため、起動スクリプトで環境変数PORT
を利用するように書きます。
{
"scripts": {
"docusaurus": "docusaurus",
"build": "docusaurus build",
"start": "docusaurus serve -p $PORT",
},
...
}
cloudbuild.yml を作成
Cloud Build でイメージの作成とCloud Runのデプロイを行います。GitHubからソースコードが連携される想定です。用意したDockerfileを使いましょう。
steps:
- id: build
name: gcr.io/cloud-builders/docker
args:
- build
- --file=Dockerfile
- --tag=$_ARTIFACT_REPOSITORY_IMAGE_TAG
- .
dir: "docs"
- id: push
name: gcr.io/cloud-builders/docker
args:
- push
- $_ARTIFACT_REPOSITORY_IMAGE_TAG
dir: "docs"
waitFor: ["build"]
- id: deploy
name: gcr.io/google.com/cloudsdktool/cloud-sdk:alpine
entrypoint: gcloud
args:
- run
- deploy
- docs
- --quiet
- --platform=managed
- --project=$PROJECT_ID
- --region=$_REGION
- --image=$_ARTIFACT_REPOSITORY_IMAGE_TAG
- --service-account=$_CLOUD_RUN_SERVICE_ACCOUNT
- --revision-suffix=${SHORT_SHA}-${_SHORT_BUILD_ID}
- --tag=latest
- --concurrency=80
- --cpu=1
- --memory=512Mi
- --max-instances=1
- --min-instances=0
- --no-use-http2
- --no-allow-unauthenticated
dir: "docs"
waitFor: ["push"]
substitutions:
_REGION: asia-northeast1
_CLOUD_RUN_SERVICE_ACCOUNT: terraform
_ARTIFACT_REPOSITORY_IMAGE_NAME: terraform
_ARTIFACT_REPOSITORY_IMAGE_TAG: "${_ARTIFACT_REPOSITORY_IMAGE_NAME}:${SHORT_SHA}"
# ビルド結果に生成したイメージ情報を表示する
# https://cloud.google.com/build/docs/building/build-containers
images:
- $_ARTIFACT_REPOSITORY_IMAGE_TAG
options:
logging: CLOUD_LOGGING_ONLY
Artifact Registry のイメージ名などは環境に合わせて埋めてください。これで準備ができました。
Cloud Run のデプロイ
先ほど用意したcloudbuild.yml
を利用して、ドキュメントをCloud Runへデプロイします。Cloud Buildトリガーの構成にもよりますが、GitHubアプリトリガーを利用している場合、ブランチにプッシュしてビルドを開始できます。
Docusaurusによってビルドされたドキュメントが閲覧できました。(--no-allow-unauthenticated
なので本来はForbiddenですが、一時的に Cloud Load Balancing につないでIAP認証後、表示しました)
おわりに
Docusaurus でビルドしたドキュメントを Cloud Run で起動するように移行しました。Cloud Load Balancing とつないでIAPを有効にできます。Cloud Runへ本格的に移設する…となった場合はそちらの手順も追記したいと思います。
Discussion