0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[GO+PostgreSQL+GitHub Actions] サービスコンテナを使ってdocker-composeを使わずにテストを実行しよう

Posted at

前提

  • GitHub Actionsの基本的な用語についてある程度理解している
  • 言語はGOを使用
  • DBはPostgresを使用

サービスコンテナとは

ワークフロー中でアプリケーションをテストもしくはビルドするのに必要なサービスを提供するためのDockerコンテナです
サービスコンテナを使うことでワークフロー内で例えばdocker-composeを使って自前でDBを作成せずにテストを実行することができます
runner内のリソースは限られているのでGitHub側で用意するサービスコンテナなどを使うケースが多いです
また、docker-composeを使わずにワークフローを実行するのでコンテナの起動時間分ワークフローの時間を短縮できます
今回はPostgresのサービスコンテナを使ってテストコードを実行させます

ファイル構成

ファイル構成は以下の通りです

❯ tree 
.
├── .github
│   └── workflows
│       └── test.yml
└── application # GOのプロジェクトファイルおよびgo.mod、go.sumが入ったディレクトリ
    ├── go.mod
    ├── go.sub
    └── main.go

ワークフローの作成

.github/workflows/test.ymlにテストの自動実行までの処理を記載していきます

.github/workflows/test.yml
name: Run Test
on:
  pull_request:
    types: [opened, reopened, synchronize, ready_for_review]

env:
  WORKING_DIRECTORY: application
  POSTGRES_NAME: test
  POSTGRES_USER: test
  POSTGRES_PASSWORD: test
  POSTGRES_HOST: 127.0.0.1
  POSTGRES_PORT: 5432

jobs:
  Test:
    if: |
      github.event.pull_request.draft == false
      && !startsWith(github.head_ref, 'release')
      && !startsWith(github.head_ref, 'doc')
    name: Run Test Code
    runs-on: ubuntu-22.04
    # ルート直下にgo.modを置いている場合は不要
    # 今回はapplication/内にgo.modを含めたGOのソースコードが含まれているため、指定する
    defaults:
      run:
        working-directory: {{ env.WORKING_DIRECTORY }}
    # Postgresのサービスコンテナを設定
    services:
      db:
        # PostgresのDocker imageを使用
        image: postgres:16.2
        ports:
          - 5432:5432
        env:
          POSTGRES_NAME: ${{ env.POSTGRES_NAME }}
          POSTGRES_USER: ${{ env.POSTGRES_USER }}
          POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
        # Postgresより先にGOが起動しないようヘルスチェックを使って起動順を制御
        options: >-
          --health-cmd "pg_isready"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - name: Chekcout code
        uses: actions/checkout@v4
      # GOのセットアップを実行
      # 2回目以降のテスト実行時はrunner内にCacheを生成してGOのセットアップを高速化
      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.20'
          cache: true
          cache-dependency-path: ${{ env.WORKING_DIRECTORY }}/go.sum
      - name: Install dependencies
        run: go get -u
      - name: Build Go
        run: go build -v
      - name: Run Test
        run: go test -p 1 -v ./...

それでは、一つずつ解説していきます

ワークフローを実行する前の設定

以下のように冒頭で

  • どの場面でワークフローを実行するか
  • どの環境変数を使用するか

記載します
今回はがプルリクエスト

  • opened(作成時)
  • reopened(再作成時)
  • synchronize(pushするたびに)
  • ready_for_review(レビューできる状態になったら)

の時にワークフローを実行します
また、envを使うとワークフロー内で使用できる独自の環境変数を定義できます
今回はテストを実行するだけのワークフロー内に秘匿情報を使う必要がないです
そのため、下記のようにsecretsを使わずに環境変数を直書きしています

.github/workflows/test.yml
name: Run Test
on:
  pull_request:
    types: [opened, reopened, synchronize, ready_for_review]

env:
  WORKING_DIRECTORY: application
  POSTGRES_NAME: test
  POSTGRES_USER: test
  POSTGRES_PASSWORD: test
  POSTGRES_HOST: 127.0.0.1
  POSTGRES_PORT: 5432

テストの実行を制限したいとき

テストに関しては

  • draft
  • releaseブランチ
  • docブランチ(ドキュメント作成用)

の時は実行したくないので

.github/workflows/test.yml
if: |
      github.event.pull_request.draft == false
      && !startsWith(github.head_ref, 'release')
      && !startsWith(github.head_ref, 'doc')

を追記します

ワーキングディレクトリの指定

今回はapplication/内にgo.modを含めたGOのソースコードが含まれているため、以下のように記載します

.github/workflows/test.yml
    defaults:
      run:
        working-directory: {{ env.WORKING_DIRECTORY }}

Postgres用のサービスコンテナの設定

Postgresのサービスコンテナを設定する際に

  • Docker image
  • ポート
  • 環境変数
  • ヘルスチェック

を記載します
Docker imageはPostgres16.2のものを使用します

Postgresの環境変数で必要なものは

  • POSTGRES_NAME
  • POSTGRES_USER
  • POSTGRES_PASSWORD

です
上記がないとDBへ接続できずにテストが失敗してしまうので必ず設定しましょう

optionsでヘルスチェックを行い、GOより先にPostgresの起動が完了するよう制御します

ヘルスチェックについて知りたい方は以下の記事を参照してください

.github/workflows/test.yml
    # Postgresのサービスコンテナを設定
    services:
      db:
        # PostgresのDocker imageを使用
        image: postgres:16.2
        ports:
          - 3306:3306
        env:
          POSTGRES_NAME: ${{ env.POSTGRES_NAME }}
          POSTGRES_USER: ${{ env.POSTGRES_USER }}
          POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
        # Postgresより先にGOが起動しないようヘルスチェックを使って起動順を制御
        options: >-
          --health-cmd "pg_isready"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

どうして127.0.0.1を指定しているのか

docker-composeを使う際はPOSTGRES_HOSTにservice名を指定することにより名前解決でPostgresのIPアドレスを取得して接続していましたが、今回はDockerを使わずにランナー上で直接テストを実行しています
公式ドキュメントでも記載しているようにホストを127.0.0.1に指定します

ランナーマシン上でのジョブの実行
ランナーマシン上でジョブを直接実行する場合、localhost:port か 127.0.0.1:port を使ってサービスコンテナにアクセスできます。 GitHubは、サービスコンテナからDockerホストへの通信を可能にするよう、コンテナネットワークを設定します

GOのセットアップとパッケージのインストール

公式ドキュメントに記載の通りGOのセットアップとパッケージのインストールを行います

go.mod内のパッケージをインストールしていきます

cache: true
cache-dependency-path: ${{ env.WORKING_DIRECTORY }}/go.sum

と指定することで2回目以降のpoetry installをCacheを使って高速化させます
スクリーンショット 2024-04-30 15.01.54.png
スクリーンショット 2024-04-30 15.05.03.png

.github/workflows/test.yml
      # GOのセットアップを実行
      # 2回目以降のテスト実行時はrunner内にCacheを生成してGOのセットアップを高速化
      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.20'
          cache: true
          cache-dependency-path: ${{ env.WORKING_DIRECTORY }}/go.sum
      - name: Install dependencies
        run: go get -u

buildの実行

GOのbuildを実行します

.github/workflows/test.yml
      - name: Build Go
        run: go build -v

テストの実行

テストコードを実行します

.github/workflows/test.yml
      - name: Run Test
        run: go test -p 1 -v ./...

ワークフローを実行しよう

PRを作成したらワークフローが実行されます
下記のようにテストが実行できたら成功です

スクリーンショット 2024-04-30 15.04.18.png

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?