Zenn Tech Blog
🦕

Docusaurusのドキュメントを App Engine から Cloud Run へ移行する

2024/12/19に公開

この記事は、Google Cloud Champion Innovators Advent Calendar 2024 19 日目の記事です。

こんにちは。Zennチームでは、おもに開発メンバー向けの内部ドキュメントがあり、そこで仕様やアーキテクチャ記録しています。あまり手間はかけたくないが、ソースコードと一緒にGitHubでバージョン管理できると嬉しい、という理由から Docusaurus を利用しています。

https://docusaurus.io/docs

お作法にしたがって Markdown ファイルをかけば、マニュアル向けのHTMLとしてビルドでき、Node.js での serve が可能です。

App Engine から Cloud Run へ移行したい

Docusaurus はビルドからサーバー起動まで docusaurus コマンドが面倒をみてくれるため、この点で苦労することはありません。1点、内部ドキュメントということから、特定のメンバーだけアクセス可能にしたいという要件がありました。これに対して、私たちは App Engine へデプロイし、IAP で保護する方法をとっていました。

https://cloud.google.com/iap/docs/enabling-app-engine?hl=ja#enabling_iap_console

閲覧するタイミングは限定的であり、アクセスするのは開発メンバーであるため、ゼロスケールするよう設定しています。必然的にアクセス時はコールドスタートになるのですが、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を用意します。

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 --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.docusaurus ./.docusaurus
COPY --from=builder /app/build ./build
COPY --from=builder /app/public ./public
COPY --from=builder /app/docs-custom.css ./
COPY --from=builder /app/docs-sidebars.js ./
COPY --from=builder /app/docusaurus.config.js ./
COPY --from=builder /app/package.json ./

CMD ["yarn", "start"]

マルチステージビルドを行うほどではないかもしれませんが、少しでもデプロイするイメージサイズを小さくするため必要なファイルのみ移すようにしています。なお、Dockerfileについては公式ドキュメントでガイドラインが用意されており、そちらに従うでも構いません。公式のDockerfileではわざわざファイルを移動することはせず、FROM prod AS serveのようにしてビルド成果物を使っていますね。

https://docusaurus.community/knowledge/deployment/docker/?package-managers=yarn

package.jsonも注意が必要です。Cloud Run が決めたポート番号で起動する必要があるため、起動スクリプトで環境変数PORTを利用するように書きます。

package.json(一部)
{
  "scripts": {
    "docusaurus": "docusaurus",
    "build": "docusaurus build",
    "start": "docusaurus serve -p $PORT",
  },
  ...
}

cloudbuild.yml を作成

Cloud Build でイメージの作成とCloud Runのデプロイを行います。GitHubからソースコードが連携される想定です。用意したDockerfileを使いましょう。

cloudbuild.yml
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へ本格的に移設する…となった場合はそちらの手順も追記したいと思います。

Zenn Tech Blog
Zenn Tech Blog

Discussion