爆速にdocker composeを使うためのGitHub ActionをMarketplaceに出した

GitHub Actions上で docker compose を爆速に使うための GitHub Action 「Spin-Up Docker Compose」を Marketplace に出しました。

https://github.com/marketplace/actions/spin-up-docker-compose

# 背景

先日、「[GitHub Actions上でdocker composeを使ってCIを回すためにうまいことキャッシュする方法](https://qiita.com/yu-ichiro/items/c1a1248c0cdeeb0e6b42)」という記事を投稿させていただきました。

https://qiita.com/yu-ichiro/items/c1a1248c0cdeeb0e6b42

ありがたいことにさまざまな方にLGTMをいただくことができ、参考にしていただけたのかなと思っています。

さて、当該の記事への反応を確認しようとはてなブックマークなども閲覧させていただいていたのですが、気になるコメントを見つけました

![naari_3: このあたり1発で簡単に書けるようにならんかなぁーー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39754/c246a49b-dbfc-02f6-6634-76169ae1435d.png)

たしかに！いい感じの docker compose 環境を作れたとして、プロジェクトごとにあの分量のymlをコピペして調整して回るのは大変ですよね。

ということで、前回の記事で用意した環境をパッケージ化し、単一のGitHub Actionとしてさまざまなプロジェクトに簡単に導入できるようにしてみました。（[naari_3](https://b.hatena.ne.jp/naari_3/20220628#bookmark-4721560264628545186)さん、ありがとうございます！）

# 使い方

基本的な使い方は以下のようになっています。fileオプションのみが必須となっています。

```project/.github/workflows/ci.yml
name: CI

on:
  push:
jobs:
  # イメージのビルド
  build_image:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml  # ターゲットとなる yaml ファイルを指定
      # この step 以下で docker compose が up された状態になっている
      - name: Check Batch Runner
        run: docker compose exec my-runner bash -c 'cat <(curl -s echo:5678) /the_message'
```

# オプションの説明

より詳しい情報はレポジトリのREADMEもご参照ください

https://github.com/yu-ichiro/spin-up-docker-compose-action/blob/main/README.md


## file

ターゲットとなる yaml ファイルを指定します。必須です。レポジトリのルートからの相対パスで指定します。

```yaml
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml  # ターゲットとなる yaml ファイルを指定
```

## registry

GitHub Actions内でキャッシュされる、localhost上で動くregistry立ち上げるためのオプションです。

```yaml
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml
          registry: true  # registry を使用する
```

## localhost

後述する、ビルドするイメージのregistryを書き換え、localhostへ向け直すためのオプションです。registryとともに利用します

```yaml
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml
          registry: true  # registry を使用する
          localhost: true  # ビルドしたイメージのregistryをlocalhostに書き換える
```

## shared

registry と localhost を同時に指定する場合の syntax sugar になっています。

```diff_yaml
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml
-         registry: true  # registry を使用する
-         localhost: true  # ビルドしたイメージのregistryをlocalhostに書き換える
+         shared: true  # 以上二つを指定した場合と同じ
```

## pull

docker compose pull を実行するか、のオプションになります。pull-optsにオプションを渡すことで細かい挙動を変えることができます。

```yaml
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml
          pull: true  # docker compose pull を実行する
          pull-opts: "--ignore-pull-failures"  # pull時のエラーを無視する
```

## bake

docker buildx bake を実行するか、のオプションになります。このオプションが有効になると、buildxのセットアップなども走るようになり、ビルドキャッシュも効くようになります。bake-optsにオプションを渡すことで挙動を変更できます

```yaml
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml
          bake: true  # docker buildx bake を実行する
          bake-opts: --metadata-file metadata.json  # ビルド時のメタデータをjsonに吐き出す
```

## push

docker buildx bake 時に push を実行するかを設定できます。【注意】 localhost オプションを設定していない場合、push 先は compose.yml に従います。

```yaml
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml
          registry: true  # registry を使用する
          localhost: true  # ビルドしたイメージのregistry（プッシュ先）をlocalhostに書き換える
          bake: true  # docker buildx bake を実行する
          push: true  # localhostにプッシュする
```

## up

docker compose up を実行します。デフォルトで true　になっており、 up-opts のデフォルトが "-d" であるため、何も設定しなければdocker compose環境が立ち上がるようになっています。

```yaml
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml
          # デフォルトの挙動
          up: true
          up-opts: -d
      # ここ以下で docker compose　環境が使える
```

# localhost オプションについて

デフォルトでは渡された compose.yml をそのまま読むようになっていますが、このオプションを使うと image: を書き換え、イメージの registry が localhost:5000 を向くように変更されます。これによって、セットアップを意識しない yaml の記述が可能になります。(正確な動作は [convert.py](https://github.com/yu-ichiro/spin-up-docker-compose-action/blob/main/convert.py#L31-L37) を参照していただければと思います)

なお、名前とタグは自動で設定される（なにも名前などを指定しなかった場合のdocker composeの挙動を模しています）ため、微調整を行いたい場合は適宜特化したymlを用意し、localhostオプションはオフにしてご利用ください。

```diff_yaml:app/compose.yml
 version: 'Compose-Spec'
 services:
   hoge:
     image: ghcr.io/hoge:v1
   fuga:
     # 以下が自動で書き換えられます（タグは自動設定）
-    image: ghcr.io/fuga:v2
+    image: localhost:5000/app_fuga:latest
     build:
       context: .
```

# 前回の記事の動作を再現したもの

以上のオプションを組み合わせることで、前回の記事でご紹介させていただいたセットアップを再現することができます。

```app/.github/workflows/ci.yml
name: CI

on:
  push:
jobs:
  # イメージのビルド
  build_image:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml
          shared: true  # localhost　の　registryを使い、ビルドの向き先を書き換える
          bake: true  # docker buildx bake を実行する
          push: true  # localhostにプッシュする
          up: false  # docker compose up は実行しない
          
  use_image:
    needs: build_image  # ビルド用のjobの完了を待つ
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Setup Docker Compose
        uses: yu-ichiro/spin-up-docker-compose-action@v1
        with:
          file: app/compose.yml
          shared: true  # localhost　の　registryを使い、プルの向き先を書き換える
          pull: true  # build_image で作ったイメージをプルする
          # up を指定していないので docker compose up -d が実行される
      - name: Check Batch Runner
        run: docker compose exec my-runner bash -c 'cat <(curl -s echo:5678) /the_message'

  # 複数のjobで並列に利用することができます
  use_image2:
    needs: build_image  # ビルド用のjobの完了を待つ
　　　　　　　　# ... 省略 ...
```

# 詰まったところ

さて今回、汎用的なActionsを作るために一連の動作をオプションで区切れるようにしていったのですが、一箇所解決できなくて詰まったところがありました。それが、buildxでビルドしたイメージが docker compose up -d で使われない、というものでした。

![ビルドが終わったのにもう一回ビルドが走る](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39754/38079a00-4334-aa7e-bb5d-bc32b92a2a90.png)

結論としては、imageタグが指定されていない場合の動作が、docker compose build と docker buildx bake で異なっており、前者は compose.yml が存在するディレクトリ名とサービス名を組み合わせて自動的にイメージ名・タグを割り振ってくれるのに対し、後者は `<none>` となってしまっていたからでした。（ https://github.com/docker/buildx/issues/902 ）

https://twitter.com/yu___smith/status/1542073066205097984?s=20&t=wSk3zOQWL4MiOGqXCkJ-PQ

解決方法として、buildだけが指定されていてimageがない場合はdocker compose buildの挙動に合わせたイメージ名、タグを指定するようにyamlを書き換えるようになっています。（→ [convert.py](https://github.com/yu-ichiro/spin-up-docker-compose-action/blob/main/convert.py#L21-L28) )

このワークアラウンドを使用することで、buildxサブコマンドをシームレスに使うことができるようになっています。

# ぜひご利用ください

他の細かい挙動は基本的に前回の記事でご紹介したものがそのまま詰まったものになっています。GitHub Actionsで docker compose　をストレスなく使えるようになると、CI をとっても簡単に整備することができるようになります。ぜひ便利にご利用いただければと思います！

https://github.com/marketplace/actions/spin-up-docker-compose

https://github.com/yu-ichiro/spin-up-docker-compose-action