コンテンツへスキップ

QualiArtsengineer blog

QualiArts engineer blogの歴史とその運用について

QualiArts engineer blogの歴史とその運用について

8 min read

はじめに

今、皆さんがご覧頂いているこのQualiArts engineer blogですが、はやいもので開設から2年以上が経過しました。 当初は2021年6月24日のIDOLY PRIDEリリースに合わせてその関連記事を投稿することを目的に開始されたと記憶しています。 かなりハイペースで構築されたにもかかわらず、コンスタントに記事が投稿され、たまにTwitterでプチバズりしていたりとブログがしっかり活躍してくれているなと感じています。

自己紹介が遅れましたが、株式会社QualiArtsのバックエンドエンジニアをしている鈴木です。 普段はプロジェクトでゲーム開発をしているのですが、社内システムの運用やエンジニアブログの管理といった業務も行っています。 今回はQualiArts engineer blogの歴史とその運用について紹介していきたいと思います。

本記事はQualiArts Advent Calendar 2023の18日目の記事です。ぜひ他の記事もご覧ください。

エンジニアブログのはじまり

当初、QualiArtsは独自のエンジニアブログを所有していませんでした。 その代わり、CyberAgentのGame & Entertainment事業部所有の公式ブログへQualiArts名義で記事を公開していました。 ただ、IDOLY PRIDEのリリースに合わせ、エンジニアリング的にも会社を宣伝していこうということでエンジニアブログの開設が決まりました

実装

エンジニアブログを開設するとほぼ同時に、QualiArtsコーポレートサイトのリプレース作業をする話が上がっていました。 WordPressで実装されていたコーポレートサイトに不具合が見つかったのですが、管理者不在でメンテナンスも出来ない状態だったためリプレースを行うことになりました。 つまり、ほぼ2サイトを同時に実装することとなります。WordPress時代を鑑みて可能な限り低コスト・運用レスなシステムの構築を目指しました。 専任ならまだしも、兼任でシステムを管理するとなると、できるだけ管理するものを減らして楽したいところです。

以下のような要件で技術選定を行いました。

  • マークダウン形式で記事をGit管理したい
  • 静的サイトホスティングサービスを使いたい
  • 記事を投稿するという性質上、PRごとにプレビューURLが発行されるSaaSが良い
  • 公開前にチェックをしたいので、プレビューURLにはアクセス制限をしたい
  • 大量のアクセスは来ないので、コストは安ければ安いほどほど良い

記事の移設

今回、QualiArtsのコーポレートサイトで記事を管理していたWebフロントエンジニアと共同で実装することになったのですが、やはりWordPressの記事管理は辛いということでマークダウン形式のファイルで記事をGit管理することとなりました。

ただし、今までコーポレートサイトに投稿してきた記事をすべてマークダウンファイルに置き換える作業が必要です。そこで、当初はWordPressへGraphQLのプラグインを追加して、ビルド時にAPIを叩いて記事を自動生成する手法が用いられていました。いったんはシステムをこれで稼働させ、徐々に記事をマークダウンファイルに置き換えていくという作業をすることでリプレースが進んでいきました。

エンジニアブログのほうはまた別の問題として、以前までGame & Entertainment事業部の公式ブログへ投稿していた記事はどうしようという話があがります。そのまま置いておくのか、記事を移設するのか、両方に記事を置くのか……。 結果として両方に記事を置くことになりました。たとえ内容が重複した記事があっても、QualiArtsの技術記事がまとまっているサイトのほうが良いという判断です。これも手作業での移設となりました。

サービス選定

上記はほとんどWebフロントエンジニアの方に作業していただき、その間に自分はシステムの構築に着手していました。 前述した要件を満たすようなサービスを選定した結果、最終的に「Cloudflare Pages」と「Gatsby Cloud」の2つが候補として上がりました。 「Cloudflare Pages」はCDNで有名なCloudflareが提供している静的サイトホスティングサービスで、Gatsby CloudはGatsbyJSを開発しているGatsbyが提供していた静的サイトホスティングサービスです。 どちらも要件をほぼ満たしていて、何より価格がとても安かったのです。両方を検証した結果、「Gatsby Cloud」に軍配が上がりました。これはエンジニアブログがGatsbyJSで実装されており、それ専用にチューニングされているGatsby Cloudだとビルド時間がとても短かったこと、管理画面のUIや料金体系がシンプルだったことなどが理由です。

記事の運用

記事は技術広報のメンバーが各所に対して執筆依頼を投げる形式で運用しています。当初は月に1本記事を公開する目標でしたが、最近では自らエンジニアブログに執筆したいというメンバーも増えてきてありがたい限りです。

記事はまずGitHubに対してPRを発行することでレビューを受けます。 Gatsby CloudのBot

PRを発行すると、BotよりGatsby CloudのプレビューURLのリンクやビルド画面へのリンクなどがコメントされます。執筆者やレビュー担当者はこれを見ながら本番へどのように公開されるかを見ていきます。レビューはGitHub上で行い、各種修正を行った後にmasterブランチへマージすることで本番公開となります。

Gatsby CloudのプレビューURL

Gatsby CloudからVercelへの移行

Gatsby Cloudのサービス終了と移設先の選定

2023年08月24日、NetlifyによるGatsbyの買収に続きGatsby Cloudのサービス終了がアナウンスされました。 これにより、2年間運用していたGatsby Cloudを別サービスに移設することになります。「Vercel」、「Netlify」、「Cloudflare Pages」などを検証した結果、一番コストパフォーマンスに優れる「Vercel」へ移設することにしました。 今回の選定でネックになっていたのは「プレビューURLへのアクセス制限」機能でした。プレビューURLを発行するだけならどのサービスもデフォルトで対応しているのですが、アクセス制限をつけようと思うと高額なEnterpriseプランが必要となったりします。そんな中、Vercelはサイト数にかかわらず定額でアクセス制限をかけることができました。

実装の変更

Vercelに移行することを決定したのは良いものの、Vercelはユーザー数単位で課金が発生します。これはとくにプレビューURLへアクセスするときやビルド実行に影響します。 エンジニアブログは不特定多数の関係者が記事を投稿します。毎日の記事投稿数はそこまで多くないので、ユーザーを都度招待して不要になったら削除するという運用を徹底すれば最低限許容範囲の課金で済むのですが、エンジニアブログにそこまでコストをかけたくありません。また、Vercelの説明やアカウント作成についてなどを執筆者へ説明する作業もなくしたいところです。 そこで、ユーザー数を少なくしながら今までの体感を損なわないような実装が求められました。

Botの実装

Vercelはアクセストークンを発行してAPIを利用することが可能です。これを用いてGitHub Actions経由でVercelへデプロイしている方の記事を読み、これと同じアイデアで実装することに決めました。この記事も同じような課題を解決する目的の実装だったようです。 GitHub Actionsのワークフローファイルを実装し、Actions経由でデプロイするようにしてみました。

VercelのBot

また、Gatsby Cloudでは爆速だったビルドがキャッシュ機能がなくなったために遅くなってしまいました。そこでGatsbyJSのキャッシュをactions/cacheで永続化し、ビルドを高速化することで可能な限り体感が変わらないように努めました。 今回実装したワークフローファイルを掲載しておきます。ぜひご活用ください。

name: Deploy Preview

env:
  # https://vercel.com/teams/[my-org]/settings のTeamID
  VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
  # https://vercel.com/[my-org]/[my-site]/settings のProjectID
  VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
  # VERCEL_TOKENは https://vercel.com/account/tokens から作成したものを利用

on:
  push:
    branches:
      - '**'
      - '!master'

jobs:
  run:
    runs-on: [ ubuntu-22.04 ]
    environment:
      name: Preview
      url: ${{ steps.deploy.outputs.PREVIEW_URL }}
    steps:
      - uses: actions/checkout@v4

      - name: Read node version
        id: node-version
        run: echo "NODE_VERSION=$(cat .tool-versions | grep nodejs | cut -d ' ' -f 2)" >> $GITHUB_OUTPUT

      - name: Cache Node SDK
        uses: actions/cache@v3
        with:
          path: /opt/hostedtoolcache/node/${{ steps.node-version.outputs.NODE_VERSION }}
          key: node-sdk-cache/${{ runner.os }}/${{ steps.node-version.outputs.NODE_VERSION }}
      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: ${{ steps.node-version.outputs.NODE_VERSION }}

      - name: Cache Vercel CLI
        id: vercel-cli-cache
        uses: actions/cache@v3
        with:
          path: ~/.npm
          key: vercel-cli-cache/${{ runner.os }}/latest
      - name: Install Vercel CLI
        if: steps.vercel-cli-cache.outputs.cache-hit != 'true'
        run: npm install --global vercel@latest

      - name: Cache Vercel Build
        id: vercel-build-cache
        uses: actions/cache@v3
        with:
          path: |
            ./node_modules
            ./.cache
            ./public
          key: vercel-build-cache/${{ runner.os }}/${{ hashFiles('**/yarn.lock') }}
          restore-keys: |
            vercel-build-cache/${{ runner.os }}/

      - name: Pull Vercel Environment Information
        run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}

      - name: Build Project Artifacts
        run: vercel build --token=${{ secrets.VERCEL_TOKEN }}

      - name: Deploy Project Artifacts to Vercel
        id: deploy
        run: |
          vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} > stdout.txt 2> stderr.txt
          echo "INSPECT_URL=$(cat stderr.txt | grep Inspect | cut -d ' ' -f 2)" >> $GITHUB_OUTPUT
          echo "PREVIEW_URL=$(cat stdout.txt)" >> $GITHUB_OUTPUT

      - name: Get PR Number
        id: pr-number
        run: echo "PR_NUMBER=$(gh pr view --json number -q .number || echo '')" >> $GITHUB_OUTPUT
        env:
          GH_TOKEN: ${{ github.token }}

      - name: Create comment
        uses: peter-evans/create-or-update-comment@v3
        with:
          issue-number: ${{ steps.pr-number.outputs.PR_NUMBER }}
          body: |
            プレビュービルドのデプロイが完了しました! :rocket:            

            Build Commit: ${{ github.sha }}
            Inspect URL: ${{ steps.deploy.outputs.INSPECT_URL }}
            Preview URL: ${{ steps.deploy.outputs.PREVIEW_URL }}

おわりに

今回はQualiArts engineer blogの歴史とその運用について紹介しました。 安定した運用は関係者の尽力もありますが、何よりアクセスしていただいている皆さまのおかげです。 これからもQualiArts engineer blogをよろしくお願いします。

2019年にサイバーエージェントに新卒入社。QualiArtsにて運用プロジェクトのバックエンドエンジニアとして開発に携わり、いくつかのプロジェクトを経験。現在は新規プロジェクトのバックエンドエンジニアとして従事。