GitHub Actions ワークフローのサービスコンテナ機能を利用してみる

create
2021年03月26日
update
2021年03月26日

はじめに🤔

本ブログは Asciidoc 記法で記事を書いており、その中でダイアグラム図を描画するのに Kroki APIサーバーを利用している。
デフォルト設定では公式のAPIサーバーを利用するので、ブログをビルドするたびに負担をかけるのは申し訳ないなぁ、と思ってなんとかしたかった。

そこで GitHub Actions ワークフローで使えるサービスコンテナという機能を利用して、ビルド時に kroki をセルフホストしてみる。

サービスコンテナ📦

GitHub Actions ワークフローのジョブ実行時にいっしょに起動させる Docker コンテナのこと。
テストやビルド時にデータベースやAPIサーバが必要なときに利用する。
(公式ドキュメントでは RedisPostgreSQL のサンプルが紹介されている。)

サービスコンテナの定義は以下のように jobs.<job_id>.services キーで定義する。
なお本記事の例はランナーマシン上での実行を前提としている。

ランナーマシン上って?

GitHub Actions ワークフローにおいて、ジョブを実行する環境は用意されている環境から選ぶだけでなく、任意の Docker コンテナ上で実行させることもできる。

ランナーマシン or コンテナ 上でのジョブ実行
ジョブを実行する環境 指定方法

ランナーマシン

jobs.<job_id>.runs-on で指定。

コンテナ

jobs.<job_id>.container で指定。

よってランナーマシン上での実行とは、 jobs.<job_id>.container を使っていないということ。

Example 1. サービスコンテナの例
.github/workflows/service-container.yml
jobs:
  build:
    runs-on: ubuntu-20.04

    services:   (1)
      kroki:    (2)
        image: yuzutech/kroki   (3)
        ports:
          - 8000:8000   (4)

    steps:
      # ...
1 サービスコンテナを定義するキー。
2 ここで指定したキーがそのままコンテナ名となる。
3 利用する Docker イメージを指定。
4 <host>:<container> を書式とするポートマッピング。
ランナーマシン上で実行する場合はアクセスするために必須。
ランナーマシン上でワークフロー・ジョブを実行する場合、サービスコンテナには http://localhost:<PORT> でアクセスできる。
GitHub Actions のローカル実行ツール act では、残念ながら現時点(v0.2.20)でこのサービスコンテナに対応できていない。

GitHub Actions ワークフローで Kroki コンテナを利用する例🧾

サービスコンテナを使って kroki を利用する GitHub Actions ワークフローおよび AsciidocJavascript の例。

GitHub Actions ワークフロー

krokiDocker コンテナの記述についてはKroki公式ドキュメントの docker-compose.yamlを参考。

ワークフロー全体の例。

Example 2. サービスコンテナでkrokiを利用するワークフロー
.github/workflows/asciidoc.yml
name: Asciidoc with Kroki
on:
  push:
    branches:
      - main
jobs:
  build:
    runs-on: ubuntu-20.04
    services:
      kroki:  (1)
        image: yuzutech/kroki
        env:
          KROKI_MERMAID_HOST: mermaid   (2)
        ports:
          - 8000:8000   (3)
      mermaid:  (4)
        image: yuzutech/kroki-mermaid
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: setup node
        uses: actions/setup-node@v1
        with:
          node-version: '12.x'
      - name: install packages
        run: yarn install
      - name: build
        run: yarn build
1 kroki コンテナの定義を行う。
2 Mermaid 記法は別コンテナで提供されるため、この環境変数に mermaid コンテナ名を指定しておく。
3 ポートマッピング。kroki コンテナは 8000 ポートを利用する。
4 mermaid コンテナの定義。

Asciidoc の例

asciidoctor/core を利用する場合の例。

GitHub Actions ワークフローでは環境変数 GITHUB_ACTIONStrue に設定されているため、それを指標にして条件分岐している。
Example 3. Asciidoc
= サービスコンテナkrokiのテスト
ifdef::env-github[]   (1)
:kroki-server-url: http://localhost:8000
:kroki-default-options: inline
endif::[]

`kroki` Docerコンテナのテスト。

.Mermaid.js
[mermaid, mermaid.js, svg]
....
gantt
  title サンプル

  section サンプルタスク
    apple :a, 2017-07-20, 1w
    banana :crit, b, 2017-07-23, 1d
    ぶどう :active, c, after b a, 1d
    オレンジ  : d, after c, 3d
....
1 env-github 属性が設定されていれば kroki はローカルサーバーのものを利用する。
Example 4. Asciidocを変換するjavascript
/** @type {import('@asciidoctor/core').Asciidoctor} */
const asciidoctor = require('@asciidoctor/core')()
const kroki = require('asciidoctor-kroki')
const { resolve } = require('path')

kroki.register(asciidoctor.Extensions)

const doc = asciidoctor.convertFile(resolve(__dirname, 'test.adoc'), {
  safe: 'safe',
  mkdirs: true,
  base_dir: __dirname,
  to_dir: 'dist',
  attributes: Object.assign(
    { 'allow-uri-read': true },
    process.env.GITHUB_ACTIONS != null ? { 'env-github': true } : undefined   (1)
  ),
})

// output file
doc.convert()
1 環境変数 GITHUB_ACTIONS が設定されていれば、条件分岐用に env-github 属性を設定しておく。

おわりに😎

GitHub Actions ワークフローのサービスコンテナを使うことで外部APIサーバーに負担をかけなくてすむようになった。
ついでに外部通信がなくなることでワークフローの実行時間も短縮できた。

こういう便利な機能を知らなかったの悔しい😣。