[Advent Calendar 2021][Day19]改善リストアップと、CI構築

はじめに

Advent Calendar 2021のDay19。 Day19になり、残りあと1週間となりました。 これまでを振り返りつつ残りの1週間で何を改善していくかを考えたいと思います。

振り返り

ある程度予測は出来たものの、少し予定が変更になるような部分が見受けられました。 Google Appengineをフロントで使おうと思っていましたが、断念したのと、Goをバックエンドに使うというのも現時点では出来ていないです。 あとは、雑に進めてしまった部分があり次の日にバグがあることに気づいて修正したりと、あまり順調ではなかったです。 今回初めて触る技術も多く、Nuxt3やそれに関連する部分は結構ハマりました。 反省点は、多々ありましたが、良かった点もありました。 Nuxt3のことを実際に触って理解できたこと。urqlなどこれまで使ったことのなかったライブラリが結構イケてる。urqlとクエリ自動生成による開発は結構ありだと思いました。

改善すること

開発をしてきた中で、これはほしいなと思っていたのを順に列挙します。

  • CIパイプライン構築
  • CDパイプライン構築
  • 更新・削除機能
  • ドキュメント

CI/CDは最初に作っておけばよかったなと思いました。大抵のプロジェクトでCI/CDを最初に作っているのですが、今回は新機能を試すなどを優先してきました。

CIを構築する

CIパイプラインには、GitHub Actionsを利用しようと思います。 RepositoryはGitHubを使っているので、すぐに利用が出来ます。 また、unittest, integration testを作っているのでCIパイプラインでテストを実施できるようにします。

name: CI
on:
  push:

defaults:
  run:
    shell: bash
    working-directory: ./nuxt3-app

jobs:
  node-dev:
    name: Node Build for Dev
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.CR_PAT }}
      - name: Prepare Firebase Config
        run: |
          echo $FIREBASE_ENV > env.development.ts
        env:
          FIREBASE_ENV: ${{ secrets.FIREBASE_ENV }}
      - name: Build and push for dev
        uses: docker/build-push-action@v2
        with:
          push: true
          context: nuxt3-app
          build-args: |
            GRAPHQL_URL=http://localhost:8080/v1/graphql
          tags: |
            ghcr.io/${{ github.repository_owner }}/advent-calendar-2021/${{ env.IMAGE_NAME }}:latest
            ghcr.io/${{ github.repository_owner }}/advent-calendar-2021/${{ env.IMAGE_NAME }}:${{ github.sha}}
        env:
          IMAGE_NAME: nuxt3-app-dev
  node:
    name: Node Build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.CR_PAT }}
      - name: Prepare Firebase Config
        run: |
          echo $FIREBASE_ENV > env.development.ts
        env:
          FIREBASE_ENV: ${{ secrets.FIREBASE_ENV }}
      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          push: true
          context: nuxt3-app
          build-args: |
            GRAPHQL_URL=https://hasura-graphql-7nqeahsy2q-an.a.run.app/v1/graphql
          tags: |
            ghcr.io/${{ github.repository_owner }}/advent-calendar-2021/${{ env.IMAGE_NAME }}:latest
            ghcr.io/${{ github.repository_owner }}/advent-calendar-2021/${{ env.IMAGE_NAME }}:${{ github.sha}}
        env:
          IMAGE_NAME: nuxt3-app

  hasura:
    name: Hasura Build
    runs-on: ubuntu-latest
    env:
      IMAGE_NAME: hasura
    steps:
      - name: Check out the repo
        uses: actions/checkout@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.CR_PAT }}
      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          push: true
          context: hasura
          tags: |
            ghcr.io/${{ github.repository_owner }}/advent-calendar-2021/${{ env.IMAGE_NAME }}:latest
            ghcr.io/${{ github.repository_owner }}/advent-calendar-2021/${{ env.IMAGE_NAME }}:${{ github.sha}}
  test:
    name: Test
    runs-on: ubuntu-latest
    needs: [node-dev, node, hasura]
    strategy:
      matrix:
        node-version: [14.x]
    steps:
      - name: Check out the repo
        uses: actions/checkout@v2
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.CR_PAT }}
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v2
        with:
          node-version: ${{ matrix.node-version }}
      - name: Prepare Secrets
        run: |
          echo $FIREBASE_ENV > env.development.ts
          echo $FIREBASE_SA_KEY > serviceAccount.json
        env:
          FIREBASE_ENV: ${{ secrets.FIREBASE_ENV }}
          FIREBASE_SA_KEY: ${{ secrets.FIREBASE_SA_KEY }}
      - name: Install
        run: |
          yarn install
      - name: Build
        run: |
          yarn build
      - name: Test
        run: |
          yarn test
      - name: Install Cypress
        uses: cypress-io/github-action@v2
        with:
          runTests: false
          browser: chrome
          working-directory: nuxt3-app
      - name: 'UI Tests - Chrome'
        run: |
          docker-compose up -d
          sleep 10
          yarn e2e
        env:
          TAG: ${{ github.sha }}
          HASURA_GRAPHQL_JWT_SECRET: ${{ secrets.HASURA_GRAPHQL_JWT_SECRET }}
          CYPRESS_TEST_UID: ${{ secrets.CYPRESS_TEST_UID }}

nuxtは、ビルド時に環境変数、たとえば、今回だとGraphqlのエンドポイントURLなどを設定してからビルドする必要があります。ランタイムで設定変更ができないので、ローカル向けのコンテナイメージとCloudRunで動作させるようの2つをビルドするようにしています。

コンテナのビルドが完了したら、unittestとdocker-composeを使ってE2Eテストを実行します。

少し冗長なので、改善するとしたら最近GitHubから発表された再利用可能なWorkflowを定義してみれば、もう少しシンプルにできそうです。またnodeのCacheやDockerのCacheが効くように設定すれば、ビルド時間を短縮することができそうですが今回はこれで良しとします。

GitHubには環境よって変わる情報や秘匿情報をSecretsに設定しておきます。

  • GitHubのRepositoryに設定するSecrets
シークレット説明
CR_PATGitHubのContainer RegistryにアクセスするためのPersonal Access Token
CYPRESS_TEST_UIDCypressFirebaseに渡すFirebase AuthenticationのテストユーザのUID
FIREBASE_ENVFirebaseのConfig
FIREBASE_SA_KEYFirebaseAdminのServiceAccountの鍵情報(json)
HASURA_GRAPHQL_JWT_SECRETHasuraが検証するJWT Secret

まとめ

今回は、改善点のリストアップと、CIパイプラインの構築を行いました。 次回は、CDパイプラインを構築していきます。